2 * Copyright 2003, 2004 Martin Fuchs
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 // Explorer start menu
27 // Martin Fuchs, 19.08.2003
29 // Credits: Thanks to Everaldo (http://www.everaldo.com) for his nice looking icons.
35 #include "../resource.h"
37 #include "desktopbar.h"
38 #include "startmenu.h"
40 #include "../dialogs/searchprogram.h"
41 #include "../dialogs/settings.h"
44 #define SHELLPATH_CONTROL_PANEL TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}")
45 #define SHELLPATH_PRINTERS TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}")
46 #define SHELLPATH_NET_CONNECTIONS TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}")
49 StartMenu::StartMenu(HWND hwnd
, int icon_size
)
53 _next_id
= IDC_FIRST_MENU
;
58 _bottom_max
= INT_MAX
;
60 _floating_btn
= false;
62 _scroll_mode
= SCROLL_NOT
;
66 _last_pos
= WindowRect(hwnd
).pos();
67 #ifdef _LIGHT_STARTMENU
73 StartMenu::StartMenu(HWND hwnd
, const StartMenuCreateInfo
& create_info
, int icon_size
)
75 _create_info(create_info
),
78 for(StartMenuFolders::const_iterator it
=create_info
._folders
.begin(); it
!=create_info
._folders
.end(); ++it
)
80 _dirs
.push_back(ShellDirectory(GetDesktopFolder(), *it
, _hwnd
));
82 _next_id
= IDC_FIRST_MENU
;
86 _border_top
= create_info
._border_top
;
87 _bottom_max
= INT_MAX
;
89 _floating_btn
= create_info
._border_top
? true: false;
91 _scroll_mode
= SCROLL_NOT
;
95 _last_pos
= WindowRect(hwnd
).pos();
96 #ifdef _LIGHT_STARTMENU
102 StartMenu::~StartMenu()
104 SendParent(PM_STARTMENU_CLOSED
);
108 // We need this wrapper function for s_wcStartMenu, it calls the WIN32 API,
109 // though static C++ initializers are not allowed for Winelib applications.
110 BtnWindowClass
& StartMenu::GetWndClasss()
112 static BtnWindowClass
s_wcStartMenu(CLASSNAME_STARTMENU
);
114 return s_wcStartMenu
;
118 Window::CREATORFUNC_INFO
StartMenu::s_def_creator
= STARTMENU_CREATOR(StartMenu
);
120 HWND
StartMenu::Create(int x
, int y
, const StartMenuFolders
& folders
, HWND hwndParent
, LPCTSTR title
,
121 CREATORFUNC_INFO creator
, void* info
, const String
& filter
)
123 UINT style
, ex_style
;
127 style
= WS_POPUP
|WS_THICKFRAME
|WS_CLIPCHILDREN
|WS_VISIBLE
;
129 top_height
= STARTMENU_TOP_BTN_SPACE
;
131 style
= WS_POPUP
|WS_CAPTION
|WS_SYSMENU
|WS_CLIPCHILDREN
|WS_VISIBLE
;
132 ex_style
= WS_EX_TOOLWINDOW
;
136 int icon_size
= ICON_SIZE_SMALL
;
137 RECT rect
= {x
, y
-STARTMENU_LINE_HEIGHT(icon_size
)-top_height
, x
+STARTMENU_WIDTH_MIN
, y
};
139 #ifndef _LIGHT_STARTMENU
140 rect
.top
+= STARTMENU_LINE_HEIGHT(icon_size
);
143 AdjustWindowRectEx(&rect
, style
, FALSE
, ex_style
);
145 StartMenuCreateInfo create_info
;
147 create_info
._folders
= folders
;
148 create_info
._border_top
= top_height
;
149 create_info
._creator
= creator
;
150 create_info
._info
= info
;
151 create_info
._filter
= filter
;
154 create_info
._title
= title
;
156 HWND hwnd
= Window::Create(creator
, &create_info
, ex_style
, GetWndClasss(), title
,
157 style
, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
, hwndParent
);
159 // make sure the window is not off the screen
166 LRESULT
StartMenu::Init(LPCREATESTRUCT pcs
)
171 if (super::Init(pcs
))
174 // create buttons for registered entries in _entries
175 for(ShellEntryMap::const_iterator it
=_entries
.begin(); it
!=_entries
.end(); ++it
) {
176 const StartMenuEntry
& sme
= it
->second
;
177 bool hasSubmenu
= false;
179 for(ShellEntrySet::const_iterator it
=sme
._entries
.begin(); it
!=sme
._entries
.end(); ++it
)
180 if ((*it
)->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
183 #ifdef _LIGHT_STARTMENU
184 _buttons
.push_back(SMBtnInfo(sme
, it
->first
, hasSubmenu
));
186 AddButton(sme
._title
, sme
._hIcon
, hasSubmenu
, it
->first
);
190 #ifdef _LIGHT_STARTMENU
191 if (_buttons
.empty())
193 if (!GetWindow(_hwnd
, GW_CHILD
))
195 AddButton(ResString(IDS_EMPTY
), ICID_NONE
, false, 0, false);
197 #ifdef _LIGHT_STARTMENU
201 #ifdef _LAZY_ICONEXTRACT
202 PostMessage(_hwnd
, PM_UPDATE_ICONS
, 0, 0);
204 } catch(COMException
& e
) {
205 HandleException(e
, pcs
->hwndParent
); // destroys the start menu window while switching focus
211 void StartMenu::AddEntries()
213 for(StartMenuShellDirs::iterator it
=_dirs
.begin(); it
!=_dirs
.end(); ++it
) {
214 StartMenuDirectory
& smd
= *it
;
215 ShellDirectory
& dir
= smd
._dir
;
220 #ifdef _LAZY_ICONEXTRACT
221 dir
.smart_scan(SORT_NAME
, SCAN_DONT_EXTRACT_ICONS
); // lazy icon extraction, try to read directly from filesystem
223 dir
.smart_scan(SORT_NAME
);
227 AddShellEntries(dir
, -1, smd
._ignore
);
232 static LPTSTR
trim_path_slash(LPTSTR path
)
239 if (p
>path
&& (p
[-1]=='\\' || p
[-1]=='/'))
245 void StartMenu::AddShellEntries(const ShellDirectory
& dir
, int max
, const String
& ignore
)
247 TCHAR ignore_path
[MAX_PATH
], ignore_dir
[MAX_PATH
], ignore_name
[_MAX_FNAME
], ignore_ext
[_MAX_EXT
];
248 TCHAR dir_path
[MAX_PATH
];
250 if (!ignore
.empty()) {
251 _tsplitpath_s(ignore
, ignore_path
, COUNTOF(ignore_path
), ignore_dir
, COUNTOF(ignore_dir
), ignore_name
, COUNTOF(ignore_name
), ignore_ext
, COUNTOF(ignore_ext
));
253 _tcscat(ignore_path
, ignore_dir
);
254 _tcscat(ignore_name
, ignore_ext
);
256 dir
.get_path(dir_path
, COUNTOF(dir_path
));
258 if (_tcsicmp(trim_path_slash(dir_path
), trim_path_slash(ignore_path
)))
263 String lwr_filter
= _create_info
._filter
;
264 lwr_filter
.toLower();
267 for(Entry
*entry
=dir
._down
; entry
; entry
=entry
->_next
) {
268 // hide files like "desktop.ini"
269 if (entry
->_shell_attribs
& SFGAO_HIDDEN
)
270 //not appropriate for drive roots: if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
273 // hide "Programs" subfolders if requested
274 if (*ignore_name
&& !_tcsicmp(entry
->_data
.cFileName
, ignore_name
))
277 // only 'max' entries shall be added.
281 // filter only non-directory entries
282 if (!(entry
->_data
.dwFileAttributes
&FILE_ATTRIBUTE_DIRECTORY
) && !lwr_filter
.empty()) {
283 String lwr_name
= entry
->_data
.cFileName
;
284 String lwr_disp
= entry
->_display_name
;
289 if (!_tcsstr(lwr_name
,lwr_filter
) && !_tcsstr(lwr_disp
,lwr_filter
))
293 if (entry
->_etype
== ET_SHELL
)
294 AddEntry(dir
._folder
, static_cast<ShellEntry
*>(entry
));
296 AddEntry(dir
._folder
, entry
);
301 LRESULT
StartMenu::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
305 PaintCanvas
canvas(_hwnd
);
310 ResizeButtons(LOWORD(lparam
)-_border_left
);
315 pos
.x
= LOWORD(lparam
);
316 pos
.y
= HIWORD(lparam
);
318 // move open submenus of floating menus
320 int dx
= pos
.x
- _last_pos
.x
;
321 int dy
= pos
.y
- _last_pos
.y
;
324 WindowRect
rt(_submenu
);
325 SetWindowPos(_submenu
, 0, rt
.left
+dx
, rt
.top
+dy
, 0, 0, SWP_NOSIZE
|SWP_NOACTIVATE
);
326 //MoveVisible(_submenu);
335 LRESULT res
= super::WndProc(nmsg
, wparam
, lparam
);
337 if (res
>=HTSIZEFIRST
&& res
<=HTSIZELAST
)
338 return HTCLIENT
; // disable window resizing
342 case WM_LBUTTONDOWN
: {
345 // check mouse cursor for coordinates of floating button
346 GetFloatingButtonRect(&rect
);
348 if (PtInRect(&rect
, Point(lparam
))) {
349 // create a floating copy of the current start menu
350 WindowRect
pos(_hwnd
);
352 ///@todo do something similar to StartMenuRoot::TrackStartmenu() in order to automatically close submenus when clicking on the desktop background
353 StartMenu::Create(pos
.left
+3, pos
.bottom
-3, _create_info
._folders
, 0, _create_info
._title
, _create_info
._creator
, _create_info
._info
);
357 #ifdef _LIGHT_STARTMENU
358 int id
= ButtonHitTest(Point(lparam
));
361 Command(id
, BN_CLICKED
);
366 if ((wparam
&0xFFF0) == SC_SIZE
)
367 return 0; // disable window resizing
371 // close start menu when activating another application
374 break; // don't call super::WndProc in case "this" has been deleted
379 #ifdef _LIGHT_STARTMENU
380 if (_scroll_mode
!= SCROLL_NOT
) {
387 #ifdef _LIGHT_STARTMENU
389 // automatically set the focus to startmenu entries when moving the mouse over them
390 if (lparam
!= _last_mouse_pos
) { // don't process WM_MOUSEMOVE when opening submenus using keyboard navigation
394 RECT rect_up
, rect_down
;
396 GetArrowButtonRects(&rect_up
, &rect_down
, _icon_size
);
398 SCROLL_MODE scroll_mode
= SCROLL_NOT
;
400 if (PtInRect(&rect_up
, pt
))
401 scroll_mode
= SCROLL_UP
;
402 else if (PtInRect(&rect_down
, pt
))
403 scroll_mode
= SCROLL_DOWN
;
405 if (scroll_mode
!= _scroll_mode
) {
406 if (scroll_mode
== SCROLL_NOT
) {
411 SetTimer(_hwnd
, 0, 150, NULL
); // 150 ms scroll interval
415 _scroll_mode
= scroll_mode
;
419 int new_id
= ButtonHitTest(pt
);
421 if (new_id
>0 && new_id
!=_selected_id
)
422 SelectButton(new_id
);
424 _last_mouse_pos
= lparam
;
429 if (_scroll_mode
== SCROLL_UP
) {
430 if (_scroll_pos
> 0) {
432 InvalidateRect(_hwnd
, NULL
, TRUE
);
435 if (_scroll_pos
<= _invisible_lines
) {
437 InvalidateRect(_hwnd
, NULL
, TRUE
);
446 case PM_STARTENTRY_FOCUSED
: { ///@todo use TrackMouseEvent() and WM_MOUSEHOVER to wait a bit before opening submenus
447 BOOL hasSubmenu
= wparam
;
448 HWND hctrl
= (HWND
)lparam
;
450 // automatically open submenus
452 UpdateWindow(_hwnd
); // draw focused button before waiting on submenu creation
453 //SendMessage(_hwnd, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hctrl),BN_CLICKED), (LPARAM)hctrl);
454 Command(GetDlgCtrlID(hctrl
), BN_CLICKED
);
456 // close any open submenu
457 CloseOtherSubmenus();
462 #ifdef _LAZY_ICONEXTRACT
463 case PM_UPDATE_ICONS
:
464 UpdateIcons(/*wparam*/);
468 case PM_STARTENTRY_LAUNCHED
:
469 if (GetWindowStyle(_hwnd
) & WS_CAPTION
) // don't automatically close floating menus
472 // route message to the parent menu and close menus after launching an entry
473 if (!SendParent(nmsg
, wparam
, lparam
))
475 return 1; // signal that we have received and processed the message
477 case PM_STARTMENU_CLOSED
:
481 case PM_SELECT_ENTRY
:
482 SelectButtonIndex(0, wparam
!=0);
485 #ifdef _LIGHT_STARTMENU
486 case WM_CONTEXTMENU
: {
487 Point
screen_pt(lparam
), clnt_pt
=screen_pt
;
488 ScreenToClient(_hwnd
, &clnt_pt
);
490 int id
= ButtonHitTest(clnt_pt
);
493 StartMenuEntry
& sme
= _entries
[id
];
495 for(ShellEntrySet::iterator it
=sme
._entries
.begin(); it
!=sme
._entries
.end(); ++it
) {
499 CHECKERROR(entry
->do_context_menu(_hwnd
, screen_pt
, _cm_ifs
)); // may close start menu because of focus loss
500 ///@todo refresh on successfull context menu execution?
501 break; ///@todo handle context menu for more than one entry
509 return super::WndProc(nmsg
, wparam
, lparam
);
516 #ifdef _LIGHT_STARTMENU
518 int StartMenu::ButtonHitTest(POINT pt
)
520 ClientRect
clnt(_hwnd
);
521 const int icon_size
= _icon_size
;
522 RECT rect
= {_border_left
, _border_top
, clnt
.right
, STARTMENU_LINE_HEIGHT(icon_size
)};
524 if (pt
.x
<rect
.left
|| pt
.x
>rect
.right
)
527 for(SMBtnVector::const_iterator it
=_buttons
.begin()+_scroll_pos
; it
!=_buttons
.end(); ++it
) {
528 const SMBtnInfo
& info
= *it
;
533 rect
.bottom
= rect
.top
+ (info
._id
==-1? STARTMENU_SEP_HEIGHT(icon_size
): STARTMENU_LINE_HEIGHT(icon_size
));
535 if (rect
.bottom
> _bottom_max
)
538 if (pt
.y
< rect
.bottom
) // PtInRect(&rect, pt)
541 rect
.top
= rect
.bottom
;
547 void StartMenu::InvalidateSelection()
549 if (_selected_id
<= 0)
552 ClientRect
clnt(_hwnd
);
553 const int icon_size
= _icon_size
;
554 RECT rect
= {_border_left
, _border_top
, clnt
.right
, STARTMENU_LINE_HEIGHT(icon_size
)};
556 for(SMBtnVector::const_iterator it
=_buttons
.begin()+_scroll_pos
; it
!=_buttons
.end(); ++it
) {
557 const SMBtnInfo
& info
= *it
;
559 rect
.bottom
= rect
.top
+ (info
._id
==-1? STARTMENU_SEP_HEIGHT(icon_size
): STARTMENU_LINE_HEIGHT(icon_size
));
561 if (info
._id
== _selected_id
) {
562 InvalidateRect(_hwnd
, &rect
, TRUE
);
566 rect
.top
= rect
.bottom
;
570 const SMBtnInfo
* StartMenu::GetButtonInfo(int id
) const
572 for(SMBtnVector::const_iterator it
=_buttons
.begin(); it
!=_buttons
.end(); ++it
)
579 bool StartMenu::SelectButton(int id
, bool open_sub
)
584 if (id
== _selected_id
)
587 InvalidateSelection();
589 const SMBtnInfo
* btn
= GetButtonInfo(id
);
591 if (btn
&& btn
->_enabled
) {
594 InvalidateSelection();
596 // automatically open submenus
597 if (btn
->_hasSubmenu
) {
601 CloseOtherSubmenus(); // close any open submenu
610 bool StartMenu::OpenSubmenu(bool select_first
)
612 if (_selected_id
== -1)
615 InvalidateSelection();
617 const SMBtnInfo
* btn
= GetButtonInfo(_selected_id
);
619 // automatically open submenus
620 if (btn
->_hasSubmenu
) {
621 //@@ allows destroying of startmenu when processing PM_UPDATE_ICONS -> GPF
622 UpdateWindow(_hwnd
); // draw focused button before waiting on submenu creation
623 Command(_selected_id
, BN_CLICKED
);
625 if (select_first
&& _submenu
)
626 SendMessage(_submenu
, PM_SELECT_ENTRY
, (WPARAM
)false, 0);
634 int StartMenu::GetSelectionIndex()
636 if (_selected_id
== -1)
639 for(int i
=0; i
<(int)_buttons
.size(); ++i
)
640 if (_buttons
[i
]._id
== _selected_id
)
646 bool StartMenu::SelectButtonIndex(int idx
, bool open_sub
)
648 if (idx
>=0 && idx
<(int)_buttons
.size())
649 return SelectButton(_buttons
[idx
]._id
, open_sub
);
654 void StartMenu::ProcessKey(int vk
)
659 Command(_selected_id
, BN_CLICKED
);
671 SelectButtonIndex(0, false);
675 SelectButtonIndex(_buttons
.size()-1, false);
680 CloseOtherSubmenus();
681 else if (!(GetWindowStyle(_hwnd
) & WS_CAPTION
)) // don't automatically close floating menus
682 DestroyWindow(_hwnd
);
694 if (vk
>='0' && vk
<='Z')
695 JumpToNextShortcut(vk
);
699 bool StartMenu::Navigate(int step
)
701 int idx
= GetSelectionIndex();
708 idx
= _buttons
.size() - step
;
714 if (_buttons
.size()<=1 && (idx
<0 || idx
>(int)_buttons
.size()))
718 idx
+= _buttons
.size();
720 if (idx
> (int)_buttons
.size())
721 idx
-= _buttons
.size()+1;
723 if (SelectButtonIndex(idx
, false))
730 bool StartMenu::JumpToNextShortcut(char c
)
732 int cur_idx
= GetSelectionIndex();
740 SMBtnVector::const_iterator cur_it
= _buttons
.begin();
741 cur_it
+= cur_idx
+ 1;
743 // first search down from current item...
744 SMBtnVector::const_iterator it
= cur_it
;
745 for(; it
!=_buttons
.end(); ++it
) {
746 const SMBtnInfo
& btn
= *it
;
748 if (!btn
._title
.empty() && toupper((TBYTE
)btn
._title
.at(0)) == c
) {
750 first_found
= btn
._id
;
756 // ...now search from top to the current item
757 it
= _buttons
.begin();
758 for(; it
!=_buttons
.end() && it
!=cur_it
; ++it
) {
759 const SMBtnInfo
& btn
= *it
;
761 if (!btn
._title
.empty() && toupper((TBYTE
)btn
._title
.at(0)) == c
) {
763 first_found
= btn
._id
;
770 SelectButton(first_found
);
773 Command(first_found
, BN_CLICKED
);
780 #endif // _LIGHT_STARTMENU
783 bool StartMenu::GetButtonRect(int id
, PRECT prect
) const
785 #ifdef _LIGHT_STARTMENU
786 ClientRect
clnt(_hwnd
);
787 const int icon_size
= _icon_size
;
788 RECT rect
= {_border_left
, _border_top
, clnt
.right
, STARTMENU_LINE_HEIGHT(icon_size
)};
790 for(SMBtnVector::const_iterator it
=_buttons
.begin()+_scroll_pos
; it
!=_buttons
.end(); ++it
) {
791 const SMBtnInfo
& info
= *it
;
793 rect
.bottom
= rect
.top
+ (info
._id
==-1? STARTMENU_SEP_HEIGHT(icon_size
): STARTMENU_LINE_HEIGHT(icon_size
));
795 if (info
._id
== id
) {
800 rect
.top
= rect
.bottom
;
805 HWND btn
= GetDlgItem(_hwnd
, id
);
808 GetWindowRect(btn
, prect
);
809 ScreenToClient(_hwnd
, prect
);
818 void StartMenu::DrawFloatingButton(HDC hdc
)
820 static ResIconEx
floatingIcon(IDI_FLOATING
, 8, 4);
822 ClientRect
clnt(_hwnd
);
824 DrawIconEx(hdc
, clnt
.right
-12, 0, floatingIcon
, 8, 4, 0, 0, DI_NORMAL
);
827 void StartMenu::GetFloatingButtonRect(LPRECT prect
)
829 GetClientRect(_hwnd
, prect
);
832 prect
->left
= prect
->right
- 8;
837 void StartMenu::DrawArrows(HDC hdc
, int icon_size
)
839 int cx
= icon_size
/ 2;
840 int cy
= icon_size
/ 4;
842 ResIconEx
arrowUpIcon(IDI_ARROW_UP
, cx
, cy
);
843 ResIconEx
arrowDownIcon(IDI_ARROW_DOWN
, cx
, cy
);
845 ClientRect
clnt(_hwnd
);
847 DrawIconEx(hdc
, clnt
.right
/2-cx
/2, _floating_btn
?3:1, arrowUpIcon
, cx
, cy
, 0, 0, DI_NORMAL
);
848 DrawIconEx(hdc
, clnt
.right
/2-cx
/2, clnt
.bottom
-cy
-1, arrowDownIcon
, cx
, cy
, 0, 0, DI_NORMAL
);
851 void StartMenu::GetArrowButtonRects(LPRECT prect_up
, LPRECT prect_down
, int icon_size
)
853 int cx
= icon_size
/ 2;
854 int cy
= icon_size
/ 4;
856 GetClientRect(_hwnd
, prect_up
);
857 *prect_down
= *prect_up
;
859 // prect_up->left = prect_up->right/2 - cx/2;
860 // prect_up->right = prect_up->left + cy;
861 prect_up
->right
-= cx
;
862 prect_up
->top
= _floating_btn
? cy
-1: 1;
863 prect_up
->bottom
= prect_up
->top
+ cy
;
865 // prect_down->left = prect_down->right/2 - cx/2;
866 // prect_down->right = prect_down->left + cy;
867 prect_down
->right
-= cx
;
868 prect_down
->top
= prect_down
->bottom
- cy
- 1;
872 void StartMenu::Paint(PaintCanvas
& canvas
)
875 DrawFloatingButton(canvas
);
877 #ifdef _LIGHT_STARTMENU
879 DrawArrows(canvas
, _icon_size
);
881 ClientRect
clnt(_hwnd
);
882 const int icon_size
= _icon_size
;
883 RECT rect
= {_border_left
, _border_top
, clnt
.right
, STARTMENU_LINE_HEIGHT(icon_size
)};
885 int sep_width
= rect
.right
-rect
.left
- 4;
887 FontSelection
font(canvas
, GetStockFont(DEFAULT_GUI_FONT
));
888 BkMode
bk_mode(canvas
, TRANSPARENT
);
890 for(SMBtnVector::const_iterator it
=_buttons
.begin()+_scroll_pos
; it
!=_buttons
.end(); ++it
) {
891 const SMBtnInfo
& btn
= *it
;
893 if (rect
.top
> canvas
.rcPaint
.bottom
)
896 if (btn
._id
== -1) { // a separator?
897 rect
.bottom
= rect
.top
+ STARTMENU_SEP_HEIGHT(icon_size
);
899 if (rect
.bottom
> _bottom_max
)
902 BrushSelection
brush_sel(canvas
, GetSysColorBrush(COLOR_BTNSHADOW
));
903 PatBlt(canvas
, rect
.left
+2, rect
.top
+STARTMENU_SEP_HEIGHT(icon_size
)/2-1, sep_width
, 1, PATCOPY
);
905 SelectBrush(canvas
, GetSysColorBrush(COLOR_BTNHIGHLIGHT
));
906 PatBlt(canvas
, rect
.left
+2, rect
.top
+STARTMENU_SEP_HEIGHT(icon_size
)/2, sep_width
, 1, PATCOPY
);
908 rect
.bottom
= rect
.top
+ STARTMENU_LINE_HEIGHT(icon_size
);
910 if (rect
.bottom
> _bottom_max
)
913 if (rect
.top
>= canvas
.rcPaint
.top
)
914 DrawStartMenuButton(canvas
, rect
, btn
._title
, btn
, btn
._id
==_selected_id
, false, _icon_size
);
917 rect
.top
= rect
.bottom
;
922 #ifdef _LAZY_ICONEXTRACT
923 void StartMenu::UpdateIcons(/*int idx*/)
927 #ifdef _SINGLE_ICONEXTRACT
930 int idx
= _scroll_pos
;
932 for(; idx
<(int)_buttons
.size(); ++idx
) {
933 SMBtnInfo
& btn
= _buttons
[idx
];
935 if (btn
._icon_id
==ICID_UNKNOWN
&& btn
._id
>0) {
936 StartMenuEntry
& sme
= _entries
[btn
._id
];
938 btn
._icon_id
= ICID_NONE
;
940 for(ShellEntrySet::iterator it
=sme
._entries
.begin(); it
!=sme
._entries
.end(); ++it
) {
943 if (entry
->_icon_id
== ICID_UNKNOWN
)
944 entry
->_icon_id
= entry
->safe_extract_icon(ICF_FROM_ICON_SIZE(_icon_size
));
946 if (entry
->_icon_id
> ICID_NONE
) {
947 btn
._icon_id
= (ICON_ID
)/*@@*/ entry
->_icon_id
;
951 GetButtonRect(btn
._id
, &rect
);
953 if (rect
.bottom
> _bottom_max
)
956 WindowCanvas
canvas(_hwnd
);
957 DrawStartMenuButton(canvas
, rect
, NULL
, btn
, btn
._id
==_selected_id
, false, _icon_size
);
959 //InvalidateRect(_hwnd, &rect, FALSE);
960 //UpdateWindow(_hwnd);
969 // if (++idx < (int)_buttons.size())
970 // PostMessage(_hwnd, PM_UPDATE_ICONS, idx, 0);
974 int icons_extracted
= 0;
975 int icons_updated
= 0;
977 for(StartMenuShellDirs::iterator it
=_dirs
.begin(); it
!=_dirs
.end(); ++it
) {
978 ShellDirectory
& dir
= it
->_dir
;
980 icons_extracted
+= dir
.extract_icons(icon_size
);
983 if (icons_extracted
) {
984 for(ShellEntryMap::iterator it1
=_entries
.begin(); it1
!=_entries
.end(); ++it1
) {
985 StartMenuEntry
& sme
= it1
->second
;
988 sme
._hIcon
= (HICON
)-1;
990 for(ShellEntrySet::const_iterator it2
=sme
._entries
.begin(); it2
!=sme
._entries
.end(); ++it2
) {
991 const Entry
* sm_entry
= *it2
;
993 if (sm_entry
->_hIcon
) {
994 sme
._hIcon
= sm_entry
->_hIcon
;
1001 for(SMBtnVector::iterator it
=_buttons
.begin(); it
!=_buttons
.end(); ++it
) {
1002 SMBtnInfo
& info
= *it
;
1004 if (info
._id
>0 && !info
._hIcon
) {
1005 info
._hIcon
= _entries
[info
._id
]._hIcon
;
1011 if (icons_updated
) {
1012 InvalidateRect(_hwnd
, NULL
, FALSE
);
1013 UpdateWindow(_hwnd
);
1020 // resize child button controls to accomodate for new window size
1021 void StartMenu::ResizeButtons(int cx
)
1023 HDWP hdwp
= BeginDeferWindowPos(10);
1025 for(HWND ctrl
=GetWindow(_hwnd
,GW_CHILD
); ctrl
; ctrl
=GetNextWindow(ctrl
,GW_HWNDNEXT
)) {
1026 ClientRect
rt(ctrl
);
1028 if (rt
.right
!= cx
) {
1029 int height
= rt
.bottom
- rt
.top
;
1031 // special handling for separator controls
1032 if (!height
&& (GetWindowStyle(ctrl
)&SS_TYPEMASK
)==SS_ETCHEDHORZ
)
1035 hdwp
= DeferWindowPos(hdwp
, ctrl
, 0, 0, 0, cx
, height
, SWP_NOMOVE
|SWP_NOZORDER
|SWP_NOACTIVATE
);
1039 EndDeferWindowPos(hdwp
);
1043 int StartMenu::Command(int id
, int code
)
1045 #ifndef _LIGHT_STARTMENU
1053 ShellEntryMap::iterator found
= _entries
.find(id
);
1055 if (found
!= _entries
.end()) {
1056 ActivateEntry(id
, found
->second
._entries
);
1060 return super::Command(id
, code
);
1061 #ifndef _LIGHT_STARTMENU
1070 ShellEntryMap::iterator
StartMenu::AddEntry(const String
& title
, ICON_ID icon_id
, Entry
* entry
)
1072 // search for an already existing subdirectory entry with the same name
1073 if (entry
->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1075 for(ShellEntryMap::iterator it
=_entries
.begin(); it
!=_entries
.end(); ++it
) {
1076 StartMenuEntry
& sme
= it
->second
;
1078 if (!_tcsicmp(sme
._title
, title
)) ///@todo speed up by using a map indexed by name
1080 for(ShellEntrySet::iterator it2
=sme
._entries
.begin(); it2
!=sme
._entries
.end(); ++it2
) {
1081 if ((*it2
)->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) {
1082 // merge the new shell entry with the existing of the same name
1083 sme
._entries
.insert(entry
);
1092 ShellEntryMap::iterator sme
= AddEntry(title
, icon_id
);
1094 sme
->second
._entries
.insert(entry
);
1099 ShellEntryMap::iterator
StartMenu::AddEntry(const String
& title
, ICON_ID icon_id
, int id
)
1107 sme
._icon_id
= icon_id
;
1109 ShellEntryMap::iterator it
= _entries
.insert(make_pair(id
, sme
)).first
;
1114 ShellEntryMap::iterator
StartMenu::AddEntry(const ShellFolder folder
, ShellEntry
* entry
)
1118 if (entry
->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1119 icon_id
= ICID_APPS
;
1121 icon_id
= (ICON_ID
)/*@@*/ entry
->_icon_id
;
1123 return AddEntry(folder
.get_name(entry
->_pidl
), icon_id
, entry
);
1126 ShellEntryMap::iterator
StartMenu::AddEntry(const ShellFolder folder
, Entry
* entry
)
1130 if (entry
->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1131 icon_id
= ICID_APPS
;
1133 icon_id
= (ICON_ID
)/*@@*/ entry
->_icon_id
;
1135 return AddEntry(entry
->_display_name
, icon_id
, entry
);
1139 void StartMenu::AddButton(LPCTSTR title
, ICON_ID icon_id
, bool hasSubmenu
, int id
, bool enabled
)
1141 #ifdef _LIGHT_STARTMENU
1142 _buttons
.push_back(SMBtnInfo(title
, icon_id
, id
, hasSubmenu
, enabled
));
1144 DWORD style
= enabled
? WS_VISIBLE
|WS_CHILD
|BS_OWNERDRAW
: WS_VISIBLE
|WS_CHILD
|BS_OWNERDRAW
|WS_DISABLED
;
1146 WindowRect
rect(_hwnd
);
1147 ClientRect
clnt(_hwnd
);
1149 // increase window height to make room for the new button
1150 rect
.top
-= STARTMENU_LINE_HEIGHT(icon_size
);
1152 // move down if we are too high now
1154 rect
.top
+= STARTMENU_LINE_HEIGHT(icon_size
);
1155 rect
.bottom
+= STARTMENU_LINE_HEIGHT(icon_size
);
1158 WindowCanvas
canvas(_hwnd
);
1159 FontSelection
font(canvas
, GetStockFont(DEFAULT_GUI_FONT
));
1161 // widen window, if it is too small
1162 int text_width
= GetStartMenuBtnTextWidth(canvas
, title
, _hwnd
) + icon_size
+ 10/*placeholder*/ + 16/*arrow*/;
1164 int cx
= clnt
.right
- _border_left
;
1165 if (text_width
> cx
)
1166 rect
.right
+= text_width
-cx
;
1168 MoveWindow(_hwnd
, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
, TRUE
);
1170 StartMenuCtrl(_hwnd
, _border_left
, clnt
.bottom
, rect
.right
-rect
.left
-_border_left
,
1171 title
, id
, g_Globals
._icon_cache
.get_icon(icon_id
)._hIcon
, hasSubmenu
, style
);
1175 void StartMenu::AddSeparator()
1177 #ifdef _LIGHT_STARTMENU
1178 _buttons
.push_back(SMBtnInfo(NULL
, ICID_NONE
, -1, false));
1180 WindowRect
rect(_hwnd
);
1181 ClientRect
clnt(_hwnd
);
1183 // increase window height to make room for the new separator
1184 rect
.top
-= STARTMENU_SEP_HEIGHT(icon_size
);
1186 // move down if we are too high now
1188 rect
.top
+= STARTMENU_LINE_HEIGHT(icon_size
);
1189 rect
.bottom
+= STARTMENU_LINE_HEIGHT(icon_size
);
1192 MoveWindow(_hwnd
, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
, TRUE
);
1194 StartMenuSeparator(_hwnd
, _border_left
, clnt
.bottom
, rect
.right
-rect
.left
-_border_left
);
1199 bool StartMenu::CloseOtherSubmenus(int id
)
1202 if (IsWindow(_submenu
)) {
1203 if (_submenu_id
== id
)
1207 DestroyWindow(_submenu
);
1208 // _submenu should be reset automatically by PM_STARTMENU_CLOSED, but safety first...
1219 void StartMenu::CreateSubmenu(int id
, LPCTSTR title
, CREATORFUNC_INFO creator
, void* info
)
1221 CreateSubmenu(id
, StartMenuFolders(), title
, creator
, info
);
1224 bool StartMenu::CreateSubmenu(int id
, int folder_id
, LPCTSTR title
, CREATORFUNC_INFO creator
, void* info
)
1227 SpecialFolderPath
folder(folder_id
, _hwnd
);
1229 StartMenuFolders new_folders
;
1230 new_folders
.push_back(folder
);
1232 CreateSubmenu(id
, new_folders
, title
, creator
, info
);
1235 } catch(COMException
&) {
1236 // ignore Exception and don't display anything
1237 CloseOtherSubmenus(id
);
1238 _buttons
[GetSelectionIndex()]._enabled
= false; // disable entries for non-existing folders
1243 bool StartMenu::CreateSubmenu(int id
, int folder_id1
, int folder_id2
, LPCTSTR title
, CREATORFUNC_INFO creator
, void* info
)
1245 StartMenuFolders new_folders
;
1248 new_folders
.push_back(SpecialFolderPath(folder_id1
, _hwnd
));
1249 } catch(COMException
&) {
1253 new_folders
.push_back(SpecialFolderPath(folder_id2
, _hwnd
));
1254 } catch(COMException
&) {
1257 if (!new_folders
.empty()) {
1258 CreateSubmenu(id
, new_folders
, title
, creator
, info
);
1261 CloseOtherSubmenus(id
);
1262 _buttons
[GetSelectionIndex()]._enabled
= false; // disable entries for non-existing folders
1267 void StartMenu::CreateSubmenu(int id
, const StartMenuFolders
& new_folders
, LPCTSTR title
, CREATORFUNC_INFO creator
, void* info
)
1269 // Only open one submenu at a time.
1270 if (!CloseOtherSubmenus(id
))
1276 if (GetButtonRect(id
, &rect
)) {
1277 ClientToScreen(_hwnd
, &rect
);
1279 x
= rect
.right
; // Submenus should overlap their parent a bit.
1280 const int icon_size
= _icon_size
;
1281 y
= rect
.top
+STARTMENU_LINE_HEIGHT(icon_size
) +_border_top
/*own border*/ -STARTMENU_TOP_BTN_SPACE
/*border of new submenu*/;
1283 WindowRect
pos(_hwnd
);
1290 _submenu
= StartMenu::Create(x
, y
, new_folders
, _hwnd
, title
, creator
, info
, _create_info
._filter
);
1294 void StartMenu::ActivateEntry(int id
, const ShellEntrySet
& entries
)
1296 StartMenuFolders new_folders
;
1299 for(ShellEntrySet::const_iterator it
=entries
.begin(); it
!=entries
.end(); ++it
) {
1300 Entry
* entry
= const_cast<Entry
*>(*it
);
1302 if (entry
->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) {
1304 ///@todo If the user explicitly clicked on a submenu, display this folder as floating start menu.
1306 if (entry
->_etype
== ET_SHELL
)
1307 new_folders
.push_back(entry
->create_absolute_pidl());
1309 TCHAR path
[MAX_PATH
];
1311 if (entry
->get_path(path
, COUNTOF(path
)))
1312 new_folders
.push_back(path
);
1316 title
= entry
->_display_name
;
1318 // The entry is no subdirectory, so there can only be one shell entry.
1319 assert(entries
.size()==1);
1321 HWND hparent
= GetParent(_hwnd
);
1322 ShellPath shell_path
= entry
->create_absolute_pidl();
1324 // close start menus when launching the selected entry
1327 ///@todo launch in the background; specify correct HWND for error message box titles
1328 SHELLEXECUTEINFO shexinfo
;
1330 shexinfo
.cbSize
= sizeof(SHELLEXECUTEINFO
);
1331 shexinfo
.fMask
= SEE_MASK_IDLIST
; // SEE_MASK_INVOKEIDLIST is also possible.
1332 shexinfo
.hwnd
= hparent
;
1333 shexinfo
.lpVerb
= NULL
;
1334 shexinfo
.lpFile
= NULL
;
1335 shexinfo
.lpParameters
= NULL
;
1336 shexinfo
.lpDirectory
= NULL
;
1337 shexinfo
.nShow
= SW_SHOWNORMAL
;
1339 shexinfo
.lpIDList
= &*shell_path
;
1341 // add PIDL to the recent file list
1342 SHAddToRecentDocs(SHARD_PIDL
, shexinfo
.lpIDList
);
1344 if (!ShellExecuteEx(&shexinfo
))
1345 display_error(hparent
, GetLastError());
1347 // we may have deleted 'this' - ensure we leave the loop and function
1352 if (!new_folders
.empty()) {
1353 // Only open one submenu at a time.
1354 if (!CloseOtherSubmenus(id
))
1357 CreateSubmenu(id
, new_folders
, title
);
1362 /// close all windows of the start menu popup
1363 void StartMenu::CloseStartMenu(int id
)
1365 if (!(GetWindowStyle(_hwnd
) & WS_CAPTION
)) { // don't automatically close floating menus
1366 if (!SendParent(PM_STARTENTRY_LAUNCHED
, id
, (LPARAM
)_hwnd
))
1367 DestroyWindow(_hwnd
);
1368 } else if (_submenu
) // instead close submenus of floating parent menus
1373 int GetStartMenuBtnTextWidth(HDC hdc
, LPCTSTR title
, HWND hwnd
)
1375 RECT rect
= {0, 0, 0, 0};
1376 DrawText(hdc
, title
, -1, &rect
, DT_SINGLELINE
|DT_NOPREFIX
|DT_CALCRECT
);
1378 return rect
.right
-rect
.left
;
1381 #ifdef _LIGHT_STARTMENU
1382 void DrawStartMenuButton(HDC hdc
, const RECT
& rect
, LPCTSTR title
, const SMBtnInfo
& btn
, bool has_focus
, bool pushed
, int icon_size
)
1384 void DrawStartMenuButton(HDC hdc
, const RECT
& rect
, LPCTSTR title
, HICON hIcon
,
1385 bool hasSubmenu
, bool enabled
, bool has_focus
, bool pushed
, int icon_size
);
1388 UINT style
= DFCS_BUTTONPUSH
;
1391 style
|= DFCS_INACTIVE
;
1393 POINT iconPos
= {rect
.left
+2, (rect
.top
+rect
.bottom
-icon_size
)/2};
1394 RECT textRect
= {rect
.left
+icon_size
+4, rect
.top
+2, rect
.right
-4, rect
.bottom
-4};
1397 style
|= DFCS_PUSHED
;
1398 ++iconPos
.x
; ++iconPos
.y
;
1399 ++textRect
.left
; ++textRect
.top
;
1400 ++textRect
.right
; ++textRect
.bottom
;
1403 int bk_color_idx
= COLOR_BTNFACE
;
1404 int text_color_idx
= COLOR_BTNTEXT
;
1407 bk_color_idx
= COLOR_HIGHLIGHT
;
1408 text_color_idx
= COLOR_HIGHLIGHTTEXT
;
1411 COLORREF bk_color
= GetSysColor(bk_color_idx
);
1412 HBRUSH bk_brush
= GetSysColorBrush(bk_color_idx
);
1415 FillRect(hdc
, &rect
, bk_brush
);
1417 if (btn
._icon_id
> ICID_NONE
)
1418 g_Globals
._icon_cache
.get_icon(btn
._icon_id
).draw(hdc
, iconPos
.x
, iconPos
.y
, icon_size
, icon_size
, bk_color
, bk_brush
/*, icon_size*/);
1420 // draw submenu arrow at the right
1421 if (btn
._hasSubmenu
) {
1422 ResIconEx
arrowIcon(IDI_ARROW
, icon_size
, icon_size
);
1423 ResIconEx
selArrowIcon(IDI_ARROW_SELECTED
, icon_size
, icon_size
);
1425 DrawIconEx(hdc
, rect
.right
-icon_size
, iconPos
.y
,
1426 has_focus
? selArrowIcon
: arrowIcon
,
1427 icon_size
, icon_size
, 0, bk_brush
, DI_NORMAL
);
1431 BkMode
bk_mode(hdc
, TRANSPARENT
);
1433 if (!btn
._enabled
) // dis->itemState & (ODS_DISABLED|ODS_GRAYED)
1434 DrawGrayText(hdc
, &textRect
, title
, DT_SINGLELINE
|DT_NOPREFIX
|DT_VCENTER
);
1436 TextColor
lcColor(hdc
, GetSysColor(text_color_idx
));
1437 DrawText(hdc
, title
, -1, &textRect
, DT_SINGLELINE
|DT_NOPREFIX
|DT_VCENTER
);
1443 #ifdef _LIGHT_STARTMENU
1445 void StartMenu::ResizeToButtons()
1447 WindowRect
rect(_hwnd
);
1449 WindowCanvas
canvas(_hwnd
);
1450 FontSelection
font(canvas
, GetStockFont(DEFAULT_GUI_FONT
));
1452 const int icon_size
= _icon_size
;
1454 int max_width
= STARTMENU_WIDTH_MIN
;
1457 for(SMBtnVector::const_iterator it
=_buttons
.begin(); it
!=_buttons
.end(); ++it
) {
1458 int w
= GetStartMenuBtnTextWidth(canvas
, it
->_title
, _hwnd
);
1464 height
+= STARTMENU_SEP_HEIGHT(icon_size
);
1466 height
+= STARTMENU_LINE_HEIGHT(icon_size
);
1469 // calculate new window size
1470 int text_width
= max_width
+ icon_size
+ 10/*placeholder*/ + 16/*arrow*/;
1472 RECT rt_hgt
= {rect
.left
, rect
.bottom
-_border_top
-height
, rect
.left
+_border_left
+text_width
, rect
.bottom
};
1473 AdjustWindowRectEx(&rt_hgt
, GetWindowStyle(_hwnd
), FALSE
, GetWindowExStyle(_hwnd
));
1475 // ignore movement, only look at the size change
1476 rect
.right
= rect
.left
+ (rt_hgt
.right
-rt_hgt
.left
);
1477 rect
.top
= rect
.bottom
- (rt_hgt
.bottom
-rt_hgt
.top
);
1479 // move down if we are too high
1486 // enable scroll mode for long start menus, which span more than the whole screen height
1487 int cyscreen
= GetSystemMetrics(SM_CYSCREEN
);
1490 if (rect
.bottom
> cyscreen
) {
1493 _invisible_lines
= (rect
.bottom
-cyscreen
+(STARTMENU_LINE_HEIGHT(icon_size
)+1))/STARTMENU_LINE_HEIGHT(icon_size
)+1;
1494 rect
.bottom
-= _invisible_lines
* STARTMENU_LINE_HEIGHT(icon_size
);
1496 bottom_max
= rect
.bottom
;
1499 rect
.bottom
+= 6; // lower scroll arrow
1501 _border_top
+= 6; // upper scroll arrow
1502 rect
.bottom
+= 2*6; // upper+lower scroll arrow
1506 MoveWindow(_hwnd
, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
, TRUE
);
1509 POINT pt
= {0, bottom_max
};
1511 ScreenToClient(_hwnd
, &pt
);
1517 #else // _LIGHT_STARTMENU
1519 LRESULT
StartMenuButton::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
1523 // automatically set the focus to startmenu entries when moving the mouse over them
1524 if (GetFocus()!=_hwnd
&& !(GetWindowStyle(_hwnd
)&WS_DISABLED
))
1529 PostParent(PM_STARTENTRY_FOCUSED
, _hasSubmenu
, (LPARAM
)_hwnd
);
1533 // route WM_CANCELMODE to the startmenu window
1534 return SendParent(nmsg
, wparam
, lparam
);
1537 return super::WndProc(nmsg
, wparam
, lparam
);
1543 void StartMenuButton::DrawItem(LPDRAWITEMSTRUCT dis
)
1545 TCHAR title
[BUFFER_LEN
];
1547 GetWindowText(_hwnd
, title
, BUFFER_LEN
);
1549 DrawStartMenuButton(dis
->hDC
, dis
->rcItem
, title
, _hIcon
,
1551 !(dis
->itemState
& ODS_DISABLED
),
1552 dis
->itemState
&ODS_FOCUS
? true: false,
1553 dis
->itemState
&ODS_SELECTED
? true: false);
1559 StartMenuRoot::StartMenuRoot(HWND hwnd
, const StartMenuRootCreateInfo
& info
)
1560 : super(hwnd
, info
._icon_size
),
1563 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
1564 if (!g_Globals
._SHRestricted
|| !SHRestricted(REST_NOCOMMONGROUPS
))
1567 // insert directory "All Users\Start Menu"
1568 ShellDirectory
cmn_startmenu(GetDesktopFolder(), SpecialFolderPath(CSIDL_COMMON_STARTMENU
, _hwnd
), _hwnd
);
1569 _dirs
.push_back(StartMenuDirectory(cmn_startmenu
, (LPCTSTR
)SpecialFolderFSPath(CSIDL_COMMON_PROGRAMS
, _hwnd
)));
1570 } catch(COMException
&) {
1571 // ignore exception and don't show additional shortcuts
1575 // insert directory "<user name>\Start Menu"
1576 ShellDirectory
usr_startmenu(GetDesktopFolder(), SpecialFolderPath(CSIDL_STARTMENU
, _hwnd
), _hwnd
);
1577 _dirs
.push_back(StartMenuDirectory(usr_startmenu
, (LPCTSTR
)SpecialFolderFSPath(CSIDL_PROGRAMS
, _hwnd
)));
1578 } catch(COMException
&) {
1579 // ignore exception and don't show additional shortcuts
1585 void StartMenuRoot::ReadLogoSize()
1587 // read size of logo bitmap
1589 GetObject(ResBitmap(GetLogoResId()), sizeof(BITMAP
), &bmp_hdr
);
1590 _logo_size
.cx
= bmp_hdr
.bmWidth
;
1591 _logo_size
.cy
= bmp_hdr
.bmHeight
;
1594 _border_left
= _logo_size
.cx
+ 1;
1598 static void CalculateStartPos(HWND hwndOwner
, RECT
& rect
, int icon_size
)
1600 WindowRect
pos(hwndOwner
);
1602 rect
.left
= pos
.left
;
1603 rect
.top
= pos
.top
-STARTMENU_LINE_HEIGHT(icon_size
)-4;
1604 rect
.right
= pos
.left
+STARTMENU_WIDTH_MIN
;
1605 rect
.bottom
= pos
.top
;
1607 #ifndef _LIGHT_STARTMENU
1608 rect
.top
+= STARTMENU_LINE_HEIGHT(icon_size
);
1612 HWND
StartMenuRoot::Create(HWND hwndOwner
, int icon_size
)
1616 CalculateStartPos(hwndOwner
, rect
, icon_size
);
1618 StartMenuRootCreateInfo create_info
;
1620 create_info
._icon_size
= icon_size
;
1622 return Window::Create(WINDOW_CREATOR_INFO(StartMenuRoot
,StartMenuRootCreateInfo
), &create_info
, 0, GetWndClasss(), TITLE_STARTMENU
,
1623 WS_POPUP
|WS_THICKFRAME
|WS_CLIPCHILDREN
,
1624 rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
, hwndOwner
);
1628 void StartMenuRoot::TrackStartmenu()
1633 #ifdef _LIGHT_STARTMENU
1637 #ifdef _LIGHT_STARTMENU
1638 // recalculate start menu root position
1641 CalculateStartPos(_hwndStartButton
, rect
, _icon_size
);
1643 SetWindowPos(hwnd
, 0, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
, 0);
1648 // show previously hidden start menu
1649 ShowWindow(hwnd
, SW_SHOW
);
1650 SetForegroundWindow(hwnd
);
1652 while(IsWindow(hwnd
) && IsWindowVisible(hwnd
)) {
1653 if (!GetMessage(&msg
, 0, 0, 0)) {
1654 PostQuitMessage(msg
.wParam
);
1658 // Check for a mouse click on any window, that is not part of the start menu
1659 if (msg
.message
==WM_LBUTTONDOWN
|| msg
.message
==WM_MBUTTONDOWN
|| msg
.message
==WM_RBUTTONDOWN
) {
1660 StartMenu
* menu_wnd
= NULL
;
1662 for(HWND hwnd
=msg
.hwnd
; hwnd
; hwnd
=GetParent(hwnd
)) {
1663 menu_wnd
= WINDOW_DYNAMIC_CAST(StartMenu
, hwnd
);
1676 if (pretranslate_msg(&msg
))
1679 if (dispatch_dialog_msg(&msg
))
1682 TranslateMessage(&msg
);
1685 DispatchMessage(&msg
);
1686 } catch(COMException
& e
) {
1687 HandleException(e
, _hwnd
);
1689 } catch(COMException
& e
) {
1690 HandleException(e
, _hwnd
);
1696 LRESULT
StartMenuRoot::Init(LPCREATESTRUCT pcs
)
1698 // add buttons for entries in _entries
1699 if (super::Init(pcs
))
1709 if (RegOpenKey(HKEY_CURRENT_USER
, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer"), &hkey
))
1712 if (RegOpenKey(HKEY_CURRENT_USER
, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"), &hkeyAdv
))
1715 #define IS_VALUE_ZERO(hk, name) \
1716 (!hk || (len=sizeof(value),RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE)&value, &len) || !value))
1718 #define IS_VALUE_NOT_ZERO(hk, name) \
1719 (!hk || (len=sizeof(value),RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE)&value, &len) || value>0))
1723 // insert hard coded start entries
1724 AddButton(ResString(IDS_PROGRAMS
), ICID_APPS
, true, IDC_PROGRAMS
);
1726 AddButton(ResString(IDS_DOCUMENTS
), ICID_DOCUMENTS
, true, IDC_DOCUMENTS
);
1728 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
1729 if (!g_Globals
._SHRestricted
|| !SHRestricted(REST_NORECENTDOCSMENU
))
1731 if (IS_VALUE_ZERO(hkey
, _T("NoRecentDocsMenu")))
1733 AddButton(ResString(IDS_RECENT
), ICID_RECENT
, true, IDC_RECENT
);
1735 AddButton(ResString(IDS_FAVORITES
), ICID_FAVORITES
, true, IDC_FAVORITES
);
1737 AddButton(ResString(IDS_SETTINGS
), ICID_CONFIG
, true, IDC_SETTINGS
);
1739 AddButton(ResString(IDS_BROWSE
), ICID_FOLDER
, true, IDC_BROWSE
);
1741 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
1742 if (!g_Globals
._SHRestricted
|| !SHRestricted(REST_NOFIND
))
1744 if (IS_VALUE_ZERO(hkey
, _T("NoFind")))
1746 AddButton(ResString(IDS_SEARCH
), ICID_SEARCH
, true, IDC_SEARCH
);
1748 AddButton(ResString(IDS_START_HELP
), ICID_INFO
, false, IDC_START_HELP
);
1750 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
1751 if (!g_Globals
._SHRestricted
|| !SHRestricted(REST_NORUN
))
1753 if (IS_VALUE_ZERO(hkey
, _T("NoRun")))
1755 AddButton(ResString(IDS_LAUNCH
), ICID_ACTION
, false, IDC_LAUNCH
);
1761 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
1762 if (!g_Globals
._SHRestricted
|| SHRestricted(REST_STARTMENULOGOFF
) != 1)
1764 if (IS_VALUE_NOT_ZERO(hkeyAdv
, _T("StartMenuLogoff")))
1766 AddButton(ResString(IDS_LOGOFF
), ICID_LOGOFF
, false, IDC_LOGOFF
);
1769 AddButton(ResString(IDS_RESTART
), ICID_RESTART
, false, IDC_RESTART
);
1772 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
1773 if (!g_Globals
._SHRestricted
|| !SHRestricted(REST_NOCLOSE
))
1775 if (IS_VALUE_ZERO(hkey
, _T("NoClose")))
1777 AddButton(ResString(IDS_SHUTDOWN
), ICID_SHUTDOWN
, false, IDC_SHUTDOWN
);
1780 AddButton(ResString(IDS_TERMINATE
), ICID_LOGOFF
, false, IDC_TERMINATE
);
1785 RegCloseKey(hkeyAdv
);
1790 #ifdef _LIGHT_STARTMENU
1791 // set the window size to fit all buttons
1799 void StartMenuRoot::AddEntries()
1801 super::AddEntries();
1803 AddButton(ResString(IDS_EXPLORE
), ICID_EXPLORER
, false, IDC_EXPLORE
);
1807 LRESULT
StartMenuRoot::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
1811 PaintCanvas
canvas(_hwnd
);
1815 case WM_DISPLAYCHANGE
:
1816 // re-evaluate logo size using the correct color depth
1821 return super::WndProc(nmsg
, wparam
, lparam
);
1827 void StartMenuRoot::Paint(PaintCanvas
& canvas
)
1830 ResBitmap
bmp(GetLogoResId());
1831 BitmapSelection
sel(mem_dc
, bmp
);
1833 ClientRect
clnt(_hwnd
);
1834 int h
= min(_logo_size
.cy
, clnt
.bottom
);
1836 RECT rect
= {0, 0, _logo_size
.cx
, clnt
.bottom
-h
};
1837 HBRUSH hbr
= CreateSolidBrush(GetPixel(mem_dc
, 0, 0));
1838 FillRect(canvas
, &rect
, hbr
);
1841 PatBlt(canvas
, _logo_size
.cx
, 0, 1, clnt
.bottom
, WHITENESS
);
1843 BitBlt(canvas
, 0, clnt
.bottom
-h
, _logo_size
.cx
, h
, mem_dc
, 0, ( h
<_logo_size
.cy
? _logo_size
.cy
-h
: 0) , SRCCOPY
);
1845 super::Paint(canvas
);
1848 UINT
StartMenuRoot::GetLogoResId()
1850 WindowCanvas
dc(_hwnd
);
1852 int clr_bits
= GetDeviceCaps(dc
, BITSPIXEL
);
1856 else if (clr_bits
> 4)
1857 return IDB_LOGOV256
;
1863 void StartMenuRoot::CloseStartMenu(int id
)
1868 ShowWindow(_hwnd
, SW_HIDE
);
1871 void StartMenuRoot::ProcessKey(int vk
)
1876 CloseOtherSubmenus();
1877 // don't close start menu root
1881 super::ProcessKey(vk
);
1886 int StartMenuHandler::Command(int id
, int code
)
1893 CreateSubmenu(id
, CSIDL_COMMON_PROGRAMS
, CSIDL_PROGRAMS
, ResString(IDS_PROGRAMS
));
1898 explorer_show_frame(SW_SHOWNORMAL
);
1903 ShowLaunchDialog(g_Globals
._hwndDesktopBar
);
1907 CreateSubmenu(id
, CSIDL_PERSONAL
, ResString(IDS_DOCUMENTS
));
1911 CreateSubmenu(id
, CSIDL_RECENT
, ResString(IDS_RECENT
), STARTMENU_CREATOR(RecentStartMenu
));
1915 #ifndef _SHELL32_FAVORITES
1916 CreateSubmenu(id
, ResString(IDS_FAVORITES
), STARTMENU_CREATOR(FavoritesMenu
), &static_cast<BookmarkList
&>(g_Globals
._favorites
));
1918 CreateSubmenu(id
, CSIDL_COMMON_FAVORITES
, CSIDL_FAVORITES
, ResString(IDS_FAVORITES
));
1923 CreateSubmenu(id
, ResString(IDS_BROWSE
), STARTMENU_CREATOR(BrowseMenu
));
1927 CreateSubmenu(id
, ResString(IDS_SETTINGS
), STARTMENU_CREATOR(SettingsMenu
));
1931 CreateSubmenu(id
, ResString(IDS_SEARCH
), STARTMENU_CREATOR(SearchMenu
));
1934 case IDC_START_HELP
:
1936 MessageBox(g_Globals
._hwndDesktopBar
, TEXT("Help not yet implemented"), ResString(IDS_TITLE
), MB_OK
);
1941 ShowLogoffDialog(g_Globals
._hwndDesktopBar
);
1946 DestroyWindow(g_Globals
._hwndDesktopBar
);
1947 DestroyWindow(g_Globals
._hwndDesktop
);
1953 ShowExitWindowsDialog(g_Globals
._hwndDesktop
);
1958 ShowRestartDialog(g_Globals
._hwndDesktop
, EWX_REBOOT
);
1959 /* An alternative way to do restart without shell32 help */
1960 //launch_file(_hwnd, TEXT("shutdown.exe"), SW_HIDE, TEXT("-r"));
1965 case ID_DESKTOPBAR_SETTINGS
:
1967 ExplorerPropertySheet(g_Globals
._hwndDesktopBar
);
1970 case IDC_CONTROL_PANEL
: {
1974 XMLPos explorer_options
= g_Globals
.get_cfg("general/explorer");
1975 bool mdi
= XMLBool(explorer_options
, "mdi", true);
1978 MDIMainFrame::Create(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}"), 0);
1981 SDIMainFrame::Create(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}"), 0);
1983 launch_file(_hwnd
, SHELLPATH_CONTROL_PANEL
);
1987 case IDC_SETTINGS_MENU
:
1988 CreateSubmenu(id
, CSIDL_CONTROLS
, ResString(IDS_SETTINGS_MENU
));
1991 case IDC_PRINTERS
: {
1996 XMLPos explorer_options
= g_Globals
.get_cfg("general/explorer");
1997 bool mdi
= XMLBool(explorer_options
, "mdi", true);
2000 MDIMainFrame::Create(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}"), 0);
2003 SDIMainFrame::Create(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}"), 0);
2005 launch_file(_hwnd
, SHELLPATH_PRINTERS
);
2009 #if 0 ///@todo use printer start menu folder per default and allow opening "printers" cabinet window using the context menu
2010 case IDC_PRINTERS_MENU
:
2011 CreateSubmenu(id
, CSIDL_PRINTERS
, CSIDL_PRINTHOOD
, ResString(IDS_PRINTERS
));
2012 /* StartMenuFolders new_folders;
2015 new_folders.push_back(ShellPath(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}")));
2016 } catch(COMException&) {
2019 CreateSubmenu(id, new_folders, ResString(IDS_PRINTERS));*/
2025 CreateSubmenu(id
, CSIDL_COMMON_ADMINTOOLS
, CSIDL_ADMINTOOLS
, ResString(IDS_ADMIN
));
2026 //CloseStartMenu(id);
2027 //MainFrame::Create(SpecialFolderPath(CSIDL_COMMON_ADMINTOOLS, _hwnd), OWM_PIDL);
2029 launch_file(_hwnd
, SpecialFolderFSPath(CSIDL_COMMON_ADMINTOOLS
, _hwnd
));
2033 case IDC_CONNECTIONS
:
2035 #ifdef __REACTOS__ // to be removed when RAS will be implemented
2036 MessageBox(0, TEXT("RAS folder not yet implemented in SHELL32"), ResString(IDS_TITLE
), MB_OK
);
2038 CreateSubmenu(id
, CSIDL_CONNECTIONS
, ResString(IDS_CONNECTIONS
));
2039 //CloseStartMenu(id);
2040 //MainFrame::Create(SpecialFolderPath(CSIDL_CONNECTIONS, _hwnd), OWM_PIDL);
2043 launch_file(_hwnd
, SHELLPATH_NET_CONNECTIONS
);
2051 #ifdef __REACTOS__ ///@todo to be removed when network browsing will be implemented in shell namespace
2052 MessageBox(0, TEXT("network not yet implemented"), ResString(IDS_TITLE
), MB_OK
);
2054 CreateSubmenu(id
, CSIDL_NETWORK
, ResString(IDS_NETWORK
));
2059 ///@todo exclude removable drives
2060 CreateSubmenu(id
, CSIDL_DRIVES
, ResString(IDS_DRIVES
));
2066 case IDC_SEARCH_PROGRAM
:
2068 Dialog::DoModal(IDD_SEARCH_PROGRAM
, WINDOW_CREATOR(FindProgramDlg
));
2071 case IDC_SEARCH_FILES
:
2076 case IDC_SEARCH_COMPUTER
:
2078 ShowSearchComputer();
2083 return super::Command(id
, code
);
2090 void StartMenuHandler::ShowSearchDialog()
2092 #ifndef __REACTOS__ ///@todo to be removed when SHFindFiles() will be implemented in shell32.dll
2093 static DynamicFct
<SHFINDFILES
> SHFindFiles(TEXT("SHELL32"), 90);
2096 (*SHFindFiles
)(NULL
, NULL
);
2099 MessageBox(0, TEXT("SHFindFiles() not yet implemented in SHELL32"), ResString(IDS_TITLE
), MB_OK
);
2102 void StartMenuHandler::ShowSearchComputer()
2104 #ifndef __REACTOS__ ///@todo to be removed when SHFindComputer() will be implemented in shell32.dll
2105 static DynamicFct
<SHFINDCOMPUTER
> SHFindComputer(TEXT("SHELL32"), 91);
2108 (*SHFindComputer
)(NULL
, NULL
);
2111 MessageBox(0, TEXT("SHFindComputer() not yet implemented in SHELL32"), ResString(IDS_TITLE
), MB_OK
);
2114 void StartMenuHandler::ShowLaunchDialog(HWND hwndOwner
)
2116 static DynamicFct
<RUNFILEDLG
> RunFileDlg(TEXT("SHELL32"), 61);
2118 // Show "Run..." dialog
2120 (*RunFileDlg
)(hwndOwner
, 0, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
2124 void StartMenuHandler::ShowLogoffDialog(HWND hwndOwner
)
2126 static DynamicFct
<LOGOFFWINDOWSDIALOG
> LogoffWindowsDialog(TEXT("SHELL32"), 54);
2127 // static DynamicFct<RESTARTWINDOWSDLG> RestartDialog(TEXT("SHELL32"), 59);
2129 if (LogoffWindowsDialog
)
2130 (*LogoffWindowsDialog
)(0);
2131 /* The RestartDialog function prompts about some system setting change. This is not what we want to display here.
2132 else if (RestartDialog)
2133 return (*RestartDialog)(hwndOwner, (LPWSTR)L"You selected <Log Off>.\n\n", EWX_LOGOFF) == 1; ///@todo ANSI string conversion if needed
2136 MessageBox(hwndOwner
, TEXT("LogoffWindowsDialog() not yet implemented in SHELL32"), ResString(IDS_TITLE
), MB_OK
);
2139 void ShowExitWindowsDialog(HWND hwndOwner
)
2141 static DynamicFct
<EXITWINDOWSDLG
> ExitWindowsDialog(TEXT("SHELL32"), 60);
2143 if (ExitWindowsDialog
)
2144 (*ExitWindowsDialog
)(hwndOwner
);
2146 MessageBox(hwndOwner
, TEXT("ExitWindowsDialog() not yet implemented in SHELL32"), ResString(IDS_TITLE
), MB_OK
);
2149 void StartMenuHandler::ShowRestartDialog(HWND hwndOwner
, UINT flags
)
2151 static DynamicFct
<RESTARTWINDOWSDLG
> RestartDlg(TEXT("SHELL32"), 59);
2154 (*RestartDlg
)(hwndOwner
, (LPWSTR
)L
"You selected restart.\n\n", flags
);
2156 MessageBox(hwndOwner
, TEXT("RestartDlg() not yet implemented in SHELL32"), ResString(IDS_TITLE
), MB_OK
);
2159 void SettingsMenu::AddEntries()
2161 super::AddEntries();
2163 #if defined(ROSSHELL) || defined(__REACTOS__) // __REACTOS__ to be removed when printer/network will be implemented
2164 //TODO AddButton(ResString(IDS_PRINTERS), ICID_PRINTER, false, IDC_PRINTERS_MENU);
2165 AddButton(ResString(IDS_CONNECTIONS
), ICID_NETWORK
, false, IDC_CONNECTIONS
);
2167 //TODO AddButton(ResString(IDS_PRINTERS), ICID_PRINTER, true, IDC_PRINTERS_MENU);
2168 AddButton(ResString(IDS_CONNECTIONS
), ICID_NETCONNS
, false, IDC_CONNECTIONS
);
2170 AddButton(ResString(IDS_ADMIN
), ICID_ADMIN
, true, IDC_ADMIN
);
2172 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
2173 if (!g_Globals
._SHRestricted
|| !SHRestricted(REST_NOCONTROLPANEL
))
2175 AddButton(ResString(IDS_SETTINGS_MENU
), ICID_CONFIG
, true, IDC_SETTINGS_MENU
);
2177 AddButton(ResString(IDS_DESKTOPBAR_SETTINGS
), ICID_DESKSETTING
, false, ID_DESKTOPBAR_SETTINGS
);
2179 AddButton(ResString(IDS_PRINTERS
), ICID_PRINTER
, false, IDC_PRINTERS
);
2181 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
2182 if (!g_Globals
._SHRestricted
|| !SHRestricted(REST_NOCONTROLPANEL
))
2184 AddButton(ResString(IDS_CONTROL_PANEL
), ICID_CONTROLPAN
, false, IDC_CONTROL_PANEL
);
2187 void BrowseMenu::AddEntries()
2189 super::AddEntries();
2191 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
2192 if (!g_Globals
._SHRestricted
|| !SHRestricted(REST_NONETHOOD
)) // or REST_NOENTIRENETWORK ?
2194 #if defined(ROSSHELL) || defined(__REACTOS__) // __REACTOS__ to be removed when printer/network will be implemented
2195 AddButton(ResString(IDS_NETWORK
), ICID_NETWORK
, false, IDC_NETWORK
);
2197 AddButton(ResString(IDS_NETWORK
), ICID_NETWORK
, true, IDC_NETWORK
);
2200 AddButton(ResString(IDS_DRIVES
), ICID_FOLDER
, true, IDC_DRIVES
);
2203 void SearchMenu::AddEntries()
2205 super::AddEntries();
2207 AddButton(ResString(IDS_SEARCH_FILES
), ICID_SEARCH_DOC
, false, IDC_SEARCH_FILES
);
2209 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
2210 if (!g_Globals
._SHRestricted
|| !SHRestricted(REST_HASFINDCOMPUTERS
))
2212 AddButton(ResString(IDS_SEARCH_COMPUTER
),ICID_COMPUTER
, false, IDC_SEARCH_COMPUTER
);
2214 AddButton(ResString(IDS_SEARCH_PRG
), ICID_APPS
, false, IDC_SEARCH_PROGRAM
);
2218 void RecentStartMenu::AddEntries()
2220 for(StartMenuShellDirs::iterator it
=_dirs
.begin(); it
!=_dirs
.end(); ++it
) {
2221 StartMenuDirectory
& smd
= *it
;
2222 ShellDirectory
& dir
= smd
._dir
;
2224 if (!dir
._scanned
) {
2227 #ifdef _LAZY_ICONEXTRACT
2228 dir
.smart_scan(SORT_NAME
, SCAN_DONT_EXTRACT_ICONS
);
2230 dir
.smart_scan(SORT_NAME
);
2234 dir
.sort_directory(SORT_DATE
);
2235 AddShellEntries(dir
, RECENT_DOCS_COUNT
, smd
._ignore
); ///@todo read max. count of entries from registry
2240 #ifndef _SHELL32_FAVORITES
2242 void FavoritesMenu::AddEntries()
2244 super::AddEntries();
2246 String lwr_filter
= _create_info
._filter
;
2247 lwr_filter
.toLower();
2249 for(BookmarkList::iterator it
=_bookmarks
.begin(); it
!=_bookmarks
.end(); ++it
) {
2250 BookmarkNode
& node
= *it
;
2252 int id
= ++_next_id
;
2254 _entries
[id
] = node
;
2256 if (node
._type
== BookmarkNode::BMNT_FOLDER
) {
2257 BookmarkFolder
& folder
= *node
._pfolder
;
2259 AddButton(folder
._name
, ICID_FOLDER
, true, id
);
2260 } else if (node
._type
== BookmarkNode::BMNT_BOOKMARK
) {
2261 Bookmark
& bookmark
= *node
._pbookmark
;
2263 ICON_ID icon
= ICID_NONE
;
2265 if (!bookmark
._icon_path
.empty())
2266 icon
= g_Globals
._icon_cache
.extract(bookmark
._icon_path
, bookmark
._icon_idx
);
2268 // filter non-directory entries
2269 if (!lwr_filter
.empty()) {
2270 String lwr_name
= bookmark
._name
;
2271 String lwr_desc
= bookmark
._description
;
2272 String lwr_url
= bookmark
._url
;
2278 if (!_tcsstr(lwr_name
,lwr_filter
) && !_tcsstr(lwr_desc
,lwr_filter
) && !_tcsstr(lwr_url
,lwr_filter
))
2282 AddButton(bookmark
._name
, icon
!=ICID_NONE
?icon
:ICID_BOOKMARK
, false, id
);
2287 int FavoritesMenu::Command(int id
, int code
)
2289 BookmarkMap::iterator found
= _entries
.find(id
);
2291 if (found
!= _entries
.end()) {
2292 BookmarkNode
& node
= found
->second
;
2294 if (node
._type
== BookmarkNode::BMNT_FOLDER
) {
2295 BookmarkFolder
& folder
= *node
._pfolder
;
2297 if (CloseOtherSubmenus(id
))
2298 CreateSubmenu(id
, folder
._name
, STARTMENU_CREATOR(FavoritesMenu
), &static_cast<BookmarkList
&>(folder
._bookmarks
));
2299 } else if (node
._type
== BookmarkNode::BMNT_BOOKMARK
) {
2300 Bookmark
& bookmark
= *node
._pbookmark
;
2302 String url
= bookmark
._url
;
2303 HWND hparent
= GetParent(_hwnd
);
2307 launch_file(hparent
, url
, SW_SHOWNORMAL
);
2313 return super::Command(id
, code
);