merge ROS Shell without integrated explorer part into trunk
[reactos.git] / reactos / subsys / system / explorer / taskbar / startmenu.cpp
index 328bbfd..2a00ded 100644 (file)
@@ -18,7 +18,7 @@
 
 
  //
- // Explorer clone, lean version
+ // Explorer clone
  //
  // startmenu.cpp
  //
@@ -37,6 +37,7 @@
 #include "desktopbar.h"
 #include "startmenu.h"
 
+#include "../dialogs/searchprogram.h"
 #include "../dialogs/settings.h"
 
 
@@ -114,7 +115,7 @@ BtnWindowClass& StartMenu::GetWndClasss()
 
 Window::CREATORFUNC_INFO StartMenu::s_def_creator = STARTMENU_CREATOR(StartMenu);
 
-HWND StartMenu::Create(int x, int y, const StartMenuFolders& folders, HWND hwndParent, LPCTSTR title, CREATORFUNC_INFO creator)
+HWND StartMenu::Create(int x, int y, const StartMenuFolders& folders, HWND hwndParent, LPCTSTR title, CREATORFUNC_INFO creator, void* info)
 {
        UINT style, ex_style;
        int top_height;
@@ -142,6 +143,7 @@ HWND StartMenu::Create(int x, int y, const StartMenuFolders& folders, HWND hwndP
        create_info._folders = folders;
        create_info._border_top = top_height;
        create_info._creator = creator;
+       create_info._info = info;
 
        if (title)
                create_info._title = title;
@@ -211,9 +213,9 @@ void StartMenu::AddEntries()
                        WaitCursor wait;
 
 #ifdef _LAZY_ICONEXTRACT
-                       dir.smart_scan(SCAN_FILESYSTEM);        // lazy icon extraction, try to read directly from filesystem
+                       dir.smart_scan(SORT_NAME, SCAN_FILESYSTEM);     // lazy icon extraction, try to read directly from filesystem
 #else
-                       dir.smart_scan(SCAN_EXTRACT_ICONS|SCAN_FILESYSTEM);
+                       dir.smart_scan(SORT_NAME, SCAN_EXTRACT_ICONS|SCAN_FILESYSTEM);
 #endif
                }
 
@@ -299,7 +301,7 @@ LRESULT StartMenu::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
                        WindowRect pos(_hwnd);
 
                        ///@todo do something similar to StartMenuRoot::TrackStartmenu() in order to automatically close submenus when clicking on the desktop background
-                       StartMenu::Create(pos.left+3, pos.bottom-3, _create_info._folders, 0, _create_info._title, _create_info._creator);
+                       StartMenu::Create(pos.left+3, pos.bottom-3, _create_info._folders, 0, _create_info._title, _create_info._creator, _create_info._info);
                        CloseStartMenu();
                }
 
@@ -367,7 +369,7 @@ LRESULT StartMenu::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
 
                        int new_id = ButtonHitTest(pt);
 
-                       if (new_id != _selected_id)
+                       if (new_id > 0 && new_id != _selected_id)
                                SelectButton(new_id);
 
                        _last_mouse_pos = lparam;
@@ -428,9 +430,31 @@ LRESULT StartMenu::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
                break;
 
          case PM_SELECT_ENTRY:
-               SelectButtonIndex(0, wparam?true:false);
+               SelectButtonIndex(0, wparam!=0);
                break;
 
+#ifdef _LIGHT_STARTMENU
+         case WM_CONTEXTMENU: {
+               Point screen_pt(lparam), clnt_pt=screen_pt;
+               ScreenToClient(_hwnd, &clnt_pt);
+
+               int id = ButtonHitTest(clnt_pt);
+
+               if (id) {
+                       StartMenuEntry& sme = _entries[id];
+
+                       for(ShellEntrySet::iterator it=sme._entries.begin(); it!=sme._entries.end(); ++it) {
+                               Entry* entry = *it;
+
+                               if (entry) {
+                                       CHECKERROR(entry->do_context_menu(_hwnd, screen_pt, _cm_ifs));  // may close start menu because of focus loss
+                                       break;  ///@todo handle context menu for more than one entry
+                               }
+                       }
+               }
+               break;}
+#endif
+
          default: def:
                return super::WndProc(nmsg, wparam, lparam);
        }
