icon caching

svn path=/trunk/; revision=7450
This commit is contained in:
Martin Fuchs 2004-01-04 17:11:53 +00:00
parent 7babf71f1f
commit 3073e11cf8
18 changed files with 425 additions and 270 deletions

View file

@ -60,7 +60,7 @@ void CollectProgramsThread::collect_programs(const ShellPath& path)
ShellDirectory* dir = new ShellDirectory(Desktop(), path, 0);
_dirs.push(dir);
dir->smart_scan(SCAN_EXTRACT_ICONS|SCAN_FILESYSTEM);
dir->smart_scan(/*SCAN_EXTRACT_ICONS|*/SCAN_FILESYSTEM);
for(Entry*entry=dir->_down; entry; entry=entry->_next) {
if (!_alive)
@ -70,10 +70,7 @@ void CollectProgramsThread::collect_programs(const ShellPath& path)
continue;
if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
ShellPath shell_path;
if (get_entry_pidl(entry, shell_path))
collect_programs(shell_path);
collect_programs(entry->create_absolute_pidl());
} else if (entry->_shell_attribs & SFGAO_LINK)
if (_alive)
_callback(entry, _para);
@ -212,11 +209,7 @@ void FindProgramDlg::collect_programs_callback(Entry* entry, void* param)
new_entry._entry = entry;
new_entry._menu_path = menu_path;
new_entry._path = path;
if (entry->_hIcon != (HICON)-1)
new_entry._idxIcon = ImageList_AddIcon(pThis->_himl, entry->_hIcon);
else
new_entry._idxIcon = pThis->_idxNoIcon;
new_entry._idxIcon = I_IMAGECALLBACK;
pThis->_cache.push_front(new_entry);
FPDEntry& cache_entry = pThis->_cache.front();
@ -311,22 +304,23 @@ void FindProgramDlg::LaunchSelected()
int FindProgramDlg::Notify(int id, NMHDR* pnmh)
{
switch(pnmh->code) {
case LVN_GETDISPINFO: {/*
case LVN_GETDISPINFO: {
LV_DISPINFO* pDispInfo = (LV_DISPINFO*) pnmh;
if (pnmh->hwndFrom == _list_ctrl) {
if (pDispInfo->item.mask & LVIF_IMAGE) {
int icon;
HRESULT hr = pShellLink->GetIconLocation(path, MAX_PATH-1, &icon);
FPDEntry& cache_entry = *(FPDEntry*)pDispInfo->item.lParam;
Entry* entry = cache_entry._entry;
HICON hIcon = ExtractIcon();
pDispInfo->item.iImage = ImageList_AddIcon(_himl, hIcon);
if (entry->_icon_id == ICID_UNKNOWN)
entry->extract_icon();
pDispInfo->item.iImage = ImageList_AddIcon(_himl, g_Globals._icon_cache.get_icon(entry->_icon_id)._hIcon); //@@ directly use image list in icon cache
pDispInfo->item.mask |= LVIF_DI_SETITEM;
return 1;
}
}*/}
}}
break;
case NM_DBLCLK:

View file

@ -53,3 +53,4 @@ If you search for more information, look into the CVS repository.
02.01.2004 m. fuchs reimplemented start menu as light weight version
03.01.2004 m. fuchs lazy icon extraction for start menu
direct file system access for start menu
04.01.2004 m. fuchs implemented icon cache

View file

@ -3,7 +3,7 @@
<tr>
<td><address style="align: right;"><small>
ROS Explorer Source Code Documentation
<br>generated on 03.01.2004 by <a href="http://www.doxygen.org/index.html">
<br>generated on 04.01.2004 by <a href="http://www.doxygen.org/index.html">
<img src="doxygen.png" alt="doxygen" align="middle" border=0>
</small></address>
</td>

View file

