00001 /* 00002 * Copyright 2003, 2004 Martin Fuchs 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2.1 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public 00015 * License along with this library; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 */ 00018 00019 00020 // 00021 // Explorer clone 00022 // 00023 // startmenu.cpp 00024 // 00025 // Explorer start menu 00026 // 00027 // Martin Fuchs, 19.08.2003 00028 // 00029 // Credits: Thanks to Everaldo (http://www.everaldo.com) for his nice looking icons. 00030 // 00031 00032 00033 #include <precomp.h> 00034 00035 #include "../resource.h" 00036 00037 #include "desktopbar.h" 00038 #include "startmenu.h" 00039 00040 #include "../dialogs/searchprogram.h" 00041 #include "../dialogs/settings.h" 00042 00043 00044 #define SHELLPATH_CONTROL_PANEL TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}") 00045 #define SHELLPATH_PRINTERS TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}") 00046 #define SHELLPATH_NET_CONNECTIONS TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}") 00047 00048 00049 StartMenu::StartMenu(HWND hwnd, int icon_size) 00050 : super(hwnd), 00051 _icon_size(icon_size) 00052 { 00053 _next_id = IDC_FIRST_MENU; 00054 _submenu_id = 0; 00055 00056 _border_left = 0; 00057 _border_top = 0; 00058 _bottom_max = INT_MAX; 00059 00060 _floating_btn = false; 00061 _arrow_btns = false; 00062 _scroll_mode = SCROLL_NOT; 00063 _scroll_pos = 0; 00064 _invisible_lines = 0; 00065 00066 _last_pos = WindowRect(hwnd).pos(); 00067 #ifdef _LIGHT_STARTMENU 00068 _selected_id = -1; 00069 _last_mouse_pos = 0; 00070 #endif 00071 } 00072 00073 StartMenu::StartMenu(HWND hwnd, const StartMenuCreateInfo& create_info, int icon_size) 00074 : super(hwnd), 00075 _create_info(create_info), 00076 _icon_size(icon_size) 00077 { 00078 for(StartMenuFolders::const_iterator it=create_info._folders.begin(); it!=create_info._folders.end(); ++it) 00079 if (*it) 00080 _dirs.push_back(ShellDirectory(GetDesktopFolder(), *it, _hwnd)); 00081 00082 _next_id = IDC_FIRST_MENU; 00083 _submenu_id = 0; 00084 00085 _border_left = 0; 00086 _border_top = create_info._border_top; 00087 _bottom_max = INT_MAX; 00088 00089 _floating_btn = create_info._border_top? true: false; 00090 _arrow_btns = false; 00091 _scroll_mode = SCROLL_NOT; 00092 _scroll_pos = 0; 00093 _invisible_lines = 0; 00094 00095 _last_pos = WindowRect(hwnd).pos(); 00096 #ifdef _LIGHT_STARTMENU 00097 _selected_id = -1; 00098 _last_mouse_pos = 0; 00099 #endif 00100 } 00101 00102 StartMenu::~StartMenu() 00103 { 00104 SendParent(PM_STARTMENU_CLOSED); 00105 } 00106 00107 00108 // We need this wrapper function for s_wcStartMenu, it calls the WIN32 API, 00109 // though static C++ initializers are not allowed for Winelib applications. 00110 BtnWindowClass& StartMenu::GetWndClasss() 00111 { 00112 static BtnWindowClass s_wcStartMenu(CLASSNAME_STARTMENU); 00113 00114 return s_wcStartMenu; 00115 } 00116 00117 00118 Window::CREATORFUNC_INFO StartMenu::s_def_creator = STARTMENU_CREATOR(StartMenu); 00119 00120 HWND StartMenu::Create(int x, int y, const StartMenuFolders& folders, HWND hwndParent, LPCTSTR title, 00121 CREATORFUNC_INFO creator, void* info, const String& filter) 00122 { 00123 UINT style, ex_style; 00124 int top_height; 00125 00126 if (hwndParent) { 00127 style = WS_POPUP|WS_THICKFRAME|WS_CLIPCHILDREN|WS_VISIBLE; 00128 ex_style = 0; 00129 top_height = STARTMENU_TOP_BTN_SPACE; 00130 } else { 00131 style = WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_CLIPCHILDREN|WS_VISIBLE; 00132 ex_style = WS_EX_TOOLWINDOW; 00133 top_height = 0; 00134 } 00135 00136 int icon_size = ICON_SIZE_SMALL; 00137 RECT rect = {x, y-STARTMENU_LINE_HEIGHT(icon_size)-top_height, x+STARTMENU_WIDTH_MIN, y}; 00138 00139 #ifndef _LIGHT_STARTMENU 00140 rect.top += STARTMENU_LINE_HEIGHT(icon_size); 00141 #endif 00142 00143 AdjustWindowRectEx(&rect, style, FALSE, ex_style); 00144 00145 StartMenuCreateInfo create_info; 00146 00147 create_info._folders = folders; 00148 create_info._border_top = top_height; 00149 create_info._creator = creator; 00150 create_info._info = info; 00151 create_info._filter = filter; 00152 00153 if (title) 00154 create_info._title = title; 00155 00156 HWND hwnd = Window::Create(creator, &create_info, ex_style, GetWndClasss(), title, 00157 style, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, hwndParent); 00158 00159 // make sure the window is not off the screen 00160 MoveVisible(hwnd); 00161 00162 return hwnd; 00163 } 00164 00165 00166 LRESULT StartMenu::Init(LPCREATESTRUCT pcs) 00167 { 00168 try { 00169 AddEntries(); 00170 00171 if (super::Init(pcs)) 00172 return 1; 00173 00174 // create buttons for registered entries in _entries 00175 for(ShellEntryMap::const_iterator it=_entries.begin(); it!=_entries.end(); ++it) { 00176 const StartMenuEntry& sme = it->second; 00177 bool hasSubmenu = false; 00178 00179 for(ShellEntrySet::const_iterator it=sme._entries.begin(); it!=sme._entries.end(); ++it) 00180 if ((*it)->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 00181 hasSubmenu = true; 00182 00183 #ifdef _LIGHT_STARTMENU 00184 _buttons.push_back(SMBtnInfo(sme, it->first, hasSubmenu)); 00185 #else 00186 AddButton(sme._title, sme._hIcon, hasSubmenu, it->first); 00187 #endif 00188 } 00189 00190 #ifdef _LIGHT_STARTMENU 00191 if (_buttons.empty()) 00192 #else 00193 if (!GetWindow(_hwnd, GW_CHILD)) 00194 #endif 00195 AddButton(ResString(IDS_EMPTY), ICID_NONE, false, 0, false); 00196 00197 #ifdef _LIGHT_STARTMENU 00198 ResizeToButtons(); 00199 #endif 00200 00201 #ifdef _LAZY_ICONEXTRACT 00202 PostMessage(_hwnd, PM_UPDATE_ICONS, 0, 0); 00203 #endif 00204 } catch(COMException& e) { 00205 HandleException(e, pcs->hwndParent); // destroys the start menu window while switching focus 00206 } 00207 00208 return 0; 00209 } 00210 00211 void StartMenu::AddEntries() 00212 { 00213 for(StartMenuShellDirs::iterator it=_dirs.begin(); it!=_dirs.end(); ++it) { 00214 StartMenuDirectory& smd = *it; 00215 ShellDirectory& dir = smd._dir; 00216 00217 if (!dir._scanned) { 00218 WaitCursor wait; 00219 00220 #ifdef _LAZY_ICONEXTRACT 00221 dir.smart_scan(SORT_NAME, SCAN_DONT_EXTRACT_ICONS); // lazy icon extraction, try to read directly from filesystem 00222 #else 00223 dir.smart_scan(SORT_NAME); 00224 #endif 00225 } 00226 00227 AddShellEntries(dir, -1, smd._ignore); 00228 } 00229 } 00230 00231 00232 static LPTSTR trim_path_slash(LPTSTR path) 00233 { 00234 LPTSTR p = path; 00235 00236 while(*p) 00237 ++p; 00238 00239 if (p>path && (p[-1]=='\\' || p[-1]=='/')) 00240 *--p = '\0'; 00241 00242 return path; 00243 } 00244 00245 void StartMenu::AddShellEntries(const ShellDirectory& dir, int max, const String& ignore) 00246 { 00247 TCHAR ignore_path[MAX_PATH], ignore_dir[MAX_PATH], ignore_name[_MAX_FNAME], ignore_ext[_MAX_EXT]; 00248 TCHAR dir_path[MAX_PATH]; 00249 00250 if (!ignore.empty()) { 00251 _tsplitpath_s(ignore, ignore_path, COUNTOF(ignore_path), ignore_dir, COUNTOF(ignore_dir), ignore_name, COUNTOF(ignore_name), ignore_ext, COUNTOF(ignore_ext)); 00252 00253 _tcscat(ignore_path, ignore_dir); 00254 _tcscat(ignore_name, ignore_ext); 00255 00256 dir.get_path(dir_path, COUNTOF(dir_path)); 00257 00258 if (_tcsicmp(trim_path_slash(dir_path), trim_path_slash(ignore_path))) 00259 *ignore_name = '\0'; 00260 } else 00261 *ignore_name = '\0'; 00262 00263 String lwr_filter = _create_info._filter; 00264 lwr_filter.toLower(); 00265 00266 int cnt = 0; 00267 for(Entry*entry=dir._down; entry; entry=entry->_next) { 00268 // hide files like "desktop.ini" 00269 if (entry->_shell_attribs & SFGAO_HIDDEN) 00270 //not appropriate for drive roots: if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) 00271 continue; 00272 00273 // hide "Programs" subfolders if requested 00274 if (*ignore_name && !_tcsicmp(entry->_data.cFileName, ignore_name)) 00275 continue; 00276 00277 // only 'max' entries shall be added. 00278 if (++cnt == max) 00279 break; 00280 00281 // filter only non-directory entries 00282 if (!(entry->_data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) && !lwr_filter.empty()) { 00283 String lwr_name = entry->_data.cFileName; 00284 String lwr_disp = entry->_display_name; 00285 00286 lwr_name.toLower(); 00287 lwr_disp.toLower(); 00288 00289 if (!_tcsstr(lwr_name,lwr_filter) && !_tcsstr(lwr_disp,lwr_filter)) 00290 continue; 00291 } 00292 00293 if (entry->_etype == ET_SHELL) 00294 AddEntry(dir._folder, static_cast<ShellEntry*>(entry)); 00295 else 00296 AddEntry(dir._folder, entry); 00297 } 00298 } 00299 00300 00301 LRESULT StartMenu::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) 00302 { 00303 switch(nmsg) { 00304 case WM_PAINT: { 00305 PaintCanvas canvas(_hwnd); 00306 Paint(canvas); 00307 break;} 00308 00309 case WM_SIZE: 00310 ResizeButtons(LOWORD(lparam)-_border_left); 00311 break; 00312 00313 case WM_MOVE: { 00314 POINTS pos; 00315 pos.x = LOWORD(lparam); 00316 pos.y = HIWORD(lparam); 00317 00318 // move open submenus of floating menus 00319 if (_submenu) { 00320 int dx = pos.x - _last_pos.x; 00321 int dy = pos.y - _last_pos.y; 00322 00323 if (dx || dy) { 00324 WindowRect rt(_submenu); 00325 SetWindowPos(_submenu, 0, rt.left+dx, rt.top+dy, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE); 00326 //MoveVisible(_submenu); 00327 } 00328 } 00329 00330 _last_pos.x = pos.x; 00331 _last_pos.y = pos.y; 00332 goto def;} 00333 00334 case WM_NCHITTEST: { 00335 LRESULT res = super::WndProc(nmsg, wparam, lparam); 00336 00337 if (res>=HTSIZEFIRST && res<=HTSIZELAST) 00338 return HTCLIENT; // disable window resizing 00339 00340 return res;} 00341 00342 case WM_LBUTTONDOWN: { 00343 RECT rect; 00344 00345 // check mouse cursor for coordinates of floating button 00346 GetFloatingButtonRect(&rect); 00347 00348 if (PtInRect(&rect, Point(lparam))) { 00349 // create a floating copy of the current start menu 00350 WindowRect pos(_hwnd); 00351 00352 ///@todo do something similar to StartMenuRoot::TrackStartmenu() in order to automatically close submenus when clicking on the desktop background 00353 StartMenu::Create(pos.left+3, pos.bottom-3, _create_info._folders, 0, _create_info._title, _create_info._creator, _create_info._info); 00354 CloseStartMenu(); 00355 } 00356 00357 #ifdef _LIGHT_STARTMENU 00358 int id = ButtonHitTest(Point(lparam)); 00359 00360 if (id) 00361 Command(id, BN_CLICKED); 00362 #endif 00363 break;} 00364 00365 case WM_SYSCOMMAND: 00366 if ((wparam&0xFFF0) == SC_SIZE) 00367 return 0; // disable window resizing 00368 goto def; 00369 00370 case WM_ACTIVATEAPP: 00371 // close start menu when activating another application 00372 if (!wparam) 00373 CloseStartMenu(); 00374 break; // don't call super::WndProc in case "this" has been deleted 00375 00376 case WM_CANCELMODE: 00377 CloseStartMenu(); 00378 00379 #ifdef _LIGHT_STARTMENU 00380 if (_scroll_mode != SCROLL_NOT) { 00381 ReleaseCapture(); 00382 KillTimer(_hwnd, 0); 00383 } 00384 #endif 00385 break; 00386 00387 #ifdef _LIGHT_STARTMENU 00388 case WM_MOUSEMOVE: { 00389 // automatically set the focus to startmenu entries when moving the mouse over them 00390 if (lparam != _last_mouse_pos) { // don't process WM_MOUSEMOVE when opening submenus using keyboard navigation 00391 Point pt(lparam); 00392 00393 if (_arrow_btns) { 00394 RECT rect_up, rect_down; 00395 00396 GetArrowButtonRects(&rect_up, &rect_down, _icon_size); 00397 00398 SCROLL_MODE scroll_mode = SCROLL_NOT; 00399 00400 if (PtInRect(&rect_up, pt)) 00401 scroll_mode = SCROLL_UP; 00402 else if (PtInRect(&rect_down, pt)) 00403 scroll_mode = SCROLL_DOWN; 00404 00405 if (scroll_mode != _scroll_mode) { 00406 if (scroll_mode == SCROLL_NOT) { 00407 ReleaseCapture(); 00408 KillTimer(_hwnd, 0); 00409 } else { 00410 CloseSubmenus(); 00411 SetTimer(_hwnd, 0, 150, NULL); // 150 ms scroll interval 00412 SetCapture(_hwnd); 00413 } 00414 00415 _scroll_mode = scroll_mode; 00416 } 00417 } 00418 00419 int new_id = ButtonHitTest(pt); 00420 00421 if (new_id>0 && new_id!=_selected_id) 00422 SelectButton(new_id); 00423 00424 _last_mouse_pos = lparam; 00425 } 00426 break;} 00427 00428 case WM_TIMER: 00429 if (_scroll_mode == SCROLL_UP) { 00430 if (_scroll_pos > 0) { 00431 --_scroll_pos; 00432 InvalidateRect(_hwnd, NULL, TRUE); 00433 } 00434 } else { 00435 if (_scroll_pos <= _invisible_lines) { 00436 ++_scroll_pos; 00437 InvalidateRect(_hwnd, NULL, TRUE); 00438 } 00439 } 00440 break; 00441 00442 case WM_KEYDOWN: 00443 ProcessKey(wparam); 00444 break; 00445 #else 00446 case PM_STARTENTRY_FOCUSED: { ///@todo use TrackMouseEvent() and WM_MOUSEHOVER to wait a bit before opening submenus 00447 BOOL hasSubmenu = wparam; 00448 HWND hctrl = (HWND)lparam; 00449 00450 // automatically open submenus 00451 if (hasSubmenu) { 00452 UpdateWindow(_hwnd); // draw focused button before waiting on submenu creation 00453 //SendMessage(_hwnd, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hctrl),BN_CLICKED), (LPARAM)hctrl); 00454 Command(GetDlgCtrlID(hctrl), BN_CLICKED); 00455 } else { 00456 // close any open submenu 00457 CloseOtherSubmenus(); 00458 } 00459 break;} 00460 #endif 00461 00462 #ifdef _LAZY_ICONEXTRACT 00463 case PM_UPDATE_ICONS: 00464 UpdateIcons(/*wparam*/); 00465 break; 00466 #endif 00467 00468 case PM_STARTENTRY_LAUNCHED: 00469 if (GetWindowStyle(_hwnd) & WS_CAPTION) // don't automatically close floating menus 00470 return 0; 00471 00472 // route message to the parent menu and close menus after launching an entry 00473 if (!SendParent(nmsg, wparam, lparam)) 00474 CloseStartMenu(); 00475 return 1; // signal that we have received and processed the message 00476 00477 case PM_STARTMENU_CLOSED: 00478 _submenu = 0; 00479 break; 00480 00481 case PM_SELECT_ENTRY: 00482 SelectButtonIndex(0, wparam!=0); 00483 break; 00484 00485 #ifdef _LIGHT_STARTMENU 00486 case WM_CONTEXTMENU: { 00487 Point screen_pt(lparam), clnt_pt=screen_pt; 00488 ScreenToClient(_hwnd, &clnt_pt); 00489 00490 int id = ButtonHitTest(clnt_pt); 00491 00492 if (id) { 00493 StartMenuEntry& sme = _entries[id]; 00494 00495 for(ShellEntrySet::iterator it=sme._entries.begin(); it!=sme._entries.end(); ++it) { 00496 Entry* entry = *it; 00497 00498 if (entry) { 00499 CHECKERROR(entry->do_context_menu(_hwnd, screen_pt, _cm_ifs)); // may close start menu because of focus loss 00500 ///@todo refresh on successfull context menu execution? 00501 break; ///@todo handle context menu for more than one entry 00502 } 00503 } 00504 } 00505 break;} 00506 #endif 00507 00508 default: def: 00509 return super::WndProc(nmsg, wparam, lparam); 00510 } 00511 00512 return 0; 00513 } 00514 00515 00516 #ifdef _LIGHT_STARTMENU 00517 00518 int StartMenu::ButtonHitTest(POINT pt) 00519 { 00520 ClientRect clnt(_hwnd); 00521 const int icon_size = _icon_size; 00522 RECT rect = {_border_left, _border_top, clnt.right, STARTMENU_LINE_HEIGHT(icon_size)}; 00523 00524 if (pt.x<rect.left || pt.x>rect.right) 00525 return 0; 00526 00527 for(SMBtnVector::const_iterator it=_buttons.begin()+_scroll_pos; it!=_buttons.end(); ++it) { 00528 const SMBtnInfo& info = *it; 00529 00530 if (rect.top > pt.y) 00531 break; 00532 00533 rect.bottom = rect.top + (info._id==-1? STARTMENU_SEP_HEIGHT(icon_size): STARTMENU_LINE_HEIGHT(icon_size)); 00534 00535 if (rect.bottom > _bottom_max) 00536 break; 00537 00538 if (pt.y < rect.bottom) // PtInRect(&rect, pt) 00539 return info._id; 00540 00541 rect.top = rect.bottom; 00542 } 00543 00544 return 0; 00545 } 00546 00547 void StartMenu::InvalidateSelection() 00548 { 00549 if (_selected_id <= 0) 00550 return; 00551 00552 ClientRect clnt(_hwnd); 00553 const int icon_size = _icon_size; 00554 RECT rect = {_border_left, _border_top, clnt.right, STARTMENU_LINE_HEIGHT(icon_size)}; 00555 00556 for(SMBtnVector::const_iterator it=_buttons.begin()+_scroll_pos; it!=_buttons.end(); ++it) { 00557 const SMBtnInfo& info = *it; 00558 00559 rect.bottom = rect.top + (info._id==-1? STARTMENU_SEP_HEIGHT(icon_size): STARTMENU_LINE_HEIGHT(icon_size)); 00560 00561 if (info._id == _selected_id) { 00562 InvalidateRect(_hwnd, &rect, TRUE); 00563 break; 00564 } 00565 00566 rect.top = rect.bottom; 00567 } 00568 } 00569 00570 const SMBtnInfo* StartMenu::GetButtonInfo(int id) const 00571 { 00572 for(SMBtnVector::const_iterator it=_buttons.begin(); it!=_buttons.end(); ++it) 00573 if (it->_id == id) 00574 return &*it; 00575 00576 return NULL; 00577 } 00578 00579 bool StartMenu::SelectButton(int id, bool open_sub) 00580 { 00581 if (id == -1) 00582 return false; 00583 00584 if (id == _selected_id) 00585 return true; 00586 00587 InvalidateSelection(); 00588 00589 const SMBtnInfo* btn = GetButtonInfo(id); 00590 00591 if (btn && btn->_enabled) { 00592 _selected_id = id; 00593 00594 InvalidateSelection(); 00595 00596 // automatically open submenus 00597 if (btn->_hasSubmenu) { 00598 if (open_sub) 00599 OpenSubmenu(); 00600 } else 00601 CloseOtherSubmenus(); // close any open submenu 00602 00603 return true; 00604 } else { 00605 _selected_id = -1; 00606 return false; 00607 } 00608 } 00609 00610 bool StartMenu::OpenSubmenu(bool select_first) 00611 { 00612 if (_selected_id == -1) 00613 return false; 00614 00615 InvalidateSelection(); 00616 00617 const SMBtnInfo* btn = GetButtonInfo(_selected_id); 00618 00619 // automatically open submenus 00620 if (btn->_hasSubmenu) { 00621 //@@ allows destroying of startmenu when processing PM_UPDATE_ICONS -> GPF 00622 UpdateWindow(_hwnd); // draw focused button before waiting on submenu creation 00623 Command(_selected_id, BN_CLICKED); 00624 00625 if (select_first && _submenu) 00626 SendMessage(_submenu, PM_SELECT_ENTRY, (WPARAM)false, 0); 00627 00628 return true; 00629 } else 00630 return false; 00631 } 00632 00633 00634 int StartMenu::GetSelectionIndex() 00635 { 00636 if (_selected_id == -1) 00637 return -1; 00638 00639 for(int i=0; i<(int)_buttons.size(); ++i) 00640 if (_buttons[i]._id == _selected_id) 00641 return i; 00642 00643 return -1; 00644 } 00645 00646 bool StartMenu::SelectButtonIndex(int idx, bool open_sub) 00647 { 00648 if (idx>=0 && idx<(int)_buttons.size()) 00649 return SelectButton(_buttons[idx]._id, open_sub); 00650 else 00651 return false; 00652 } 00653 00654 void StartMenu::ProcessKey(int vk) 00655 { 00656 switch(vk) { 00657 case VK_RETURN: 00658 if (_selected_id) 00659 Command(_selected_id, BN_CLICKED); 00660 break; 00661 00662 case VK_UP: 00663 Navigate(-1); 00664 break; 00665 00666 case VK_DOWN: 00667 Navigate(+1); 00668 break; 00669 00670 case VK_HOME: 00671 SelectButtonIndex(0, false); 00672 break; 00673 00674 case VK_END: 00675 SelectButtonIndex(_buttons.size()-1, false); 00676 break; 00677 00678 case VK_LEFT: 00679 if (_submenu) 00680 CloseOtherSubmenus(); 00681 else if (!(GetWindowStyle(_hwnd) & WS_CAPTION)) // don't automatically close floating menus 00682 DestroyWindow(_hwnd); 00683 break; 00684 00685 case VK_RIGHT: 00686 OpenSubmenu(true); 00687 break; 00688 00689 case VK_ESCAPE: 00690 CloseStartMenu(); 00691 break; 00692 00693 default: 00694 if (vk>='0' && vk<='Z') 00695 JumpToNextShortcut(vk); 00696 } 00697 } 00698 00699 bool StartMenu::Navigate(int step) 00700 { 00701 int idx = GetSelectionIndex(); 00702 00703 if (idx == -1) 00704 { 00705 if (step > 0) 00706 idx = 0 - step; 00707 else 00708 idx = _buttons.size() - step; 00709 } 00710 00711 for(;;) { 00712 idx += step; 00713 00714 if (_buttons.size()<=1 && (idx<0 || idx>(int)_buttons.size())) 00715 break; 00716 00717 if (idx < 0) 00718 idx += _buttons.size(); 00719 00720 if (idx > (int)_buttons.size()) 00721 idx -= _buttons.size()+1; 00722 00723 if (SelectButtonIndex(idx, false)) 00724 return true; 00725 } 00726 00727 return false; 00728 } 00729 00730 bool StartMenu::JumpToNextShortcut(char c) 00731 { 00732 int cur_idx = GetSelectionIndex(); 00733 00734 if (cur_idx == -1) 00735 cur_idx = 0; 00736 00737 int first_found = 0; 00738 int found_more = 0; 00739 00740 SMBtnVector::const_iterator cur_it = _buttons.begin(); 00741 cur_it += cur_idx + 1; 00742 00743 // first search down from current item... 00744 SMBtnVector::const_iterator it = cur_it; 00745 for(; it!=_buttons.end(); ++it) { 00746 const SMBtnInfo& btn = *it; 00747 00748 if (!btn._title.empty() && toupper((TBYTE)btn._title.at(0)) == c) { 00749 if (!first_found) 00750 first_found = btn._id; 00751 else 00752 ++found_more; 00753 } 00754 } 00755 00756 // ...now search from top to the current item 00757 it = _buttons.begin(); 00758 for(; it!=_buttons.end() && it!=cur_it; ++it) { 00759 const SMBtnInfo& btn = *it; 00760 00761 if (!btn._title.empty() && toupper((TBYTE)btn._title.at(0)) == c) { 00762 if (!first_found) 00763 first_found = btn._id; 00764 else 00765 ++found_more; 00766 } 00767 } 00768 00769 if (first_found) { 00770 SelectButton(first_found); 00771 00772 if (!found_more) 00773 Command(first_found, BN_CLICKED); 00774 00775 return true; 00776 } else 00777 return false; 00778 } 00779 00780 #endif // _LIGHT_STARTMENU 00781 00782 00783 bool StartMenu::GetButtonRect(int id, PRECT prect) const 00784 { 00785 #ifdef _LIGHT_STARTMENU 00786 ClientRect clnt(_hwnd); 00787 const int icon_size = _icon_size; 00788 RECT rect = {_border_left, _border_top, clnt.right, STARTMENU_LINE_HEIGHT(icon_size)}; 00789 00790 for(SMBtnVector::const_iterator it=_buttons.begin()+_scroll_pos; it!=_buttons.end(); ++it) { 00791 const SMBtnInfo& info = *it; 00792 00793 rect.bottom = rect.top + (info._id==-1? STARTMENU_SEP_HEIGHT(icon_size): STARTMENU_LINE_HEIGHT(icon_size)); 00794 00795 if (info._id == id) { 00796 *prect = rect; 00797 return true; 00798 } 00799 00800 rect.top = rect.bottom; 00801 } 00802 00803 return false; 00804 #else 00805 HWND btn = GetDlgItem(_hwnd, id); 00806 00807 if (btn) { 00808 GetWindowRect(btn, prect); 00809 ScreenToClient(_hwnd, prect); 00810 00811 return true; 00812 } else 00813 return false; 00814 #endif 00815 } 00816 00817 00818 void StartMenu::DrawFloatingButton(HDC hdc) 00819 { 00820 static ResIconEx floatingIcon(IDI_FLOATING, 8, 4); 00821 00822 ClientRect clnt(_hwnd); 00823 00824 DrawIconEx(hdc, clnt.right-12, 0, floatingIcon, 8, 4, 0, 0, DI_NORMAL); 00825 } 00826 00827 void StartMenu::GetFloatingButtonRect(LPRECT prect) 00828 { 00829 GetClientRect(_hwnd, prect); 00830 00831 prect->right -= 4; 00832 prect->left = prect->right - 8; 00833 prect->bottom = 4; 00834 } 00835 00836 00837 void StartMenu::DrawArrows(HDC hdc, int icon_size) 00838 { 00839 int cx = icon_size / 2; 00840 int cy = icon_size / 4; 00841 00842 ResIconEx arrowUpIcon(IDI_ARROW_UP, cx, cy); 00843 ResIconEx arrowDownIcon(IDI_ARROW_DOWN, cx, cy); 00844 00845 ClientRect clnt(_hwnd); 00846 00847 DrawIconEx(hdc, clnt.right/2-cx/2, _floating_btn?3:1, arrowUpIcon, cx, cy, 0, 0, DI_NORMAL); 00848 DrawIconEx(hdc, clnt.right/2-cx/2, clnt.bottom-cy-1, arrowDownIcon, cx, cy, 0, 0, DI_NORMAL); 00849 } 00850 00851 void StartMenu::GetArrowButtonRects(LPRECT prect_up, LPRECT prect_down, int icon_size) 00852 { 00853 int cx = icon_size / 2; 00854 int cy = icon_size / 4; 00855 00856 GetClientRect(_hwnd, prect_up); 00857 *prect_down = *prect_up; 00858 00859 // prect_up->left = prect_up->right/2 - cx/2; 00860 // prect_up->right = prect_up->left + cy; 00861 prect_up->right -= cx; 00862 prect_up->top = _floating_btn? cy-1: 1; 00863 prect_up->bottom = prect_up->top + cy; 00864 00865 // prect_down->left = prect_down->right/2 - cx/2; 00866 // prect_down->right = prect_down->left + cy; 00867 prect_down->right -= cx; 00868 prect_down->top = prect_down->bottom - cy - 1; 00869 } 00870 00871 00872 void StartMenu::Paint(PaintCanvas& canvas) 00873 { 00874 if (_floating_btn) 00875 DrawFloatingButton(canvas); 00876 00877 #ifdef _LIGHT_STARTMENU 00878 if (_arrow_btns) 00879 DrawArrows(canvas, _icon_size); 00880 00881 ClientRect clnt(_hwnd); 00882 const int icon_size = _icon_size; 00883 RECT rect = {_border_left, _border_top, clnt.right, STARTMENU_LINE_HEIGHT(icon_size)}; 00884 00885 int sep_width = rect.right-rect.left - 4; 00886 00887 FontSelection font(canvas, GetStockFont(DEFAULT_GUI_FONT)); 00888 BkMode bk_mode(canvas, TRANSPARENT); 00889 00890 for(SMBtnVector::const_iterator it=_buttons.begin()+_scroll_pos; it!=_buttons.end(); ++it) { 00891 const SMBtnInfo& btn = *it; 00892 00893 if (rect.top > canvas.rcPaint.bottom) 00894 break; 00895 00896 if (btn._id == -1) { // a separator? 00897 rect.bottom = rect.top + STARTMENU_SEP_HEIGHT(icon_size); 00898 00899 if (rect.bottom > _bottom_max) 00900 break; 00901 00902 BrushSelection brush_sel(canvas, GetSysColorBrush(COLOR_BTNSHADOW)); 00903 PatBlt(canvas, rect.left+2, rect.top+STARTMENU_SEP_HEIGHT(icon_size)/2-1, sep_width, 1, PATCOPY); 00904 00905 SelectBrush(canvas, GetSysColorBrush(COLOR_BTNHIGHLIGHT)); 00906 PatBlt(canvas, rect.left+2, rect.top+STARTMENU_SEP_HEIGHT(icon_size)/2, sep_width, 1, PATCOPY); 00907 } else { 00908 rect.bottom = rect.top + STARTMENU_LINE_HEIGHT(icon_size); 00909 00910 if (rect.bottom > _bottom_max) 00911 break; 00912 00913 if (rect.top >= canvas.rcPaint.top) 00914 DrawStartMenuButton(canvas, rect, btn._title, btn, btn._id==_selected_id, false, _icon_size); 00915 } 00916 00917 rect.top = rect.bottom; 00918 } 00919 #endif 00920 } 00921 00922 #ifdef _LAZY_ICONEXTRACT 00923 void StartMenu::UpdateIcons(/*int idx*/) 00924 { 00925 UpdateWindow(_hwnd); 00926 00927 #ifdef _SINGLE_ICONEXTRACT 00928 00929 //if (idx >= 0) 00930 int idx = _scroll_pos; 00931 00932 for(; idx<(int)_buttons.size(); ++idx) { 00933 SMBtnInfo& btn = _buttons[idx]; 00934 00935 if (btn._icon_id==ICID_UNKNOWN && btn._id>0) { 00936 StartMenuEntry& sme = _entries[btn._id]; 00937 00938 btn._icon_id = ICID_NONE; 00939 00940 for(ShellEntrySet::iterator it=sme._entries.begin(); it!=sme._entries.end(); ++it) { 00941 Entry* entry = *it; 00942 00943 if (entry->_icon_id == ICID_UNKNOWN) 00944 entry->_icon_id = entry->safe_extract_icon(ICF_FROM_ICON_SIZE(_icon_size)); 00945 00946 if (entry->_icon_id > ICID_NONE) { 00947 btn._icon_id = (ICON_ID)/*@@*/ entry->_icon_id; 00948 00949 RECT rect; 00950 00951 GetButtonRect(btn._id, &rect); 00952 00953 if (rect.bottom > _bottom_max) 00954 break; 00955 00956 WindowCanvas canvas(_hwnd); 00957 DrawStartMenuButton(canvas, rect, NULL, btn, btn._id==_selected_id, false, _icon_size); 00958 00959 //InvalidateRect(_hwnd, &rect, FALSE); 00960 //UpdateWindow(_hwnd); 00961 //break; 00962 00963 break; 00964 } 00965 } 00966 } 00967 } 00968 00969 // if (++idx < (int)_buttons.size()) 00970 // PostMessage(_hwnd, PM_UPDATE_ICONS, idx, 0); 00971 00972 #else 00973 00974 int icons_extracted = 0; 00975 int icons_updated = 0; 00976 00977 for(StartMenuShellDirs::iterator it=_dirs.begin(); it!=_dirs.end(); ++it) { 00978 ShellDirectory& dir = it->_dir; 00979 00980 icons_extracted += dir.extract_icons(icon_size); 00981 } 00982 00983 if (icons_extracted) { 00984 for(ShellEntryMap::iterator it1=_entries.begin(); it1!=_entries.end(); ++it1) { 00985 StartMenuEntry& sme = it1->second; 00986 00987 if (!sme._hIcon) { 00988 sme._hIcon = (HICON)-1; 00989 00990 for(ShellEntrySet::const_iterator it2=sme._entries.begin(); it2!=sme._entries.end(); ++it2) { 00991 const Entry* sm_entry = *it2; 00992 00993 if (sm_entry->_hIcon) { 00994 sme._hIcon = sm_entry->_hIcon; 00995 break; 00996 } 00997 } 00998 } 00999 } 01000 01001 for(SMBtnVector::iterator it=_buttons.begin(); it!=_buttons.end(); ++it) { 01002 SMBtnInfo& info = *it; 01003 01004 if (info._id>0 && !info._hIcon) { 01005 info._hIcon = _entries[info._id]._hIcon; 01006 ++icons_updated; 01007 } 01008 } 01009 } 01010 01011 if (icons_updated) { 01012 InvalidateRect(_hwnd, NULL, FALSE); 01013 UpdateWindow(_hwnd); 01014 } 01015 #endif 01016 } 01017 #endif 01018 01019 01020 // resize child button controls to accomodate for new window size 01021 void StartMenu::ResizeButtons(int cx) 01022 { 01023 HDWP hdwp = BeginDeferWindowPos(10); 01024 01025 for(HWND ctrl=GetWindow(_hwnd,GW_CHILD); ctrl; ctrl=GetNextWindow(ctrl,GW_HWNDNEXT)) { 01026 ClientRect rt(ctrl); 01027 01028 if (rt.right != cx) { 01029 int height = rt.bottom - rt.top; 01030 01031 // special handling for separator controls 01032 if (!height && (GetWindowStyle(ctrl)&SS_TYPEMASK)==SS_ETCHEDHORZ) 01033 height = 2; 01034 01035 hdwp = DeferWindowPos(hdwp, ctrl, 0, 0, 0, cx, height, SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE); 01036 } 01037 } 01038 01039 EndDeferWindowPos(hdwp); 01040 } 01041 01042 01043 int StartMenu::Command(int id, int code) 01044 { 01045 #ifndef _LIGHT_STARTMENU 01046 switch(id) { 01047 case IDCANCEL: 01048 CloseStartMenu(id); 01049 break; 01050 01051 default: { 01052 #endif 01053 ShellEntryMap::iterator found = _entries.find(id); 01054 01055 if (found != _entries.end()) { 01056 ActivateEntry(id, found->second._entries); 01057 return 0; 01058 } 01059 01060 return super::Command(id, code); 01061 #ifndef _LIGHT_STARTMENU 01062 } 01063 } 01064 01065 return 0; 01066 #endif 01067 } 01068 01069 01070 ShellEntryMap::iterator StartMenu::AddEntry(const String& title, ICON_ID icon_id, Entry* entry) 01071 { 01072 // search for an already existing subdirectory entry with the same name 01073 if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 01074 { 01075 for(ShellEntryMap::iterator it=_entries.begin(); it!=_entries.end(); ++it) { 01076 StartMenuEntry& sme = it->second; 01077 01078 if (!_tcsicmp(sme._title, title)) ///@todo speed up by using a map indexed by name 01079 { 01080 for(ShellEntrySet::iterator it2=sme._entries.begin(); it2!=sme._entries.end(); ++it2) { 01081 if ((*it2)->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 01082 // merge the new shell entry with the existing of the same name 01083 sme._entries.insert(entry); 01084 01085 return it; 01086 } 01087 } 01088 } 01089 } 01090 } 01091 01092 ShellEntryMap::iterator sme = AddEntry(title, icon_id); 01093 01094 sme->second._entries.insert(entry); 01095 01096 return sme; 01097 } 01098 01099 ShellEntryMap::iterator StartMenu::AddEntry(const String& title, ICON_ID icon_id, int id) 01100 { 01101 if (id == -1) 01102 id = ++_next_id; 01103 01104 StartMenuEntry sme; 01105 01106 sme._title = title; 01107 sme._icon_id = icon_id; 01108 01109 ShellEntryMap::iterator it = _entries.insert(make_pair(id, sme)).first; 01110 01111 return it; 01112 } 01113 01114 ShellEntryMap::iterator StartMenu::AddEntry(const ShellFolder folder, ShellEntry* entry) 01115 { 01116 ICON_ID icon_id; 01117 01118 if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 01119 icon_id = ICID_APPS; 01120 else 01121 icon_id = (ICON_ID)/*@@*/ entry->_icon_id; 01122 01123 return AddEntry(folder.get_name(entry->_pidl), icon_id, entry); 01124 } 01125 01126 ShellEntryMap::iterator StartMenu::AddEntry(const ShellFolder folder, Entry* entry) 01127 { 01128 ICON_ID icon_id; 01129 01130 if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 01131 icon_id = ICID_APPS; 01132 else 01133 icon_id = (ICON_ID)/*@@*/ entry->_icon_id; 01134 01135 return AddEntry(entry->_display_name, icon_id, entry); 01136 } 01137 01138 01139 void StartMenu::AddButton(LPCTSTR title, ICON_ID icon_id, bool hasSubmenu, int id, bool enabled) 01140 { 01141 #ifdef _LIGHT_STARTMENU 01142 _buttons.push_back(SMBtnInfo(title, icon_id, id, hasSubmenu, enabled)); 01143 #else 01144 DWORD style = enabled? WS_VISIBLE|WS_CHILD|BS_OWNERDRAW: WS_VISIBLE|WS_CHILD|BS_OWNERDRAW|WS_DISABLED; 01145 01146 WindowRect rect(_hwnd); 01147 ClientRect clnt(_hwnd); 01148 01149 // increase window height to make room for the new button 01150 rect.top -= STARTMENU_LINE_HEIGHT(icon_size); 01151 01152 // move down if we are too high now 01153 if (rect.top < 0) { 01154 rect.top += STARTMENU_LINE_HEIGHT(icon_size); 01155 rect.bottom += STARTMENU_LINE_HEIGHT(icon_size); 01156 } 01157 01158 WindowCanvas canvas(_hwnd); 01159 FontSelection font(canvas, GetStockFont(DEFAULT_GUI_FONT)); 01160 01161 // widen window, if it is too small 01162 int text_width = GetStartMenuBtnTextWidth(canvas, title, _hwnd) + icon_size + 10/*placeholder*/ + 16/*arrow*/; 01163 01164 int cx = clnt.right - _border_left; 01165 if (text_width > cx) 01166 rect.right += text_width-cx; 01167 01168 MoveWindow(_hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE); 01169 01170 StartMenuCtrl(_hwnd, _border_left, clnt.bottom, rect.right-rect.left-_border_left, 01171 title, id, g_Globals._icon_cache.get_icon(icon_id)._hIcon, hasSubmenu, style); 01172 #endif 01173 } 01174 01175 void StartMenu::AddSeparator() 01176 { 01177 #ifdef _LIGHT_STARTMENU 01178 _buttons.push_back(SMBtnInfo(NULL, ICID_NONE, -1, false)); 01179 #else 01180 WindowRect rect(_hwnd); 01181 ClientRect clnt(_hwnd); 01182 01183 // increase window height to make room for the new separator 01184 rect.top -= STARTMENU_SEP_HEIGHT(icon_size); 01185 01186 // move down if we are too high now 01187 if (rect.top < 0) { 01188 rect.top += STARTMENU_LINE_HEIGHT(icon_size); 01189 rect.bottom += STARTMENU_LINE_HEIGHT(icon_size); 01190 } 01191 01192 MoveWindow(_hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE); 01193 01194 StartMenuSeparator(_hwnd, _border_left, clnt.bottom, rect.right-rect.left-_border_left); 01195 #endif 01196 } 01197 01198 01199 bool StartMenu::CloseOtherSubmenus(int id) 01200 { 01201 if (_submenu) { 01202 if (IsWindow(_submenu)) { 01203 if (_submenu_id == id) 01204 return false; 01205 else { 01206 _submenu_id = 0; 01207 DestroyWindow(_submenu); 01208 // _submenu should be reset automatically by PM_STARTMENU_CLOSED, but safety first... 01209 } 01210 } 01211 01212 _submenu = 0; 01213 } 01214 01215 return true; 01216 } 01217 01218 01219 void StartMenu::CreateSubmenu(int id, LPCTSTR title, CREATORFUNC_INFO creator, void* info) 01220 { 01221 CreateSubmenu(id, StartMenuFolders(), title, creator, info); 01222 } 01223 01224 bool StartMenu::CreateSubmenu(int id, int folder_id, LPCTSTR title, CREATORFUNC_INFO creator, void* info) 01225 { 01226 try { 01227 SpecialFolderPath folder(folder_id, _hwnd); 01228 01229 StartMenuFolders new_folders; 01230 new_folders.push_back(folder); 01231 01232 CreateSubmenu(id, new_folders, title, creator, info); 01233 01234 return true; 01235 } catch(COMException&) { 01236 // ignore Exception and don't display anything 01237 CloseOtherSubmenus(id); 01238 _buttons[GetSelectionIndex()]._enabled = false; // disable entries for non-existing folders 01239 return false; 01240 } 01241 } 01242 01243 bool StartMenu::CreateSubmenu(int id, int folder_id1, int folder_id2, LPCTSTR title, CREATORFUNC_INFO creator, void* info) 01244 { 01245 StartMenuFolders new_folders; 01246 01247 try { 01248 new_folders.push_back(SpecialFolderPath(folder_id1, _hwnd)); 01249 } catch(COMException&) { 01250 } 01251 01252 try { 01253 new_folders.push_back(SpecialFolderPath(folder_id2, _hwnd)); 01254 } catch(COMException&) { 01255 } 01256 01257 if (!new_folders.empty()) { 01258 CreateSubmenu(id, new_folders, title, creator, info); 01259 return true; 01260 } else { 01261 CloseOtherSubmenus(id); 01262 _buttons[GetSelectionIndex()]._enabled = false; // disable entries for non-existing folders 01263 return false; 01264 } 01265 } 01266 01267 void StartMenu::CreateSubmenu(int id, const StartMenuFolders& new_folders, LPCTSTR title, CREATORFUNC_INFO creator, void* info) 01268 { 01269 // Only open one submenu at a time. 01270 if (!CloseOtherSubmenus(id)) 01271 return; 01272 01273 RECT rect; 01274 int x, y; 01275 01276 if (GetButtonRect(id, &rect)) { 01277 ClientToScreen(_hwnd, &rect); 01278 01279 x = rect.right; // Submenus should overlap their parent a bit. 01280 const int icon_size = _icon_size; 01281 y = rect.top+STARTMENU_LINE_HEIGHT(icon_size) +_border_top/*own border*/ -STARTMENU_TOP_BTN_SPACE/*border of new submenu*/; 01282 } else { 01283 WindowRect pos(_hwnd); 01284 01285 x = pos.right; 01286 y = pos.top; 01287 } 01288 01289 _submenu_id = id; 01290 _submenu = StartMenu::Create(x, y, new_folders, _hwnd, title, creator, info, _create_info._filter); 01291 } 01292 01293 01294 void StartMenu::ActivateEntry(int id, const ShellEntrySet& entries) 01295 { 01296 StartMenuFolders new_folders; 01297 String title; 01298 01299 for(ShellEntrySet::const_iterator it=entries.begin(); it!=entries.end(); ++it) { 01300 Entry* entry = const_cast<Entry*>(*it); 01301 01302 if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 01303 01304 ///@todo If the user explicitly clicked on a submenu, display this folder as floating start menu. 01305 01306 if (entry->_etype == ET_SHELL) 01307 new_folders.push_back(entry->create_absolute_pidl()); 01308 else { 01309 TCHAR path[MAX_PATH]; 01310 01311 if (entry->get_path(path, COUNTOF(path))) 01312 new_folders.push_back(path); 01313 } 01314 01315 if (title.empty()) 01316 title = entry->_display_name; 01317 } else { 01318 // The entry is no subdirectory, so there can only be one shell entry. 01319 assert(entries.size()==1); 01320 01321 HWND hparent = GetParent(_hwnd); 01322 ShellPath shell_path = entry->create_absolute_pidl(); 01323 01324 // close start menus when launching the selected entry 01325 CloseStartMenu(id); 01326 01327 ///@todo launch in the background; specify correct HWND for error message box titles 01328 SHELLEXECUTEINFO shexinfo; 01329 01330 shexinfo.cbSize = sizeof(SHELLEXECUTEINFO); 01331 shexinfo.fMask = SEE_MASK_IDLIST; // SEE_MASK_INVOKEIDLIST is also possible. 01332 shexinfo.hwnd = hparent; 01333 shexinfo.lpVerb = NULL; 01334 shexinfo.lpFile = NULL; 01335 shexinfo.lpParameters = NULL; 01336 shexinfo.lpDirectory = NULL; 01337 shexinfo.nShow = SW_SHOWNORMAL; 01338 01339 shexinfo.lpIDList = &*shell_path; 01340 01341 // add PIDL to the recent file list 01342 SHAddToRecentDocs(SHARD_PIDL, shexinfo.lpIDList); 01343 01344 if (!ShellExecuteEx(&shexinfo)) 01345 display_error(hparent, GetLastError()); 01346 01347 // we may have deleted 'this' - ensure we leave the loop and function 01348 return; 01349 } 01350 } 01351 01352 if (!new_folders.empty()) { 01353 // Only open one submenu at a time. 01354 if (!CloseOtherSubmenus(id)) 01355 return; 01356 01357 CreateSubmenu(id, new_folders, title); 01358 } 01359 } 01360 01361 01362 /// close all windows of the start menu popup 01363 void StartMenu::CloseStartMenu(int id) 01364 { 01365 if (!(GetWindowStyle(_hwnd) & WS_CAPTION)) { // don't automatically close floating menus 01366 if (!SendParent(PM_STARTENTRY_LAUNCHED, id, (LPARAM)_hwnd)) 01367 DestroyWindow(_hwnd); 01368 } else if (_submenu) // instead close submenus of floating parent menus 01369 CloseSubmenus(); 01370 } 01371 01372 01373 int GetStartMenuBtnTextWidth(HDC hdc, LPCTSTR title, HWND hwnd) 01374 { 01375 RECT rect = {0, 0, 0, 0}; 01376 DrawText(hdc, title, -1, &rect, DT_SINGLELINE|DT_NOPREFIX|DT_CALCRECT); 01377 01378 return rect.right-rect.left; 01379 } 01380 01381 #ifdef _LIGHT_STARTMENU 01382 void DrawStartMenuButton(HDC hdc, const RECT& rect, LPCTSTR title, const SMBtnInfo& btn, bool has_focus, bool pushed, int icon_size) 01383 #else 01384 void DrawStartMenuButton(HDC hdc, const RECT& rect, LPCTSTR title, HICON hIcon, 01385 bool hasSubmenu, bool enabled, bool has_focus, bool pushed, int icon_size); 01386 #endif 01387 { 01388 UINT style = DFCS_BUTTONPUSH; 01389 01390 if (!btn._enabled) 01391 style |= DFCS_INACTIVE; 01392 01393 POINT iconPos = {rect.left+2, (rect.top+rect.bottom-icon_size)/2}; 01394 RECT textRect = {rect.left+icon_size+4, rect.top+2, rect.right-4, rect.bottom-4}; 01395 01396 if (pushed) { 01397 style |= DFCS_PUSHED; 01398 ++iconPos.x; ++iconPos.y; 01399 ++textRect.left; ++textRect.top; 01400 ++textRect.right; ++textRect.bottom; 01401 } 01402 01403 int bk_color_idx = COLOR_BTNFACE; 01404 int text_color_idx = COLOR_BTNTEXT; 01405 01406 if (has_focus) { 01407 bk_color_idx = COLOR_HIGHLIGHT; 01408 text_color_idx = COLOR_HIGHLIGHTTEXT; 01409 } 01410 01411 COLORREF bk_color = GetSysColor(bk_color_idx); 01412 HBRUSH bk_brush = GetSysColorBrush(bk_color_idx); 01413 01414 if (title) 01415 FillRect(hdc, &rect, bk_brush); 01416 01417 if (btn._icon_id > ICID_NONE) 01418 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*/); 01419 01420 // draw submenu arrow at the right 01421 if (btn._hasSubmenu) { 01422 ResIconEx arrowIcon(IDI_ARROW, icon_size, icon_size); 01423 ResIconEx selArrowIcon(IDI_ARROW_SELECTED, icon_size, icon_size); 01424 01425 DrawIconEx(hdc, rect.right-icon_size, iconPos.y, 01426 has_focus? selArrowIcon: arrowIcon, 01427 icon_size, icon_size, 0, bk_brush, DI_NORMAL); 01428 } 01429 01430 if (title) { 01431 BkMode bk_mode(hdc, TRANSPARENT); 01432 01433 if (!btn._enabled) // dis->itemState & (ODS_DISABLED|ODS_GRAYED) 01434 DrawGrayText(hdc, &textRect, title, DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER); 01435 else { 01436 TextColor lcColor(hdc, GetSysColor(text_color_idx)); 01437 DrawText(hdc, title, -1, &textRect, DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER); 01438 } 01439 } 01440 } 01441 01442 01443 #ifdef _LIGHT_STARTMENU 01444 01445 void StartMenu::ResizeToButtons() 01446 { 01447 WindowRect rect(_hwnd); 01448 01449 WindowCanvas canvas(_hwnd); 01450 FontSelection font(canvas, GetStockFont(DEFAULT_GUI_FONT)); 01451 01452 const int icon_size = _icon_size; 01453 01454 int max_width = STARTMENU_WIDTH_MIN; 01455 int height = 0; 01456 01457 for(SMBtnVector::const_iterator it=_buttons.begin(); it!=_buttons.end(); ++it) { 01458 int w = GetStartMenuBtnTextWidth(canvas, it->_title, _hwnd); 01459 01460 if (w > max_width) 01461 max_width = w; 01462 01463 if (it->_id == -1) 01464 height += STARTMENU_SEP_HEIGHT(icon_size); 01465 else 01466 height += STARTMENU_LINE_HEIGHT(icon_size); 01467 } 01468 01469 // calculate new window size 01470 int text_width = max_width + icon_size + 10/*placeholder*/ + 16/*arrow*/; 01471 01472 RECT rt_hgt = {rect.left, rect.bottom-_border_top-height, rect.left+_border_left+text_width, rect.bottom}; 01473 AdjustWindowRectEx(&rt_hgt, GetWindowStyle(_hwnd), FALSE, GetWindowExStyle(_hwnd)); 01474 01475 // ignore movement, only look at the size change 01476 rect.right = rect.left + (rt_hgt.right-rt_hgt.left); 01477 rect.top = rect.bottom - (rt_hgt.bottom-rt_hgt.top); 01478 01479 // move down if we are too high 01480 if (rect.top < 0) { 01481 int dy = -rect.top; 01482 rect.top += dy; 01483 rect.bottom += dy; 01484 } 01485 01486 // enable scroll mode for long start menus, which span more than the whole screen height 01487 int cyscreen = GetSystemMetrics(SM_CYSCREEN); 01488 int bottom_max = 0; 01489 01490 if (rect.bottom > cyscreen) { 01491 _arrow_btns = true; 01492 01493 _invisible_lines = (rect.bottom-cyscreen+(STARTMENU_LINE_HEIGHT(icon_size)+1))/STARTMENU_LINE_HEIGHT(icon_size)+1; 01494 rect.bottom -= _invisible_lines * STARTMENU_LINE_HEIGHT(icon_size); 01495 01496 bottom_max = rect.bottom; 01497 01498 if (_floating_btn) 01499 rect.bottom += 6; // lower scroll arrow 01500 else { 01501 _border_top += 6; // upper scroll arrow 01502 rect.bottom += 2*6; // upper+lower scroll arrow 01503 } 01504 } 01505 01506 MoveWindow(_hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE); 01507 01508 if (bottom_max) { 01509 POINT pt = {0, bottom_max}; 01510 01511 ScreenToClient(_hwnd, &pt); 01512 01513 _bottom_max = pt.y; 01514 } 01515 } 01516 01517 #else // _LIGHT_STARTMENU 01518 01519 LRESULT StartMenuButton::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) 01520 { 01521 switch(nmsg) { 01522 case WM_MOUSEMOVE: 01523 // automatically set the focus to startmenu entries when moving the mouse over them 01524 if (GetFocus()!=_hwnd && !(GetWindowStyle(_hwnd)&WS_DISABLED)) 01525 SetFocus(_hwnd); 01526 break; 01527 01528 case WM_SETFOCUS: 01529 PostParent(PM_STARTENTRY_FOCUSED, _hasSubmenu, (LPARAM)_hwnd); 01530 goto def; 01531 01532 case WM_CANCELMODE: 01533 // route WM_CANCELMODE to the startmenu window 01534 return SendParent(nmsg, wparam, lparam); 01535 01536 default: def: 01537 return super::WndProc(nmsg, wparam, lparam); 01538 } 01539 01540 return 0; 01541 } 01542 01543 void StartMenuButton::DrawItem(LPDRAWITEMSTRUCT dis) 01544 { 01545 TCHAR title[BUFFER_LEN]; 01546 01547 GetWindowText(_hwnd, title, BUFFER_LEN); 01548 01549 DrawStartMenuButton(dis->hDC, dis->rcItem, title, _hIcon, 01550 _hasSubmenu, 01551 !(dis->itemState & ODS_DISABLED), 01552 dis->itemState&ODS_FOCUS? true: false, 01553 dis->itemState&ODS_SELECTED? true: false); 01554 } 01555 01556 #endif 01557 01558 01559 StartMenuRoot::StartMenuRoot(HWND hwnd, const StartMenuRootCreateInfo& info) 01560 : super(hwnd, info._icon_size), 01561 _hwndStartButton(0) 01562 { 01563 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003) 01564 if (!g_Globals._SHRestricted || !SHRestricted(REST_NOCOMMONGROUPS)) 01565 #endif 01566 try { 01567 // insert directory "All Users\Start Menu" 01568 ShellDirectory cmn_startmenu(GetDesktopFolder(), SpecialFolderPath(CSIDL_COMMON_STARTMENU, _hwnd), _hwnd); 01569 _dirs.push_back(StartMenuDirectory(cmn_startmenu, (LPCTSTR)SpecialFolderFSPath(CSIDL_COMMON_PROGRAMS, _hwnd))); 01570 } catch(COMException&) { 01571 // ignore exception and don't show additional shortcuts 01572 } 01573 01574 try { 01575 // insert directory "<user name>\Start Menu" 01576 ShellDirectory usr_startmenu(GetDesktopFolder(), SpecialFolderPath(CSIDL_STARTMENU, _hwnd), _hwnd); 01577 _dirs.push_back(StartMenuDirectory(usr_startmenu, (LPCTSTR)SpecialFolderFSPath(CSIDL_PROGRAMS, _hwnd))); 01578 } catch(COMException&) { 01579 // ignore exception and don't show additional shortcuts 01580 } 01581 01582 ReadLogoSize(); 01583 } 01584 01585 void StartMenuRoot::ReadLogoSize() 01586 { 01587 // read size of logo bitmap 01588 BITMAP bmp_hdr; 01589 GetObject(ResBitmap(GetLogoResId()), sizeof(BITMAP), &bmp_hdr); 01590 _logo_size.cx = bmp_hdr.bmWidth; 01591 _logo_size.cy = bmp_hdr.bmHeight; 01592 01593 // cache logo width 01594 _border_left = _logo_size.cx + 1; 01595 } 01596 01597 01598 static void CalculateStartPos(HWND hwndOwner, RECT& rect, int icon_size) 01599 { 01600 WindowRect pos(hwndOwner); 01601 01602 rect.left = pos.left; 01603 rect.top = pos.top-STARTMENU_LINE_HEIGHT(icon_size)-4; 01604 rect.right = pos.left+STARTMENU_WIDTH_MIN; 01605 rect.bottom = pos.top; 01606 01607 #ifndef _LIGHT_STARTMENU 01608 rect.top += STARTMENU_LINE_HEIGHT(icon_size); 01609 #endif 01610 01611 AdjustWindowRectEx(&rect, WS_POPUP|WS_THICKFRAME|WS_CLIPCHILDREN|WS_VISIBLE, FALSE, 0); 01612 } 01613 01614 HWND StartMenuRoot::Create(HWND hwndOwner, int icon_size) 01615 { 01616 RECT rect; 01617 01618 CalculateStartPos(hwndOwner, rect, icon_size); 01619 01620 StartMenuRootCreateInfo create_info; 01621 01622 create_info._icon_size = icon_size; 01623 01624 return Window::Create(WINDOW_CREATOR_INFO(StartMenuRoot,StartMenuRootCreateInfo), &create_info, 0, GetWndClasss(), TITLE_STARTMENU, 01625 WS_POPUP|WS_THICKFRAME|WS_CLIPCHILDREN, 01626 rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, hwndOwner); 01627 } 01628 01629 01630 void StartMenuRoot::TrackStartmenu() 01631 { 01632 MSG msg; 01633 HWND hwnd = _hwnd; 01634 01635 #ifdef _LIGHT_STARTMENU 01636 _selected_id = -1; 01637 #endif 01638 01639 #ifdef _LIGHT_STARTMENU 01640 // recalculate start menu root position 01641 RECT rect; 01642 01643 CalculateStartPos(_hwndStartButton, rect, _icon_size); 01644 01645 SetWindowPos(hwnd, 0, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, 0); 01646 01647 ResizeToButtons(); 01648 #endif 01649 01650 // show previously hidden start menu 01651 ShowWindow(hwnd, SW_SHOW); 01652 SetForegroundWindow(hwnd); 01653 01654 while(IsWindow(hwnd) && IsWindowVisible(hwnd)) { 01655 if (!GetMessage(&msg, 0, 0, 0)) { 01656 PostQuitMessage(msg.wParam); 01657 break; 01658 } 01659 01660 // Check for a mouse click on any window, that is not part of the start menu 01661 if (msg.message==WM_LBUTTONDOWN || msg.message==WM_MBUTTONDOWN || msg.message==WM_RBUTTONDOWN) { 01662 StartMenu* menu_wnd = NULL; 01663 01664 for(HWND hwnd=msg.hwnd; hwnd; hwnd=GetParent(hwnd)) { 01665 menu_wnd = WINDOW_DYNAMIC_CAST(StartMenu, hwnd); 01666 01667 if (menu_wnd) 01668 break; 01669 } 01670 01671 if (!menu_wnd) { 01672 CloseStartMenu(); 01673 break; 01674 } 01675 } 01676 01677 try { 01678 if (pretranslate_msg(&msg)) 01679 continue; 01680 01681 if (dispatch_dialog_msg(&msg)) 01682 continue; 01683 01684 TranslateMessage(&msg); 01685 01686 try { 01687 DispatchMessage(&msg); 01688 } catch(COMException& e) { 01689 HandleException(e, _hwnd); 01690 } 01691 } catch(COMException& e) { 01692 HandleException(e, _hwnd); 01693 } 01694 } 01695 } 01696 01697 01698 LRESULT StartMenuRoot::Init(LPCREATESTRUCT pcs) 01699 { 01700 // add buttons for entries in _entries 01701 if (super::Init(pcs)) 01702 return 1; 01703 01704 AddSeparator(); 01705 01706 01707 #ifdef __MINGW32__ 01708 HKEY hkey, hkeyAdv; 01709 DWORD value, len; 01710 01711 if (RegOpenKey(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer"), &hkey)) 01712 hkey = 0; 01713 01714 if (RegOpenKey(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"), &hkeyAdv)) 01715 hkeyAdv = 0; 01716 01717 #define IS_VALUE_ZERO(hk, name) \ 01718 (!hk || (len=sizeof(value),RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE)&value, &len) || !value)) 01719 01720 #define IS_VALUE_NOT_ZERO(hk, name) \ 01721 (!hk || (len=sizeof(value),RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE)&value, &len) || value>0)) 01722 #endif 01723 01724 01725 // insert hard coded start entries 01726 AddButton(ResString(IDS_PROGRAMS), ICID_APPS, true, IDC_PROGRAMS); 01727 01728 AddButton(ResString(IDS_DOCUMENTS), ICID_DOCUMENTS, true, IDC_DOCUMENTS); 01729 01730 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003) 01731 if (!g_Globals._SHRestricted || !SHRestricted(REST_NORECENTDOCSMENU)) 01732 #else 01733 if (IS_VALUE_ZERO(hkey, _T("NoRecentDocsMenu"))) 01734 #endif 01735 AddButton(ResString(IDS_RECENT), ICID_RECENT, true, IDC_RECENT); 01736 01737 AddButton(ResString(IDS_FAVORITES), ICID_FAVORITES, true, IDC_FAVORITES); 01738 01739 AddButton(ResString(IDS_SETTINGS), ICID_CONFIG, true, IDC_SETTINGS); 01740 01741 AddButton(ResString(IDS_BROWSE), ICID_FOLDER, true, IDC_BROWSE); 01742 01743 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003) 01744 if (!g_Globals._SHRestricted || !SHRestricted(REST_NOFIND)) 01745 #else 01746 if (IS_VALUE_ZERO(hkey, _T("NoFind"))) 01747 #endif 01748 AddButton(ResString(IDS_SEARCH), ICID_SEARCH, true, IDC_SEARCH); 01749 01750 AddButton(ResString(IDS_START_HELP), ICID_INFO, false, IDC_START_HELP); 01751 01752 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003) 01753 if (!g_Globals._SHRestricted || !SHRestricted(REST_NORUN)) 01754 #else 01755 if (IS_VALUE_ZERO(hkey, _T("NoRun"))) 01756 #endif 01757 AddButton(ResString(IDS_LAUNCH), ICID_ACTION, false, IDC_LAUNCH); 01758 01759 01760 AddSeparator(); 01761 01762 01763 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003) 01764 if (!g_Globals._SHRestricted || SHRestricted(REST_STARTMENULOGOFF) != 1) 01765 #else 01766 if (IS_VALUE_NOT_ZERO(hkeyAdv, _T("StartMenuLogoff"))) 01767 #endif 01768 AddButton(ResString(IDS_LOGOFF), ICID_LOGOFF, false, IDC_LOGOFF); 01769 01770 #ifdef __REACTOS__ 01771 AddButton(ResString(IDS_RESTART), ICID_RESTART, false, IDC_RESTART); 01772 #endif 01773 01774 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003) 01775 if (!g_Globals._SHRestricted || !SHRestricted(REST_NOCLOSE)) 01776 #else 01777 if (IS_VALUE_ZERO(hkey, _T("NoClose"))) 01778 #endif 01779 AddButton(ResString(IDS_SHUTDOWN), ICID_SHUTDOWN, false, IDC_SHUTDOWN); 01780 01781 #ifndef __REACTOS__ 01782 AddButton(ResString(IDS_TERMINATE), ICID_LOGOFF, false, IDC_TERMINATE); 01783 #endif 01784 01785 01786 #ifdef __MINGW32__ 01787 RegCloseKey(hkeyAdv); 01788 RegCloseKey(hkey); 01789 #endif 01790 01791 01792 #ifdef _LIGHT_STARTMENU 01793 // set the window size to fit all buttons 01794 ResizeToButtons(); 01795 #endif 01796 01797 return 0; 01798 } 01799 01800 01801 void StartMenuRoot::AddEntries() 01802 { 01803 super::AddEntries(); 01804 01805 AddButton(ResString(IDS_EXPLORE), ICID_EXPLORER, false, IDC_EXPLORE); 01806 } 01807 01808 01809 LRESULT StartMenuRoot::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) 01810 { 01811 switch(nmsg) { 01812 case WM_PAINT: { 01813 PaintCanvas canvas(_hwnd); 01814 Paint(canvas); 01815 break;} 01816 01817 case WM_DISPLAYCHANGE: 01818 // re-evaluate logo size using the correct color depth 01819 ReadLogoSize(); 01820 break; 01821 01822 default: 01823 return super::WndProc(nmsg, wparam, lparam); 01824 } 01825 01826 return 0; 01827 } 01828 01829 void StartMenuRoot::Paint(PaintCanvas& canvas) 01830 { 01831 MemCanvas mem_dc; 01832 ResBitmap bmp(GetLogoResId()); 01833 BitmapSelection sel(mem_dc, bmp); 01834 01835 ClientRect clnt(_hwnd); 01836 int h = min(_logo_size.cy, clnt.bottom); 01837 01838 RECT rect = {0, 0, _logo_size.cx, clnt.bottom-h}; 01839 HBRUSH hbr = CreateSolidBrush(GetPixel(mem_dc, 0, 0)); 01840 FillRect(canvas, &rect, hbr); 01841 DeleteObject(hbr); 01842 01843 PatBlt(canvas, _logo_size.cx, 0, 1, clnt.bottom, WHITENESS); 01844 01845 BitBlt(canvas, 0, clnt.bottom-h, _logo_size.cx, h, mem_dc, 0, ( h<_logo_size.cy ? _logo_size.cy-h : 0) , SRCCOPY); 01846 01847 super::Paint(canvas); 01848 } 01849 01850 UINT StartMenuRoot::GetLogoResId() 01851 { 01852 WindowCanvas dc(_hwnd); 01853 01854 int clr_bits = GetDeviceCaps(dc, BITSPIXEL); 01855 01856 if (clr_bits > 8) 01857 return IDB_LOGOV; 01858 else if (clr_bits > 4) 01859 return IDB_LOGOV256; 01860 else 01861 return IDB_LOGOV16; 01862 } 01863 01864 01865 void StartMenuRoot::CloseStartMenu(int id) 01866 { 01867 if (_submenu) 01868 CloseSubmenus(); 01869 01870 ShowWindow(_hwnd, SW_HIDE); 01871 } 01872 01873 void StartMenuRoot::ProcessKey(int vk) 01874 { 01875 switch(vk) { 01876 case VK_LEFT: 01877 if (_submenu) 01878 CloseOtherSubmenus(); 01879 // don't close start menu root 01880 break; 01881 01882 default: 01883 super::ProcessKey(vk); 01884 } 01885 } 01886 01887 01888 int StartMenuHandler::Command(int id, int code) 01889 { 01890 switch(id) { 01891 01892 // start menu root 01893 01894 case IDC_PROGRAMS: 01895 CreateSubmenu(id, CSIDL_COMMON_PROGRAMS, CSIDL_PROGRAMS, ResString(IDS_PROGRAMS)); 01896 break; 01897 01898 case IDC_EXPLORE: 01899 CloseStartMenu(id); 01900 explorer_show_frame(SW_SHOWNORMAL); 01901 break; 01902 01903 case IDC_LAUNCH: 01904 CloseStartMenu(id); 01905 ShowLaunchDialog(g_Globals._hwndDesktopBar); 01906 break; 01907 01908 case IDC_DOCUMENTS: 01909 CreateSubmenu(id, CSIDL_PERSONAL, ResString(IDS_DOCUMENTS)); 01910 break; 01911 01912 case IDC_RECENT: 01913 CreateSubmenu(id, CSIDL_RECENT, ResString(IDS_RECENT), STARTMENU_CREATOR(RecentStartMenu)); 01914 break; 01915 01916 case IDC_FAVORITES: 01917 #ifndef _SHELL32_FAVORITES 01918 CreateSubmenu(id, ResString(IDS_FAVORITES), STARTMENU_CREATOR(FavoritesMenu), &static_cast<BookmarkList&>(g_Globals._favorites)); 01919 #else 01920 CreateSubmenu(id, CSIDL_COMMON_FAVORITES, CSIDL_FAVORITES, ResString(IDS_FAVORITES)); 01921 #endif 01922 break; 01923 01924 case IDC_BROWSE: 01925 CreateSubmenu(id, ResString(IDS_BROWSE), STARTMENU_CREATOR(BrowseMenu)); 01926 break; 01927 01928 case IDC_SETTINGS: 01929 CreateSubmenu(id, ResString(IDS_SETTINGS), STARTMENU_CREATOR(SettingsMenu)); 01930 break; 01931 01932 case IDC_SEARCH: 01933 CreateSubmenu(id, ResString(IDS_SEARCH), STARTMENU_CREATOR(SearchMenu)); 01934 break; 01935 01936 case IDC_START_HELP: 01937 CloseStartMenu(id); 01938 MessageBox(g_Globals._hwndDesktopBar, TEXT("Help not yet implemented"), ResString(IDS_TITLE), MB_OK); 01939 break; 01940 01941 case IDC_LOGOFF: 01942 CloseStartMenu(id); 01943 ShowLogoffDialog(g_Globals._hwndDesktopBar); 01944 break; 01945 01946 #ifndef __REACTOS__ 01947 case IDC_TERMINATE: 01948 DestroyWindow(GetParent(_hwnd)); 01949 break; 01950 #endif 01951 01952 case IDC_SHUTDOWN: 01953 CloseStartMenu(id); 01954 ShowExitWindowsDialog(g_Globals._hwndDesktop); 01955 break; 01956 01957 case IDC_RESTART: 01958 CloseStartMenu(id); 01959 ShowRestartDialog(g_Globals._hwndDesktop, EWX_REBOOT); 01960 /* An alternative way to do restart without shell32 help */ 01961 //launch_file(_hwnd, TEXT("shutdown.exe"), SW_HIDE, TEXT("-r")); 01962 break; 01963 01964 // settings menu 01965 01966 case ID_DESKTOPBAR_SETTINGS: 01967 CloseStartMenu(id); 01968 ExplorerPropertySheet(g_Globals._hwndDesktopBar); 01969 break; 01970 01971 case IDC_CONTROL_PANEL: { 01972 CloseStartMenu(id); 01973 #ifndef ROSSHELL 01974 #ifndef _NO_MDI 01975 XMLPos explorer_options = g_Globals.get_cfg("general/explorer"); 01976 bool mdi = XMLBool(explorer_options, "mdi", true); 01977 01978 if (mdi) 01979 MDIMainFrame::Create(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}"), 0); 01980 else 01981 #endif 01982 SDIMainFrame::Create(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}"), 0); 01983 #else 01984 launch_file(_hwnd, SHELLPATH_CONTROL_PANEL); 01985 #endif 01986 break;} 01987 01988 case IDC_SETTINGS_MENU: 01989 CreateSubmenu(id, CSIDL_CONTROLS, ResString(IDS_SETTINGS_MENU)); 01990 break; 01991 01992 case IDC_PRINTERS: { 01993 CloseStartMenu(id); 01994 01995 #ifndef ROSSHELL 01996 #ifndef _NO_MDI 01997 XMLPos explorer_options = g_Globals.get_cfg("general/explorer"); 01998 bool mdi = XMLBool(explorer_options, "mdi", true); 01999 02000 if (mdi) 02001 MDIMainFrame::Create(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}"), 0); 02002 else 02003 #endif 02004 SDIMainFrame::Create(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}"), 0); 02005 #else 02006 launch_file(_hwnd, SHELLPATH_PRINTERS); 02007 #endif 02008 break;} 02009 02010 #if 0 ///@todo use printer start menu folder per default and allow opening "printers" cabinet window using the context menu 02011 case IDC_PRINTERS_MENU: 02012 CreateSubmenu(id, CSIDL_PRINTERS, CSIDL_PRINTHOOD, ResString(IDS_PRINTERS)); 02013 /* StartMenuFolders new_folders; 02014 02015 try { 02016 new_folders.push_back(ShellPath(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}"))); 02017 } catch(COMException&) { 02018 } 02019 02020 CreateSubmenu(id, new_folders, ResString(IDS_PRINTERS));*/ 02021 break; 02022 #endif 02023 02024 case IDC_ADMIN: 02025 #ifndef ROSSHELL 02026 CreateSubmenu(id, CSIDL_COMMON_ADMINTOOLS, CSIDL_ADMINTOOLS, ResString(IDS_ADMIN)); 02027 //CloseStartMenu(id); 02028 //MainFrame::Create(SpecialFolderPath(CSIDL_COMMON_ADMINTOOLS, _hwnd), OWM_PIDL); 02029 #else 02030 launch_file(_hwnd, SpecialFolderFSPath(CSIDL_COMMON_ADMINTOOLS, _hwnd)); 02031 #endif 02032 break; 02033 02034 case IDC_CONNECTIONS: 02035 #ifndef ROSSHELL 02036 #ifdef __REACTOS__ // to be removed when RAS will be implemented 02037 MessageBox(0, TEXT("RAS folder not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK); 02038 #else 02039 CreateSubmenu(id, CSIDL_CONNECTIONS, ResString(IDS_CONNECTIONS)); 02040 //CloseStartMenu(id); 02041 //MainFrame::Create(SpecialFolderPath(CSIDL_CONNECTIONS, _hwnd), OWM_PIDL); 02042 #endif 02043 #else 02044 launch_file(_hwnd, SHELLPATH_NET_CONNECTIONS); 02045 #endif 02046 break; 02047 02048 02049 // browse menu 02050 02051 case IDC_NETWORK: 02052 #ifdef __REACTOS__ ///@todo to be removed when network browsing will be implemented in shell namespace 02053 MessageBox(0, TEXT("network not yet implemented"), ResString(IDS_TITLE), MB_OK); 02054 #else 02055 CreateSubmenu(id, CSIDL_NETWORK, ResString(IDS_NETWORK)); 02056 #endif 02057 break; 02058 02059 case IDC_DRIVES: 02060 ///@todo exclude removable drives 02061 CreateSubmenu(id, CSIDL_DRIVES, ResString(IDS_DRIVES)); 02062 break; 02063 02064 02065 // search menu 02066 02067 case IDC_SEARCH_PROGRAM: 02068 CloseStartMenu(id); 02069 Dialog::DoModal(IDD_SEARCH_PROGRAM, WINDOW_CREATOR(FindProgramDlg)); 02070 break; 02071 02072 case IDC_SEARCH_FILES: 02073 CloseStartMenu(id); 02074 ShowSearchDialog(); 02075 break; 02076 02077 case IDC_SEARCH_COMPUTER: 02078 CloseStartMenu(id); 02079 ShowSearchComputer(); 02080 break; 02081 02082 02083 default: 02084 return super::Command(id, code); 02085 } 02086 02087 return 0; 02088 } 02089 02090 02091 void StartMenuHandler::ShowSearchDialog() 02092 { 02093 #ifndef __REACTOS__ ///@todo to be removed when SHFindFiles() will be implemented in shell32.dll 02094 static DynamicFct<SHFINDFILES> SHFindFiles(TEXT("SHELL32"), 90); 02095 02096 if (SHFindFiles) 02097 (*SHFindFiles)(NULL, NULL); 02098 else 02099 #endif 02100 MessageBox(0, TEXT("SHFindFiles() not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK); 02101 } 02102 02103 void StartMenuHandler::ShowSearchComputer() 02104 { 02105 #ifndef __REACTOS__ ///@todo to be removed when SHFindComputer() will be implemented in shell32.dll 02106 static DynamicFct<SHFINDCOMPUTER> SHFindComputer(TEXT("SHELL32"), 91); 02107 02108 if (SHFindComputer) 02109 (*SHFindComputer)(NULL, NULL); 02110 else 02111 #endif 02112 MessageBox(0, TEXT("SHFindComputer() not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK); 02113 } 02114 02115 void StartMenuHandler::ShowLaunchDialog(HWND hwndOwner) 02116 { 02117 static DynamicFct<RUNFILEDLG> RunFileDlg(TEXT("SHELL32"), 61); 02118 02119 // Show "Run..." dialog 02120 if (RunFileDlg) { 02121 (*RunFileDlg)(hwndOwner, 0, NULL, NULL, NULL, RFF_CALCDIRECTORY); 02122 } 02123 } 02124 02125 void StartMenuHandler::ShowLogoffDialog(HWND hwndOwner) 02126 { 02127 static DynamicFct<LOGOFFWINDOWSDIALOG> LogoffWindowsDialog(TEXT("SHELL32"), 54); 02128 // static DynamicFct<RESTARTWINDOWSDLG> RestartDialog(TEXT("SHELL32"), 59); 02129 02130 if (LogoffWindowsDialog) 02131 (*LogoffWindowsDialog)(0); 02132 /* The RestartDialog function prompts about some system setting change. This is not what we want to display here. 02133 else if (RestartDialog) 02134 return (*RestartDialog)(hwndOwner, (LPWSTR)L"You selected <Log Off>.\n\n", EWX_LOGOFF) == 1; ///@todo ANSI string conversion if needed 02135 */ 02136 else 02137 MessageBox(hwndOwner, TEXT("LogoffWindowsDialog() not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK); 02138 } 02139 02140 void ShowExitWindowsDialog(HWND hwndOwner) 02141 { 02142 static DynamicFct<EXITWINDOWSDLG> ExitWindowsDialog(TEXT("SHELL32"), 60); 02143 02144 if (ExitWindowsDialog) 02145 (*ExitWindowsDialog)(hwndOwner); 02146 else 02147 MessageBox(hwndOwner, TEXT("ExitWindowsDialog() not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK); 02148 } 02149 02150 void StartMenuHandler::ShowRestartDialog(HWND hwndOwner, UINT flags) 02151 { 02152 static DynamicFct<RESTARTWINDOWSDLG> RestartDlg(TEXT("SHELL32"), 59); 02153 02154 if (RestartDlg) 02155 (*RestartDlg)(hwndOwner, (LPWSTR)L"You selected restart.\n\n", flags); 02156 else 02157 MessageBox(hwndOwner, TEXT("RestartDlg() not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK); 02158 } 02159 02160 void SettingsMenu::AddEntries() 02161 { 02162 super::AddEntries(); 02163 02164 #if defined(ROSSHELL) || defined(__REACTOS__) // __REACTOS__ to be removed when printer/network will be implemented 02165 //TODO AddButton(ResString(IDS_PRINTERS), ICID_PRINTER, false, IDC_PRINTERS_MENU); 02166 AddButton(ResString(IDS_CONNECTIONS), ICID_NETWORK, false, IDC_CONNECTIONS); 02167 #else 02168 //TODO AddButton(ResString(IDS_PRINTERS), ICID_PRINTER, true, IDC_PRINTERS_MENU); 02169 AddButton(ResString(IDS_CONNECTIONS), ICID_NETCONNS, false, IDC_CONNECTIONS); 02170 #endif 02171 AddButton(ResString(IDS_ADMIN), ICID_ADMIN, true, IDC_ADMIN); 02172 02173 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003) 02174 if (!g_Globals._SHRestricted || !SHRestricted(REST_NOCONTROLPANEL)) 02175 #endif 02176 AddButton(ResString(IDS_SETTINGS_MENU), ICID_CONFIG, true, IDC_SETTINGS_MENU); 02177 02178 AddButton(ResString(IDS_DESKTOPBAR_SETTINGS), ICID_DESKSETTING, false, ID_DESKTOPBAR_SETTINGS); 02179 02180 AddButton(ResString(IDS_PRINTERS), ICID_PRINTER, false, IDC_PRINTERS); 02181 02182 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003) 02183 if (!g_Globals._SHRestricted || !SHRestricted(REST_NOCONTROLPANEL)) 02184 #endif 02185 AddButton(ResString(IDS_CONTROL_PANEL), ICID_CONTROLPAN, false, IDC_CONTROL_PANEL); 02186 } 02187 02188 void BrowseMenu::AddEntries() 02189 { 02190 super::AddEntries(); 02191 02192 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003) 02193 if (!g_Globals._SHRestricted || !SHRestricted(REST_NONETHOOD)) // or REST_NOENTIRENETWORK ? 02194 #endif 02195 #if defined(ROSSHELL) || defined(__REACTOS__) // __REACTOS__ to be removed when printer/network will be implemented 02196 AddButton(ResString(IDS_NETWORK), ICID_NETWORK, false, IDC_NETWORK); 02197 #else 02198 AddButton(ResString(IDS_NETWORK), ICID_NETWORK, true, IDC_NETWORK); 02199 #endif 02200 02201 AddButton(ResString(IDS_DRIVES), ICID_FOLDER, true, IDC_DRIVES); 02202 } 02203 02204 void SearchMenu::AddEntries() 02205 { 02206 super::AddEntries(); 02207 02208 AddButton(ResString(IDS_SEARCH_FILES), ICID_SEARCH_DOC, false, IDC_SEARCH_FILES); 02209 02210 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003) 02211 if (!g_Globals._SHRestricted || !SHRestricted(REST_HASFINDCOMPUTERS)) 02212 #endif 02213 AddButton(ResString(IDS_SEARCH_COMPUTER),ICID_COMPUTER, false, IDC_SEARCH_COMPUTER); 02214 02215 AddButton(ResString(IDS_SEARCH_PRG), ICID_APPS, false, IDC_SEARCH_PROGRAM); 02216 } 02217 02218 02219 void RecentStartMenu::AddEntries() 02220 { 02221 for(StartMenuShellDirs::iterator it=_dirs.begin(); it!=_dirs.end(); ++it) { 02222 StartMenuDirectory& smd = *it; 02223 ShellDirectory& dir = smd._dir; 02224 02225 if (!dir._scanned) { 02226 WaitCursor wait; 02227 02228 #ifdef _LAZY_ICONEXTRACT 02229 dir.smart_scan(SORT_NAME, SCAN_DONT_EXTRACT_ICONS); 02230 #else 02231 dir.smart_scan(SORT_NAME); 02232 #endif 02233 } 02234 02235 dir.sort_directory(SORT_DATE); 02236 AddShellEntries(dir, RECENT_DOCS_COUNT, smd._ignore); ///@todo read max. count of entries from registry 02237 } 02238 } 02239 02240 02241 #ifndef _SHELL32_FAVORITES 02242 02243 void FavoritesMenu::AddEntries() 02244 { 02245 super::AddEntries(); 02246 02247 String lwr_filter = _create_info._filter; 02248 lwr_filter.toLower(); 02249 02250 for(BookmarkList::iterator it=_bookmarks.begin(); it!=_bookmarks.end(); ++it) { 02251 BookmarkNode& node = *it; 02252 02253 int id = ++_next_id; 02254 02255 _entries[id] = node; 02256 02257 if (node._type == BookmarkNode::BMNT_FOLDER) { 02258 BookmarkFolder& folder = *node._pfolder; 02259 02260 AddButton(folder._name, ICID_FOLDER, true, id); 02261 } else if (node._type == BookmarkNode::BMNT_BOOKMARK) { 02262 Bookmark& bookmark = *node._pbookmark; 02263 02264 ICON_ID icon = ICID_NONE; 02265 02266 if (!bookmark._icon_path.empty()) 02267 icon = g_Globals._icon_cache.extract(bookmark._icon_path, bookmark._icon_idx); 02268 02269 // filter non-directory entries 02270 if (!lwr_filter.empty()) { 02271 String lwr_name = bookmark._name; 02272 String lwr_desc = bookmark._description; 02273 String lwr_url = bookmark._url; 02274 02275 lwr_name.toLower(); 02276 lwr_desc.toLower(); 02277 lwr_url.toLower(); 02278 02279 if (!_tcsstr(lwr_name,lwr_filter) && !_tcsstr(lwr_desc,lwr_filter) && !_tcsstr(lwr_url,lwr_filter)) 02280 continue; 02281 } 02282 02283 AddButton(bookmark._name, icon!=ICID_NONE?icon:ICID_BOOKMARK, false, id); 02284 } 02285 } 02286 } 02287 02288 int FavoritesMenu::Command(int id, int code) 02289 { 02290 BookmarkMap::iterator found = _entries.find(id); 02291 02292 if (found != _entries.end()) { 02293 BookmarkNode& node = found->second; 02294 02295 if (node._type == BookmarkNode::BMNT_FOLDER) { 02296 BookmarkFolder& folder = *node._pfolder; 02297 02298 if (CloseOtherSubmenus(id)) 02299 CreateSubmenu(id, folder._name, STARTMENU_CREATOR(FavoritesMenu), &static_cast<BookmarkList&>(folder._bookmarks)); 02300 } else if (node._type == BookmarkNode::BMNT_BOOKMARK) { 02301 Bookmark& bookmark = *node._pbookmark; 02302 02303 String url = bookmark._url; 02304 HWND hparent = GetParent(_hwnd); 02305 02306 CloseStartMenu(id); 02307 02308 launch_file(hparent, url, SW_SHOWNORMAL); 02309 } 02310 02311 return 0; 02312 } 02313 02314 return super::Command(id, code); 02315 } 02316 02317 #endif
ROS Explorer Source Code Documentation
generated on 02.01.2013 by ![]() |