print KERNEL_VERSION_STR
[reactos.git] / reactos / subsys / system / explorer / taskbar / startmenu.cpp
1 /*
2 * Copyright 2003 Martin Fuchs
3 *
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.
8 *
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.
13 *
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
17 */
18
19
20 //
21 // Explorer clone
22 //
23 // startmenu.cpp
24 //
25 // Explorer start menu
26 //
27 // Martin Fuchs, 19.08.2003
28 //
29
30
31 #include "../utility/utility.h"
32
33 #include "../explorer.h"
34 #include "../globals.h"
35 #include "../externals.h"
36 #include "../explorer_intres.h"
37
38 #include "desktopbar.h"
39 #include "startmenu.h"
40
41
42 StartMenu::StartMenu(HWND hwnd)
43 : super(hwnd)
44 {
45 _next_id = IDC_FIRST_MENU;
46 _submenu_id = 0;
47 _border_left = 0;
48 }
49
50 StartMenu::StartMenu(HWND hwnd, const StartMenuFolders& info)
51 : super(hwnd)
52 {
53 for(StartMenuFolders::const_iterator it=info.begin(); it!=info.end(); ++it)
54 if (*it)
55 _dirs.push_back(ShellDirectory(Desktop(), *it, _hwnd));
56
57 _next_id = IDC_FIRST_MENU;
58 _submenu_id = 0;
59 _border_left = 0;
60 }
61
62 StartMenu::~StartMenu()
63 {
64 SendParent(PM_STARTMENU_CLOSED);
65 }
66
67
68 // We need this wrapper function for s_wcStartMenu, it calls to the WIN32 API
69 // through static C++ initializers are not allowed for Winelib applications.
70 BtnWindowClass& StartMenu::GetWndClasss()
71 {
72 static BtnWindowClass s_wcStartMenu(CLASSNAME_STARTMENU);
73
74 return s_wcStartMenu;
75 }
76
77 /*
78 HWND StartMenu::Create(int x, int y, HWND hwndParent)
79 {
80 return Window::Create(WINDOW_CREATOR(StartMenu), NULL, GetWndClasss(), TITLE_STARTMENU,
81 WS_POPUP|WS_THICKFRAME|WS_CLIPCHILDREN|WS_VISIBLE, x, y, STARTMENU_WIDTH_MIN, 4, hwndParent);
82 }
83 */
84
85 Window::CREATORFUNC StartMenu::s_def_creator = STARTMENU_CREATOR(StartMenu);
86
87 HWND StartMenu::Create(int x, int y, const StartMenuFolders& folders, HWND hwndParent, CREATORFUNC creator)
88 {
89 //TODO: check, if coordinates x/y are visible on the screen
90 return Window::Create(creator, &folders, 0, GetWndClasss(), NULL,
91 WS_POPUP|WS_THICKFRAME|WS_CLIPCHILDREN|WS_VISIBLE, x, y, STARTMENU_WIDTH_MIN, 4/*start height*/, hwndParent);
92 }
93
94
95 LRESULT StartMenu::Init(LPCREATESTRUCT pcs)
96 {
97 WaitCursor wait;
98
99 AddEntries();
100
101 if (super::Init(pcs))
102 return 1;
103
104 // create buttons for registered entries in _entries
105 if (_entries.empty()) {
106 AddButton(ResString(IDS_EMPTY), 0, false, (UINT)-1, WS_VISIBLE|WS_CHILD|BS_OWNERDRAW|WS_DISABLED);
107 } else {
108 for(ShellEntryMap::const_iterator it=_entries.begin(); it!=_entries.end(); ++it) {
109 const StartMenuEntry& sme = it->second;
110 bool hasSubmenu = false;
111
112 if (sme._entry && (sme._entry->_data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY))
113 hasSubmenu = true;
114
115 AddButton(sme._title, sme._hIcon, hasSubmenu, it->first);
116 }
117 }
118
119 return 0;
120 }
121
122 void StartMenu::AddEntries()
123 {
124 for(StartMenuShellDirs::iterator it=_dirs.begin(); it!=_dirs.end(); ++it) {
125 StartMenuDirectory& smd = *it;
126 ShellDirectory& dir = smd._dir;
127
128 dir.smart_scan();
129
130 AddShellEntries(dir, -1, smd._subfolders);
131 }
132 }
133
134
135 void StartMenu::AddShellEntries(const ShellDirectory& dir, int max, bool subfolders)
136 {
137 int cnt = 0;
138
139 for(const Entry*entry=dir._down; entry; entry=entry->_next) {
140 // hide files like "desktop.ini"
141 if (entry->_shell_attribs & SFGAO_HIDDEN)
142 //not appropriate for drive roots: if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
143 continue;
144
145 // hide subfolders if requested
146 if (!subfolders)
147 if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
148 continue;
149
150 // only 'max' entries shall be added.
151 if (++cnt == max)
152 break;
153
154 const ShellEntry* shell_entry = static_cast<const ShellEntry*>(entry);
155
156 AddEntry(dir._folder, shell_entry);
157 }
158 }
159
160
161 LRESULT StartMenu::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
162 {
163 switch(nmsg) {
164 case WM_SIZE:
165 ResizeButtons(LOWORD(lparam)-_border_left);
166 break;
167
168 case WM_NCHITTEST: {
169 LRESULT res = super::WndProc(nmsg, wparam, lparam);
170
171 if (res>=HTSIZEFIRST && res<=HTSIZELAST)
172 return HTCLIENT; // disable window resizing
173
174 return res;}
175
176 case WM_SYSCOMMAND:
177 if ((wparam&0xFFF0) == SC_SIZE)
178 return 0; // disable window resizing
179 goto def;
180
181 case WM_ACTIVATEAPP:
182 // close start menu when activating another application
183 if (!wparam)
184 CloseStartMenu();
185 break; // don't call super::WndProc in case "this" has been deleted
186
187 case WM_CANCELMODE:
188 CloseStartMenu();
189 break;
190
191 case PM_STARTENTRY_FOCUSED: { //TODO: use TrackMouseEvent() and WM_MOUSEHOVER to wait a bit before opening submenus
192 BOOL hasSubmenu = wparam;
193 HWND hctrl = (HWND)lparam;
194
195 // automatically open submenus
196 if (hasSubmenu) {
197 UpdateWindow(_hwnd); // draw focused button before waiting on submenu creation
198 //SendMessage(_hwnd, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hctrl),BN_CLICKED), (LPARAM)hctrl);
199 Command(GetDlgCtrlID(hctrl), BN_CLICKED);
200 } else {
201 // close any open submenu
202 CloseOtherSubmenus(0);
203 }
204 break;}
205
206 case PM_STARTENTRY_LAUNCHED:
207 // route message to the parent menu and close menus after launching an entry
208 if (!SendParent(nmsg, wparam, lparam))
209 DestroyWindow(_hwnd);
210 return 1; // signal that we have received and processed the message
211
212 case PM_STARTMENU_CLOSED:
213 _submenu = 0;
214 break;
215
216 default: def:
217 return super::WndProc(nmsg, wparam, lparam);
218 }
219
220 return 0;
221 }
222
223
224 // resize child button controls to accomodate for new window size
225 void StartMenu::ResizeButtons(int cx)
226 {
227 HDWP hdwp = BeginDeferWindowPos(10);
228
229 for(HWND ctrl=GetWindow(_hwnd,GW_CHILD); ctrl; ctrl=GetNextWindow(ctrl,GW_HWNDNEXT)) {
230 ClientRect rt(ctrl);
231
232 if (rt.right != cx) {
233 int height = rt.bottom - rt.top;
234
235 // special handling for separator controls
236 if (!height && (GetWindowStyle(ctrl)&SS_TYPEMASK)==SS_ETCHEDHORZ)
237 height = 2;
238
239 hdwp = DeferWindowPos(hdwp, ctrl, 0, 0, 0, cx, height, SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
240 }
241 }
242
243 EndDeferWindowPos(hdwp);
244 }
245
246
247 int StartMenu::Command(int id, int code)
248 {
249 switch(id) {
250 case IDCANCEL:
251 DestroyWindow(_hwnd);
252 break;
253
254 default: {
255 ShellEntryMap::const_iterator found = _entries.find(id);
256
257 if (found != _entries.end()) {
258 ShellEntry* entry = const_cast<ShellEntry*>(found->second._entry);
259
260 if (entry)
261 ActivateEntry(id, entry);
262 break;
263 }
264
265 return super::Command(id, code);}
266 }
267
268 return 0;
269 }
270
271
272 StartMenuEntry& StartMenu::AddEntry(LPCTSTR title, HICON hIcon, UINT id)
273 {
274 if (id == (UINT)-1)
275 id = ++_next_id;
276
277 StartMenuEntry& sme = _entries[id];
278
279 sme._title = title;
280 sme._hIcon = hIcon;
281
282 return sme;
283 }
284
285 StartMenuEntry& StartMenu::AddEntry(const ShellFolder folder, const ShellEntry* entry)
286 {
287 HICON hIcon = entry->_hIcon;
288
289 if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
290 hIcon = SmallIcon(IDI_EXPLORER);
291
292 const String& entry_name = folder.get_name(entry->_pidl);
293
294 StartMenuEntry& sme = AddEntry(entry_name, hIcon);
295
296 sme._entry = entry;
297
298 return sme;
299 }
300
301
302 void StartMenu::AddButton(LPCTSTR title, HICON hIcon, bool hasSubmenu, UINT id, DWORD style)
303 {
304 WindowRect rect(_hwnd);
305
306 // increase window height to make room for the new button
307 rect.top -= STARTMENU_LINE_HEIGHT;
308
309 if (rect.top < 0) {
310 rect.top += STARTMENU_LINE_HEIGHT;
311 rect.bottom += STARTMENU_LINE_HEIGHT;
312 }
313
314 // widen window, if it is too small
315 int text_width = StartMenuButton::GetTextWidth(title,_hwnd) + 16/*icon*/ + 10/*placeholder*/ + 16/*arrow*/;
316
317 ClientRect clnt(_hwnd);
318 int cx = clnt.right - _border_left;
319 if (text_width > cx)
320 rect.right += text_width-cx;
321
322 MoveWindow(_hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE);
323
324 StartMenuCtrl(_hwnd, _border_left, rect.bottom-rect.top-STARTMENU_LINE_HEIGHT-6, rect.right-rect.left-_border_left,
325 title, id, hIcon, hasSubmenu, style);
326 }
327
328 void StartMenu::AddSeparator()
329 {
330 WindowRect rect(_hwnd);
331
332 rect.top -= STARTMENU_SEP_HEIGHT;
333
334 if (rect.top < 0) {
335 rect.top += STARTMENU_LINE_HEIGHT;
336 rect.bottom += STARTMENU_LINE_HEIGHT;
337 }
338
339 MoveWindow(_hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE);
340
341 StartMenuSeparator(_hwnd, _border_left, rect.bottom-rect.top-STARTMENU_SEP_HEIGHT-6, rect.right-rect.left-_border_left);
342 }
343
344
345 bool StartMenu::CloseOtherSubmenus(int id)
346 {
347 if (_submenu) {
348 if (IsWindow(_submenu)) {
349 if (_submenu_id == id)
350 return false;
351 else {
352 DestroyWindow(_submenu);
353 _submenu_id = 0;
354 // _submenu should be reset automatically by PM_STARTMENU_CLOSED, but safety first...
355 }
356 }
357
358 _submenu = 0;
359 }
360
361 return true;
362 }
363
364
365 void StartMenu::CreateSubmenu(int id, const StartMenuFolders& new_folders, CREATORFUNC creator)
366 {
367 // Only open one submenu at a time.
368 if (!CloseOtherSubmenus(id))
369 return;
370
371 HWND btn = GetDlgItem(_hwnd, id);
372 int x, y;
373
374 if (btn) {
375 WindowRect pos(btn);
376
377 x = pos.right-3; // Submenus should overlap their parent a bit.
378 y = pos.top+STARTMENU_LINE_HEIGHT-3;
379 } else {
380 WindowRect pos(_hwnd);
381
382 x = pos.right-3;
383 y = pos.top;
384 }
385
386 _submenu_id = id;
387 _submenu = StartMenu::Create(x, y, new_folders, _hwnd, creator);
388 }
389
390 void StartMenu::CreateSubmenu(int id, int folder_id, CREATORFUNC creator)
391 {
392 StartMenuFolders new_folders;
393
394 SpecialFolderPath folder(folder_id, _hwnd);
395
396 if (folder)
397 new_folders.push_back(folder);
398
399 CreateSubmenu(id, new_folders, creator);
400 }
401
402 void StartMenu::CreateSubmenu(int id, int folder_id1, int folder_id2, CREATORFUNC creator)
403 {
404 StartMenuFolders new_folders;
405
406 SpecialFolderPath folder1(folder_id1, _hwnd);
407
408 if (folder1)
409 new_folders.push_back(folder1);
410
411 SpecialFolderPath folder2(folder_id2, _hwnd);
412
413 if (folder2)
414 new_folders.push_back(folder2);
415
416 CreateSubmenu(id, new_folders, creator);
417 }
418
419
420 void StartMenu::ActivateEntry(int id, ShellEntry* entry)
421 {
422 if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
423 // Only open one submenu at a time.
424 if (!CloseOtherSubmenus(id))
425 return;
426
427 StartMenuFolders new_folders;
428
429 new_folders.push_back(entry->create_absolute_pidl(_hwnd));
430
431 //TODO: merge all entries of subdirectories with the same name, like "All Users\...\Accessories" and "<user>\...\Accessories"
432
433 CreateSubmenu(id, new_folders);
434 } else {
435 entry->launch_entry(_hwnd); //TODO: launch in the background; specify correct HWND for error message box titles
436
437 // close start menus after launching the selected entry
438 CloseStartMenu(id);
439 }
440 }
441
442
443 /// close all windows of the start menu popup
444 void StartMenu::CloseStartMenu(int id)
445 {
446 if (!SendParent(PM_STARTENTRY_LAUNCHED, id, (LPARAM)_hwnd))
447 DestroyWindow(_hwnd);
448 }
449
450
451 int StartMenuButton::GetTextWidth(LPCTSTR title, HWND hwnd)
452 {
453 WindowCanvas canvas(hwnd);
454 FontSelection font(canvas, GetStockFont(DEFAULT_GUI_FONT));
455
456 RECT rect = {0, 0, 0, 0};
457 DrawText(canvas, title, -1, &rect, DT_SINGLELINE|DT_NOPREFIX|DT_CALCRECT);
458
459 return rect.right-rect.left;
460 }
461
462
463 LRESULT StartMenuButton::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
464 {
465 switch(nmsg) {
466 case WM_MOUSEMOVE:
467 // automatically set the focus to startmenu entries when moving the mouse over them
468 if (GetFocus()!=_hwnd && !(GetWindowStyle(_hwnd)&WS_DISABLED))
469 SetFocus(_hwnd);
470 break;
471
472 case WM_SETFOCUS:
473 PostParent(PM_STARTENTRY_FOCUSED, _hasSubmenu, (LPARAM)_hwnd);
474 goto def;
475
476 case WM_CANCELMODE:
477 // route WM_CANCELMODE to the startmenu window
478 return SendParent(nmsg, wparam, lparam);
479
480 default: def:
481 return super::WndProc(nmsg, wparam, lparam);
482 }
483
484 return 0;
485 }
486
487 void StartMenuButton::DrawItem(LPDRAWITEMSTRUCT dis)
488 {
489 UINT style = DFCS_BUTTONPUSH;
490
491 if (dis->itemState & ODS_DISABLED)
492 style |= DFCS_INACTIVE;
493
494 POINT iconPos = {dis->rcItem.left+2, (dis->rcItem.top+dis->rcItem.bottom-16)/2};
495 RECT textRect = {dis->rcItem.left+16+4, dis->rcItem.top+2, dis->rcItem.right-4, dis->rcItem.bottom-4};
496
497 if (dis->itemState & ODS_SELECTED) {
498 style |= DFCS_PUSHED;
499 ++iconPos.x; ++iconPos.y;
500 ++textRect.left; ++textRect.top;
501 ++textRect.right; ++textRect.bottom;
502 }
503
504 int bk_color = COLOR_BTNFACE;
505 int text_color = COLOR_BTNTEXT;
506
507 if (dis->itemState & ODS_FOCUS) {
508 bk_color = COLOR_HIGHLIGHT;
509 text_color = COLOR_HIGHLIGHTTEXT;
510 }
511
512 HBRUSH bk_brush = GetSysColorBrush(bk_color);
513
514 FillRect(dis->hDC, &dis->rcItem, bk_brush);
515 DrawIconEx(dis->hDC, iconPos.x, iconPos.y, _hIcon, 16, 16, 0, bk_brush, DI_NORMAL);
516
517 // draw submenu arrow at the right
518 if (_hasSubmenu) {
519 static SmallIcon arrowIcon(IDI_ARROW);
520 static SmallIcon selArrowIcon(IDI_ARROW_SELECTED);
521
522 DrawIconEx(dis->hDC, dis->rcItem.right-16, iconPos.y,
523 dis->itemState&ODS_FOCUS?selArrowIcon:arrowIcon, 16, 16, 0, bk_brush, DI_NORMAL);
524 }
525
526 TCHAR title[BUFFER_LEN];
527 GetWindowText(_hwnd, title, BUFFER_LEN);
528
529 if (dis->itemState & (ODS_DISABLED|ODS_GRAYED))
530 DrawGrayText(dis, &textRect, title, DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER);
531 else {
532 BkMode mode(dis->hDC, TRANSPARENT);
533 TextColor lcColor(dis->hDC, GetSysColor(text_color));
534 DrawText(dis->hDC, title, -1, &textRect, DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER);
535 }
536 }
537
538
539 StartMenuRoot::StartMenuRoot(HWND hwnd)
540 : super(hwnd)
541 {
542 // insert directory "All Users\Start Menu"
543 ShellDirectory cmn_startmenu(Desktop(), SpecialFolderPath(CSIDL_COMMON_STARTMENU, _hwnd), _hwnd);
544 _dirs.push_back(StartMenuDirectory(cmn_startmenu, false)); // don't add subfolders
545
546 // insert directory "<user name>\Start Menu"
547 ShellDirectory usr_startmenu(Desktop(), SpecialFolderPath(CSIDL_STARTMENU, _hwnd), _hwnd);
548 _dirs.push_back(StartMenuDirectory(usr_startmenu, false)); // don't add subfolders
549
550 // read size of logo bitmap
551 BITMAP bmp_hdr;
552 GetObject(ResBitmap(IDB_LOGOV), sizeof(BITMAP), &bmp_hdr);
553 _logo_size.cx = bmp_hdr.bmWidth;
554 _logo_size.cy = bmp_hdr.bmHeight;
555
556 _border_left = _logo_size.cx;
557 }
558
559
560 HWND StartMenuRoot::Create(HWND hwndDesktopBar)
561 {
562 WindowRect pos(hwndDesktopBar);
563
564 return Window::Create(WINDOW_CREATOR(StartMenuRoot), 0, GetWndClasss(), TITLE_STARTMENU,
565 WS_POPUP|WS_THICKFRAME|WS_CLIPCHILDREN|WS_VISIBLE, pos.left, pos.top-4, STARTMENU_WIDTH_MIN, 4, hwndDesktopBar);
566 }
567
568
569 void StartMenuRoot::TrackStartmenu()
570 {
571 MSG msg;
572 HWND hwnd = _hwnd;
573
574 while(IsWindow(hwnd)) {
575 if (!GetMessage(&msg, 0, 0, 0)) {
576 PostQuitMessage(msg.wParam);
577 break;
578 }
579
580 // Check for a mouse click on any window, which is not part of the start menu
581 if (msg.message==WM_LBUTTONDOWN || msg.message==WM_MBUTTONDOWN || msg.message==WM_RBUTTONDOWN) {
582 StartMenu* menu_wnd = NULL;
583
584 for(HWND hwnd=msg.hwnd; hwnd; hwnd=GetParent(hwnd)) {
585 menu_wnd = WINDOW_DYNAMIC_CAST(StartMenu, hwnd);
586
587 if (menu_wnd)
588 break;
589 }
590
591 if (!menu_wnd) {
592 DestroyWindow(_hwnd);
593 break;
594 }
595 }
596
597 try {
598 if (pretranslate_msg(&msg))
599 continue;
600
601 if (dispatch_dialog_msg(&msg))
602 continue;
603
604 TranslateMessage(&msg);
605
606 try {
607 DispatchMessage(&msg);
608 } catch(COMException& e) {
609 HandleException(e, g_Globals._hMainWnd);
610 }
611 } catch(COMException& e) {
612 HandleException(e, g_Globals._hMainWnd);
613 }
614 }
615 }
616
617
618 LRESULT StartMenuRoot::Init(LPCREATESTRUCT pcs)
619 {
620 // add buttons for entries in _entries
621 if (super::Init(pcs))
622 return 1;
623
624 AddButton(ResString(IDS_EXPLORE), SmallIcon(IDI_EXPLORER), false, IDC_EXPLORE);
625
626 AddSeparator();
627
628 // insert hard coded start entries
629 AddButton(ResString(IDS_PROGRAMS), 0, true, IDC_PROGRAMS);
630 AddButton(ResString(IDS_FAVORITES), 0, true, IDC_FAVORITES);
631 AddButton(ResString(IDS_DOCUMENTS), 0, true, IDC_DOCUMENTS);
632 AddButton(ResString(IDS_RECENT), 0, true, IDC_RECENT);
633 AddButton(ResString(IDS_SETTINGS), 0, true, IDC_SETTINGS);
634 AddButton(ResString(IDS_PRINTERS), 0, true, IDC_PRINTERS);
635 AddButton(ResString(IDS_SETTINGS_WND), 0, false, IDC_SETTINGS_WND);
636 AddButton(ResString(IDS_ADMIN), 0, true, IDC_ADMIN);
637 AddButton(ResString(IDS_DRIVES), 0, true, IDC_DRIVES);
638 AddButton(ResString(IDS_NETWORK), 0, true, IDC_NETWORK);
639 AddButton(ResString(IDS_CONNECTIONS), 0, true, IDC_CONNECTIONS);
640 AddButton(ResString(IDS_SEARCH), 0, false, IDC_SEARCH);
641 AddButton(ResString(IDS_SEARCH_COMPUTER),0,false, IDC_SEARCH_COMPUTER);
642 AddButton(ResString(IDS_START_HELP), 0, false, IDC_START_HELP);
643 AddButton(ResString(IDS_LAUNCH), 0, false, IDC_LAUNCH);
644
645 AddSeparator();
646
647 AddButton(ResString(IDS_LOGOFF), SmallIcon(IDI_LOGOFF), false, IDC_LOGOFF);
648 AddButton(ResString(IDS_SHUTDOWN), SmallIcon(IDI_LOGOFF), false, IDC_SHUTDOWN);
649
650 return 0;
651 }
652
653
654 LRESULT StartMenuRoot::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
655 {
656 switch(nmsg) {
657 case WM_PAINT: {
658 PaintCanvas canvas(_hwnd);
659 MemCanvas mem_dc;
660 ResBitmap bmp(IDB_LOGOV);
661 BitmapSelection sel(mem_dc, bmp);
662
663 ClientRect clnt(_hwnd);
664 int h = min(_logo_size.cy, clnt.bottom);
665
666 RECT rect = {0, 0, _logo_size.cx-1, clnt.bottom-h};
667 HBRUSH hbr = CreateSolidBrush(RGB(166,202,240)); // same color as the background color in the logo bitmap
668 FillRect(canvas, &rect, hbr);
669 PatBlt(canvas, _logo_size.cx-1, 0, 1, clnt.bottom-h, WHITENESS);
670 DeleteObject(hbr);
671
672 BitBlt(canvas, 0, clnt.bottom-h, _logo_size.cx, h, mem_dc, 0, 0, SRCCOPY);
673 break;}
674
675 default:
676 return super::WndProc(nmsg, wparam, lparam);
677 }
678
679 return 0;
680 }
681
682
683 int StartMenuRoot::Command(int id, int code)
684 {
685 switch(id) {
686 case IDC_PROGRAMS:
687 CreateSubmenu(id, CSIDL_COMMON_PROGRAMS, CSIDL_PROGRAMS);
688 break;
689
690 case IDC_EXPLORE:
691 explorer_show_frame(_hwnd, SW_SHOWNORMAL);
692 CloseStartMenu(id);
693 break;
694
695 case IDC_LAUNCH: {
696 HWND hwndDesktopBar = GetWindow(_hwnd, GW_OWNER);
697 CloseStartMenu(id);
698 ShowLaunchDialog(hwndDesktopBar);
699 break;}
700
701 case IDC_DOCUMENTS:
702 CreateSubmenu(id, CSIDL_PERSONAL);
703 break;
704
705 case IDC_RECENT:
706 CreateSubmenu(id, CSIDL_RECENT, STARTMENU_CREATOR(RecentStartMenu));
707 break;
708
709 case IDC_SETTINGS:
710 CreateSubmenu(id, CSIDL_CONTROLS);
711 break;
712
713 case IDC_PRINTERS:
714 CreateSubmenu(id, CSIDL_PRINTERS, CSIDL_PRINTHOOD);
715 break;
716
717 case IDC_SETTINGS_WND:
718 CloseStartMenu(id);
719 MainFrame::Create(_T("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}"), FALSE);
720 break;
721
722 case IDC_FAVORITES:
723 CreateSubmenu(id, CSIDL_FAVORITES);
724 break;
725
726 case IDC_ADMIN:
727 CreateSubmenu(id, CSIDL_COMMON_ADMINTOOLS, CSIDL_ADMINTOOLS);
728 break;
729
730 case IDC_NETWORK:
731 CreateSubmenu(id, CSIDL_NETWORK);
732 break;
733
734 case IDC_CONNECTIONS:
735 CreateSubmenu(id, CSIDL_CONNECTIONS);
736 break;
737
738 case IDC_DRIVES:
739 //TODO: exclude removeable drives
740 CreateSubmenu(id, CSIDL_DRIVES);
741 break;
742
743 case IDC_SEARCH:
744 ShowSearchDialog();
745 break;
746
747 case IDC_SEARCH_COMPUTER:
748 ShowSearchComputer();
749 break;
750
751 case IDC_LOGOFF:
752 /* The shell32 Dialog prompts about some system setting change. This is not what we want to display here.
753 HWND hwndDesktopBar = GetWindow(_hwnd, GW_OWNER);
754 CloseStartMenu(id);
755 ShowRestartDialog(hwndDesktopBar, EWX_LOGOFF);*/
756 DestroyWindow(GetParent(_hwnd));
757 break;
758
759 case IDC_SHUTDOWN: {
760 HWND hwndDesktopBar = GetWindow(_hwnd, GW_OWNER);
761 CloseStartMenu(id);
762 ShowExitWindowsDialog(hwndDesktopBar);
763 break;}
764
765 default:
766 return super::Command(id, code);
767 }
768
769 return 0;
770 }
771
772
773 void StartMenuRoot::ShowLaunchDialog(HWND hwndDesktopBar)
774 {
775 //TODO: All text phrases should be put into the resources.
776 static LPCSTR szTitle = "Create New Task";
777 static LPCSTR szText = "Type the name of a program, folder, document, or Internet resource, and Task Manager will open it for you.";
778
779 HMODULE hShell32 = GetModuleHandle(_T("SHELL32"));
780 RUNFILEDLG RunFileDlg = (RUNFILEDLG)GetProcAddress(hShell32, (LPCSTR)61);
781
782 // Show "Run..." dialog
783 if (RunFileDlg) {
784 #define W_VER_NT 0
785 if ((HIWORD(GetVersion())>>14) == W_VER_NT) {
786 WCHAR wTitle[40], wText[256];
787
788 MultiByteToWideChar(CP_ACP, 0, szTitle, -1, wTitle, 40);
789 MultiByteToWideChar(CP_ACP, 0, szText, -1, wText, 256);
790
791 RunFileDlg(hwndDesktopBar, 0, NULL, (LPCSTR)wTitle, (LPCSTR)wText, RFF_CALCDIRECTORY);
792 }
793 else
794 RunFileDlg(hwndDesktopBar, 0, NULL, szTitle, szText, RFF_CALCDIRECTORY);
795 }
796 }
797
798 void StartMenuRoot::ShowExitWindowsDialog(HWND hwndOwner)
799 {
800 HMODULE hShell32 = GetModuleHandle(_T("SHELL32"));
801 EXITWINDOWSDLG ExitWindowsDlg = (EXITWINDOWSDLG)GetProcAddress(hShell32, (LPCSTR)60);
802
803 if (ExitWindowsDlg)
804 ExitWindowsDlg(hwndOwner);
805 }
806
807 void StartMenuRoot::ShowRestartDialog(HWND hwndOwner, UINT flags)
808 {
809 HMODULE hShell32 = GetModuleHandle(_T("SHELL32"));
810 RESTARTWINDOWSDLG RestartDlg = (RESTARTWINDOWSDLG)GetProcAddress(hShell32, (LPCSTR)59);
811
812 if (RestartDlg)
813 RestartDlg(hwndOwner, (LPWSTR)L"You selected <Log Off>.\n\n", flags); //TODO: ANSI string conversion if needed
814 }
815
816 void StartMenuRoot::ShowSearchDialog()
817 {
818 HMODULE hShell32 = GetModuleHandle(_T("SHELL32"));
819 SHFINDFILES SHFindFiles = (SHFINDFILES)GetProcAddress(hShell32, (LPCSTR)90);
820
821 if (SHFindFiles)
822 SHFindFiles(NULL, NULL);
823 }
824
825 void StartMenuRoot::ShowSearchComputer()
826 {
827 HMODULE hShell32 = GetModuleHandle(_T("SHELL32"));
828 SHFINDCOMPUTER SHFindComputer = (SHFINDCOMPUTER)GetProcAddress(hShell32, (LPCSTR)91);
829
830 if (SHFindComputer)
831 SHFindComputer(NULL, NULL);
832 }
833
834
835 RecentStartMenu::RecentStartMenu(HWND hwnd, const StartMenuFolders& info)
836 : super(hwnd, info)
837 {
838 }
839
840 void RecentStartMenu::AddEntries()
841 {
842 for(StartMenuShellDirs::iterator it=_dirs.begin(); it!=_dirs.end(); ++it) {
843 StartMenuDirectory& smd = *it;
844 ShellDirectory& dir = smd._dir;
845
846 dir.smart_scan();
847
848 dir.sort_directory(SORT_DATE);
849 AddShellEntries(dir, 16, smd._subfolders); //TODO: read max. count of entries from registry
850 }
851 }