@ -67,6 +67,18 @@ ExplorerGlobals::ExplorerGlobals()
}
void ExplorerGlobals::init(HINSTANCE hInstance)
{
_hInstance = hInstance;
#ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
_SHRestricted = (DWORD(STDAPICALLTYPE*)(RESTRICTIONS)) GetProcAddress(GetModuleHandle(TEXT("SHELL32")), "SHRestricted");
#endif
_icon_cache.init();
}
void _log_(LPCTSTR txt)
{
FmtString msg(TEXT("%s\n"), txt);
@ -81,7 +93,7 @@ void _log_(LPCTSTR txt)
const FileTypeInfo& FileTypeManager::operator[](String ext)
{
#ifndef __WINE__ ///@todo
_tcslwr((LPTSTR)ext.data());
_tcslwr((LPTSTR)ext.c_str());
#endif
iterator found = find(ext);
@ -111,6 +123,153 @@ const FileTypeInfo& FileTypeManager::operator[](String ext)
}
Icon::Icon()
: _id(ICID_UNKNOWN),
_itype(IT_STATIC),
_hIcon(0)
{
}
Icon::Icon(ICON_ID id, UINT nid)
: _id(id),
_itype(IT_STATIC),
_hIcon(SmallIcon(nid))
{
}
Icon::Icon(ICON_TYPE itype, int id, HICON hIcon)
: _id((ICON_ID)id),
_itype(itype),
_hIcon(hIcon)
{
}
int IconCache::s_next_id = ICID_DYNAMIC;
void IconCache::init()
{
_icons[ICID_NONE] = Icon(IT_STATIC, ICID_NONE, 0);
_icons[ICID_FOLDER] = Icon(ICID_FOLDER, IDI_FOLDER);
//_icons[ICID_DOCUMENT] = Icon(ICID_DOCUMENT, IDI_DOCUMENT);
_icons[ICID_EXPLORER] = Icon(ICID_EXPLORER, IDI_EXPLORER);
_icons[ICID_APP] = Icon(ICID_APP, IDI_APPICON);
_icons[ICID_CONFIG] = Icon(ICID_CONFIG, IDI_CONFIG);
_icons[ICID_DOCUMENTS] = Icon(ICID_DOCUMENTS, IDI_DOCUMENTS);
_icons[ICID_FAVORITES] = Icon(ICID_FAVORITES, IDI_FAVORITES);
_icons[ICID_INFO] = Icon(ICID_INFO, IDI_INFO);
_icons[ICID_APPS] = Icon(ICID_APPS, IDI_APPS);
_icons[ICID_SEARCH] = Icon(ICID_SEARCH, IDI_SEARCH);
_icons[ICID_ACTION] = Icon(ICID_ACTION, IDI_ACTION);
_icons[ICID_SEARCH_DOC] = Icon(ICID_SEARCH_DOC, IDI_SEARCH_DOC);
_icons[ICID_PRINTER] = Icon(ICID_PRINTER, IDI_PRINTER);
_icons[ICID_NETWORK] = Icon(ICID_NETWORK, IDI_NETWORK);
_icons[ICID_COMPUTER] = Icon(ICID_COMPUTER, IDI_COMPUTER);
_icons[ICID_LOGOFF] = Icon(ICID_LOGOFF, IDI_LOGOFF);
}
const Icon& IconCache::extract(IExtractIcon* pExtract, LPCTSTR path, int idx)
{
HICON hIconLarge = 0;
HICON hIcon;
HRESULT hr = pExtract->Extract(path, idx, &hIconLarge, &hIcon, MAKELONG(0/*GetSystemMetrics(SM_CXICON)*/,GetSystemMetrics(SM_CXSMICON)));
if (hr == NOERROR) {
if (hIconLarge)
DestroyIcon(hIconLarge);
if (hIcon)
return add(hIcon);
}
return _icons[ICID_NONE];
}
const Icon& IconCache::extract_from_file(LPCTSTR path, int idx)
{
CachePair key(path, idx);
#ifndef __WINE__ ///@todo
_tcslwr((LPTSTR)key.first.c_str());
#endif
CacheMap::iterator found = _cache_map.find(key);
if (found != _cache_map.end())
return _icons[found->second];
HICON hIcon;
if ((int)ExtractIconEx(path, idx, NULL, &hIcon, 1) > 0) {
const Icon& icon = add_cached(hIcon, path, idx);
_cache_map[key] = icon._id;
return icon;
} else
return _icons[ICID_NONE];
}
const Icon& IconCache::add(HICON hIcon)
{
int id = ++s_next_id;
return _icons[id] = Icon(IT_DYNAMIC, id, hIcon);
}
const Icon& IconCache::add_cached(HICON hIcon, LPCTSTR path, int idx)
{
int id = ++s_next_id;
return _icons[id] = Icon(IT_CACHED, id, hIcon);
}
const Icon& IconCache::get_icon(int id)
{
return _icons[id];
}
HBITMAP IconCache::get_icon_bitmap(int id, HBRUSH hbrBkgnd, HDC hdc)
{
return create_bitmap_from_icon(_icons[id]._hIcon, hbrBkgnd, hdc);
}
void IconCache::free_icon(int icon_id)
{
IconMap::iterator found = _icons.find(icon_id);
if (found != _icons.end()) {
Icon& icon = found->second;
if (icon._itype == IT_DYNAMIC) {
DestroyIcon(icon._hIcon);
_icons.erase(found);
}
}
}
HBITMAP create_bitmap_from_icon(HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd)
{
HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, 16, 16);
MemCanvas canvas;
BitmapSelection sel(canvas, hbmp);
RECT rect = {0, 0, 16, 16};
FillRect(canvas, &rect, hbrush_bkgnd);
DrawIconEx(canvas, 0, 0, hIcon, 16, 16, 0, hbrush_bkgnd, DI_NORMAL);
return hbmp;
}
ResString::ResString(UINT nid)
{
TCHAR buffer[BUFFER_LEN];
@ -394,10 +553,7 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL
initialize_gdb_stub();
}
g_Globals._hInstance = hInstance;
#ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
g_Globals._SHRestricted = (DWORD(STDAPICALLTYPE*)(RESTRICTIONS)) GetProcAddress(GetModuleHandle(TEXT("SHELL32")), "SHRestricted");
#endif
g_Globals.init(hInstance);
// initialize COM and OLE before creating the desktop window
OleInit usingCOM;

View file

@ -54,8 +54,8 @@
#define IDI_FLOATING 135
#define IDD_ABOUT_EXPLORER 135
#define IDI_REACTOS_BIG 137
#define IDI_CONFIG 138
#define IDI_DOCUMENTS 139
#define IDI_DOCUMENTS 138
#define IDI_CONFIG 139
#define IDI_FAVORITES 140
#define IDI_INFO 141
#define IDI_APPS 142

View file

@ -40,11 +40,86 @@ struct FileTypeManager : public map<String, FileTypeInfo>
};
/// structure containing global variable of Explorer
enum ICON_TYPE {
IT_STATIC,
IT_CACHED,
IT_DYNAMIC,
IT_SYSCACHE
};
enum ICON_ID {
ICID_UNKNOWN,
ICID_NONE,
ICID_FOLDER,
//ICID_DOCUMENT,
ICID_APP,
ICID_EXPLORER,
ICID_CONFIG,
ICID_DOCUMENTS,
ICID_FAVORITES,
ICID_INFO,
ICID_APPS,
ICID_SEARCH,
ICID_ACTION,
ICID_SEARCH_DOC,
ICID_PRINTER,
ICID_NETWORK,
ICID_COMPUTER,
ICID_LOGOFF,
ICID_DYNAMIC
};
struct Icon {
ICON_ID _id;
ICON_TYPE _itype;
HICON _hIcon;
Icon();
Icon(ICON_ID id, UINT nid);
Icon(ICON_TYPE itype, int id, HICON hIcon);
};
struct IconCache {
void init();
const Icon& extract(IExtractIcon* pExtract, LPCTSTR path, int idx);
const Icon& extract_from_file(LPCTSTR path, int idx);
const Icon& add(HICON hIcon);
const Icon& add_cached(HICON hIcon, LPCTSTR path, int idx);
const Icon& get_icon(int icon_id);
HBITMAP get_icon_bitmap(int icon_id, HBRUSH hbrBkgnd, HDC hdc);
void free_icon(int icon_id);
protected:
typedef map<int, Icon> IconMap;
typedef pair<String, int> CachePair;
typedef map<CachePair, ICON_ID> CacheMap;
static int s_next_id;
IconMap _icons;
CacheMap _cache_map;
};
/// create a bitmap from an icon
extern HBITMAP create_bitmap_from_icon(HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd);
/// structure containing global variables of Explorer
extern struct ExplorerGlobals
{
ExplorerGlobals();
void init(HINSTANCE hInstance);
HINSTANCE _hInstance;
ATOM _hframeClass;
UINT _cfStrFName;
@ -59,6 +134,7 @@ extern struct ExplorerGlobals
#endif
FileTypeManager _ftype_mgr;
IconCache _icon_cache;
} g_Globals;

