Make start menu icons small until we have 24x24 icons.
[reactos.git] / reactos / subsys / system / explorer / taskbar / startmenu.cpp
index 7ffef19..b0f1712 100644 (file)
@@ -30,9 +30,9 @@
  //
 
 
-#include "precomp.h"
+#include <precomp.h>
 
-#include "../explorer_intres.h"
+#include "../resource.h"
 
 #include "desktopbar.h"
 #include "startmenu.h"
 #include "../dialogs/settings.h"
 
 
-StartMenu::StartMenu(HWND hwnd)
- :     super(hwnd)
+#define        SHELLPATH_CONTROL_PANEL         TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}")
+#define        SHELLPATH_PRINTERS                      TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}")
+#define        SHELLPATH_NET_CONNECTIONS       TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}")
+
+
+StartMenu::StartMenu(HWND hwnd, bool big_icons)
+ :     super(hwnd),
+       _big_icons(big_icons)
 {
        _next_id = IDC_FIRST_MENU;
        _submenu_id = 0;
@@ -64,9 +70,10 @@ StartMenu::StartMenu(HWND hwnd)
 #endif
 }
 
-StartMenu::StartMenu(HWND hwnd, const StartMenuCreateInfo& create_info)
+StartMenu::StartMenu(HWND hwnd, const StartMenuCreateInfo& create_info, bool big_icons)
  :     super(hwnd),
-       _create_info(create_info)
+       _create_info(create_info),
+       _big_icons(big_icons)
 {
        for(StartMenuFolders::const_iterator it=create_info._folders.begin(); it!=create_info._folders.end(); ++it)
                if (*it)
@@ -110,7 +117,8 @@ 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, void* info)
+HWND StartMenu::Create(int x, int y, const StartMenuFolders& folders, HWND hwndParent, LPCTSTR title, bool parent_big_icons,
+                                               CREATORFUNC_INFO creator, void* info, const String& filter)
 {
        UINT style, ex_style;
        int top_height;
@@ -125,6 +133,7 @@ HWND StartMenu::Create(int x, int y, const StartMenuFolders& folders, HWND hwndP
                top_height = 0;
        }
 
+       bool big_icons = false;
        RECT rect = {x, y-STARTMENU_LINE_HEIGHT-top_height, x+STARTMENU_WIDTH_MIN, y};
 
 #ifndef _LIGHT_STARTMENU
@@ -139,6 +148,7 @@ HWND StartMenu::Create(int x, int y, const StartMenuFolders& folders, HWND hwndP
        create_info._border_top = top_height;
        create_info._creator = creator;
        create_info._info = info;
+       create_info._filter = filter;
 
        if (title)
                create_info._title = title;
@@ -214,30 +224,72 @@ void StartMenu::AddEntries()
 #endif
                }
 
-               AddShellEntries(dir, -1, smd._subfolders);
+               AddShellEntries(dir, -1, smd._ignore);
        }
 }
 
 