@@ -471,7 +495,7 @@ int StartMenu::ButtonHitTest(POINT pt)
 
 void StartMenu::InvalidateSelection()
 {
-       if (!_selected_id)
+       if (_selected_id <= 0)
                return;
 
        ClientRect clnt(_hwnd);
@@ -979,44 +1003,47 @@ int StartMenu::Command(int id, int code)
 }
 
 
-StartMenuEntry& StartMenu::AddEntry(const String& title, ICON_ID icon_id, Entry* entry)
+ShellEntryMap::iterator 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)
                for(ShellEntryMap::iterator it=_entries.begin(); it!=_entries.end(); ++it) {
                        StartMenuEntry& sme = it->second;
 
-                       if (sme._title == title)        ///@todo speed up by using a map indexed by name
+                       if (!_tcsicmp(sme._title, title))       ///@todo speed up by using a map indexed by name
                                for(ShellEntrySet::iterator it2=sme._entries.begin(); it2!=sme._entries.end(); ++it2) {
                                        if ((*it2)->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                                                 // merge the new shell entry with the existing of the same name
                                                sme._entries.insert(entry);
-                                               return sme;
+
+                                               return it;
                                        }
                                }
                }
 
-       StartMenuEntry& sme = AddEntry(title, icon_id);
+       ShellEntryMap::iterator sme = AddEntry(title, icon_id);
 
-       sme._entries.insert(entry);
+       sme->second._entries.insert(entry);
 
        return sme;
 }
 
-StartMenuEntry& StartMenu::AddEntry(const String& title, ICON_ID icon_id, int id)
+ShellEntryMap::iterator StartMenu::AddEntry(const String& title, ICON_ID icon_id, int id)
 {
        if (id == -1)
                id = ++_next_id;
 
-       StartMenuEntry& sme = _entries[id];
+       StartMenuEntry sme;
 
        sme._title = title;
        sme._icon_id = icon_id;
 
-       return sme;
+       ShellEntryMap::iterator it = _entries.insert(make_pair(id, sme)).first;
+
+       return it;
 }
 
-StartMenuEntry& StartMenu::AddEntry(const ShellFolder folder, ShellEntry* entry)
+ShellEntryMap::iterator StartMenu::AddEntry(const ShellFolder folder, ShellEntry* entry)
 {
        ICON_ID icon_id;
 
@@ -1028,7 +1055,7 @@ StartMenuEntry& StartMenu::AddEntry(const ShellFolder folder, ShellEntry* entry)
        return AddEntry(folder.get_name(entry->_pidl), icon_id, entry);
 }
 
-StartMenuEntry& StartMenu::AddEntry(const ShellFolder folder, Entry* entry)
+ShellEntryMap::iterator StartMenu::AddEntry(const ShellFolder folder, Entry* entry)
 {
        ICON_ID icon_id;
 
@@ -1121,12 +1148,12 @@ bool StartMenu::CloseOtherSubmenus(int id)
 }
 
 
-void StartMenu::CreateSubmenu(int id, LPCTSTR title, CREATORFUNC_INFO creator)
+void StartMenu::CreateSubmenu(int id, LPCTSTR title, CREATORFUNC_INFO creator, void* info)
 {
-       CreateSubmenu(id, StartMenuFolders(), title, creator);
+       CreateSubmenu(id, StartMenuFolders(), title, creator, info);
 }
 