View file

@ -44,7 +44,7 @@ Entry::Entry(ENTRY_TYPE etype)
_scanned = false;
_bhfi_valid = false;
_level = 0;
_hIcon = 0;
_icon_id = ICID_UNKNOWN;
_display_name = _data.cFileName;
}
@ -58,7 +58,7 @@ Entry::Entry(Entry* parent, ENTRY_TYPE etype)
_scanned = false;
_bhfi_valid = false;
_level = 0;
_hIcon = 0;
_icon_id = ICID_UNKNOWN;
_display_name = _data.cFileName;
}
@ -82,7 +82,7 @@ Entry::Entry(const Entry& other)
_display_name = other._display_name==other._data.cFileName? _data.cFileName: _tcsdup(other._display_name);
_etype = other._etype;
_hIcon = other._hIcon;
_icon_id = other._icon_id;
_bhfi = other._bhfi;
_bhfi_valid = other._bhfi_valid;
@ -91,8 +91,8 @@ Entry::Entry(const Entry& other)
// free a directory entry
Entry::~Entry()
{
if (_hIcon && _hIcon!=(HICON)-1)
DestroyIcon(_hIcon);
if (_icon_id > ICID_NONE)
g_Globals._icon_cache.free_icon(_icon_id);
if (_display_name != _data.cFileName)
free(_display_name);
@ -295,6 +295,78 @@ void Entry::smart_scan(int scan_flags)
}
ShellPath Entry::create_absolute_pidl() const
{
CONTEXT("Entry::create_absolute_pidl()");
TCHAR path[MAX_PATH];
if (get_path(path))
return ShellPath(path);
return ShellPath();
}
void Entry::extract_icon()
{
ICON_ID icon_id = ICID_NONE;
IExtractIcon* pExtract;
if (SUCCEEDED(GetUIObjectOf(0, IID_IExtractIcon, (LPVOID*)&pExtract))) {
TCHAR path[MAX_PATH];
unsigned flags;
int idx;
if (SUCCEEDED(pExtract->GetIconLocation(GIL_FORSHELL, path, MAX_PATH, &idx, &flags))) {
if (flags & GIL_NOTFILENAME)
icon_id = g_Globals._icon_cache.extract(pExtract, path, idx)._id;
else {
if (idx == -1)
idx = 0; // special case for some control panel applications ("System")
icon_id = g_Globals._icon_cache.extract_from_file(path, idx)._id;
}
/* using create_absolute_pidl() [see below] results in more correct icons for some control panel applets ("NVidia").
if (icon_id == ICID_NONE) {
SHFILEINFO sfi;
if (SHGetFileInfo(path, 0, &sfi, sizeof(sfi), SHGFI_ICON|SHGFI_SMALLICON))
icon_id = g_Globals._icon_cache.add(sfi.hIcon)._id;
}
*/
/*
if (icon_id == ICID_NONE) {
LPBYTE b = (LPBYTE) alloca(0x10000);
SHFILEINFO sfi;
FILE* file = fopen(path, "rb");
if (file) {
int l = fread(b, 1, 0x10000, file);
fclose(file);
if (l)
icon_id = g_Globals._icon_cache.add(CreateIconFromResourceEx(b, l, TRUE, 0x00030000, 16, 16, LR_DEFAULTCOLOR));
}
}
*/ }
}
if (icon_id == ICID_NONE) {
SHFILEINFO sfi;
const ShellPath& pidl_abs = create_absolute_pidl();
LPCITEMIDLIST pidl = pidl_abs;
if (SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_PIDL|SHGFI_ICON|SHGFI_SMALLICON)) //@@ besser SHGFI_SYSICONINDEX ?
icon_id = g_Globals._icon_cache.add(sfi.hIcon)._id;
}
_icon_id = icon_id;
}
BOOL Entry::launch_entry(HWND hwnd, UINT nCmdShow)
{
TCHAR cmd[MAX_PATH];

View file

@ -75,7 +75,7 @@ public:
LPTSTR _display_name;
ENTRY_TYPE _etype;
HICON _hIcon;
int /*ICON_ID*/ _icon_id;
BY_HANDLE_FILE_INFORMATION _bhfi;
bool _bhfi_valid;
@ -86,11 +86,13 @@ public:
Entry* read_tree(const void* path, SORT_ORDER sortOrder);
void sort_directory(SORT_ORDER sortOrder);
void smart_scan(int scan_flags=SCAN_ALL);
void extract_icon();
virtual void read_directory(int scan_flags=SCAN_ALL) {}
virtual const void* get_next_path_component(const void*) {return NULL;}
virtual Entry* find_entry(const void*) {return NULL;}
virtual bool get_path(PTSTR path) const = 0;
virtual ShellPath create_absolute_pidl() const;
virtual HRESULT GetUIObjectOf(HWND hWnd, REFIID riid, LPVOID* ppvOut);
virtual BOOL launch_entry(HWND hwnd, UINT nCmdShow=SW_SHOWNORMAL);
};

