2 * Copyright 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 // Explorer start menu
27 // Martin Fuchs, 19.08.2003
31 #include "../utility/utility.h"
33 #include "../explorer.h"
34 #include "../globals.h"
35 #include "../externals.h"
36 #include "../explorer_intres.h"
38 #include "desktopbar.h"
39 #include "startmenu.h"
40 #include "../dialogs/searchprogram.h"
43 StartMenu::StartMenu(HWND hwnd
)
46 _next_id
= IDC_FIRST_MENU
;
50 _last_pos
= WindowRect(hwnd
).pos();
53 StartMenu::StartMenu(HWND hwnd
, const StartMenuCreateInfo
& create_info
)
55 _create_info(create_info
)
57 for(StartMenuFolders::const_iterator it
=create_info
._folders
.begin(); it
!=create_info
._folders
.end(); ++it
)
59 _dirs
.push_back(ShellDirectory(Desktop(), *it
, _hwnd
));
61 _next_id
= IDC_FIRST_MENU
;
64 _border_top
= create_info
._border_top
;
65 _last_pos
= WindowRect(hwnd
).pos();
68 StartMenu::~StartMenu()
70 SendParent(PM_STARTMENU_CLOSED
);
74 // We need this wrapper function for s_wcStartMenu, it calls the WIN32 API,
75 // though static C++ initializers are not allowed for Winelib applications.
76 BtnWindowClass
& StartMenu::GetWndClasss()
78 static BtnWindowClass
s_wcStartMenu(CLASSNAME_STARTMENU
);
84 Window::CREATORFUNC
StartMenu::s_def_creator
= STARTMENU_CREATOR(StartMenu
);
86 HWND
StartMenu::Create(int x
, int y
, const StartMenuFolders
& folders
, HWND hwndParent
, LPCTSTR title
, CREATORFUNC creator
)
92 style
= WS_POPUP
|WS_THICKFRAME
|WS_CLIPCHILDREN
|WS_VISIBLE
;
94 top_height
= STARTMENU_TOP_BTN_SPACE
;
96 style
= WS_POPUP
|WS_CAPTION
|WS_SYSMENU
|WS_CLIPCHILDREN
|WS_VISIBLE
;
97 ex_style
= WS_EX_TOOLWINDOW
;
101 RECT rect
= {x
, y
, x
+STARTMENU_WIDTH_MIN
, y
+top_height
}; // start height before adding an menu button
103 AdjustWindowRectEx(&rect
, style
, FALSE
, ex_style
);
105 StartMenuCreateInfo create_info
;
107 create_info
._folders
= folders
;
108 create_info
._border_top
= top_height
;
109 create_info
._creator
= creator
;
112 create_info
._title
= title
;
114 HWND hwnd
= Window::Create(creator
, &create_info
, ex_style
, GetWndClasss(), title
,
115 style
, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
, hwndParent
);
117 // make sure the window is not off the screen
124 LRESULT
StartMenu::Init(LPCREATESTRUCT pcs
)
129 if (super::Init(pcs
))
132 // create buttons for registered entries in _entries
133 for(ShellEntryMap::const_iterator it
=_entries
.begin(); it
!=_entries
.end(); ++it
) {
134 const StartMenuEntry
& sme
= it
->second
;
135 bool hasSubmenu
= false;
137 for(ShellEntrySet::const_iterator it
=sme
._entries
.begin(); it
!=sme
._entries
.end(); ++it
)
138 if ((*it
)->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
141 AddButton(sme
._title
, sme
._hIcon
, hasSubmenu
, it
->first
);
144 if (!GetWindow(_hwnd
, GW_CHILD
))
145 AddButton(ResString(IDS_EMPTY
), 0, false, (UINT
)-1, WS_VISIBLE
|WS_CHILD
|BS_OWNERDRAW
|WS_DISABLED
);
146 } catch(COMException
& e
) {
147 HandleException(e
, pcs
->hwndParent
); // destroys the start menu window while switching focus
153 void StartMenu::AddEntries()
155 for(StartMenuShellDirs::iterator it
=_dirs
.begin(); it
!=_dirs
.end(); ++it
) {
156 StartMenuDirectory
& smd
= *it
;
157 ShellDirectory
& dir
= smd
._dir
;
165 AddShellEntries(dir
, -1, smd
._subfolders
);
170 void StartMenu::AddShellEntries(const ShellDirectory
& dir
, int max
, bool subfolders
)
174 for(const Entry
*entry
=dir
._down
; entry
; entry
=entry
->_next
) {
175 // hide files like "desktop.ini"
176 if (entry
->_shell_attribs
& SFGAO_HIDDEN
)
177 //not appropriate for drive roots: if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
180 // hide subfolders if requested
182 if (entry
->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
185 // only 'max' entries shall be added.
189 const ShellEntry
* shell_entry
= static_cast<const ShellEntry
*>(entry
);
191 AddEntry(dir
._folder
, shell_entry
);
196 LRESULT
StartMenu::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
200 DrawFloatingButton(PaintCanvas(_hwnd
));
204 ResizeButtons(LOWORD(lparam
)-_border_left
);
208 POINTS
& pos
= MAKEPOINTS(lparam
);
210 // move open submenus of floating menus
212 int dx
= pos
.x
- _last_pos
.x
;
213 int dy
= pos
.y
- _last_pos
.y
;
216 WindowRect
rt(_submenu
);
217 SetWindowPos(_submenu
, 0, rt
.left
+dx
, rt
.top
+dy
, 0, 0, SWP_NOSIZE
|SWP_NOACTIVATE
);
218 //MoveVisible(_submenu);
227 LRESULT res
= super::WndProc(nmsg
, wparam
, lparam
);
229 if (res
>=HTSIZEFIRST
&& res
<=HTSIZELAST
)
230 return HTCLIENT
; // disable window resizing
234 case WM_LBUTTONDOWN
: {
237 // check mouse cursor for coordinates of floating button
238 GetFloatingButonRect(&rect
);
240 if (PtInRect(&rect
, Point(lparam
))) {
241 // create a floating copy of the current start menu
242 WindowRect
pos(_hwnd
);
244 ///@todo do something similar to StartMenuRoot::TrackStartmenu() in order to automatically close submenus when clicking on the desktop background
245 StartMenu::Create(pos
.left
+3, pos
.bottom
-3, _create_info
._folders
, 0, _create_info
._title
, _create_info
._creator
);
251 if ((wparam
&0xFFF0) == SC_SIZE
)
252 return 0; // disable window resizing
256 // close start menu when activating another application
259 break; // don't call super::WndProc in case "this" has been deleted
265 case PM_STARTENTRY_FOCUSED
: { ///@todo use TrackMouseEvent() and WM_MOUSEHOVER to wait a bit before opening submenus
266 BOOL hasSubmenu
= wparam
;
267 HWND hctrl
= (HWND
)lparam
;
269 // automatically open submenus
271 UpdateWindow(_hwnd
); // draw focused button before waiting on submenu creation
272 //SendMessage(_hwnd, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hctrl),BN_CLICKED), (LPARAM)hctrl);
273 Command(GetDlgCtrlID(hctrl
), BN_CLICKED
);
275 // close any open submenu
276 CloseOtherSubmenus(0);
280 case PM_STARTENTRY_LAUNCHED
:
281 if (GetWindowStyle(_hwnd
) & WS_CAPTION
) // don't automatically close floating menus
284 // route message to the parent menu and close menus after launching an entry
285 if (!SendParent(nmsg
, wparam
, lparam
))
286 DestroyWindow(_hwnd
);
287 return 1; // signal that we have received and processed the message
289 case PM_STARTMENU_CLOSED
:
294 return super::WndProc(nmsg
, wparam
, lparam
);
301 void StartMenu::DrawFloatingButton(HDC hdc
)
303 static ResIconEx
floatingIcon(IDI_FLOATING
, 8, 4);
305 ClientRect
clnt(_hwnd
);
307 DrawIconEx(hdc
, clnt
.right
-12, 0, floatingIcon
, 8, 4, 0, 0, DI_NORMAL
);
310 void StartMenu::GetFloatingButonRect(LPRECT prect
)
312 GetClientRect(_hwnd
, prect
);
315 prect
->left
= prect
->right
- 8;
320 // resize child button controls to accomodate for new window size
321 void StartMenu::ResizeButtons(int cx
)
323 HDWP hdwp
= BeginDeferWindowPos(10);
325 for(HWND ctrl
=GetWindow(_hwnd
,GW_CHILD
); ctrl
; ctrl
=GetNextWindow(ctrl
,GW_HWNDNEXT
)) {
328 if (rt
.right
!= cx
) {
329 int height
= rt
.bottom
- rt
.top
;
331 // special handling for separator controls
332 if (!height
&& (GetWindowStyle(ctrl
)&SS_TYPEMASK
)==SS_ETCHEDHORZ
)
335 hdwp
= DeferWindowPos(hdwp
, ctrl
, 0, 0, 0, cx
, height
, SWP_NOMOVE
|SWP_NOZORDER
|SWP_NOACTIVATE
);
339 EndDeferWindowPos(hdwp
);
343 int StartMenu::Command(int id
, int code
)
347 DestroyWindow(_hwnd
);
351 ShellEntryMap::iterator found
= _entries
.find(id
);
353 if (found
!= _entries
.end()) {
354 ActivateEntry(id
, found
->second
._entries
);
358 return super::Command(id
, code
);}
365 StartMenuEntry
& StartMenu::AddEntry(LPCTSTR title
, HICON hIcon
, UINT id
)
370 StartMenuEntry
& sme
= _entries
[id
];
378 StartMenuEntry
& StartMenu::AddEntry(const ShellFolder folder
, const ShellEntry
* entry
)
380 HICON hIcon
= entry
->_hIcon
;
382 if (entry
->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
383 hIcon
= SmallIcon(IDI_EXPLORER
);
385 const String
& entry_name
= folder
.get_name(entry
->_pidl
);
387 // search for an already existing subdirectory entry with the same name
388 if (entry
->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
389 for(ShellEntryMap::iterator it
=_entries
.begin(); it
!=_entries
.end(); ++it
) {
390 StartMenuEntry
& sme
= it
->second
;
392 if (sme
._title
== entry_name
) ///@todo speed up by using a map indexed by name
393 for(ShellEntrySet::iterator it2
=sme
._entries
.begin(); it2
!=sme
._entries
.end(); ++it2
) {
394 if ((*it2
)->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) {
395 // merge the new shell entry with the existing of the same name
396 sme
._entries
.insert(entry
);
402 StartMenuEntry
& sme
= AddEntry(entry_name
, hIcon
);
404 sme
._entries
.insert(entry
);
410 void StartMenu::AddButton(LPCTSTR title
, HICON hIcon
, bool hasSubmenu
, UINT id
, DWORD style
)
412 WindowRect
rect(_hwnd
);
413 ClientRect
clnt(_hwnd
);
415 // increase window height to make room for the new button
416 rect
.top
-= STARTMENU_LINE_HEIGHT
;
418 // move down if we are too high now
420 rect
.top
+= STARTMENU_LINE_HEIGHT
;
421 rect
.bottom
+= STARTMENU_LINE_HEIGHT
;
424 // widen window, if it is too small
425 int text_width
= StartMenuButton::GetTextWidth(title
,_hwnd
) + 16/*icon*/ + 10/*placeholder*/ + 16/*arrow*/;
427 int cx
= clnt
.right
- _border_left
;
429 rect
.right
+= text_width
-cx
;
431 MoveWindow(_hwnd
, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
, TRUE
);
433 StartMenuCtrl(_hwnd
, _border_left
, clnt
.bottom
, rect
.right
-rect
.left
-_border_left
,
434 title
, id
, hIcon
, hasSubmenu
, style
);
437 void StartMenu::AddSeparator()
439 WindowRect
rect(_hwnd
);
440 ClientRect
clnt(_hwnd
);
442 // increase window height to make room for the new separator
443 rect
.top
-= STARTMENU_SEP_HEIGHT
;
445 // move down if we are too high now
447 rect
.top
+= STARTMENU_LINE_HEIGHT
;
448 rect
.bottom
+= STARTMENU_LINE_HEIGHT
;
451 MoveWindow(_hwnd
, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
, TRUE
);
453 StartMenuSeparator(_hwnd
, _border_left
, clnt
.bottom
, rect
.right
-rect
.left
-_border_left
);
457 bool StartMenu::CloseOtherSubmenus(int id
)
460 if (IsWindow(_submenu
)) {
461 if (_submenu_id
== id
)
464 DestroyWindow(_submenu
);
466 // _submenu should be reset automatically by PM_STARTMENU_CLOSED, but safety first...
477 void StartMenu::CreateSubmenu(int id
, LPCTSTR title
, CREATORFUNC creator
)
479 CreateSubmenu(id
, StartMenuFolders(), title
, creator
);
482 void StartMenu::CreateSubmenu(int id
, int folder_id
, LPCTSTR title
, CREATORFUNC creator
)
485 SpecialFolderPath
folder(folder_id
, _hwnd
);
487 StartMenuFolders new_folders
;
488 new_folders
.push_back(folder
);
490 CreateSubmenu(id
, new_folders
, title
, creator
);
491 } catch(COMException
&) {
492 // ignore Exception and don't display anything
496 void StartMenu::CreateSubmenu(int id
, int folder_id1
, int folder_id2
, LPCTSTR title
, CREATORFUNC creator
)
498 StartMenuFolders new_folders
;
501 new_folders
.push_back(SpecialFolderPath(folder_id1
, _hwnd
));
502 } catch(COMException
&) {
506 new_folders
.push_back(SpecialFolderPath(folder_id2
, _hwnd
));
507 } catch(COMException
&) {
510 if (!new_folders
.empty())
511 CreateSubmenu(id
, new_folders
, title
, creator
);
514 void StartMenu::CreateSubmenu(int id
, const StartMenuFolders
& new_folders
, LPCTSTR title
, CREATORFUNC creator
)
516 // Only open one submenu at a time.
517 if (!CloseOtherSubmenus(id
))
520 HWND btn
= GetDlgItem(_hwnd
, id
);
526 x
= pos
.right
; // Submenus should overlap their parent a bit.
527 y
= pos
.top
+STARTMENU_LINE_HEIGHT
-_border_top
;
529 WindowRect
pos(_hwnd
);
536 _submenu
= StartMenu::Create(x
, y
, new_folders
, _hwnd
, title
, creator
);
540 void StartMenu::ActivateEntry(int id
, const ShellEntrySet
& entries
)
542 StartMenuFolders new_folders
;
545 for(ShellEntrySet::const_iterator it
=entries
.begin(); it
!=entries
.end(); ++it
) {
546 ShellEntry
* entry
= const_cast<ShellEntry
*>(*it
);
548 if (entry
->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) {
549 new_folders
.push_back(entry
->create_absolute_pidl());
552 title
= entry
->_display_name
;
554 // If the entry is no subdirectory, there can only be one shell entry.
555 assert(entries
.size()==1);
557 entry
->launch_entry(_hwnd
); ///@todo launch in the background; specify correct HWND for error message box titles
559 // close start menus after launching the selected entry
562 // we deleted 'this' - ensure we leave loop and function
567 if (!new_folders
.empty()) {
568 // Only open one submenu at a time.
569 if (!CloseOtherSubmenus(id
))
572 CreateSubmenu(id
, new_folders
, title
);
577 /// close all windows of the start menu popup
578 void StartMenu::CloseStartMenu(int id
)
580 if (!(GetWindowStyle(_hwnd
) & WS_CAPTION
)) { // don't automatically close floating menus
581 if (!SendParent(PM_STARTENTRY_LAUNCHED
, id
, (LPARAM
)_hwnd
))
582 DestroyWindow(_hwnd
);
583 } else if (_submenu
) // instead close submenus of floating parent menus
588 int StartMenuButton::GetTextWidth(LPCTSTR title
, HWND hwnd
)
590 WindowCanvas
canvas(hwnd
);
591 FontSelection
font(canvas
, GetStockFont(DEFAULT_GUI_FONT
));
593 RECT rect
= {0, 0, 0, 0};
594 DrawText(canvas
, title
, -1, &rect
, DT_SINGLELINE
|DT_NOPREFIX
|DT_CALCRECT
);
596 return rect
.right
-rect
.left
;
600 LRESULT
StartMenuButton::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
604 // automatically set the focus to startmenu entries when moving the mouse over them
605 if (GetFocus()!=_hwnd
&& !(GetWindowStyle(_hwnd
)&WS_DISABLED
))
610 PostParent(PM_STARTENTRY_FOCUSED
, _hasSubmenu
, (LPARAM
)_hwnd
);
614 // route WM_CANCELMODE to the startmenu window
615 return SendParent(nmsg
, wparam
, lparam
);
618 return super::WndProc(nmsg
, wparam
, lparam
);
624 void StartMenuButton::DrawItem(LPDRAWITEMSTRUCT dis
)
626 UINT style
= DFCS_BUTTONPUSH
;
628 if (dis
->itemState
& ODS_DISABLED
)
629 style
|= DFCS_INACTIVE
;
631 POINT iconPos
= {dis
->rcItem
.left
+2, (dis
->rcItem
.top
+dis
->rcItem
.bottom
-16)/2};
632 RECT textRect
= {dis
->rcItem
.left
+16+4, dis
->rcItem
.top
+2, dis
->rcItem
.right
-4, dis
->rcItem
.bottom
-4};
634 if (dis
->itemState
& ODS_SELECTED
) {
635 style
|= DFCS_PUSHED
;
636 ++iconPos
.x
; ++iconPos
.y
;
637 ++textRect
.left
; ++textRect
.top
;
638 ++textRect
.right
; ++textRect
.bottom
;
641 int bk_color
= COLOR_BTNFACE
;
642 int text_color
= COLOR_BTNTEXT
;
644 if (dis
->itemState
& ODS_FOCUS
) {
645 bk_color
= COLOR_HIGHLIGHT
;
646 text_color
= COLOR_HIGHLIGHTTEXT
;
649 HBRUSH bk_brush
= GetSysColorBrush(bk_color
);
651 FillRect(dis
->hDC
, &dis
->rcItem
, bk_brush
);
652 DrawIconEx(dis
->hDC
, iconPos
.x
, iconPos
.y
, _hIcon
, 16, 16, 0, bk_brush
, DI_NORMAL
);
654 // draw submenu arrow at the right
656 static SmallIcon
arrowIcon(IDI_ARROW
);
657 static SmallIcon
selArrowIcon(IDI_ARROW_SELECTED
);
659 DrawIconEx(dis
->hDC
, dis
->rcItem
.right
-16, iconPos
.y
,
660 dis
->itemState
&ODS_FOCUS
?selArrowIcon
:arrowIcon
, 16, 16, 0, bk_brush
, DI_NORMAL
);
663 TCHAR title
[BUFFER_LEN
];
664 GetWindowText(_hwnd
, title
, BUFFER_LEN
);
666 BkMode
bk_mode(dis
->hDC
, TRANSPARENT
);
668 if (dis
->itemState
& (ODS_DISABLED
|ODS_GRAYED
))
669 DrawGrayText(dis
, &textRect
, title
, DT_SINGLELINE
|DT_NOPREFIX
|DT_VCENTER
);
671 TextColor
lcColor(dis
->hDC
, GetSysColor(text_color
));
672 DrawText(dis
->hDC
, title
, -1, &textRect
, DT_SINGLELINE
|DT_NOPREFIX
|DT_VCENTER
);
677 StartMenuRoot::StartMenuRoot(HWND hwnd
)
680 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
681 if (!g_Globals
._SHRestricted
|| !SHRestricted(REST_NOCOMMONGROUPS
))
684 // insert directory "All Users\Start Menu"
685 ShellDirectory
cmn_startmenu(Desktop(), SpecialFolderPath(CSIDL_COMMON_STARTMENU
, _hwnd
), _hwnd
);
686 _dirs
.push_back(StartMenuDirectory(cmn_startmenu
, false)); // don't add subfolders
687 } catch(COMException
&) {
688 // ignore exception and don't show additional shortcuts
692 // insert directory "<user name>\Start Menu"
693 ShellDirectory
usr_startmenu(Desktop(), SpecialFolderPath(CSIDL_STARTMENU
, _hwnd
), _hwnd
);
694 _dirs
.push_back(StartMenuDirectory(usr_startmenu
, false)); // don't add subfolders
695 } catch(COMException
&) {
696 // ignore exception and don't show additional shortcuts
699 // read size of logo bitmap
701 GetObject(ResBitmap(IDB_LOGOV
), sizeof(BITMAP
), &bmp_hdr
);
702 _logo_size
.cx
= bmp_hdr
.bmWidth
;
703 _logo_size
.cy
= bmp_hdr
.bmHeight
;
705 _border_left
= _logo_size
.cx
;
709 HWND
StartMenuRoot::Create(HWND hwndDesktopBar
)
711 WindowRect
pos(hwndDesktopBar
);
713 return Window::Create(WINDOW_CREATOR(StartMenuRoot
), 0, GetWndClasss(), TITLE_STARTMENU
,
714 WS_POPUP
|WS_THICKFRAME
|WS_CLIPCHILDREN
|WS_VISIBLE
, pos
.left
, pos
.top
-4, STARTMENU_WIDTH_MIN
, 4, hwndDesktopBar
);
718 void StartMenuRoot::TrackStartmenu()
723 while(IsWindow(hwnd
)) {
724 if (!GetMessage(&msg
, 0, 0, 0)) {
725 PostQuitMessage(msg
.wParam
);
729 // Check for a mouse click on any window, which is not part of the start menu
730 if (msg
.message
==WM_LBUTTONDOWN
|| msg
.message
==WM_MBUTTONDOWN
|| msg
.message
==WM_RBUTTONDOWN
) {
731 StartMenu
* menu_wnd
= NULL
;
733 for(HWND hwnd
=msg
.hwnd
; hwnd
; hwnd
=GetParent(hwnd
)) {
734 menu_wnd
= WINDOW_DYNAMIC_CAST(StartMenu
, hwnd
);
741 DestroyWindow(_hwnd
);
747 if (pretranslate_msg(&msg
))
750 if (dispatch_dialog_msg(&msg
))
753 TranslateMessage(&msg
);
756 DispatchMessage(&msg
);
757 } catch(COMException
& e
) {
758 HandleException(e
, _hwnd
);
760 } catch(COMException
& e
) {
761 HandleException(e
, _hwnd
);
767 LRESULT
StartMenuRoot::Init(LPCREATESTRUCT pcs
)
769 // add buttons for entries in _entries
770 if (super::Init(pcs
))
780 if (RegOpenKey(HKEY_CURRENT_USER
, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer"), &hkey
))
783 if (RegOpenKey(HKEY_CURRENT_USER
, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"), &hkeyAdv
))
786 #define IS_VALUE_ZERO(hk, name) \
787 (!hk || (len=sizeof(value),RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE)&value, &len) || !value))
789 #define IS_VALUE_NOT_ZERO(hk, name) \
790 (!hk || (len=sizeof(value),RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE)&value, &len) || value>0))
794 // insert hard coded start entries
795 AddButton(ResString(IDS_PROGRAMS
), 0, true, IDC_PROGRAMS
);
797 AddButton(ResString(IDS_DOCUMENTS
), 0, true, IDC_DOCUMENTS
);
799 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
800 if (!g_Globals
._SHRestricted
|| !SHRestricted(REST_NORECENTDOCSMENU
))
802 if (IS_VALUE_ZERO(hkey
, _T("NoRecentDocsMenu")))
804 AddButton(ResString(IDS_RECENT
), 0, true, IDC_RECENT
);
806 AddButton(ResString(IDS_FAVORITES
), 0, true, IDC_FAVORITES
);
808 AddButton(ResString(IDS_SETTINGS
), 0, true, IDC_SETTINGS
);
810 AddButton(ResString(IDS_BROWSE
), 0, true, IDC_BROWSE
);
812 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
813 if (!g_Globals
._SHRestricted
|| !SHRestricted(REST_NOFIND
))
815 if (IS_VALUE_ZERO(hkey
, _T("NoFind")))
817 AddButton(ResString(IDS_SEARCH
), 0, true, IDC_SEARCH
);
819 AddButton(ResString(IDS_START_HELP
), 0, false, IDC_START_HELP
);
821 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
822 if (!g_Globals
._SHRestricted
|| !SHRestricted(REST_NORUN
))
824 if (IS_VALUE_ZERO(hkey
, _T("NoRun")))
826 AddButton(ResString(IDS_LAUNCH
), 0, false, IDC_LAUNCH
);
832 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
833 if (!g_Globals
._SHRestricted
|| !SHRestricted(REST_NOCLOSE
))
835 if (IS_VALUE_NOT_ZERO(hkeyAdv
, _T("StartMenuLogoff")))
837 AddButton(ResString(IDS_LOGOFF
), SmallIcon(IDI_LOGOFF
), false, IDC_LOGOFF
);
840 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
841 if (!g_Globals
._SHRestricted
|| SHRestricted(REST_STARTMENULOGOFF
) != 1)
843 if (IS_VALUE_ZERO(hkey
, _T("NoClose")))
845 AddButton(ResString(IDS_SHUTDOWN
), SmallIcon(IDI_LOGOFF
), false, IDC_SHUTDOWN
);
849 RegCloseKey(hkeyAdv
);
857 void StartMenuRoot::AddEntries()
861 AddButton(ResString(IDS_EXPLORE
), SmallIcon(IDI_EXPLORER
), false, IDC_EXPLORE
);
865 LRESULT
StartMenuRoot::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
870 {WindowCanvas
dc(_hwnd
); clr_bits
=GetDeviceCaps(dc
, BITSPIXEL
);}
871 bool logo256
= clr_bits
<=8;
873 PaintCanvas
canvas(_hwnd
);
876 ResBitmap
bmp(logo256
? IDB_LOGOV256
: IDB_LOGOV
);
877 BitmapSelection
sel(mem_dc
, bmp
);
879 ClientRect
clnt(_hwnd
);
880 int h
= min(_logo_size
.cy
, clnt
.bottom
);
882 RECT rect
= {0, 0, _logo_size
.cx
-1, clnt
.bottom
-h
};
883 HBRUSH hbr
= CreateSolidBrush(logo256
? RGB(166,202,240): RGB(255,255,255)); // same color as the background color in the logo bitmap
884 FillRect(canvas
, &rect
, hbr
);
886 //PatBlt(canvas, _logo_size.cx-1, 0, 1, clnt.bottom-h, WHITENESS);
887 PatBlt(canvas
, _logo_size
.cx
-1, 0, 1, clnt
.bottom
-h
, WHITENESS
);
889 BitBlt(canvas
, 0, clnt
.bottom
-h
, _logo_size
.cx
, h
, mem_dc
, 0, 0, SRCCOPY
);
892 rect
.left
= rect
.right
++;
893 rect
.bottom
= clnt
.bottom
;
894 HBRUSH hbr_border
= GetStockBrush(GRAY_BRUSH
); //CreateSolidBrush(RGB(71,88,85));
895 FillRect(canvas
, &rect
, hbr_border
);
896 //DeleteObject(hbr_border);
901 return super::WndProc(nmsg
, wparam
, lparam
);
908 int StartMenuRoot::Command(int id
, int code
)
912 CreateSubmenu(id
, CSIDL_COMMON_PROGRAMS
, CSIDL_PROGRAMS
, ResString(IDS_PROGRAMS
));
917 explorer_show_frame(_hwnd
, SW_SHOWNORMAL
);
921 HWND hwndDesktopBar
= GetWindow(_hwnd
, GW_OWNER
);
923 ShowLaunchDialog(hwndDesktopBar
);
927 CreateSubmenu(id
, CSIDL_PERSONAL
, ResString(IDS_DOCUMENTS
));
931 CreateSubmenu(id
, CSIDL_RECENT
, ResString(IDS_RECENT
), STARTMENU_CREATOR(RecentStartMenu
));
935 CreateSubmenu(id
, CSIDL_FAVORITES
, ResString(IDS_FAVORITES
));
939 CreateSubmenu(id
, ResString(IDS_BROWSE
), STARTMENU_CREATOR(BrowseMenu
));
943 CreateSubmenu(id
, ResString(IDS_SETTINGS
), STARTMENU_CREATOR(SettingsMenu
));
947 CreateSubmenu(id
, ResString(IDS_SEARCH
), STARTMENU_CREATOR(SearchMenu
));
951 /* The shell32 Dialog prompts about some system setting change. This is not what we want to display here.
952 HWND hwndDesktopBar = GetWindow(_hwnd, GW_OWNER);
954 ShowRestartDialog(hwndDesktopBar, EWX_LOGOFF);*/
955 DestroyWindow(GetParent(_hwnd
));
959 HWND hwndDesktopBar
= GetWindow(_hwnd
, GW_OWNER
);
961 ShowExitWindowsDialog(hwndDesktopBar
);
965 return super::Command(id
, code
);
972 void StartMenuRoot::ShowLaunchDialog(HWND hwndDesktopBar
)
974 ///@todo All text phrases should be put into the resources.
975 static LPCSTR szTitle
= "Create New Task";
976 static LPCSTR szText
= "Type the name of a program, folder, document, or Internet resource, and Task Manager will open it for you.";
978 static DynamicFct
<RUNFILEDLG
> RunFileDlg(TEXT("SHELL32"), 61);
980 // Show "Run..." dialog
983 if ((HIWORD(GetVersion())>>14) == W_VER_NT
) {
984 WCHAR wTitle
[40], wText
[256];
986 MultiByteToWideChar(CP_ACP
, 0, szTitle
, -1, wTitle
, 40);
987 MultiByteToWideChar(CP_ACP
, 0, szText
, -1, wText
, 256);
989 (*RunFileDlg
)(hwndDesktopBar
, 0, NULL
, (LPCSTR
)wTitle
, (LPCSTR
)wText
, RFF_CALCDIRECTORY
);
992 (*RunFileDlg
)(hwndDesktopBar
, 0, NULL
, szTitle
, szText
, RFF_CALCDIRECTORY
);
996 void StartMenuRoot::ShowExitWindowsDialog(HWND hwndOwner
)
998 static DynamicFct
<EXITWINDOWSDLG
> ExitWindowsDlg(TEXT("SHELL32"), 60);
1001 (*ExitWindowsDlg
)(hwndOwner
);
1004 void StartMenuRoot::ShowRestartDialog(HWND hwndOwner
, UINT flags
)
1006 static DynamicFct
<RESTARTWINDOWSDLG
> RestartDlg(TEXT("SHELL32"), 59);
1009 (*RestartDlg
)(hwndOwner
, (LPWSTR
)L
"You selected <Log Off>.\n\n", flags
); ///@todo ANSI string conversion if needed
1013 void SettingsMenu::AddEntries()
1015 super::AddEntries();
1017 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
1018 if (!g_Globals
._SHRestricted
|| !SHRestricted(REST_NOCONTROLPANEL
))
1020 AddButton(ResString(IDS_CONTROL_PANEL
), 0, false, IDC_CONTROL_PANEL
);
1022 AddButton(ResString(IDS_PRINTERS
), 0, true, IDC_PRINTERS
);
1023 AddButton(ResString(IDS_CONNECTIONS
), 0, true, IDC_CONNECTIONS
);
1024 AddButton(ResString(IDS_ADMIN
), 0, true, IDC_ADMIN
);
1026 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
1027 if (!g_Globals
._SHRestricted
|| !SHRestricted(REST_NOCONTROLPANEL
))
1029 AddButton(ResString(IDS_SETTINGS_MENU
), 0, true, IDC_SETTINGS_MENU
);
1032 int SettingsMenu::Command(int id
, int code
)
1035 case IDC_SETTINGS_MENU
:
1036 CreateSubmenu(id
, CSIDL_CONTROLS
, ResString(IDS_SETTINGS_MENU
));
1040 CreateSubmenu(id
, CSIDL_PRINTERS
, CSIDL_PRINTHOOD
, ResString(IDS_PRINTERS
));
1043 case IDC_CONTROL_PANEL
:
1045 MainFrame::Create(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}"), FALSE
);
1049 CreateSubmenu(id
, CSIDL_COMMON_ADMINTOOLS
, CSIDL_ADMINTOOLS
, ResString(IDS_ADMIN
));
1052 case IDC_CONNECTIONS
:
1053 CreateSubmenu(id
, CSIDL_CONNECTIONS
, ResString(IDS_CONNECTIONS
));
1057 return super::Command(id
, code
);
1064 void BrowseMenu::AddEntries()
1066 super::AddEntries();
1068 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
1069 if (!g_Globals
._SHRestricted
|| !SHRestricted(REST_NONETHOOD
)) // or REST_NOENTIRENETWORK ?
1071 AddButton(ResString(IDS_NETWORK
), 0, true, IDC_NETWORK
);
1073 AddButton(ResString(IDS_DRIVES
), 0, true, IDC_DRIVES
);
1076 int BrowseMenu::Command(int id
, int code
)
1080 CreateSubmenu(id
, CSIDL_NETWORK
, ResString(IDS_NETWORK
));
1084 ///@todo exclude removeable drives
1085 CreateSubmenu(id
, CSIDL_DRIVES
, ResString(IDS_DRIVES
));
1089 return super::Command(id
, code
);
1096 void SearchMenu::AddEntries()
1098 super::AddEntries();
1100 AddButton(ResString(IDS_SEARCH_PRG
), 0, false, IDC_SEARCH_PROGRAM
);
1102 AddButton(ResString(IDS_SEARCH_FILES
), 0, false, IDC_SEARCH_FILES
);
1104 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
1105 if (!g_Globals
._SHRestricted
|| !SHRestricted(REST_HASFINDCOMPUTERS
))
1107 AddButton(ResString(IDS_SEARCH_COMPUTER
), 0, false, IDC_SEARCH_COMPUTER
);
1110 int SearchMenu::Command(int id
, int code
)
1113 case IDC_SEARCH_PROGRAM
:
1115 Dialog::DoModal(IDD_SEARCH_PROGRAM
, WINDOW_CREATOR(FindProgramDlg
));
1118 case IDC_SEARCH_FILES
:
1122 case IDC_SEARCH_COMPUTER
:
1123 ShowSearchComputer();
1127 return super::Command(id
, code
);
1133 void SearchMenu::ShowSearchDialog()
1135 static DynamicFct
<SHFINDFILES
> SHFindFiles(TEXT("SHELL32"), 90);
1138 (*SHFindFiles
)(NULL
, NULL
);
1141 void SearchMenu::ShowSearchComputer()
1143 static DynamicFct
<SHFINDCOMPUTER
> SHFindComputer(TEXT("SHELL32"), 91);
1146 (*SHFindComputer
)(NULL
, NULL
);
1150 RecentStartMenu::RecentStartMenu(HWND hwnd
, const StartMenuCreateInfo
& create_info
)
1151 : super(hwnd
, create_info
)
1155 void RecentStartMenu::AddEntries()
1157 for(StartMenuShellDirs::iterator it
=_dirs
.begin(); it
!=_dirs
.end(); ++it
) {
1158 StartMenuDirectory
& smd
= *it
;
1159 ShellDirectory
& dir
= smd
._dir
;
1161 if (!dir
._scanned
) {
1167 dir
.sort_directory(SORT_DATE
);
1168 AddShellEntries(dir
, 16, smd
._subfolders
); ///@todo read max. count of entries from registry