-bool StartMenu::CreateSubmenu(int id, int folder_id, LPCTSTR title, CREATORFUNC_INFO creator)
+bool StartMenu::CreateSubmenu(int id, int folder_id, LPCTSTR title, CREATORFUNC_INFO creator, void* info)
 {
        try {
                SpecialFolderPath folder(folder_id, _hwnd);
@@ -1134,7 +1161,7 @@ bool StartMenu::CreateSubmenu(int id, int folder_id, LPCTSTR title, CREATORFUNC_
                StartMenuFolders new_folders;
                new_folders.push_back(folder);
 
-               CreateSubmenu(id, new_folders, title, creator);
+               CreateSubmenu(id, new_folders, title, creator, info);
 
                return true;
        } catch(COMException&) {
@@ -1145,7 +1172,7 @@ bool StartMenu::CreateSubmenu(int id, int folder_id, LPCTSTR title, CREATORFUNC_
        }
 }
 
-bool StartMenu::CreateSubmenu(int id, int folder_id1, int folder_id2, LPCTSTR title, CREATORFUNC_INFO creator)
+bool StartMenu::CreateSubmenu(int id, int folder_id1, int folder_id2, LPCTSTR title, CREATORFUNC_INFO creator, void* info)
 {
        StartMenuFolders new_folders;
 
@@ -1160,7 +1187,7 @@ bool StartMenu::CreateSubmenu(int id, int folder_id1, int folder_id2, LPCTSTR ti
        }
 
        if (!new_folders.empty()) {
-               CreateSubmenu(id, new_folders, title, creator);
+               CreateSubmenu(id, new_folders, title, creator, info);
                return true;
        } else {
                CloseOtherSubmenus(id);
@@ -1169,7 +1196,7 @@ bool StartMenu::CreateSubmenu(int id, int folder_id1, int folder_id2, LPCTSTR ti
        }
 }
 
-void StartMenu::CreateSubmenu(int id, const StartMenuFolders& new_folders, LPCTSTR title, CREATORFUNC_INFO creator)
+void StartMenu::CreateSubmenu(int id, const StartMenuFolders& new_folders, LPCTSTR title, CREATORFUNC_INFO creator, void* info)
 {
         // Only open one submenu at a time.
        if (!CloseOtherSubmenus(id))
@@ -1191,7 +1218,7 @@ void StartMenu::CreateSubmenu(int id, const StartMenuFolders& new_folders, LPCTS
        }
 
        _submenu_id = id;
-       _submenu = StartMenu::Create(x, y, new_folders, _hwnd, title, creator);
+       _submenu = StartMenu::Create(x, y, new_folders, _hwnd, title, creator, info);
 }
 
 
@@ -1225,14 +1252,14 @@ void StartMenu::ActivateEntry(int id, const ShellEntrySet& entries)
                        HWND hparent = GetParent(_hwnd);
                        ShellPath shell_path = entry->create_absolute_pidl();
 
-                        // close start menus after launching the selected entry
+                        // close start menus when launching the selected entry
                        CloseStartMenu(id);
 
                        ///@todo launch in the background; specify correct HWND for error message box titles
                        SHELLEXECUTEINFO shexinfo;
 
                        shexinfo.cbSize = sizeof(SHELLEXECUTEINFO);
-                       shexinfo.fMask = SEE_MASK_INVOKEIDLIST; // SEE_MASK_IDLIST is also possible.
+                       shexinfo.fMask = SEE_MASK_IDLIST;       // SEE_MASK_INVOKEIDLIST is also possible.
                        shexinfo.hwnd = hparent;
                        shexinfo.lpVerb = NULL;
                        shexinfo.lpFile = NULL;
@@ -1630,6 +1657,8 @@ LRESULT   StartMenuRoot::Init(LPCREATESTRUCT pcs)
 
        AddButton(ResString(IDS_SETTINGS),              ICID_CONFIG, true, IDC_SETTINGS);
 
+       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
@@ -1784,7 +1813,15 @@ int StartMenuHandler::Command(int id, int code)
                break;
 
          case IDC_FAVORITES:
-               CreateSubmenu(id, CSIDL_FAVORITES, ResString(IDS_FAVORITES));
+#ifndef _SHELL32_FAVORITES
+               CreateSubmenu(id, ResString(IDS_FAVORITES), STARTMENU_CREATOR(FavoritesMenu), &static_cast<BookmarkList&>(g_Globals._favorites));
+#else
+               CreateSubmenu(id, CSIDL_COMMON_FAVORITES, CSIDL_FAVORITES, ResString(IDS_FAVORITES));
+#endif
+               break;
+
+         case IDC_BROWSE:
+               CreateSubmenu(id, ResString(IDS_BROWSE), STARTMENU_CREATOR(BrowseMenu));
                break;
 
          case IDC_SETTINGS:
@@ -1822,45 +1859,109 @@ int StartMenuHandler::Command(int id, int code)
                ExplorerPropertySheet(g_Globals._hwndDesktopBar);
                break;
 
-         case IDC_CONTROL_PANEL:
+         case IDC_CONTROL_PANEL: {
                CloseStartMenu(id);
 #ifndef ROSSHELL
-               MainFrame::Create(SHELLPATH_CONTROL_PANEL, 0);
+#ifndef _NO_MDI
+               XMLPos explorer_options = g_Globals.get_cfg("general/explorer");
+               bool mdi = XMLBool(explorer_options, "mdi", true);
+
+               if (mdi)
+                       MDIMainFrame::Create(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}"), 0);
+               else
+#endif
+                       SDIMainFrame::Create(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}"), 0);
 #else
                launch_file(_hwnd, SHELLPATH_CONTROL_PANEL);
 #endif
+               break;}
+
+         case IDC_SETTINGS_MENU:
+               CreateSubmenu(id, CSIDL_CONTROLS, ResString(IDS_SETTINGS_MENU));
                break;
 
-         case IDC_PRINTERS:
+         case IDC_PRINTERS: {
                CloseStartMenu(id);
+
 #ifndef ROSSHELL
-               MainFrame::Create(SpecialFolderPath(CSIDL_PRINTERS, _hwnd), OWM_PIDL);
+#ifdef _ROS_   // to be removed when printer folder will be implemented
+               MessageBox(0, TEXT("printer folder not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK);
+#else
+#ifndef _NO_MDI
+               XMLPos explorer_options = g_Globals.get_cfg("general/explorer");
+               bool mdi = XMLBool(explorer_options, "mdi", true);
+
+               if (mdi)
+                       MDIMainFrame::Create(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}"), 0);
+               else
+#endif
+                       SDIMainFrame::Create(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}"), 0);
+#endif
 #else
                launch_file(_hwnd, SHELLPATH_PRINTERS);
+#endif
+               break;}
+
+         case IDC_PRINTERS_MENU:
+               CreateSubmenu(id, CSIDL_PRINTERS, CSIDL_PRINTHOOD, ResString(IDS_PRINTERS));
+/*             StartMenuFolders new_folders;
+
+               try {
+                       new_folders.push_back(ShellPath(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}")));
+               } catch(COMException&) {
+               }
+
+               CreateSubmenu(id, new_folders, ResString(IDS_PRINTERS));*/
+               break;
+
+         case IDC_ADMIN:
+#ifndef ROSSHELL
+               CreateSubmenu(id, CSIDL_COMMON_ADMINTOOLS, CSIDL_ADMINTOOLS, ResString(IDS_ADMIN));
+               //CloseStartMenu(id);
+               //MainFrame::Create(SpecialFolderPath(CSIDL_COMMON_ADMINTOOLS, _hwnd), OWM_PIDL);
+#else
+               launch_file(_hwnd, SpecialFolderFSPath(CSIDL_COMMON_ADMINTOOLS, _hwnd));
 #endif
                break;
 
          case IDC_CONNECTIONS:
-               CloseStartMenu(id);
 #ifndef ROSSHELL
-               MainFrame::Create(SpecialFolderPath(CSIDL_CONNECTIONS, _hwnd), OWM_PIDL);
+#ifdef _ROS_   // to be removed when RAS will be implemented
+               MessageBox(0, TEXT("RAS folder not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK);
+#else
+               CreateSubmenu(id, CSIDL_CONNECTIONS, ResString(IDS_CONNECTIONS));
+               //CloseStartMenu(id);
+               //MainFrame::Create(SpecialFolderPath(CSIDL_CONNECTIONS, _hwnd), OWM_PIDL);
+#endif
 #else
                launch_file(_hwnd, SHELLPATH_NET_CONNECTIONS);
 #endif
                break;
 
-         case IDC_ADMIN:
-               CloseStartMenu(id);
-#ifndef ROSSHELL
-               MainFrame::Create(SpecialFolderPath(CSIDL_COMMON_ADMINTOOLS, _hwnd), OWM_PIDL);
+
+       // browse menu
+
+         case IDC_NETWORK:
+#ifdef _ROS_   // to be removed when network will be implemented
+               MessageBox(0, TEXT("network not yet implemented"), ResString(IDS_TITLE), MB_OK);
 #else
-               launch_file(_hwnd, SpecialFolderFSPath(CSIDL_COMMON_ADMINTOOLS, _hwnd));
+               CreateSubmenu(id, CSIDL_NETWORK, ResString(IDS_NETWORK));
 #endif
                break;
 
+         case IDC_DRIVES:
+               ///@todo exclude removable drives
+               CreateSubmenu(id, CSIDL_DRIVES, ResString(IDS_DRIVES));
+               break;
+
 
        // search menu
 
+         case IDC_SEARCH_PROGRAM:
+               CloseStartMenu(id);
+               Dialog::DoModal(IDD_SEARCH_PROGRAM, WINDOW_CREATOR(FindProgramDlg));
+               break;
+
          case IDC_SEARCH_FILES:
                CloseStartMenu(id);
                ShowSearchDialog();
@@ -1911,7 +2012,6 @@ void StartMenuHandler::ShowLaunchDialog(HWND hwndOwner)
         // Show "Run..." dialog
        if (RunFileDlg) {
 #ifndef _ROS_ /* FIXME: our shell32 always expects Ansi strings */
-#define        W_VER_NT 0
                if ((HIWORD(GetVersion())>>14) == W_VER_NT) {
                        WCHAR wTitle[40], wText[256];
 
@@ -1956,28 +2056,58 @@ void SettingsMenu::AddEntries()
 {
        super::AddEntries();
 
+#ifdef _ROS_   // to be removed when printer/network will be implemented
+       AddButton(ResString(IDS_PRINTERS),                      ICID_PRINTER, false, IDC_PRINTERS_MENU);
+       AddButton(ResString(IDS_CONNECTIONS),           ICID_NETWORK, false, IDC_CONNECTIONS);
+#else
+       AddButton(ResString(IDS_PRINTERS),                      ICID_PRINTER, true, IDC_PRINTERS_MENU);
+       AddButton(ResString(IDS_CONNECTIONS),           ICID_NETWORK, true, IDC_CONNECTIONS);
+#endif
+       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), ICID_CONFIG, true, IDC_SETTINGS_MENU);
+
+       AddButton(ResString(IDS_DESKTOPBAR_SETTINGS), ICID_CONFIG, false, ID_DESKTOPBAR_SETTINGS);
+
+       AddButton(ResString(IDS_PRINTERS),                      ICID_PRINTER, false, IDC_PRINTERS);
+
 #ifndef __MINGW32__    // SHRestricted() missing in MinGW (as of 29.10.2003)
        if (!g_Globals._SHRestricted || !SHRestricted(REST_NOCONTROLPANEL))
 #endif
                AddButton(ResString(IDS_CONTROL_PANEL), ICID_CONFIG, false, IDC_CONTROL_PANEL);
+}
 
-       AddButton(ResString(IDS_PRINTERS),              ICID_PRINTER, false, IDC_PRINTERS);
-       AddButton(ResString(IDS_CONNECTIONS),   ICID_NETWORK, false, IDC_CONNECTIONS);
-       AddButton(ResString(IDS_ADMIN),                 ICID_CONFIG, false, IDC_ADMIN);
+void BrowseMenu::AddEntries()
+{
+       super::AddEntries();
 
-       AddButton(ResString(IDS_DESKTOPBAR_SETTINGS), ICID_CONFIG, false, ID_DESKTOPBAR_SETTINGS);
+#ifndef __MINGW32__    // SHRestricted() missing in MinGW (as of 29.10.2003)
+       if (!g_Globals._SHRestricted || !SHRestricted(REST_NONETHOOD))  // or REST_NOENTIRENETWORK ?
+#endif
+#ifdef _ROS_   // to be removed when printer/network will be implemented
+               AddButton(ResString(IDS_NETWORK),               ICID_NETWORK, false, IDC_NETWORK);
+#else
+               AddButton(ResString(IDS_NETWORK),               ICID_NETWORK, true, IDC_NETWORK);
+#endif
+
+       AddButton(ResString(IDS_DRIVES),                        ICID_FOLDER, true, IDC_DRIVES);
 }
 
 void SearchMenu::AddEntries()
 {
        super::AddEntries();
 
-       AddButton(ResString(IDS_SEARCH_FILES),  ICID_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),       ICID_COMPUTER, false, IDC_SEARCH_COMPUTER);
+               AddButton(ResString(IDS_SEARCH_COMPUTER),ICID_COMPUTER, false, IDC_SEARCH_COMPUTER);
+
+       AddButton(ResString(IDS_SEARCH_PRG),            ICID_APPS, false, IDC_SEARCH_PROGRAM);
 }
 
 
@@ -1991,13 +2121,75 @@ void RecentStartMenu::AddEntries()
                        WaitCursor wait;
 
 #ifdef _LAZY_ICONEXTRACT
-                       dir.smart_scan(SCAN_FILESYSTEM);
+                       dir.smart_scan(SORT_NAME, SCAN_FILESYSTEM);
 #else
-                       dir.smart_scan(SCAN_EXTRACT_ICONS|SCAN_FILESYSTEM);
+                       dir.smart_scan(SORT_NAME, SCAN_EXTRACT_ICONS|SCAN_FILESYSTEM);
 #endif
                }
 
                dir.sort_directory(SORT_DATE);
-               AddShellEntries(dir, RECENT_DOCS_COUNT, smd._subfolders);       ///@todo read max. count of entries from registry
+               AddShellEntries(dir, RECENT_DOCS_COUNT, smd._subfolders);
        }
 }
+
+
+#ifndef _SHELL32_FAVORITES
+
+void FavoritesMenu::AddEntries()
+{
+       super::AddEntries();
+
+       for(BookmarkList::iterator it=_bookmarks.begin(); it!=_bookmarks.end(); ++it) {
+               BookmarkNode& node = *it;
+
+               int id = ++_next_id;
+
+               _entries[id] = node;
+
+               if (node._type == BookmarkNode::BMNT_FOLDER) {
+                       BookmarkFolder& folder = *node._pfolder;
+
+                       AddButton(folder._name, ICID_FOLDER, true, id);
+               } else if (node._type == BookmarkNode::BMNT_BOOKMARK) {
+                       Bookmark& bookmark = *node._pbookmark;
+
+                       ICON_ID icon = ICID_NONE;
+
+                       if (!bookmark._icon_path.empty())
+                               icon = g_Globals._icon_cache.extract(bookmark._icon_path, bookmark._icon_idx);
+
+                       AddButton(bookmark._name, icon!=ICID_NONE?icon:ICID_BOOKMARK, false, id);
+               }
+       }
+}
+
+int FavoritesMenu::Command(int id, int code)
+{
+       BookmarkMap::iterator found = _entries.find(id);
+
+       if (found != _entries.end()) {
+               BookmarkNode& node = found->second;
+
+               if (node._type == BookmarkNode::BMNT_FOLDER) {
+                       BookmarkFolder& folder = *node._pfolder;
+
+                       if (CloseOtherSubmenus(id))
+                               CreateSubmenu(id, folder._name, STARTMENU_CREATOR(FavoritesMenu), &static_cast<BookmarkList&>(folder._bookmarks));
+               } else if (node._type == BookmarkNode::BMNT_BOOKMARK) {
+                       Bookmark& bookmark = *node._pbookmark;
+
+                       String url = bookmark._url;
+                       HWND hparent = GetParent(_hwnd);
+
+                       CloseStartMenu(id);
+
+                       launch_file(hparent, url, SW_SHOWNORMAL);
+               }
+
+               return 0;
+       }
+
+       return super::Command(id, code);
+}
+
+#endif