View file

@ -501,8 +501,8 @@ void Pane::draw_item(LPDRAWITEMSTRUCT dis, Entry* entry, int calcWidthCol)
if (cx > IMAGE_WIDTH)
cx = IMAGE_WIDTH;
if (entry->_hIcon && entry->_hIcon!=(HICON)-1)
DrawIconEx(dis->hDC, img_pos, dis->rcItem.top, entry->_hIcon, cx, GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
if (entry->_icon_id > ICID_NONE)
DrawIconEx(dis->hDC, img_pos, dis->rcItem.top, g_Globals._icon_cache.get_icon(entry->_icon_id)._hIcon, cx, GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
else
ImageList_DrawEx(_himl, img, dis->hDC,
img_pos, dis->rcItem.top, cx,

View file

@ -121,10 +121,7 @@ ShellPath ShellEntry::create_absolute_pidl() const
if (dir->_pidl->mkid.cb) // Caching of absolute PIDLs could enhance performance.
return _pidl.create_absolute_pidl(dir->create_absolute_pidl());
} else {
ShellPath shell_path;
if (get_entry_pidl(_up, shell_path))
return _pidl.create_absolute_pidl(shell_path);
return _pidl.create_absolute_pidl(_up->create_absolute_pidl());
}
return _pidl;
@ -151,14 +148,6 @@ bool ShellEntry::get_path(PTSTR path) const
}
HRESULT ShellEntry::GetUIObjectOf(HWND hWnd, REFIID riid, LPVOID* ppvOut)
{
LPCITEMIDLIST pidl = _pidl;
return get_parent_folder()->GetUIObjectOf(hWnd, 1, &pidl, riid, NULL, ppvOut);
}
// get full path of a shell folder
bool ShellDirectory::get_path(PTSTR path) const
{
@ -211,100 +200,11 @@ BOOL ShellEntry::launch_entry(HWND hwnd, UINT nCmdShow)
}
static HICON extract_icon(IShellFolder* folder, LPCITEMIDLIST pidl)
HRESULT ShellEntry::GetUIObjectOf(HWND hWnd, REFIID riid, LPVOID* ppvOut)
{
CONTEXT("extract_icon()");
LPCITEMIDLIST pidl = _pidl;
IExtractIcon* pExtract;
if (SUCCEEDED(folder->GetUIObjectOf(0, 1, (LPCITEMIDLIST*)&pidl, IID_IExtractIcon, 0, (LPVOID*)&pExtract))) {
TCHAR path[MAX_PATH];
unsigned flags;
HICON hIcon;
int idx;
if (SUCCEEDED(pExtract->GetIconLocation(GIL_FORSHELL, path, MAX_PATH, &idx, &flags))) {
if (!(flags & GIL_NOTFILENAME)) {
if (idx == -1)
idx = 0; // special case for some control panel applications
if ((int)ExtractIconEx(path, idx, 0, &hIcon, 1) > 0)
flags &= ~GIL_DONTCACHE;
} else {
HICON hIconLarge = 0;
HRESULT hr = pExtract->Extract(path, idx, &hIconLarge, &hIcon, MAKELONG(0/*GetSystemMetrics(SM_CXICON)*/,GetSystemMetrics(SM_CXSMICON)));
if (SUCCEEDED(hr))
DestroyIcon(hIconLarge);
}
if (!hIcon) {
SHFILEINFO sfi;
if (SHGetFileInfo(path, 0, &sfi, sizeof(sfi), SHGFI_ICON|SHGFI_SMALLICON))
hIcon = sfi.hIcon;
}
/*
if (!hIcon) {
LPBYTE b = (LPBYTE) alloca(0x10000);
SHFILEINFO sfi;
FILE* file = fopen(path, "rb");
if (file) {
int l = fread(b, 1, 0x10000, file);
fclose(file);
if (l)
hIcon = CreateIconFromResourceEx(b, l, TRUE, 0x00030000, 16, 16, LR_DEFAULTCOLOR);
}
}
*/
return hIcon;
}
}
return 0;
}
static HICON extract_icon(IShellFolder* folder, const ShellEntry* entry)
{
HICON hIcon = extract_icon(folder, entry->_pidl);
if (!hIcon) {
SHFILEINFO sfi;
ShellPath pidl_abs = entry->create_absolute_pidl();
LPCITEMIDLIST pidl = pidl_abs;
if (SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_PIDL|SHGFI_ICON|SHGFI_SMALLICON))
hIcon = sfi.hIcon;
}
return hIcon;
}
HICON extract_icon(const Entry* entry)
{
if (entry->_etype == ET_SHELL) {
const ShellEntry* shell_entry = static_cast<const ShellEntry*>(entry);
return extract_icon(shell_entry->get_parent_folder(), shell_entry);
} else {
TCHAR path[MAX_PATH];
if (entry->get_path(path)) {
SHFILEINFO sfi;
ShellPath shell_path(path);
LPCITEMIDLIST pidl = shell_path;
if (SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_PIDL|SHGFI_ICON|SHGFI_SMALLICON))
return sfi.hIcon;
}
}
return 0;
return get_parent_folder()->GetUIObjectOf(hWnd, 1, &pidl, riid, NULL, ppvOut);
}
@ -361,15 +261,10 @@ void ShellDirectory::read_directory(int scan_flags)
memcpy(&entry->_data, &w32fd, sizeof(WIN32_FIND_DATA));
if (!(w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
if (scan_flags & SCAN_EXTRACT_ICONS) {
entry->_hIcon = extract_icon(entry);
if (!entry->_hIcon)
entry->_hIcon = (HICON)-1; // don't try again later
} else
entry->_hIcon = 0;
if (scan_flags & SCAN_EXTRACT_ICONS)
entry->extract_icon();
} else
entry->_hIcon = (HICON)-1; // don't try again later
entry->_icon_id = ICID_NONE; // don't try again later
entry->_down = NULL;
entry->_expanded = false;
@ -510,15 +405,10 @@ void ShellDirectory::read_directory(int scan_flags)
// get icons for files and virtual objects
if (!(entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
!(attribs & SFGAO_FILESYSTEM)) {
if (scan_flags & SCAN_EXTRACT_ICONS) {
entry->_hIcon = extract_icon(_folder, static_cast<ShellEntry*>(entry));
if (!entry->_hIcon)
entry->_hIcon = (HICON)-1; // don't try again later
} else
entry->_hIcon = 0;
if (scan_flags & SCAN_EXTRACT_ICONS)
entry->extract_icon();
} else
entry->_hIcon = (HICON)-1; // don't try again later
entry->_icon_id = ICID_NONE; // don't try again later
entry->_down = NULL;
entry->_expanded = false;
@ -575,16 +465,13 @@ int ShellDirectory::extract_icons()
int cnt = 0;
for(Entry*entry=_down; entry; entry=entry->_next)
if (!entry->_hIcon) {
if (entry->_etype == ET_SHELL)
entry->_hIcon = extract_icon(_folder, static_cast<ShellEntry*>(entry));
else // !ET_SHELL
entry->_hIcon = extract_icon(entry);
if (entry->_icon_id == ICID_UNKNOWN) {
entry->extract_icon();
if (entry->_hIcon)
if (entry->_icon_id != ICID_NONE)
++cnt;
else
entry->_hIcon = (HICON)-1; // don't try again later
entry->_icon_id = ICID_NONE; // don't try again later
}
return cnt;

View file

@ -33,11 +33,11 @@ struct ShellEntry : public Entry
ShellEntry(Entry* parent, const ShellPath& shell_path) : Entry(parent, ET_SHELL), _pidl(shell_path) {}
virtual bool get_path(PTSTR path) const;
virtual ShellPath create_absolute_pidl() const;
virtual BOOL launch_entry(HWND hwnd, UINT nCmdShow=SW_SHOWNORMAL);
virtual HRESULT GetUIObjectOf(HWND hWnd, REFIID riid, LPVOID* ppvOut);
IShellFolder* get_parent_folder() const;
ShellPath create_absolute_pidl() const;
ShellPath _pidl; // parent relative PIDL
@ -46,23 +46,6 @@ protected:
ShellEntry(const ShellPath& shell_path) : Entry(ET_SHELL), _pidl(shell_path) {}
};
bool inline get_entry_pidl(Entry* entry, ShellPath& shell_path)
{
if (entry->_etype == ET_SHELL) {
shell_path = static_cast<ShellEntry*>(entry)->create_absolute_pidl();
return true;
} else {
TCHAR path[MAX_PATH];
if (!entry->get_path(path))
return false;
shell_path = path;
return true;
}
}
/// shell folder entry
struct ShellDirectory : public ShellEntry, public Directory
@ -138,5 +121,3 @@ inline IShellFolder* ShellEntry::get_parent_folder() const
else
return Desktop();
}
extern HICON extract_icon(const Entry* entry);

View file

@ -29,6 +29,7 @@
#include "../utility/utility.h"
#include "../explorer.h"
#include "../globals.h"
#include "quicklaunch.h"
@ -120,7 +121,7 @@ void QuickLaunchBar::AddShortcuts()
// hide subfolders
if (!(entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
HBITMAP hbmp = create_bitmap_from_icon(entry->_hIcon, GetSysColorBrush(COLOR_BTNFACE), canvas);
HBITMAP hbmp = g_Globals._icon_cache.get_icon_bitmap(entry->_icon_id, GetSysColorBrush(COLOR_BTNFACE), canvas);
TBADDBITMAP ab = {0, (UINT_PTR)hbmp};
int bmp_idx = SendMessage(_hwnd, TB_ADDBITMAP, 1, (LPARAM)&ab);

View file

@ -162,7 +162,7 @@ LRESULT StartMenu::Init(LPCREATESTRUCT pcs)
#else
if (!GetWindow(_hwnd, GW_CHILD))
#endif
AddButton(ResString(IDS_EMPTY), 0, false, 0, false);
AddButton(ResString(IDS_EMPTY), ICID_NONE, false, 0, false);
#ifdef _LIGHT_STARTMENU
ResizeToButtons();
@ -431,6 +431,7 @@ void StartMenu::SelectButton(int id)
// automatically open submenus
if (btn->_hasSubmenu) {
//@@ allows destroying of startmenu when processing PM_UPDATE_ICONS -> GPF
UpdateWindow(_hwnd); // draw focused button before waiting on submenu creation
Command(_selected_id, BN_CLICKED);
} else
@ -548,19 +549,19 @@ void StartMenu::UpdateIcons(/*int idx*/)
for(; idx<(int)_buttons.size(); ++idx) {
SMBtnInfo& btn = _buttons[idx];
if (!btn._hIcon && btn._id>0) {
if (btn._icon_id==ICID_UNKNOWN && btn._id>0) {
StartMenuEntry& sme = _entries[btn._id];
btn._hIcon = (HICON)-1;
btn._icon_id = ICID_NONE;
for(ShellEntrySet::iterator it=sme._entries.begin(); it!=sme._entries.end(); ++it) {
Entry* entry = *it;
HICON hIcon = extract_icon(entry);
if (entry->_icon_id == ICID_UNKNOWN)
entry->extract_icon();
if (hIcon) {
btn._hIcon = hIcon;
entry->_hIcon = hIcon;
if (entry->_icon_id > ICID_NONE) {
btn._icon_id = (ICON_ID)/*@@*/ entry->_icon_id;
RECT rect;
@ -674,7 +675,7 @@ int StartMenu::Command(int id, int code)
}
StartMenuEntry& StartMenu::AddEntry(const String& title, HICON hIcon, Entry* entry)
StartMenuEntry& StartMenu::AddEntry(const String& title, ICON_ID icon_id, Entry* entry)
{
// search for an already existing subdirectory entry with the same name
if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
@ -691,14 +692,14 @@ StartMenuEntry& StartMenu::AddEntry(const String& title, HICON hIcon, Entry* ent
}
}
StartMenuEntry& sme = AddEntry(title, hIcon);
StartMenuEntry& sme = AddEntry(title, icon_id);
sme._entries.insert(entry);
return sme;
}
StartMenuEntry& StartMenu::AddEntry(const String& title, HICON hIcon, int id)
StartMenuEntry& StartMenu::AddEntry(const String& title, ICON_ID icon_id, int id)
{
if (id == -1)
id = ++_next_id;
@ -706,36 +707,40 @@ StartMenuEntry& StartMenu::AddEntry(const String& title, HICON hIcon, int id)
StartMenuEntry& sme = _entries[id];
sme._title = title;
sme._hIcon = hIcon;
sme._icon_id = icon_id;
return sme;
}
StartMenuEntry& StartMenu::AddEntry(const ShellFolder folder, ShellEntry* entry)
{
HICON hIcon = entry->_hIcon;
ICON_ID icon_id;
if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
hIcon = SmallIcon(IDI_FOLDER);
icon_id = ICID_FOLDER;
else
icon_id = (ICON_ID)/*@@*/ entry->_icon_id;
return AddEntry(folder.get_name(entry->_pidl), hIcon, entry);
return AddEntry(folder.get_name(entry->_pidl), icon_id, entry);
}
StartMenuEntry& StartMenu::AddEntry(const ShellFolder folder, Entry* entry)
{
HICON hIcon = entry->_hIcon;
ICON_ID icon_id;
if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
hIcon = SmallIcon(IDI_FOLDER);
icon_id = ICID_FOLDER;
else
icon_id = (ICON_ID)/*@@*/ entry->_icon_id;
return AddEntry(entry->_display_name, hIcon, entry);
return AddEntry(entry->_display_name, icon_id, entry);
}
void StartMenu::AddButton(LPCTSTR title, HICON hIcon, bool hasSubmenu, int id, bool enabled)
void StartMenu::AddButton(LPCTSTR title, ICON_ID icon_id, bool hasSubmenu, int id, bool enabled)
{
#ifdef _LIGHT_STARTMENU
_buttons.push_back(SMBtnInfo(title, hIcon, id, hasSubmenu, enabled));
_buttons.push_back(SMBtnInfo(title, icon_id, id, hasSubmenu, enabled));
#else
DWORD style = enabled? WS_VISIBLE|WS_CHILD|BS_OWNERDRAW: WS_VISIBLE|WS_CHILD|BS_OWNERDRAW|WS_DISABLED;
@ -764,14 +769,14 @@ void StartMenu::AddButton(LPCTSTR title, HICON hIcon, bool hasSubmenu, int id, b
MoveWindow(_hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE);
StartMenuCtrl(_hwnd, _border_left, clnt.bottom, rect.right-rect.left-_border_left,
title, id, hIcon, hasSubmenu, style);
title, id, g_Globals._icon_cache.get_icon(icon_id)._hIcon, hasSubmenu, style);
#endif
}
void StartMenu::AddSeparator()
{
#ifdef _LIGHT_STARTMENU
_buttons.push_back(SMBtnInfo(NULL, 0, -1, false));
_buttons.push_back(SMBtnInfo(NULL, ICID_NONE, -1, false));
#else
WindowRect rect(_hwnd);
ClientRect clnt(_hwnd);
@ -888,7 +893,7 @@ void StartMenu::ActivateEntry(int id, const ShellEntrySet& entries)
///@todo If the user explicitely clicked on a submenu, display this folder as floating start menu.
if (entry->_etype == ET_SHELL)
new_folders.push_back(static_cast<const ShellEntry*>(entry)->create_absolute_pidl());
new_folders.push_back(entry->create_absolute_pidl());
else {
TCHAR path[MAX_PATH];
@ -976,7 +981,8 @@ void DrawStartMenuButton(HDC hdc, const RECT& rect, LPCTSTR title, HICON hIcon,
if (title)
FillRect(hdc, &rect, bk_brush);
DrawIconEx(hdc, iconPos.x, iconPos.y, btn._hIcon, 16, 16, 0, bk_brush, DI_NORMAL);
if (btn._icon_id > ICID_NONE)
DrawIconEx(hdc, iconPos.x, iconPos.y, g_Globals._icon_cache.get_icon(btn._icon_id)._hIcon, 16, 16, 0, bk_brush, DI_NORMAL);
// draw submenu arrow at the right
if (btn._hasSubmenu) {
@ -1213,38 +1219,38 @@ LRESULT StartMenuRoot::Init(LPCREATESTRUCT pcs)
// insert hard coded start entries
AddButton(ResString(IDS_PROGRAMS), SmallIcon(IDI_APPS), true, IDC_PROGRAMS);
AddButton(ResString(IDS_PROGRAMS), ICID_APPS, true, IDC_PROGRAMS);
AddButton(ResString(IDS_DOCUMENTS), SmallIcon(IDI_DOCUMENTS), true, IDC_DOCUMENTS);
AddButton(ResString(IDS_DOCUMENTS), ICID_DOCUMENTS, true, IDC_DOCUMENTS);
#ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
if (!g_Globals._SHRestricted || !SHRestricted(REST_NORECENTDOCSMENU))
#else
if (IS_VALUE_ZERO(hkey, _T("NoRecentDocsMenu")))
#endif
AddButton(ResString(IDS_RECENT), SmallIcon(IDI_DOCUMENTS), true, IDC_RECENT);
AddButton(ResString(IDS_RECENT), ICID_DOCUMENTS, true, IDC_RECENT);
AddButton(ResString(IDS_FAVORITES), SmallIcon(IDI_FAVORITES), true, IDC_FAVORITES);
AddButton(ResString(IDS_FAVORITES), ICID_FAVORITES, true, IDC_FAVORITES);
AddButton(ResString(IDS_SETTINGS), SmallIcon(IDI_CONFIG), true, IDC_SETTINGS);
AddButton(ResString(IDS_SETTINGS), ICID_CONFIG, true, IDC_SETTINGS);
AddButton(ResString(IDS_BROWSE), SmallIcon(IDI_FOLDER), true, IDC_BROWSE);
AddButton(ResString(IDS_BROWSE), ICID_FOLDER, true, IDC_BROWSE);
#ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
if (!g_Globals._SHRestricted || !SHRestricted(REST_NOFIND))
#else
if (IS_VALUE_ZERO(hkey, _T("NoFind")))
#endif
AddButton(ResString(IDS_SEARCH), SmallIcon(IDI_SEARCH), true, IDC_SEARCH);
AddButton(ResString(IDS_SEARCH), ICID_SEARCH, true, IDC_SEARCH);
AddButton(ResString(IDS_START_HELP), SmallIcon(IDI_INFO), false, IDC_START_HELP);
AddButton(ResString(IDS_START_HELP), ICID_INFO, false, IDC_START_HELP);
#ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
if (!g_Globals._SHRestricted || !SHRestricted(REST_NORUN))
#else
if (IS_VALUE_ZERO(hkey, _T("NoRun")))
#endif
AddButton(ResString(IDS_LAUNCH), SmallIcon(IDI_ACTION), false, IDC_LAUNCH);
AddButton(ResString(IDS_LAUNCH), ICID_ACTION, false, IDC_LAUNCH);
AddSeparator();
@ -1255,7 +1261,7 @@ LRESULT StartMenuRoot::Init(LPCREATESTRUCT pcs)
#else
if (IS_VALUE_NOT_ZERO(hkeyAdv, _T("StartMenuLogoff")))
#endif
AddButton(ResString(IDS_LOGOFF), SmallIcon(IDI_LOGOFF), false, IDC_LOGOFF);
AddButton(ResString(IDS_LOGOFF), ICID_LOGOFF, false, IDC_LOGOFF);
#ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
@ -1263,7 +1269,7 @@ LRESULT StartMenuRoot::Init(LPCREATESTRUCT pcs)
#else
if (IS_VALUE_ZERO(hkey, _T("NoClose")))
#endif
AddButton(ResString(IDS_SHUTDOWN), SmallIcon(IDI_LOGOFF), false, IDC_SHUTDOWN);
AddButton(ResString(IDS_SHUTDOWN), ICID_LOGOFF, false, IDC_SHUTDOWN);
#ifdef __MINGW32__
@ -1285,7 +1291,7 @@ void StartMenuRoot::AddEntries()
{
super::AddEntries();
AddButton(ResString(IDS_EXPLORE), SmallIcon(IDI_EXPLORER), false, IDC_EXPLORE);
AddButton(ResString(IDS_EXPLORE), ICID_EXPLORER, false, IDC_EXPLORE);
}
@ -1538,16 +1544,16 @@ void SettingsMenu::AddEntries()
#ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
if (!g_Globals._SHRestricted || !SHRestricted(REST_NOCONTROLPANEL))
#endif
AddButton(ResString(IDS_CONTROL_PANEL), SmallIcon(IDI_CONFIG), false, IDC_CONTROL_PANEL);
AddButton(ResString(IDS_CONTROL_PANEL), ICID_CONFIG, false, IDC_CONTROL_PANEL);
AddButton(ResString(IDS_PRINTERS), SmallIcon(IDI_PRINTER), true, IDC_PRINTERS);
AddButton(ResString(IDS_CONNECTIONS), SmallIcon(IDI_NETWORK), true, IDC_CONNECTIONS);
AddButton(ResString(IDS_ADMIN), SmallIcon(IDI_CONFIG), true, IDC_ADMIN);
AddButton(ResString(IDS_PRINTERS), ICID_PRINTER, true, IDC_PRINTERS);
AddButton(ResString(IDS_CONNECTIONS), ICID_NETWORK, true, IDC_CONNECTIONS);
AddButton(ResString(IDS_ADMIN), ICID_CONFIG, true, IDC_ADMIN);
#ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
if (!g_Globals._SHRestricted || !SHRestricted(REST_NOCONTROLPANEL))
#endif
AddButton(ResString(IDS_SETTINGS_MENU), SmallIcon(IDI_CONFIG), true, IDC_SETTINGS_MENU);
AddButton(ResString(IDS_SETTINGS_MENU), ICID_CONFIG, true, IDC_SETTINGS_MENU);
}
void BrowseMenu::AddEntries()
@ -1557,23 +1563,23 @@ void BrowseMenu::AddEntries()
#ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
if (!g_Globals._SHRestricted || !SHRestricted(REST_NONETHOOD)) // or REST_NOENTIRENETWORK ?
#endif
AddButton(ResString(IDS_NETWORK), SmallIcon(IDI_NETWORK), true, IDC_NETWORK);
AddButton(ResString(IDS_NETWORK), ICID_NETWORK, true, IDC_NETWORK);
AddButton(ResString(IDS_DRIVES), SmallIcon(IDI_FOLDER), true, IDC_DRIVES);
AddButton(ResString(IDS_DRIVES), ICID_FOLDER, true, IDC_DRIVES);
}
void SearchMenu::AddEntries()
{
super::AddEntries();
AddButton(ResString(IDS_SEARCH_PRG), SmallIcon(IDI_APPS), false, IDC_SEARCH_PROGRAM);
AddButton(ResString(IDS_SEARCH_PRG), ICID_APPS, false, IDC_SEARCH_PROGRAM);
AddButton(ResString(IDS_SEARCH_FILES), SmallIcon(IDI_SEARCH_DOC), false, IDC_SEARCH_FILES);
AddButton(ResString(IDS_SEARCH_FILES), ICID_SEARCH_DOC, false, IDC_SEARCH_FILES);
#ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
if (!g_Globals._SHRestricted || !SHRestricted(REST_HASFINDCOMPUTERS))
#endif
AddButton(ResString(IDS_SEARCH_COMPUTER), SmallIcon(IDI_COMPUTER), false, IDC_SEARCH_COMPUTER);
AddButton(ResString(IDS_SEARCH_COMPUTER), ICID_COMPUTER, false, IDC_SEARCH_COMPUTER);
}

View file

@ -75,10 +75,10 @@ typedef set<Entry*> ShellEntrySet;
/// structure holding information about one start menu entry
struct StartMenuEntry
{
StartMenuEntry() : _hIcon(0) {}
StartMenuEntry() : _icon_id(ICID_UNKNOWN) {}
String _title;
HICON _hIcon;
ICON_ID _icon_id;
ShellEntrySet _entries;
};
@ -95,14 +95,14 @@ struct StartMenuButton : public OwnerdrawnButton
{
typedef OwnerdrawnButton super;
StartMenuButton(HWND hwnd, HICON hIcon, bool hasSubmenu)
StartMenuButton(HWND hwnd, ICON_ID icon_id, bool hasSubmenu)
: super(hwnd), _hIcon(hIcon), _hasSubmenu(hasSubmenu) {}
protected:
LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam);
virtual void DrawItem(LPDRAWITEMSTRUCT dis);
HICON _hIcon;
ICON_ID _icon_id;
bool _hasSubmenu;
};
@ -159,16 +159,16 @@ struct SMBtnInfo
{
SMBtnInfo(const StartMenuEntry& entry, int id, bool hasSubmenu=false, bool enabled=true)
: _title(entry._title),
_hIcon(entry._hIcon),
_icon_id(entry._icon_id),
_id(id),
_hasSubmenu(hasSubmenu),
_enabled(enabled)
{
}
SMBtnInfo(LPCTSTR title, HICON hIcon, int id, bool hasSubmenu=false, bool enabled=true)
SMBtnInfo(LPCTSTR title, ICON_ID icon_id, int id, bool hasSubmenu=false, bool enabled=true)
: _title(title),
_hIcon(hIcon),
_icon_id(icon_id),
_id(id),
_hasSubmenu(hasSubmenu),
_enabled(enabled)
@ -176,7 +176,7 @@ struct SMBtnInfo
}
String _title;
HICON _hIcon;
ICON_ID _icon_id;
int _id;
bool _hasSubmenu;
bool _enabled;
@ -258,14 +258,14 @@ protected:
virtual void AddEntries();
StartMenuEntry& AddEntry(const String& title, HICON hIcon, Entry* entry);
StartMenuEntry& AddEntry(const String& title, HICON hIcon=0, int id=-1);
StartMenuEntry& AddEntry(const String& title, ICON_ID icon_id, Entry* entry);
StartMenuEntry& AddEntry(const String& title, ICON_ID icon_id=ICID_NONE, int id=-1);
StartMenuEntry& AddEntry(const ShellFolder folder, ShellEntry* entry);
StartMenuEntry& AddEntry(const ShellFolder folder, Entry* entry);
void AddShellEntries(const ShellDirectory& dir, int max=-1, bool subfolders=true);
void AddButton(LPCTSTR title, HICON hIcon=0, bool hasSubmenu=false, int id=-1, bool enabled=true);
void AddButton(LPCTSTR title, ICON_ID icon_id=ICID_NONE, bool hasSubmenu=false, int id=-1, bool enabled=true);
void AddSeparator();
bool CloseSubmenus() {return CloseOtherSubmenus(0);}

View file

@ -29,6 +29,7 @@
#include "../utility/utility.h"
#include "../explorer.h"
#include "../globals.h"
#include "taskbar.h"
#include "traynotify.h" // for NOTIFYAREA_WIDTH
@ -249,21 +250,6 @@ static HICON get_window_icon(HWND hwnd)
return hIcon;
}
HBITMAP create_bitmap_from_icon(HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd)
{
HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, 16, 16);
MemCanvas canvas;
BitmapSelection sel(canvas, hbmp);
RECT rect = {0, 0, 16, 16};
FillRect(canvas, &rect, hbrush_bkgnd);
DrawIconEx(canvas, 0, 0, hIcon, 16, 16, 0, hbrush_bkgnd, DI_NORMAL);
return hbmp;
}
// fill task bar with buttons for enumerated top level windows
BOOL CALLBACK TaskBar::EnumWndProc(HWND hwnd, LPARAM lparam)
{

View file

@ -134,9 +134,6 @@ extern BOOL time_to_filetime(const time_t* t, FILETIME* ftime);
// search for windows of a specific classname
extern int find_window_class(LPCTSTR classname);
// create a bitmap from an icon
extern HBITMAP create_bitmap_from_icon(HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd);
// launch a program or document file
extern BOOL launch_file(HWND hwnd, LPCTSTR cmd, UINT nCmdShow);
#ifdef UNICODE

View file

@ -591,18 +591,6 @@ PreTranslateWindow::~PreTranslateWindow()
}
DialogWindow::DialogWindow(HWND hwnd)
: super(hwnd)
{
register_dialog(hwnd);
}
DialogWindow::~DialogWindow()
{
unregister_dialog(_hwnd);
}
Dialog::Dialog(HWND hwnd)
: super(hwnd)
{

View file

@ -319,14 +319,22 @@ struct DialogWindow : public Window
{
typedef Window super;
DialogWindow(HWND);
~DialogWindow();
DialogWindow(HWND hwnd)
: super(hwnd)
{
register_dialog(hwnd);
}
~DialogWindow()
{
unregister_dialog(_hwnd);
}
};
/**
The class Dialog implements modal dialogs.
A DialogWindow object should be constructed by calling Dialog::DoModal()
A Dialog object should be constructed by calling Dialog::DoModal()
and specifying the class using the WINDOW_CREATOR() macro.
*/
struct Dialog : public Window