00001 /* 00002 * Copyright 2003, 2004, 2005 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 // traynotify.cpp 00024 // 00025 // Martin Fuchs, 22.08.2003 00026 // 00027 00028 00029 #include <precomp.h> 00030 00031 #include "../resource.h" 00032 00033 #include "traynotify.h" 00034 00035 00036 #include "../notifyhook/notifyhook.h" 00037 00038 NotifyHook::NotifyHook() 00039 : WM_GETMODULEPATH(InstallNotifyHook()) 00040 { 00041 } 00042 00043 NotifyHook::~NotifyHook() 00044 { 00045 DeinstallNotifyHook(); 00046 } 00047 00048 void NotifyHook::GetModulePath(HWND hwnd, HWND hwndCallback) 00049 { 00050 PostMessage(hwnd, WM_GETMODULEPATH, (WPARAM)hwndCallback, 0); 00051 } 00052 00053 bool NotifyHook::ModulePathCopyData(LPARAM lparam, HWND* phwnd, String& path) 00054 { 00055 char buffer[MAX_PATH]; 00056 00057 int l = GetWindowModulePathCopyData(lparam, phwnd, buffer, COUNTOF(buffer)); 00058 00059 if (l) { 00060 path.assign(buffer, l); 00061 return true; 00062 } else 00063 return false; 00064 } 00065 00066 00067 NotifyIconIndex::NotifyIconIndex(NOTIFYICONDATA* pnid) 00068 { 00069 _hWnd = pnid->hWnd; 00070 _uID = pnid->uID; 00071 00072 // special handling for windows task manager 00073 if ((int)_uID < 0) 00074 _uID = 0; 00075 } 00076 00077 NotifyIconIndex::NotifyIconIndex() 00078 { 00079 _hWnd = 0; 00080 _uID = 0; 00081 } 00082 00083 00084 NotifyInfo::NotifyInfo() 00085 { 00086 _idx = -1; 00087 _hIcon = 0; 00088 _dwState = 0; 00089 _uCallbackMessage = 0; 00090 _version = 0; 00091 00092 _mode = NIM_AUTO; 00093 _lastChange = GetTickCount(); 00094 } 00095 00096 00097 // WCHAR versions von NOTIFYICONDATA 00098 #define NID_SIZE_W6 sizeof(NOTIFYICONDATAW) // _WIN32_IE = 0x600 00099 #define NID_SIZE_W5 (sizeof(NOTIFYICONDATAW)-sizeof(GUID)) // _WIN32_IE = 0x500 00100 #define NID_SIZE_W3 (sizeof(NOTIFYICONDATAW)-sizeof(GUID)-(128-64)*sizeof(WCHAR)) // _WIN32_IE < 0x500 00101 00102 // CHAR versions von NOTIFYICONDATA 00103 #define NID_SIZE_A6 sizeof(NOTIFYICONDATAA) 00104 #define NID_SIZE_A5 (sizeof(NOTIFYICONDATAA)-sizeof(GUID)) 00105 #define NID_SIZE_A3 (sizeof(NOTIFYICONDATAA)-sizeof(GUID)-(128-64)*sizeof(CHAR)) 00106 00107 bool NotifyInfo::modify(NOTIFYICONDATA* pnid) 00108 { 00109 bool changes = false; 00110 00111 if (_hWnd!=pnid->hWnd || _uID!=pnid->uID) { 00112 _hWnd = pnid->hWnd; 00113 _uID = pnid->uID; 00114 00115 changes = true; 00116 } 00117 00118 if (pnid->uFlags & NIF_MESSAGE) { 00119 if (_uCallbackMessage != pnid->uCallbackMessage) { 00120 _uCallbackMessage = pnid->uCallbackMessage; 00121 changes = true; 00122 } 00123 } 00124 00125 if (pnid->uFlags & NIF_ICON) { 00126 // Some applications destroy the icon immediatelly after completing the 00127 // NIM_ADD/MODIFY message, so we have to make a copy of it. 00128 if (_hIcon) 00129 DestroyIcon(_hIcon); 00130 00131 _hIcon = (HICON) CopyImage(pnid->hIcon, IMAGE_ICON, NOTIFYICON_SIZE, NOTIFYICON_SIZE, 0); 00132 00133 changes = true; ///@todo compare icon 00134 } 00135 00136 #ifdef NIF_STATE // as of 21.08.2003 missing in MinGW headers 00137 if (pnid->uFlags & NIF_STATE) { 00138 DWORD new_state = (_dwState&~pnid->dwStateMask) | (pnid->dwState&pnid->dwStateMask); 00139 00140 if (_dwState != new_state) { 00141 _dwState = new_state; 00142 changes = true; 00143 } 00144 } 00145 #endif 00146 00147 // store tool tip text 00148 if (pnid->uFlags & NIF_TIP) { 00149 String new_text; 00150 00151 if (pnid->cbSize==NID_SIZE_W6 || pnid->cbSize==NID_SIZE_W5 || pnid->cbSize==NID_SIZE_W3) { 00152 // UNICODE version of NOTIFYICONDATA structure 00153 LPCWSTR txt = (LPCWSTR)pnid->szTip; 00154 int max_len = pnid->cbSize==NID_SIZE_W3? 64: 128; 00155 00156 // get tooltip string length 00157 int l = 0; 00158 for(; l<max_len; ++l) 00159 if (!txt[l]) 00160 break; 00161 00162 new_text.assign(txt, l); 00163 00164 if (new_text != _tipText) { 00165 _tipText = new_text; 00166 changes = true; 00167 } 00168 } else if (pnid->cbSize==NID_SIZE_A6 || pnid->cbSize==NID_SIZE_A5 || pnid->cbSize==NID_SIZE_A3) { 00169 LPCSTR txt = (LPCSTR)pnid->szTip; 00170 int max_len = pnid->cbSize==NID_SIZE_A3? 64: 128; 00171 00172 int l = 0; 00173 for(int l=0; l<max_len; ++l) 00174 if (!txt[l]) 00175 break; 00176 00177 new_text.assign(txt, l); 00178 00179 if (new_text != _tipText) { 00180 _tipText = new_text; 00181 changes = true; 00182 } 00183 } 00184 } 00185 00186 TCHAR title[MAX_PATH]; 00187 00188 DWORD pid; 00189 GetWindowThreadProcessId(_hWnd, &pid); 00190 00191 // avoid to send WM_GETTEXT messages to the own process 00192 if (pid != GetCurrentProcessId()) 00193 if (GetWindowText(_hWnd, title, COUNTOF(title))) { 00194 if (_windowTitle != title) { 00195 _windowTitle = title; 00196 changes = true; 00197 } 00198 } 00199 00200 if (changes) { 00201 create_name(); 00202 _lastChange = GetTickCount(); 00203 } 00204 00205 return changes; 00206 } 00207 00208 00209 NotifyArea::NotifyArea(HWND hwnd) 00210 : super(hwnd), 00211 _tooltip(hwnd) 00212 { 00213 _next_idx = 0; 00214 _clock_width = 0; 00215 _last_icon_count = 0; 00216 _show_hidden = false; 00217 _hide_inactive = true; 00218 _show_button = true; 00219 } 00220 00221 NotifyArea::~NotifyArea() 00222 { 00223 KillTimer(_hwnd, 0); 00224 00225 write_config(); 00226 } 00227 00228 static bool get_hide_clock_from_registry() 00229 { 00230 HKEY hkeyStuckRects = 0; 00231 DWORD buffer[10]; 00232 DWORD len = sizeof(buffer); 00233 00234 bool hide_clock = false; 00235 00236 // check if the clock should be hidden 00237 if (!RegOpenKey(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StuckRects2"), &hkeyStuckRects) && 00238 !RegQueryValueEx(hkeyStuckRects, TEXT("Settings"), 0, NULL, (LPBYTE)buffer, &len) && 00239 len==sizeof(buffer) && buffer[0]==sizeof(buffer)) 00240 hide_clock = buffer[2] & 0x08? true: false; 00241 00242 if (hkeyStuckRects) 00243 RegCloseKey(hkeyStuckRects); 00244 00245 return hide_clock; 00246 } 00247 00248 void NotifyArea::read_config() 00249 { 00250 bool clock_visible = true; 00251 00252 // read notification icon settings from XML configuration 00253 XMLPos cfg_pos = g_Globals.get_cfg(); 00254 00255 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003) 00256 if (!g_Globals._SHRestricted || !SHRestricted(REST_HIDECLOCK)) 00257 #endif 00258 { 00259 if (cfg_pos.go_down("desktopbar")) { 00260 clock_visible = XMLBoolRef(XMLPos(cfg_pos,"options"), "show-clock", !get_hide_clock_from_registry()); 00261 cfg_pos.back(); 00262 } 00263 } 00264 00265 if (cfg_pos.go_down("notify-icons")) { 00266 XMLPos options(cfg_pos, "options"); 00267 00268 _hide_inactive = XMLBool(options, "hide-inactive", true); ///@todo read default setting from registry 00269 _show_hidden = XMLBool(options, "show-hidden", false); ///@todo read default setting from registry 00270 _show_button = XMLBool(options, "show-button", true); 00271 00272 XMLChildrenFilter icons(cfg_pos, "icon"); 00273 00274 for(XMLChildrenFilter::iterator it=icons.begin(); it!=icons.end(); ++it) { 00275 const XMLNode& node = **it; 00276 00277 NotifyIconConfig cfg; 00278 00279 cfg._name = node.get("name").c_str(); 00280 cfg._tipText = node.get("text").c_str(); 00281 cfg._windowTitle = node.get("window").c_str(); 00282 cfg._modulePath = node.get("module").c_str(); 00283 const string& mode = node.get("show"); 00284 00285 if (mode == "show") 00286 cfg._mode = NIM_SHOW; 00287 else if (mode == "hide") 00288 cfg._mode = NIM_HIDE; 00289 else //if (mode == "auto") 00290 cfg._mode = NIM_HIDE; 00291 00292 _cfg.push_back(cfg); 00293 } 00294 00295 cfg_pos.back(); 00296 } 00297 00298 show_clock(clock_visible); 00299 } 00300 00301 void NotifyArea::write_config() 00302 { 00303 // write notification icon settings to XML configuration file 00304 XMLPos cfg_pos = g_Globals.get_cfg(); 00305 00306 cfg_pos.smart_create("desktopbar"); 00307 XMLBoolRef boolRef(XMLPos(cfg_pos,"options"), "show-clock"); 00308 boolRef = _hwndClock!=0; 00309 cfg_pos.back(); 00310 00311 cfg_pos.smart_create("notify-icons"); 00312 00313 XMLPos options(cfg_pos, "options"); 00314 XMLBoolRef(options, "hide-inactive") = _hide_inactive; 00315 XMLBoolRef(options, "show-hidden") = _show_hidden; 00316 XMLBoolRef(options, "show-button") = _show_button; 00317 00318 for(NotifyIconCfgList::iterator it=_cfg.begin(); it!=_cfg.end(); ++it) { 00319 NotifyIconConfig& cfg = *it; 00320 00321 // search for the corresponding node using the original name 00322 cfg_pos.smart_create("icon", "name", cfg._name); 00323 00324 // refresh unique name 00325 cfg.create_name(); 00326 00327 cfg_pos["name"] = cfg._name.c_str(); 00328 cfg_pos["text"] = cfg._tipText.c_str(); 00329 cfg_pos["window"] = cfg._windowTitle.c_str(); 00330 cfg_pos["module"] = cfg._modulePath.c_str(); 00331 cfg_pos["show"] = string_from_mode(cfg._mode).c_str(); 00332 00333 cfg_pos.back(); 00334 } 00335 00336 cfg_pos.back(); // smart_create 00337 } 00338 00339 void NotifyArea::show_clock(bool flag) 00340 { 00341 bool vis = _hwndClock!=0; 00342 00343 if (vis != flag) { 00344 if (flag) { 00345 // create clock window 00346 _hwndClock = ClockWindow::Create(_hwnd); 00347 00348 if (_hwndClock) { 00349 ClientRect clock_size(_hwndClock); 00350 _clock_width = clock_size.right; 00351 } 00352 } else { 00353 DestroyWindow(_hwndClock); 00354 _hwndClock = 0; 00355 _clock_width = 0; 00356 } 00357 00358 SendMessage(GetParent(_hwnd), PM_RESIZE_CHILDREN, 0, 0); 00359 } 00360 } 00361 00362 LRESULT NotifyArea::Init(LPCREATESTRUCT pcs) 00363 { 00364 if (super::Init(pcs)) 00365 return 1; 00366 00367 read_config(); 00368 00369 SetTimer(_hwnd, 0, 1000, NULL); 00370 00371 return 0; 00372 } 00373 00374 HWND NotifyArea::Create(HWND hwndParent) 00375 { 00376 static BtnWindowClass wcTrayNotify(CLASSNAME_TRAYNOTIFY, CS_DBLCLKS); 00377 00378 ClientRect clnt(hwndParent); 00379 00380 return Window::Create(WINDOW_CREATOR(NotifyArea), WS_EX_STATICEDGE, 00381 wcTrayNotify, TITLE_TRAYNOTIFY, WS_CHILD|WS_VISIBLE|WS_CLIPCHILDREN, 00382 clnt.right-(NOTIFYAREA_WIDTH_DEF+1), 1, NOTIFYAREA_WIDTH_DEF, clnt.bottom-2, hwndParent); 00383 } 00384 00385 LRESULT NotifyArea::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) 00386 { 00387 switch(nmsg) { 00388 case WM_PAINT: 00389 Paint(); 00390 break; 00391 00392 case WM_TIMER: { 00393 Refresh(); 00394 00395 ClockWindow* clock_window = GET_WINDOW(ClockWindow, _hwndClock); 00396 00397 if (clock_window) 00398 clock_window->TimerTick(); 00399 break;} 00400 00401 case PM_REFRESH: 00402 Refresh(true); 00403 break; 00404 00405 case WM_SIZE: { 00406 int cx = LOWORD(lparam); 00407 SetWindowPos(_hwndClock, 0, cx-_clock_width, 0, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE); 00408 break;} 00409 00410 case PM_GET_WIDTH: { 00411 int w = _sorted_icons.size()*NOTIFYICON_DIST + NOTIFYAREA_SPACE + _clock_width; 00412 if (_show_button) 00413 w += NOTIFYICON_DIST; 00414 return w;} 00415 00416 case PM_REFRESH_CONFIG: 00417 read_config(); 00418 break; 00419 00420 case WM_CONTEXTMENU: { 00421 Point pt(lparam); 00422 POINTS p; 00423 p.x = (SHORT) pt.x; 00424 p.y = (SHORT) pt.y; 00425 ScreenToClient(_hwnd, &pt); 00426 00427 if (IconHitTest(pt) == _sorted_icons.end()) { // display menu only when no icon clicked 00428 PopupMenu menu(IDM_NOTIFYAREA); 00429 SetMenuDefaultItem(menu, 0, MF_BYPOSITION); 00430 CheckMenuItem(menu, ID_SHOW_HIDDEN_ICONS, MF_BYCOMMAND|(_show_hidden?MF_CHECKED:MF_UNCHECKED)); 00431 CheckMenuItem(menu, ID_SHOW_ICON_BUTTON, MF_BYCOMMAND|(_show_button?MF_CHECKED:MF_UNCHECKED)); 00432 menu.TrackPopupMenu(_hwnd, p); 00433 } 00434 break;} 00435 00436 case WM_COPYDATA: { // receive NotifyHook answers 00437 String path; 00438 HWND hwnd; 00439 00440 if (_hook.ModulePathCopyData(lparam, &hwnd, path)) 00441 _window_modules[hwnd] = path; 00442 break;} 00443 00444 default: 00445 if (nmsg>=WM_MOUSEFIRST && nmsg<=WM_MOUSELAST) { 00446 // close startup menu and other popup menus 00447 // This functionality is missing in MS Windows. 00448 if (nmsg==WM_LBUTTONDOWN || nmsg==WM_MBUTTONDOWN || nmsg==WM_RBUTTONDOWN 00449 #ifdef WM_XBUTTONDOWN 00450 || nmsg==WM_XBUTTONDOWN 00451 #endif 00452 ) 00453 00454 CancelModes(); 00455 00456 Point pt(lparam); 00457 NotifyIconSet::const_iterator found = IconHitTest(pt); 00458 00459 if (found != _sorted_icons.end()) { 00460 const NotifyInfo& entry = const_cast<NotifyInfo&>(*found); // Why does GCC 3.3 need this additional const_cast ?! 00461 00462 // set activation time stamp 00463 if (nmsg == WM_LBUTTONDOWN || // Some programs need PostMessage() instead of SendMessage(). 00464 nmsg == WM_MBUTTONDOWN || // So call SendMessage() only for BUTTONUP and BLCLK messages 00465 #ifdef WM_XBUTTONDOWN 00466 nmsg == WM_XBUTTONDOWN || 00467 #endif 00468 nmsg == WM_RBUTTONDOWN) { 00469 _icon_map[entry]._lastChange = GetTickCount(); 00470 } 00471 00472 // Notify the message if the owner is still alive 00473 if (IsWindow(entry._hWnd)) { 00474 if (nmsg == WM_MOUSEMOVE || // avoid to call blocking SendMessage() for merely moving the mouse over icons 00475 nmsg == WM_LBUTTONDOWN || // Some programs need PostMessage() instead of SendMessage(). 00476 nmsg == WM_MBUTTONDOWN || // So call SendMessage() only for BUTTONUP and BLCLK messages 00477 #ifdef WM_XBUTTONDOWN 00478 nmsg == WM_XBUTTONDOWN || 00479 #endif 00480 nmsg == WM_RBUTTONDOWN) 00481 PostMessage(entry._hWnd, entry._uCallbackMessage, entry._uID, nmsg); 00482 else { 00483 // allow SetForegroundWindow() in client process 00484 DWORD pid; 00485 00486 if (GetWindowThreadProcessId(entry._hWnd, &pid)) { 00487 // bind dynamically to AllowSetForegroundWindow() to be compatible to WIN98 00488 static DynamicFct<BOOL(WINAPI*)(DWORD)> AllowSetForegroundWindow(TEXT("USER32"), "AllowSetForegroundWindow"); 00489 00490 if (AllowSetForegroundWindow) 00491 (*AllowSetForegroundWindow)(pid); 00492 } 00493 00494 // use PostMessage() for notifcation icons of Shell Service Objects in the own process 00495 if (pid == GetCurrentProcessId()) 00496 PostMessage(entry._hWnd, entry._uCallbackMessage, entry._uID, nmsg); 00497 else 00498 SendMessage(entry._hWnd, entry._uCallbackMessage, entry._uID, nmsg); 00499 } 00500 } 00501 else if (_icon_map.erase(entry)) // delete icons without valid owner window 00502 UpdateIcons(); 00503 } else 00504 // handle clicks on notification area button "show hidden icons" 00505 if (_show_button) 00506 if (nmsg == WM_LBUTTONDOWN) 00507 if (pt.x>=NOTIFYICON_X && pt.x<NOTIFYICON_X+NOTIFYICON_SIZE && 00508 pt.y>=NOTIFYICON_Y && pt.y<NOTIFYICON_Y+NOTIFYICON_SIZE) 00509 PostMessage(_hwnd, WM_COMMAND, MAKEWPARAM(ID_SHOW_HIDDEN_ICONS,0), 0); 00510 } 00511 00512 return super::WndProc(nmsg, wparam, lparam); 00513 } 00514 00515 return 0; 00516 } 00517 00518 int NotifyArea::Command(int id, int code) 00519 { 00520 switch(id) { 00521 case ID_SHOW_HIDDEN_ICONS: 00522 _show_hidden = !_show_hidden; 00523 UpdateIcons(); 00524 break; 00525 00526 case ID_SHOW_ICON_BUTTON: 00527 _show_button = !_show_button; 00528 UpdateIcons(); 00529 break; 00530 00531 case ID_CONFIG_NOTIFYAREA: 00532 Dialog::DoModal(IDD_NOTIFYAREA, WINDOW_CREATOR(TrayNotifyDlg), GetParent(_hwnd)); 00533 break; 00534 00535 case ID_CONFIG_TIME: 00536 launch_cpanel(_hwnd, TEXT("timedate.cpl")); 00537 break; 00538 00539 default: 00540 SendParent(WM_COMMAND, MAKELONG(id,code), 0); 00541 } 00542 00543 return 0; 00544 } 00545 00546 int NotifyArea::Notify(int id, NMHDR* pnmh) 00547 { 00548 if (pnmh->code == TTN_GETDISPINFO) { 00549 LPNMTTDISPINFO pdi = (LPNMTTDISPINFO)pnmh; 00550 00551 Point pt(GetMessagePos()); 00552 ScreenToClient(_hwnd, &pt); 00553 00554 if (_show_button && 00555 pt.x>=NOTIFYICON_X && pt.x<NOTIFYICON_X+NOTIFYICON_SIZE && 00556 pt.y>=NOTIFYICON_Y && pt.y<NOTIFYICON_Y+NOTIFYICON_SIZE) 00557 { 00558 static ResString sShowIcons(IDS_SHOW_HIDDEN_ICONS); 00559 static ResString sHideIcons(IDS_HIDE_ICONS); 00560 00561 pdi->lpszText = (_show_hidden? sHideIcons: sShowIcons).str(); 00562 } else { 00563 NotifyIconSet::iterator found = IconHitTest(pt); 00564 00565 if (found != _sorted_icons.end()) { 00566 NotifyInfo& entry = const_cast<NotifyInfo&>(*found); // Why does GCC 3.3 need this additional const_cast ?! 00567 00568 // enable multiline tooltips (break at CR/LF and for very long one-line strings) 00569 SendMessage(pnmh->hwndFrom, TTM_SETMAXTIPWIDTH, 0, 400); 00570 00571 pdi->lpszText = entry._tipText.str(); 00572 } 00573 } 00574 } 00575 00576 return 0; 00577 } 00578 00579 void NotifyArea::CancelModes() 00580 { 00581 PostMessage(HWND_BROADCAST, WM_CANCELMODE, 0, 0); 00582 00583 for(NotifyIconSet::const_iterator it=_sorted_icons.begin(); it!=_sorted_icons.end(); ++it) 00584 PostMessage(it->_hWnd, WM_CANCELMODE, 0, 0); 00585 } 00586 00587 LRESULT NotifyArea::ProcessTrayNotification(int notify_code, NOTIFYICONDATA* pnid) 00588 { 00589 switch(notify_code) { 00590 case NIM_ADD: 00591 case NIM_MODIFY: 00592 if ((int)pnid->uID >= 0) { ///@todo This is a fix for Windows Task Manager. 00593 NotifyInfo& entry = _icon_map[pnid]; 00594 00595 // a new entry? 00596 if (entry._idx == -1) 00597 entry._idx = ++_next_idx; 00598 /* equivalent code using iterator::find(); 00599 NotifyIconMap::iterator found = _icon_map.find(pnid); 00600 NotifyInfo* pentry; 00601 // a new entry? 00602 if (found == _icon_map.end()) { 00603 pentry = &_icon_map[pnid]; 00604 pentry->_idx = ++_next_idx; 00605 } else { 00606 pentry = &found->second; 00607 } 00608 NotifyInfo& entry = *pentry; 00609 */ 00610 bool changes = entry.modify(pnid); 00611 00612 #if NOTIFYICON_VERSION>=3 // as of 21.08.2003 missing in MinGW headers 00613 if (DetermineHideState(entry) && entry._mode==NIM_HIDE) { 00614 entry._dwState |= NIS_HIDDEN; 00615 changes = true; 00616 } 00617 #endif 00618 00619 if (changes) 00620 UpdateIcons(); ///@todo call only if really changes occurred 00621 00622 return TRUE; 00623 } 00624 break; 00625 00626 case NIM_DELETE: { 00627 NotifyIconMap::iterator found = _icon_map.find(pnid); 00628 00629 if (found != _icon_map.end()) { 00630 if (found->second._hIcon) 00631 DestroyIcon(found->second._hIcon); 00632 _icon_map.erase(found); 00633 UpdateIcons(); 00634 return TRUE; 00635 } 00636 break;} 00637 00638 #if NOTIFYICON_VERSION>=3 // as of 21.08.2003 missing in MinGW headers 00639 case NIM_SETFOCUS: 00640 SetForegroundWindow(_hwnd); 00641 return TRUE; 00642 00643 case NIM_SETVERSION: 00644 NotifyIconMap::iterator found = _icon_map.find(pnid); 00645 00646 if (found != _icon_map.end()) { 00647 found->second._version = pnid->UNION_MEMBER(uVersion); 00648 return TRUE; 00649 } else 00650 return FALSE; 00651 #endif 00652 } 00653 00654 return FALSE; 00655 } 00656 00657 void NotifyArea::UpdateIcons() 00658 { 00659 _sorted_icons.clear(); 00660 00661 // sort icon infos by display index 00662 for(NotifyIconMap::const_iterator it=_icon_map.begin(); it!=_icon_map.end(); ++it) { 00663 const NotifyInfo& entry = it->second; 00664 00665 #ifdef NIF_STATE // as of 21.08.2003 missing in MinGW headers 00666 if (_show_hidden || !(entry._dwState & NIS_HIDDEN)) 00667 #endif 00668 _sorted_icons.insert(entry); 00669 } 00670 00671 // sync tooltip areas to current icon number 00672 if (_sorted_icons.size() != _last_icon_count) { 00673 RECT rect = {NOTIFYICON_X, NOTIFYICON_Y, NOTIFYICON_X+NOTIFYICON_SIZE, NOTIFYICON_Y+NOTIFYICON_SIZE}; 00674 00675 size_t tt_idx = 0; 00676 00677 if (_show_button) { 00678 _tooltip.add(_hwnd, tt_idx++, rect); 00679 00680 rect.left += NOTIFYICON_DIST; 00681 rect.right += NOTIFYICON_DIST; 00682 } 00683 00684 size_t icon_cnt = _sorted_icons.size(); 00685 while(tt_idx < icon_cnt) { 00686 _tooltip.add(_hwnd, tt_idx++, rect); 00687 00688 rect.left += NOTIFYICON_DIST; 00689 rect.right += NOTIFYICON_DIST; 00690 } 00691 00692 while(tt_idx < _last_icon_count) 00693 _tooltip.remove(_hwnd, tt_idx++); 00694 00695 _last_icon_count = _sorted_icons.size(); 00696 } 00697 00698 SendMessage(GetParent(_hwnd), PM_RESIZE_CHILDREN, 0, 0); 00699 00700 InvalidateRect(_hwnd, NULL, FALSE); // refresh icon display 00701 UpdateWindow(_hwnd); 00702 } 00703 00704 #ifndef _NO_ALPHABLEND 00705 #ifdef _MSC_VER 00706 #pragma comment(lib, "msimg32") // for AlphaBlend() 00707 #endif 00708 #endif 00709 00710 void NotifyArea::Paint() 00711 { 00712 BufferedPaintCanvas canvas(_hwnd); 00713 00714 // first fill with the background color 00715 FillRect(canvas, &canvas.rcPaint, GetSysColorBrush(COLOR_BTNFACE)); 00716 00717 // draw icons 00718 int x = NOTIFYICON_X; 00719 int y = NOTIFYICON_Y; 00720 00721 if (_show_button) { 00722 static SmallIcon leftArrowIcon(IDI_NOTIFY_L); 00723 static SmallIcon rightArrowIcon(IDI_NOTIFY_R); 00724 00725 DrawIconEx(canvas, x, y, _show_hidden?rightArrowIcon:leftArrowIcon, NOTIFYICON_SIZE, NOTIFYICON_SIZE, 0, 0, DI_NORMAL); 00726 x += NOTIFYICON_DIST; 00727 } 00728 00729 #ifndef _NO_ALPHABLEND 00730 MemCanvas mem_dc; 00731 SelectedBitmap bmp(mem_dc, CreateCompatibleBitmap(canvas, NOTIFYICON_SIZE, NOTIFYICON_SIZE)); 00732 RECT rect = {0, 0, NOTIFYICON_SIZE, NOTIFYICON_SIZE}; 00733 BLENDFUNCTION blend = {AC_SRC_OVER, 0, 128, 0}; // 50 % visible 00734 #endif 00735 00736 for(NotifyIconSet::const_iterator it=_sorted_icons.begin(); it!=_sorted_icons.end(); ++it) { 00737 #ifndef _NO_ALPHABLEND 00738 if (it->_dwState & NIS_HIDDEN) { 00739 FillRect(mem_dc, &rect, GetSysColorBrush(COLOR_BTNFACE)); 00740 DrawIconEx(mem_dc, 0, 0, it->_hIcon, NOTIFYICON_SIZE, NOTIFYICON_SIZE, 0, 0, DI_NORMAL); 00741 AlphaBlend(canvas, x, y, NOTIFYICON_SIZE, NOTIFYICON_SIZE, mem_dc, 0, 0, NOTIFYICON_SIZE, NOTIFYICON_SIZE, blend); 00742 } else 00743 #endif 00744 DrawIconEx(canvas, x, y, it->_hIcon, NOTIFYICON_SIZE, NOTIFYICON_SIZE, 0, 0, DI_NORMAL); 00745 00746 x += NOTIFYICON_DIST; 00747 } 00748 } 00749 00750 void NotifyArea::Refresh(bool update) 00751 { 00752 // Look for task icons without valid owner window. 00753 // This is an extended feature missing in MS Windows. 00754 for(NotifyIconSet::const_iterator it=_sorted_icons.begin(); it!=_sorted_icons.end(); ++it) { 00755 const NotifyInfo& entry = *it; 00756 00757 if (!IsWindow(entry._hWnd)) 00758 if (_icon_map.erase(entry)) // delete icons without valid owner window 00759 ++update; 00760 } 00761 00762 DWORD now = GetTickCount(); 00763 00764 // handle icon hiding 00765 for(NotifyIconMap::iterator it=_icon_map.begin(); it!=_icon_map.end(); ++it) { 00766 NotifyInfo& entry = it->second; 00767 00768 DetermineHideState(entry); 00769 00770 switch(entry._mode) { 00771 case NIM_HIDE: 00772 if (!(entry._dwState & NIS_HIDDEN)) { 00773 entry._dwState |= NIS_HIDDEN; 00774 ++update; 00775 } 00776 break; 00777 00778 case NIM_SHOW: 00779 if (entry._dwState&NIS_HIDDEN) { 00780 entry._dwState &= ~NIS_HIDDEN; 00781 ++update; 00782 } 00783 break; 00784 00785 case NIM_AUTO: 00786 // automatically hide icons after long periods of inactivity 00787 if (_hide_inactive) 00788 if (!(entry._dwState & NIS_HIDDEN)) 00789 if (now-entry._lastChange > ICON_AUTOHIDE_SECONDS*1000) { 00790 entry._dwState |= NIS_HIDDEN; 00791 ++update; 00792 } 00793 break; 00794 } 00795 } 00796 00797 if (update) 00798 UpdateIcons(); 00799 } 00800 00801 /// search for a icon at a given client coordinate position 00802 NotifyIconSet::iterator NotifyArea::IconHitTest(const POINT& pos) 00803 { 00804 if (pos.y<NOTIFYICON_Y || pos.y>=NOTIFYICON_Y+NOTIFYICON_SIZE) 00805 return _sorted_icons.end(); 00806 00807 NotifyIconSet::iterator it = _sorted_icons.begin(); 00808 00809 int x = NOTIFYICON_X; 00810 00811 if (_show_button) 00812 x += NOTIFYICON_DIST; 00813 00814 for(; it!=_sorted_icons.end(); ++it) { 00815 //NotifyInfo& entry = const_cast<NotifyInfo&>(*it); // Why does GCC 3.3 need this additional const_cast ?! 00816 00817 if (pos.x>=x && pos.x<x+NOTIFYICON_SIZE) 00818 break; 00819 00820 x += NOTIFYICON_DIST; 00821 } 00822 00823 return it; 00824 } 00825 00826 00827 void NotifyIconConfig::create_name() 00828 { 00829 _name = FmtString(TEXT("'%s' - '%s' - '%s'"), _tipText.c_str(), _windowTitle.c_str(), _modulePath.c_str()); 00830 } 00831 00832 00833 #if NOTIFYICON_VERSION>=3 // as of 21.08.2003 missing in MinGW headers 00834 00835 bool NotifyIconConfig::match(const NotifyIconConfig& props) const 00836 { 00837 if (!_tipText.empty() && !props._tipText.empty()) 00838 if (props._tipText == _tipText) 00839 return true; 00840 00841 if (!_windowTitle.empty() && !props._windowTitle.empty()) 00842 if (_tcsstr(props._windowTitle, _windowTitle)) 00843 return true; 00844 00845 if (!_modulePath.empty() && !props._modulePath.empty()) 00846 if (!_tcsicmp(props._modulePath, _modulePath)) 00847 return true; 00848 00849 return false; 00850 } 00851 00852 bool NotifyArea::DetermineHideState(NotifyInfo& entry) 00853 { 00854 if (entry._modulePath.empty()) { 00855 const String& modulePath = _window_modules[entry._hWnd]; 00856 00857 // request module path for new windows (We will get an asynchronous answer by a WM_COPYDATA message.) 00858 if (!modulePath.empty()) 00859 entry._modulePath = modulePath; 00860 else 00861 _hook.GetModulePath(entry._hWnd, _hwnd); 00862 } 00863 00864 for(NotifyIconCfgList::const_iterator it=_cfg.begin(); it!=_cfg.end(); ++it) { 00865 const NotifyIconConfig& cfg = *it; 00866 00867 if (cfg.match(entry)) { 00868 entry._mode = cfg._mode; 00869 return true; 00870 } 00871 } 00872 00873 return false; 00874 } 00875 00876 #endif 00877 00878 00879 String string_from_mode(NOTIFYICONMODE mode) 00880 { 00881 switch(mode) { 00882 case NIM_SHOW: 00883 return ResString(IDS_NOTIFY_SHOW); 00884 00885 case NIM_HIDE: 00886 return ResString(IDS_NOTIFY_HIDE); 00887 00888 default: //case NIM_AUTO 00889 return ResString(IDS_NOTIFY_AUTOHIDE); 00890 } 00891 } 00892 00893 00894 TrayNotifyDlg::TrayNotifyDlg(HWND hwnd) 00895 : super(hwnd), 00896 _tree_ctrl(GetDlgItem(hwnd, IDC_NOTIFY_ICONS)), 00897 _himl(ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR24, 3, 0)), 00898 _pNotifyArea(static_cast<NotifyArea*>(Window::get_window((HWND)SendMessage(g_Globals._hwndDesktopBar, PM_GET_NOTIFYAREA, 0, 0)))) 00899 { 00900 _selectedItem = 0; 00901 00902 if (_pNotifyArea) { 00903 // save original icon states and configuration data 00904 for(NotifyIconMap::const_iterator it=_pNotifyArea->_icon_map.begin(); it!=_pNotifyArea->_icon_map.end(); ++it) 00905 _icon_states_org[it->first] = IconStatePair(it->second._mode, it->second._dwState); 00906 00907 _cfg_org = _pNotifyArea->_cfg; 00908 _show_hidden_org = _pNotifyArea->_show_hidden; 00909 } 00910 00911 SetWindowIcon(hwnd, IDI_REACTOS); 00912 00913 _haccel = LoadAccelerators(g_Globals._hInstance, MAKEINTRESOURCE(IDA_TRAYNOTIFY)); 00914 00915 { 00916 WindowCanvas canvas(_hwnd); 00917 HBRUSH hbkgnd = GetStockBrush(WHITE_BRUSH); 00918 00919 ImageList_AddAlphaIcon(_himl, SmallIcon(IDI_DOT), hbkgnd, canvas); 00920 ImageList_AddAlphaIcon(_himl, SmallIcon(IDI_DOT_TRANS), hbkgnd, canvas); 00921 ImageList_AddAlphaIcon(_himl, SmallIcon(IDI_DOT_RED), hbkgnd, canvas); 00922 } 00923 00924 (void)TreeView_SetImageList(_tree_ctrl, _himl, TVSIL_NORMAL); 00925 00926 _resize_mgr.Add(IDC_NOTIFY_ICONS, RESIZE); 00927 _resize_mgr.Add(IDC_LABEL1, MOVE_Y); 00928 _resize_mgr.Add(IDC_NOTIFY_TOOLTIP, RESIZE_X|MOVE_Y); 00929 _resize_mgr.Add(IDC_LABEL2, MOVE_Y); 00930 _resize_mgr.Add(IDC_NOTIFY_TITLE, RESIZE_X|MOVE_Y); 00931 _resize_mgr.Add(IDC_LABEL3, MOVE_Y); 00932 _resize_mgr.Add(IDC_NOTIFY_MODULE, RESIZE_X|MOVE_Y); 00933 00934 _resize_mgr.Add(IDC_LABEL4, MOVE_Y); 00935 _resize_mgr.Add(IDC_NOTIFY_SHOW, MOVE_Y); 00936 _resize_mgr.Add(IDC_NOTIFY_HIDE, MOVE_Y); 00937 _resize_mgr.Add(IDC_NOTIFY_AUTOHIDE,MOVE_Y); 00938 00939 _resize_mgr.Add(IDC_PICTURE, MOVE); 00940 _resize_mgr.Add(ID_SHOW_HIDDEN_ICONS,MOVE_Y); 00941 00942 _resize_mgr.Add(IDC_LABEL6, MOVE_Y); 00943 _resize_mgr.Add(IDC_LAST_CHANGE, MOVE_Y); 00944 00945 _resize_mgr.Add(IDOK, MOVE); 00946 _resize_mgr.Add(IDCANCEL, MOVE); 00947 00948 _resize_mgr.Resize(+150, +200); 00949 00950 Refresh(); 00951 00952 SetTimer(_hwnd, 0, 3000, NULL); 00953 register_pretranslate(hwnd); 00954 } 00955 00956 TrayNotifyDlg::~TrayNotifyDlg() 00957 { 00958 KillTimer(_hwnd, 0); 00959 unregister_pretranslate(_hwnd); 00960 ImageList_Destroy(_himl); 00961 } 00962 00963 void TrayNotifyDlg::Refresh() 00964 { 00965 ///@todo refresh incrementally 00966 00967 HiddenWindow hide(_tree_ctrl); 00968 00969 TreeView_DeleteAllItems(_tree_ctrl); 00970 00971 TV_INSERTSTRUCT tvi; 00972 00973 tvi.hParent = 0; 00974 tvi.hInsertAfter = TVI_LAST; 00975 00976 TV_ITEM& tv = tvi.item; 00977 tv.mask = TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE; 00978 00979 ResString str_cur(IDS_ITEMS_CUR); 00980 tv.pszText = str_cur.str(); 00981 tv.iSelectedImage = tv.iImage = 0; // IDI_DOT 00982 _hitemCurrent = TreeView_InsertItem(_tree_ctrl, &tvi); 00983 00984 ResString str_conf(IDS_ITEMS_CONFIGURED); 00985 tv.pszText = str_conf.str(); 00986 tv.iSelectedImage = tv.iImage = 2; // IDI_DOT_RED 00987 _hitemConfig = TreeView_InsertItem(_tree_ctrl, &tvi); 00988 00989 tvi.hParent = _hitemCurrent; 00990 00991 ResString str_visible(IDS_ITEMS_VISIBLE); 00992 tv.pszText = str_visible.str(); 00993 tv.iSelectedImage = tv.iImage = 0; // IDI_DOT 00994 _hitemCurrent_visible = TreeView_InsertItem(_tree_ctrl, &tvi); 00995 00996 ResString str_hidden(IDS_ITEMS_HIDDEN); 00997 tv.pszText = str_hidden.str(); 00998 tv.iSelectedImage = tv.iImage = 1; // IDI_DOT_TRANS 00999 _hitemCurrent_hidden = TreeView_InsertItem(_tree_ctrl, &tvi); 01000 01001 if (_pNotifyArea) { 01002 _info.clear(); 01003 01004 tv.mask |= TVIF_PARAM; 01005 01006 WindowCanvas canvas(_hwnd); 01007 01008 // insert current (visible and hidden) items 01009 for(NotifyIconMap::const_iterator it=_pNotifyArea->_icon_map.begin(); it!=_pNotifyArea->_icon_map.end(); ++it) { 01010 const NotifyInfo& entry = it->second; 01011 01012 InsertItem(entry._dwState&NIS_HIDDEN? _hitemCurrent_hidden: _hitemCurrent_visible, TVI_LAST, entry, canvas); 01013 } 01014 01015 // insert configured items in tree view 01016 const NotifyIconCfgList& cfg = _pNotifyArea->_cfg; 01017 for(NotifyIconCfgList::const_iterator it=cfg.begin(); it!=cfg.end(); ++it) { 01018 const NotifyIconConfig& cfg_entry = *it; 01019 01020 HICON hicon = 0; 01021 01022 if (!cfg_entry._modulePath.empty()) { 01023 if ((int)ExtractIconEx(cfg_entry._modulePath, 0, NULL, &hicon, 1) <= 0) 01024 hicon = 0; 01025 01026 if (!hicon) { 01027 SHFILEINFO sfi; 01028 01029 if (SHGetFileInfo(cfg_entry._modulePath, 0, &sfi, sizeof(sfi), SHGFI_ICON|SHGFI_SMALLICON)) 01030 hicon = sfi.hIcon; 01031 } 01032 } 01033 01034 InsertItem(_hitemConfig, TVI_SORT, cfg_entry, canvas, hicon, cfg_entry._mode); 01035 01036 if (hicon) 01037 DestroyIcon(hicon); 01038 } 01039 01040 CheckDlgButton(_hwnd, ID_SHOW_HIDDEN_ICONS, _pNotifyArea->_show_hidden? BST_CHECKED: BST_UNCHECKED); 01041 } 01042 01043 TreeView_Expand(_tree_ctrl, _hitemCurrent_visible, TVE_EXPAND); 01044 TreeView_Expand(_tree_ctrl, _hitemCurrent_hidden, TVE_EXPAND); 01045 TreeView_Expand(_tree_ctrl, _hitemCurrent, TVE_EXPAND); 01046 TreeView_Expand(_tree_ctrl, _hitemConfig, TVE_EXPAND); 01047 01048 TreeView_EnsureVisible(_tree_ctrl, _hitemCurrent_visible); 01049 } 01050 01051 void TrayNotifyDlg::InsertItem(HTREEITEM hparent, HTREEITEM after, const NotifyInfo& entry, HDC hdc) 01052 { 01053 InsertItem(hparent, after, entry, hdc, entry._hIcon, entry._mode); 01054 } 01055 01056 void TrayNotifyDlg::InsertItem(HTREEITEM hparent, HTREEITEM after, const NotifyIconDlgInfo& entry, 01057 HDC hdc, HICON hicon, NOTIFYICONMODE mode) 01058 { 01059 int idx = _info.size() + 1; 01060 _info[idx] = entry; 01061 01062 String mode_str = string_from_mode(mode); 01063 01064 switch(mode) { 01065 case NIM_SHOW: mode_str = ResString(IDS_NOTIFY_SHOW); break; 01066 case NIM_HIDE: mode_str = ResString(IDS_NOTIFY_HIDE); break; 01067 case NIM_AUTO: mode_str = ResString(IDS_NOTIFY_AUTOHIDE); 01068 } 01069 01070 FmtString txt(TEXT("%s - %s [%s]"), entry._tipText.c_str(), entry._windowTitle.c_str(), mode_str.c_str()); 01071 01072 TV_INSERTSTRUCT tvi; 01073 01074 tvi.hParent = hparent; 01075 tvi.hInsertAfter = after; 01076 01077 TV_ITEM& tv = tvi.item; 01078 tv.mask = TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM; 01079 01080 tv.lParam = (LPARAM)idx; 01081 tv.pszText = txt.str(); 01082 tv.iSelectedImage = tv.iImage = ImageList_AddAlphaIcon(_himl, hicon, GetStockBrush(WHITE_BRUSH), hdc); 01083 (void)TreeView_InsertItem(_tree_ctrl, &tvi); 01084 } 01085 01086 LRESULT TrayNotifyDlg::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) 01087 { 01088 switch(nmsg) { 01089 case PM_TRANSLATE_MSG: { 01090 MSG* pmsg = (MSG*) lparam; 01091 01092 if (TranslateAccelerator(_hwnd, _haccel, pmsg)) 01093 return TRUE; 01094 01095 return FALSE;} 01096 01097 case WM_TIMER: 01098 Refresh(); 01099 break; 01100 01101 default: 01102 return super::WndProc(nmsg, wparam, lparam); 01103 } 01104 01105 return 0; 01106 } 01107 01108 int TrayNotifyDlg::Command(int id, int code) 01109 { 01110 if (code == BN_CLICKED) { 01111 switch(id) { 01112 case ID_REFRESH: 01113 Refresh(); 01114 break; 01115 01116 case IDC_NOTIFY_SHOW: 01117 SetIconMode(NIM_SHOW); 01118 break; 01119 01120 case IDC_NOTIFY_HIDE: 01121 SetIconMode(NIM_HIDE); 01122 break; 01123 01124 case IDC_NOTIFY_AUTOHIDE: 01125 SetIconMode(NIM_AUTO); 01126 break; 01127 01128 case ID_SHOW_HIDDEN_ICONS: 01129 if (_pNotifyArea) 01130 SendMessage(*_pNotifyArea, WM_COMMAND, MAKEWPARAM(id,code), 0); 01131 break; 01132 01133 case IDOK: 01134 EndDialog(_hwnd, id); 01135 break; 01136 01137 case IDCANCEL: 01138 // rollback changes 01139 if (_pNotifyArea) { 01140 // restore original icon states and configuration data 01141 _pNotifyArea->_cfg = _cfg_org; 01142 _pNotifyArea->_show_hidden = _show_hidden_org; 01143 01144 for(IconStateMap::const_iterator it=_icon_states_org.begin(); it!=_icon_states_org.end(); ++it) { 01145 NotifyInfo& info = _pNotifyArea->_icon_map[it->first]; 01146 01147 info._mode = it->second.first; 01148 info._dwState = it->second.second; 01149 } 01150 01151 SendMessage(*_pNotifyArea, PM_REFRESH, 0, 0); 01152 } 01153 01154 EndDialog(_hwnd, id); 01155 break; 01156 } 01157 01158 return 0; 01159 } 01160 01161 return 1; 01162 } 01163 01164 int TrayNotifyDlg::Notify(int id, NMHDR* pnmh) 01165 { 01166 switch(pnmh->code) { 01167 case TVN_SELCHANGED: { 01168 NMTREEVIEW* pnmtv = (NMTREEVIEW*)pnmh; 01169 int idx = pnmtv->itemNew.lParam; 01170 01171 if (idx) { 01172 RefreshProperties(_info[idx]); 01173 _selectedItem = pnmtv->itemNew.hItem; 01174 } else { 01175 /* 01176 SetDlgItemText(_hwnd, IDC_NOTIFY_TOOLTIP, NULL); 01177 SetDlgItemText(_hwnd, IDC_NOTIFY_TITLE, NULL); 01178 SetDlgItemText(_hwnd, IDC_NOTIFY_MODULE, NULL); 01179 */ 01180 CheckRadioButton(_hwnd, IDC_NOTIFY_SHOW, IDC_NOTIFY_AUTOHIDE, 0); 01181 } 01182 break;} 01183 } 01184 01185 return 0; 01186 } 01187 01188 void TrayNotifyDlg::RefreshProperties(const NotifyIconDlgInfo& entry) 01189 { 01190 SetDlgItemText(_hwnd, IDC_NOTIFY_TOOLTIP, entry._tipText); 01191 SetDlgItemText(_hwnd, IDC_NOTIFY_TITLE, entry._windowTitle); 01192 SetDlgItemText(_hwnd, IDC_NOTIFY_MODULE, entry._modulePath); 01193 01194 CheckRadioButton(_hwnd, IDC_NOTIFY_SHOW, IDC_NOTIFY_AUTOHIDE, IDC_NOTIFY_SHOW+entry._mode); 01195 01196 String change_str; 01197 if (entry._lastChange) 01198 change_str.printf(TEXT("before %d s"), (GetTickCount()-entry._lastChange+500)/1000); 01199 SetDlgItemText(_hwnd, IDC_LAST_CHANGE, change_str); 01200 01201 HICON hicon = 0; //get_window_icon_big(entry._hWnd, false); 01202 01203 // If we could not find an icon associated with the owner window, try to load one from the owning module. 01204 if (!hicon && !entry._modulePath.empty()) { 01205 hicon = ExtractIcon(g_Globals._hInstance, entry._modulePath, 0); 01206 01207 if (!hicon) { 01208 SHFILEINFO sfi; 01209 01210 if (SHGetFileInfo(entry._modulePath, 0, &sfi, sizeof(sfi), SHGFI_ICON|SHGFI_LARGEICON)) 01211 hicon = sfi.hIcon; 01212 } 01213 } 01214 01215 if (hicon) { 01216 SendMessage(GetDlgItem(_hwnd, IDC_PICTURE), STM_SETICON, (LPARAM)hicon, 0); 01217 DestroyIcon(hicon); 01218 } else 01219 SendMessage(GetDlgItem(_hwnd, IDC_PICTURE), STM_SETICON, 0, 0); 01220 } 01221 01222 void TrayNotifyDlg::SetIconMode(NOTIFYICONMODE mode) 01223 { 01224 int idx = TreeView_GetItemData(_tree_ctrl, _selectedItem); 01225 01226 if (!idx) 01227 return; 01228 01229 NotifyIconConfig& entry = _info[idx]; 01230 01231 if (entry._mode != mode) { 01232 entry._mode = mode; 01233 01234 // trigger refresh in notify area and this dialog 01235 if (_pNotifyArea) 01236 SendMessage(*_pNotifyArea, PM_REFRESH, 0, 0); 01237 } 01238 01239 if (_pNotifyArea) { 01240 bool found = false; 01241 01242 NotifyIconCfgList& cfg = _pNotifyArea->_cfg; 01243 for(NotifyIconCfgList::iterator it=cfg.begin(); it!=cfg.end(); ++it) { 01244 NotifyIconConfig& cfg_entry = *it; 01245 01246 if (cfg_entry.match(entry)) { 01247 cfg_entry._mode = mode; 01248 ++found; 01249 break; 01250 } 01251 } 01252 01253 if (!found) { 01254 // insert new configuration entry 01255 NotifyIconConfig cfg_entry = entry; 01256 01257 cfg_entry._mode = mode; 01258 01259 _pNotifyArea->_cfg.push_back(cfg_entry); 01260 } 01261 } 01262 01263 Refresh(); 01264 ///@todo select treeview item at new position in tree view -> refresh HTREEITEM in _selectedItem 01265 } 01266 01267 01268 ClockWindow::ClockWindow(HWND hwnd) 01269 : super(hwnd), 01270 _tooltip(hwnd) 01271 { 01272 *_time = TEXT('\0'); 01273 FormatTime(); 01274 01275 _tooltip.add(_hwnd, _hwnd); 01276 } 01277 01278 HWND ClockWindow::Create(HWND hwndParent) 01279 { 01280 static BtnWindowClass wcClock(CLASSNAME_CLOCKWINDOW, CS_DBLCLKS); 01281 01282 ClientRect clnt(hwndParent); 01283 01284 WindowCanvas canvas(hwndParent); 01285 FontSelection font(canvas, GetStockFont(DEFAULT_GUI_FONT)); 01286 01287 RECT rect = {0, 0, 0, 0}; 01288 TCHAR buffer[8]; 01289 01290 if (!GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, NULL, NULL, buffer, sizeof(buffer)/sizeof(TCHAR))) 01291 _tcscpy(buffer, TEXT("00:00")); 01292 01293 DrawText(canvas, buffer, -1, &rect, DT_SINGLELINE|DT_NOPREFIX|DT_CALCRECT); 01294 int clockwindowWidth = rect.right-rect.left + 4; 01295 01296 return Window::Create(WINDOW_CREATOR(ClockWindow), 0, 01297 wcClock, NULL, WS_CHILD|WS_VISIBLE, 01298 clnt.right-(clockwindowWidth), 1, clockwindowWidth, clnt.bottom-2, hwndParent); 01299 } 01300 01301 LRESULT ClockWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) 01302 { 01303 switch(nmsg) { 01304 case WM_PAINT: 01305 Paint(); 01306 break; 01307 01308 case WM_LBUTTONDBLCLK: 01309 launch_cpanel(_hwnd, TEXT("timedate.cpl")); 01310 break; 01311 01312 default: 01313 return super::WndProc(nmsg, wparam, lparam); 01314 } 01315 01316 return 0; 01317 } 01318 01319 int ClockWindow::Notify(int id, NMHDR* pnmh) 01320 { 01321 if (pnmh->code == TTN_GETDISPINFO) { 01322 LPNMTTDISPINFO pdi = (LPNMTTDISPINFO)pnmh; 01323 01324 SYSTEMTIME systime; 01325 TCHAR buffer[64]; 01326 01327 GetLocalTime(&systime); 01328 01329 if (GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systime, NULL, buffer, 64)) 01330 _tcscpy(pdi->szText, buffer); 01331 else 01332 pdi->szText[0] = '\0'; 01333 } 01334 01335 return 0; 01336 } 01337 01338 void ClockWindow::TimerTick() 01339 { 01340 if (FormatTime()) 01341 InvalidateRect(_hwnd, NULL, TRUE); // refresh displayed time 01342 } 01343 01344 bool ClockWindow::FormatTime() 01345 { 01346 TCHAR buffer[16]; 01347 01348 if (GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, NULL, NULL, buffer, sizeof(buffer)/sizeof(TCHAR))) 01349 if (_tcscmp(buffer, _time)) { 01350 _tcscpy(_time, buffer); 01351 return true; // The text to display has changed. 01352 } 01353 01354 return false; // no change 01355 } 01356 01357 void ClockWindow::Paint() 01358 { 01359 PaintCanvas canvas(_hwnd); 01360 01361 FillRect(canvas, &canvas.rcPaint, GetSysColorBrush(COLOR_BTNFACE)); 01362 01363 BkMode bkmode(canvas, TRANSPARENT); 01364 FontSelection font(canvas, GetStockFont(ANSI_VAR_FONT)); 01365 01366 DrawText(canvas, _time, -1, ClientRect(_hwnd), DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX); 01367 }
ROS Explorer Source Code Documentation
generated on 02.01.2013 by ![]() |