-void StartMenu::AddShellEntries(const ShellDirectory& dir, int max, bool subfolders)
+static LPTSTR trim_path_slash(LPTSTR path)
 {
-       int cnt = 0;
+       LPTSTR p = path;
+
+       while(*p)
+               ++p;
+
+       if (p>path && (p[-1]=='\\' || p[-1]=='/'))
+               *--p = '\0';
+
+       return path;
+}
+
+void StartMenu::AddShellEntries(const ShellDirectory& dir, int max, const String& ignore)
+{
+       TCHAR ignore_path[MAX_PATH], ignore_dir[MAX_PATH], ignore_name[_MAX_FNAME], ignore_ext[_MAX_EXT];
+       TCHAR dir_path[MAX_PATH];
+
+       if (!ignore.empty()) {
+               _tsplitpath_s(ignore, ignore_path, COUNTOF(ignore_path), ignore_dir, COUNTOF(ignore_dir), ignore_name, COUNTOF(ignore_name), ignore_ext, COUNTOF(ignore_ext));
+
+               _tcscat(ignore_path, ignore_dir);
+               _tcscat(ignore_name, ignore_ext);
+
+               dir.get_path(dir_path, COUNTOF(dir_path));
+
+               if (_tcsicmp(trim_path_slash(dir_path), trim_path_slash(ignore_path)))
+                       *ignore_name = '\0';
+       } else
+               *ignore_name = '\0';
+
+       String lwr_filter = _create_info._filter;
+       lwr_filter.toLower();
 
+       int cnt = 0;
        for(Entry*entry=dir._down; entry; entry=entry->_next) {
                 // hide files like "desktop.ini"
                if (entry->_shell_attribs & SFGAO_HIDDEN)
                //not appropriate for drive roots: if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
                        continue;
 
-                // hide subfolders if requested
-               if (!subfolders)
-                       if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-                               continue;
+                // hide "Programs" subfolders if requested
+               if (*ignore_name && !_tcsicmp(entry->_data.cFileName, ignore_name))
+                       continue;
 
                 // only 'max' entries shall be added.
                if (++cnt == max)
                        break;
 
+                // filter only non-directory entries
+               if (!(entry->_data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) && !lwr_filter.empty()) {
+                       String lwr_name = entry->_data.cFileName;
+                       String lwr_disp = entry->_display_name;
+
+                       lwr_name.toLower();
+                       lwr_disp.toLower();
+
+                       if (!_tcsstr(lwr_name,lwr_filter) && !_tcsstr(lwr_disp,lwr_filter))
+                               continue;
+               }
+
                if (entry->_etype == ET_SHELL)
                        AddEntry(dir._folder, static_cast<ShellEntry*>(entry));
                else
@@ -259,7 +311,7 @@ LRESULT StartMenu::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
                break;
 
          case WM_MOVE: {
-               POINTS& pos = MAKEPOINTS(lparam);
+               const POINTS& pos = MAKEPOINTS(lparam);
 
                 // move open submenus of floating menus
                if (_submenu) {
@@ -296,7 +348,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, _create_info._info);
+                       StartMenu::Create(pos.left+3, pos.bottom-3, _create_info._folders, 0, _create_info._title, _big_icons, _create_info._creator, _create_info._info);
                        CloseStartMenu();
                }
 
@@ -339,7 +391,7 @@ LRESULT StartMenu::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
                        if (_arrow_btns) {
                                RECT rect_up, rect_down;
 
-                               GetArrowButtonRects(&rect_up, &rect_down);
+                               GetArrowButtonRects(&rect_up, &rect_down, _big_icons);
 
                                SCROLL_MODE scroll_mode = SCROLL_NOT;
 
@@ -364,7 +416,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;
@@ -425,9 +477,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);
        }
@@ -441,6 +515,7 @@ LRESULT StartMenu::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
 int StartMenu::ButtonHitTest(POINT pt)
 {
        ClientRect clnt(_hwnd);
+       const bool big_icons = _big_icons;
        RECT rect = {_border_left, _border_top, clnt.right, STARTMENU_LINE_HEIGHT};
 
        if (pt.x<rect.left || pt.x>rect.right)
@@ -468,10 +543,11 @@ int StartMenu::ButtonHitTest(POINT pt)
 
 void StartMenu::InvalidateSelection()
 {
-       if (!_selected_id)
+       if (_selected_id <= 0)
                return;
 
        ClientRect clnt(_hwnd);
+       const bool big_icons = _big_icons;
        RECT rect = {_border_left, _border_top, clnt.right, STARTMENU_LINE_HEIGHT};
 
        for(SMBtnVector::const_iterator it=_buttons.begin()+_scroll_pos; it!=_buttons.end(); ++it) {
@@ -697,6 +773,7 @@ bool StartMenu::GetButtonRect(int id, PRECT prect) const
 {
 #ifdef _LIGHT_STARTMENU
        ClientRect clnt(_hwnd);
+       const bool big_icons = _big_icons;
        RECT rect = {_border_left, _border_top, clnt.right, STARTMENU_LINE_HEIGHT};
 
        for(SMBtnVector::const_iterator it=_buttons.begin()+_scroll_pos; it!=_buttons.end(); ++it) {
@@ -746,32 +823,38 @@ void StartMenu::GetFloatingButtonRect(LPRECT prect)
 }
 
 
-void StartMenu::DrawArrows(HDC hdc)
+void StartMenu::DrawArrows(HDC hdc, bool big_icons)
 {
-       static ResIconEx arrowUpIcon(IDI_ARROW_UP, 8, 4);
-       static ResIconEx arrowDownIcon(IDI_ARROW_DOWN, 8, 4);
+       int cx = big_icons? 16: 8;
+       int cy = big_icons? 8: 4;
+
+       ResIconEx arrowUpIcon(IDI_ARROW_UP, cx, cy);
+       ResIconEx arrowDownIcon(IDI_ARROW_DOWN, cx, cy);
 
        ClientRect clnt(_hwnd);
 
-       DrawIconEx(hdc, clnt.right/2-4, _floating_btn?3:1, arrowUpIcon, 8, 4, 0, 0, DI_NORMAL);
-       DrawIconEx(hdc, clnt.right/2-4, clnt.bottom-5, arrowDownIcon, 8, 4, 0, 0, DI_NORMAL);
+       DrawIconEx(hdc, clnt.right/2-cx/2, _floating_btn?3:1, arrowUpIcon, cx, cy, 0, 0, DI_NORMAL);
+       DrawIconEx(hdc, clnt.right/2-cx/2, clnt.bottom-cy-1, arrowDownIcon, cx, cy, 0, 0, DI_NORMAL);
 }
 
-void StartMenu::GetArrowButtonRects(LPRECT prect_up, LPRECT prect_down)
+void StartMenu::GetArrowButtonRects(LPRECT prect_up, LPRECT prect_down, bool big_icons)
 {
+       int cx = big_icons? 16: 8;
+       int cy = big_icons? 8: 4;
+
        GetClientRect(_hwnd, prect_up);
        *prect_down = *prect_up;
 
-//     prect_up->left = prect_up->right/2 - 4;
-//     prect_up->right = prect_up->left + 8;
-       prect_up->right -= 8;
-       prect_up->top = _floating_btn? 3: 1;
-       prect_up->bottom = prect_up->top + 4;
+//     prect_up->left = prect_up->right/2 - cx/2;
+//     prect_up->right = prect_up->left + cy;
+       prect_up->right -= cx;
+       prect_up->top = _floating_btn? cy-1: 1;
+       prect_up->bottom = prect_up->top + cy;
 
-//     prect_down->left = prect_down->right/2 - 4;
-//     prect_down->right = prect_down->left + 8;
-       prect_down->right -= 8;
-       prect_down->top = prect_down->bottom - 5;
+//     prect_down->left = prect_down->right/2 - cx/2;
+//     prect_down->right = prect_down->left + cy;
+       prect_down->right -= cx;
+       prect_down->top = prect_down->bottom - cy - 1;
 }
 
 
@@ -782,9 +865,10 @@ void StartMenu::Paint(PaintCanvas& canvas)
 
 #ifdef _LIGHT_STARTMENU
        if (_arrow_btns)
-               DrawArrows(canvas);
+               DrawArrows(canvas, _big_icons);
 
        ClientRect clnt(_hwnd);
+       const bool big_icons = _big_icons;
        RECT rect = {_border_left, _border_top, clnt.right, STARTMENU_LINE_HEIGHT};
 
        int sep_width = rect.right-rect.left - 4;
@@ -816,7 +900,7 @@ void StartMenu::Paint(PaintCanvas& canvas)
                                break;
 
                        if (rect.top >= canvas.rcPaint.top)
-                               DrawStartMenuButton(canvas, rect, btn._title, btn, btn._id==_selected_id, false);
+                               DrawStartMenuButton(canvas, rect, btn._title, btn, btn._id==_selected_id, false, _big_icons);
                }
 
                rect.top = rect.bottom;
@@ -847,7 +931,7 @@ void StartMenu::UpdateIcons(/*int idx*/)
 
                                if (entry->_icon_id == ICID_UNKNOWN)
                                        try {
-                                               entry->extract_icon();
+                                               entry->extract_icon(_big_icons);
                                        } catch(COMException&) {
                                                // ignore unexpected exceptions while extracting icons
                                        }
@@ -863,7 +947,7 @@ void StartMenu::UpdateIcons(/*int idx*/)
                                                break;
 
                                        WindowCanvas canvas(_hwnd);
-                                       DrawStartMenuButton(canvas, rect, NULL, btn, btn._id==_selected_id, false);
+                                       DrawStartMenuButton(canvas, rect, NULL, btn, btn._id==_selected_id, false, _big_icons);
 
                                        //InvalidateRect(_hwnd, &rect, FALSE);
                                        //UpdateWindow(_hwnd);
@@ -983,7 +1067,7 @@ ShellEntryMap::iterator StartMenu::AddEntry(const String& title, ICON_ID icon_id
                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
@@ -1064,7 +1148,7 @@ void StartMenu::AddButton(LPCTSTR title, ICON_ID icon_id, bool hasSubmenu, int i
        FontSelection font(canvas, GetStockFont(DEFAULT_GUI_FONT));
 
         // widen window, if it is too small
-       int text_width = GetStartMenuBtnTextWidth(canvas, title, _hwnd) + 16/*icon*/ + 10/*placeholder*/ + 16/*arrow*/;
+       int text_width = GetStartMenuBtnTextWidth(canvas, title, _hwnd) + ICON_SIZE_X + 10/*placeholder*/ + 16/*arrow*/;
 
        int cx = clnt.right - _border_left;
        if (text_width > cx)
@@ -1182,6 +1266,7 @@ void StartMenu::CreateSubmenu(int id, const StartMenuFolders& new_folders, LPCTS
                ClientToScreen(_hwnd, &rect);
 
                x = rect.right; // Submenus should overlap their parent a bit.
+               const bool big_icons = _big_icons;
                y = rect.top+STARTMENU_LINE_HEIGHT +_border_top/*own border*/ -STARTMENU_TOP_BTN_SPACE/*border of new submenu*/;
        } else {
                WindowRect pos(_hwnd);
@@ -1191,7 +1276,7 @@ void StartMenu::CreateSubmenu(int id, const StartMenuFolders& new_folders, LPCTS
        }
 
        _submenu_id = id;
-       _submenu = StartMenu::Create(x, y, new_folders, _hwnd, title, creator, info);
+       _submenu = StartMenu::Create(x, y, new_folders, _hwnd, title, _big_icons, creator, info, _create_info._filter);
 }
 
 
@@ -1212,7 +1297,7 @@ void StartMenu::ActivateEntry(int id, const ShellEntrySet& entries)
                        else {
                                TCHAR path[MAX_PATH];
 
-                               if (entry->get_path(path))
+                               if (entry->get_path(path, COUNTOF(path)))
                                        new_folders.push_back(path);
                        }
 
@@ -1232,7 +1317,7 @@ void StartMenu::ActivateEntry(int id, const ShellEntrySet& entries)
                        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;
@@ -1283,10 +1368,10 @@ int GetStartMenuBtnTextWidth(HDC hdc, LPCTSTR title, HWND hwnd)
 }
 
 #ifdef _LIGHT_STARTMENU
-void DrawStartMenuButton(HDC hdc, const RECT& rect, LPCTSTR title, const SMBtnInfo& btn, bool has_focus, bool pushed)
+void DrawStartMenuButton(HDC hdc, const RECT& rect, LPCTSTR title, const SMBtnInfo& btn, bool has_focus, bool pushed, bool big_icons)
 #else
 void DrawStartMenuButton(HDC hdc, const RECT& rect, LPCTSTR title, HICON hIcon,
-                                                               bool hasSubmenu, bool enabled, bool has_focus, bool pushed);
+                                                               bool hasSubmenu, bool enabled, bool has_focus, bool pushed, bool big_icons);
 #endif
 {
        UINT style = DFCS_BUTTONPUSH;
@@ -1294,8 +1379,8 @@ void DrawStartMenuButton(HDC hdc, const RECT& rect, LPCTSTR title, HICON hIcon,
        if (!btn._enabled)
                style |= DFCS_INACTIVE;
 
-       POINT iconPos = {rect.left+2, (rect.top+rect.bottom-16)/2};
-       RECT textRect = {rect.left+16+4, rect.top+2, rect.right-4, rect.bottom-4};
+       POINT iconPos = {rect.left+2, (rect.top+rect.bottom-ICON_SIZE_Y)/2};
+       RECT textRect = {rect.left+ICON_SIZE_X+4, rect.top+2, rect.right-4, rect.bottom-4};
 
        if (pushed) {
                style |= DFCS_PUSHED;
@@ -1319,16 +1404,16 @@ void DrawStartMenuButton(HDC hdc, const RECT& rect, LPCTSTR title, HICON hIcon,
                FillRect(hdc, &rect, bk_brush);
 
        if (btn._icon_id > ICID_NONE)
-               g_Globals._icon_cache.get_icon(btn._icon_id).draw(hdc, iconPos.x, iconPos.y, 16, 16, bk_color, bk_brush);
+               g_Globals._icon_cache.get_icon(btn._icon_id).draw(hdc, iconPos.x, iconPos.y, ICON_SIZE_X, ICON_SIZE_Y, bk_color, bk_brush/*, big_icons*/);
 
         // draw submenu arrow at the right
        if (btn._hasSubmenu) {
-               static SmallIcon arrowIcon(IDI_ARROW);
-               static SmallIcon selArrowIcon(IDI_ARROW_SELECTED);
+               ResIconEx arrowIcon(IDI_ARROW, ICON_SIZE_X, ICON_SIZE_Y);
+               ResIconEx selArrowIcon(IDI_ARROW_SELECTED, ICON_SIZE_X, ICON_SIZE_Y);
 
-               DrawIconEx(hdc, rect.right-16, iconPos.y,
+               DrawIconEx(hdc, rect.right-ICON_SIZE_X, iconPos.y,
                                        has_focus? selArrowIcon: arrowIcon,
-                                       16, 16, 0, bk_brush, DI_NORMAL);
+                                       ICON_SIZE_X, ICON_SIZE_Y, 0, bk_brush, DI_NORMAL);
        }
 
        if (title) {
@@ -1353,6 +1438,8 @@ void StartMenu::ResizeToButtons()
        WindowCanvas canvas(_hwnd);
        FontSelection font(canvas, GetStockFont(DEFAULT_GUI_FONT));
 
+       const bool big_icons = _big_icons;
+
        int max_width = STARTMENU_WIDTH_MIN;
        int height = 0;
 
@@ -1369,7 +1456,7 @@ void StartMenu::ResizeToButtons()
        }
 
         // calculate new window size
-       int text_width = max_width + 16/*icon*/ + 10/*placeholder*/ + 16/*arrow*/;
+       int text_width = max_width + ICON_SIZE_X + 10/*placeholder*/ + 16/*arrow*/;
 
        RECT rt_hgt = {rect.left, rect.bottom-_border_top-height, rect.left+_border_left+text_width, rect.bottom};
        AdjustWindowRectEx(&rt_hgt, GetWindowStyle(_hwnd), FALSE, GetWindowExStyle(_hwnd));
@@ -1459,7 +1546,7 @@ void StartMenuButton::DrawItem(LPDRAWITEMSTRUCT dis)
 
 
 StartMenuRoot::StartMenuRoot(HWND hwnd)
- :     super(hwnd)
+ :     super(hwnd, false)      ///@todo big icons in start menu root
 {
 #ifndef __MINGW32__    // SHRestricted() missing in MinGW (as of 29.10.2003)
        if (!g_Globals._SHRestricted || !SHRestricted(REST_NOCOMMONGROUPS))
@@ -1467,41 +1554,56 @@ StartMenuRoot::StartMenuRoot(HWND hwnd)
                try {
                         // insert directory "All Users\Start Menu"
                        ShellDirectory cmn_startmenu(GetDesktopFolder(), SpecialFolderPath(CSIDL_COMMON_STARTMENU, _hwnd), _hwnd);
-                       _dirs.push_back(StartMenuDirectory(cmn_startmenu, false));      // don't add subfolders
+                       _dirs.push_back(StartMenuDirectory(cmn_startmenu, (LPCTSTR)SpecialFolderFSPath(CSIDL_COMMON_PROGRAMS, _hwnd)));
                } catch(COMException&) {
                        // ignore exception and don't show additional shortcuts
                }
 
        try {
                 // insert directory "<user name>\Start Menu"
-
                ShellDirectory usr_startmenu(GetDesktopFolder(), SpecialFolderPath(CSIDL_STARTMENU, _hwnd), _hwnd);
-               _dirs.push_back(StartMenuDirectory(usr_startmenu, false));      // don't add subfolders
+               _dirs.push_back(StartMenuDirectory(usr_startmenu, (LPCTSTR)SpecialFolderFSPath(CSIDL_PROGRAMS, _hwnd)));
        } catch(COMException&) {
                // ignore exception and don't show additional shortcuts
        }
 
+       ReadLogoSize();
+}
+
+void StartMenuRoot::ReadLogoSize()
+{
         // read size of logo bitmap
        BITMAP bmp_hdr;
-       GetObject(ResBitmap(IDB_LOGOV), sizeof(BITMAP), &bmp_hdr);
+       GetObject(ResBitmap(GetLogoResId()), sizeof(BITMAP), &bmp_hdr);
        _logo_size.cx = bmp_hdr.bmWidth;
        _logo_size.cy = bmp_hdr.bmHeight;
 
+        // cache logo width
        _border_left = _logo_size.cx + 1;
 }
 
 
-HWND StartMenuRoot::Create(HWND hwndOwner)
+static void CalculateStartPos(HWND hwndOwner, RECT& rect, bool big_icons)
 {
        WindowRect pos(hwndOwner);
 
-       RECT rect = {pos.left, pos.top-STARTMENU_LINE_HEIGHT-4, pos.left+STARTMENU_WIDTH_MIN, pos.top};
+       rect.left = pos.left;
+       rect.top = pos.top-STARTMENU_LINE_HEIGHT-4;
+       rect.right = pos.left+STARTMENU_WIDTH_MIN;
+       rect.bottom = pos.top;
 
 #ifndef _LIGHT_STARTMENU
        rect.top += STARTMENU_LINE_HEIGHT;
 #endif
 
        AdjustWindowRectEx(&rect, WS_POPUP|WS_THICKFRAME|WS_CLIPCHILDREN|WS_VISIBLE, FALSE, 0);
+}
+
+HWND StartMenuRoot::Create(HWND hwndOwner, bool big_icons)
+{
+       RECT rect;
+
+       CalculateStartPos(hwndOwner, rect, big_icons);
 
        return Window::Create(WINDOW_CREATOR(StartMenuRoot), 0, GetWndClasss(), TITLE_STARTMENU,
                                                        WS_POPUP|WS_THICKFRAME|WS_CLIPCHILDREN,
@@ -1518,17 +1620,28 @@ void StartMenuRoot::TrackStartmenu()
        _selected_id = -1;
 #endif
 
+#ifdef _LIGHT_STARTMENU
+        // recalculate start menu root position
+       RECT rect;
+
+       CalculateStartPos(GetParent(hwnd), rect, _big_icons);
+
+       SetWindowPos(hwnd, 0, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, 0);
+
+       ResizeToButtons();
+#endif
+
         // show previously hidden start menu
        ShowWindow(hwnd, SW_SHOW);
        SetForegroundWindow(hwnd);
 
-       while(IsWindow(hwnd)) {
+       while(IsWindow(hwnd) && IsWindowVisible(hwnd)) {
                if (!GetMessage(&msg, 0, 0, 0)) {
                        PostQuitMessage(msg.wParam);
                        break;
                }
 
-                // Check for a mouse click on any window, which is not part of the start menu
+                // Check for a mouse click on any window, that is not part of the start menu
                if (msg.message==WM_LBUTTONDOWN || msg.message==WM_MBUTTONDOWN || msg.message==WM_RBUTTONDOWN) {
                        StartMenu* menu_wnd = NULL;
 
@@ -1647,6 +1760,11 @@ LRESULT  StartMenuRoot::Init(LPCREATESTRUCT pcs)
                AddButton(ResString(IDS_SHUTDOWN),      ICID_LOGOFF, false, IDC_SHUTDOWN);
 
 
+#ifndef _ROS_
+       AddButton(ResString(IDS_TERMINATE),     ICID_LOGOFF, false, IDC_TERMINATE);
+#endif
+
+
 #ifdef __MINGW32__
        RegCloseKey(hkeyAdv);
        RegCloseKey(hkey);
@@ -1678,6 +1796,11 @@ LRESULT  StartMenuRoot::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
                Paint(canvas);
                break;}
 
+         case WM_DISPLAYCHANGE:
+                // re-evaluate logo size using the correct color depth
+               ReadLogoSize();
+               break;
+
          default:
                return super::WndProc(nmsg, wparam, lparam);
        }
@@ -1687,11 +1810,8 @@ LRESULT  StartMenuRoot::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
 
 void StartMenuRoot::Paint(PaintCanvas& canvas)
 {
-       int clr_bits;
-       {WindowCanvas dc(_hwnd); clr_bits=GetDeviceCaps(dc, BITSPIXEL);}
-
        MemCanvas mem_dc;
-       ResBitmap bmp(clr_bits<=8? clr_bits<=4? IDB_LOGOV16: IDB_LOGOV256: IDB_LOGOV);
+       ResBitmap bmp(GetLogoResId());
        BitmapSelection sel(mem_dc, bmp);
 
        ClientRect clnt(_hwnd);
@@ -1709,6 +1829,20 @@ void StartMenuRoot::Paint(PaintCanvas& canvas)
        super::Paint(canvas);
 }
 
+UINT StartMenuRoot::GetLogoResId()
+{
+       WindowCanvas dc(_hwnd);
+
+       int clr_bits = GetDeviceCaps(dc, BITSPIXEL);
+
+       if (clr_bits > 8)
+               return IDB_LOGOV;
+       else if (clr_bits > 4)
+               return IDB_LOGOV256;
+       else
+               return IDB_LOGOV16;
+}
+
 
 void StartMenuRoot::CloseStartMenu(int id)
 {
@@ -1787,11 +1921,15 @@ int StartMenuHandler::Command(int id, int code)
                break;
 
          case IDC_LOGOFF:
-               /* The shell32 Dialog prompts about some system setting change. This is not what we want to display here.
                CloseStartMenu(id);
-               ShowRestartDialog(g_Globals._hwndDesktopBar, EWX_LOGOFF);*/
+               ShowLogoffDialog(g_Globals._hwndDesktopBar);
+               break;
+
+#ifndef _ROS_
+         case IDC_TERMINATE:
                DestroyWindow(GetParent(_hwnd));
                break;
+#endif
 
          case IDC_SHUTDOWN:
                CloseStartMenu(id);
@@ -1806,32 +1944,82 @@ int StartMenuHandler::Command(int id, int code)
                ExplorerPropertySheet(g_Globals._hwndDesktopBar);
                break;
 
+         case IDC_CONTROL_PANEL: {
+               CloseStartMenu(id);
+#ifndef ROSSHELL
+#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
 #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
-               CreateSubmenu(id, CSIDL_PRINTERS, CSIDL_PRINTHOOD, ResString(IDS_PRINTERS));
+#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
-               break;
+                       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_CONTROL_PANEL:
-               CloseStartMenu(id);
-               //@@SDIMainFrame::Create(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}"), 0);
+         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:
+#ifndef ROSSHELL
 #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;
 
@@ -1839,7 +2027,7 @@ int StartMenuHandler::Command(int id, int code)
        // browse menu
 
          case IDC_NETWORK:
-#ifdef _ROS_   // to be removed when network will be implemented
+#ifdef _ROS_   ///@todo to be removed when network browsing will be implemented in shell namespace
                MessageBox(0, TEXT("network not yet implemented"), ResString(IDS_TITLE), MB_OK);
 #else
                CreateSubmenu(id, CSIDL_NETWORK, ResString(IDS_NETWORK));
@@ -1847,7 +2035,7 @@ int StartMenuHandler::Command(int id, int code)
                break;
 
          case IDC_DRIVES:
-               ///@todo exclude removeable drives
+               ///@todo exclude removable drives
                CreateSubmenu(id, CSIDL_DRIVES, ResString(IDS_DRIVES));
                break;
 
@@ -1880,21 +2068,25 @@ int StartMenuHandler::Command(int id, int code)
 
 void StartMenuHandler::ShowSearchDialog()
 {
+#ifndef _ROS_  ///@todo to be removed when SHFindFiles() will be implemented in shell32.dll
        static DynamicFct<SHFINDFILES> SHFindFiles(TEXT("SHELL32"), 90);
 
        if (SHFindFiles)
                (*SHFindFiles)(NULL, NULL);
        else
+#endif
                MessageBox(0, TEXT("SHFindFiles() not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK);
 }
 
 void StartMenuHandler::ShowSearchComputer()
 {
+#ifndef _ROS_  ///@todo to be removed when SHFindComputer() will be implemented in shell32.dll
        static DynamicFct<SHFINDCOMPUTER> SHFindComputer(TEXT("SHELL32"), 91);
 
        if (SHFindComputer)
                (*SHFindComputer)(NULL, NULL);
        else
+#endif
                MessageBox(0, TEXT("SHFindComputer() not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK);
 }
 
@@ -1909,7 +2101,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];
 
@@ -1924,24 +2115,29 @@ void StartMenuHandler::ShowLaunchDialog(HWND hwndOwner)
        }
 }
 
-void StartMenuHandler::ShowRestartDialog(HWND hwndOwner, UINT flags)
+void StartMenuHandler::ShowLogoffDialog(HWND hwndOwner)
 {
-       static DynamicFct<RESTARTWINDOWSDLG> RestartDlg(TEXT("SHELL32"), 59);
+       static DynamicFct<LOGOFFWINDOWSDIALOG> LogoffWindowsDialog(TEXT("SHELL32"), 54);
+//     static DynamicFct<RESTARTWINDOWSDLG> RestartDialog(TEXT("SHELL32"), 59);
 
-       if (RestartDlg)
-               (*RestartDlg)(hwndOwner, (LPWSTR)L"You selected <Log Off>.\n\n", flags);        ///@todo ANSI string conversion if needed
+       if (LogoffWindowsDialog)
+               (*LogoffWindowsDialog)(0);
+/* The RestartDialog function prompts about some system setting change. This is not what we want to display here.
+       else if (RestartDialog)
+               return (*RestartDialog)(hwndOwner, (LPWSTR)L"You selected <Log Off>.\n\n", EWX_LOGOFF) == 1;    ///@todo ANSI string conversion if needed
+*/
        else
-               MessageBox(hwndOwner, TEXT("RestartDlg() not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK);
+               MessageBox(hwndOwner, TEXT("LogoffWindowsDialog() not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK);
 }
 
 void ShowExitWindowsDialog(HWND hwndOwner)
 {
-       static DynamicFct<EXITWINDOWSDLG> ExitWindowsDlg(TEXT("SHELL32"), 60);
+       static DynamicFct<EXITWINDOWSDLG> ExitWindowsDialog(TEXT("SHELL32"), 60);
 
-       if (ExitWindowsDlg)
-               (*ExitWindowsDlg)(hwndOwner);
+       if (ExitWindowsDialog)
+               (*ExitWindowsDialog)(hwndOwner);
        else
-               MessageBox(hwndOwner, TEXT("ExitWindowsDlg() not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK);
+               MessageBox(hwndOwner, TEXT("ExitWindowsDialog() not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK);
 }
 
 
@@ -1949,16 +2145,11 @@ void SettingsMenu::AddEntries()
 {
        super::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), ICID_CONFIG, false, IDC_CONTROL_PANEL);
-
-#ifdef _ROS_   // to be removed when printer/network will be implemented
-       AddButton(ResString(IDS_PRINTERS),                      ICID_PRINTER, false, IDC_PRINTERS);
+#if defined(ROSSHELL) || defined(_ROS_)        // _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);
+       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);
@@ -1969,6 +2160,13 @@ void SettingsMenu::AddEntries()
                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);
 }
 
 void BrowseMenu::AddEntries()
@@ -1978,7 +2176,7 @@ 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
-#ifdef _ROS_   // to be removed when printer/network will be implemented
+#if defined(ROSSHELL) || defined(_ROS_)        // _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);
@@ -2019,7 +2217,7 @@ void RecentStartMenu::AddEntries()
                }
 
                dir.sort_directory(SORT_DATE);
-               AddShellEntries(dir, RECENT_DOCS_COUNT, smd._subfolders);
+               AddShellEntries(dir, RECENT_DOCS_COUNT, smd._ignore);   ///@todo read max. count of entries from registry
        }
 }
 
@@ -2030,6 +2228,9 @@ void FavoritesMenu::AddEntries()
 {
        super::AddEntries();
 
+       String lwr_filter = _create_info._filter;
+       lwr_filter.toLower();
+
        for(BookmarkList::iterator it=_bookmarks.begin(); it!=_bookmarks.end(); ++it) {
                BookmarkNode& node = *it;
 
@@ -2049,6 +2250,20 @@ void FavoritesMenu::AddEntries()
                        if (!bookmark._icon_path.empty())
                                icon = g_Globals._icon_cache.extract(bookmark._icon_path, bookmark._icon_idx);
 
+                        // filter non-directory entries
+                       if (!lwr_filter.empty()) {
+                               String lwr_name = bookmark._name;
+                               String lwr_desc = bookmark._description;
+                               String lwr_url = bookmark._url;
+
+                               lwr_name.toLower();
+                               lwr_desc.toLower();
+                               lwr_url.toLower();
+
+                               if (!_tcsstr(lwr_name,lwr_filter) && !_tcsstr(lwr_desc,lwr_filter) && !_tcsstr(lwr_url,lwr_filter))
+                                       continue;
+                       }
+
                        AddButton(bookmark._name, icon!=ICID_NONE?icon:ICID_BOOKMARK, false, id);
                }
        }
@@ -2070,8 +2285,11 @@ int FavoritesMenu::Command(int id, int code)
                        Bookmark& bookmark = *node._pbookmark;
 
                        String url = bookmark._url;
+                       HWND hparent = GetParent(_hwnd);
+
                        CloseStartMenu(id);
-                       launch_file(GetParent(_hwnd), url, SW_SHOWNORMAL);
+
+                       launch_file(hparent, url, SW_SHOWNORMAL);
                }
 
                return 0;