ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

traynotify.cpp
Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  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; 
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);   
00269         _show_hidden = XMLBool(options, "show-hidden", false);  
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) {  
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();  
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 
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 {
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();
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(ANSI_VAR_FONT));
01286 
01287     RECT rect = {0, 0, 0, 0};
01288     TCHAR buffer[16];
01289     // Arbitrary high time so that the created clock window is big enough
01290     SYSTEMTIME st = { 1601, 1, 0, 1, 23, 59, 59, 999 };
01291 
01292     if (!GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buffer, sizeof(buffer)/sizeof(TCHAR)))
01293         _tcscpy(buffer, TEXT("00:00"));
01294 
01295     // Calculate the rectangle needed to draw the time (without actually drawing it)
01296     DrawText(canvas, buffer, -1, &rect, DT_SINGLELINE|DT_NOPREFIX|DT_CALCRECT);
01297     int clockwindowWidth = rect.right-rect.left + 4;
01298 
01299     return Window::Create(WINDOW_CREATOR(ClockWindow), 0,
01300                             wcClock, NULL, WS_CHILD|WS_VISIBLE,
01301                             clnt.right-(clockwindowWidth), 1, clockwindowWidth, clnt.bottom-2, hwndParent);
01302 }
01303 
01304 LRESULT ClockWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
01305 {
01306     switch(nmsg) {
01307       case WM_PAINT:
01308         Paint();
01309         break;
01310 
01311       case WM_LBUTTONDBLCLK:
01312         launch_cpanel(_hwnd, TEXT("timedate.cpl"));
01313         break;
01314 
01315       default:
01316         return super::WndProc(nmsg, wparam, lparam);
01317     }
01318 
01319     return 0;
01320 }
01321 
01322 int ClockWindow::Notify(int id, NMHDR* pnmh)
01323 {
01324     if (pnmh->code == TTN_GETDISPINFO) {
01325         LPNMTTDISPINFO pdi = (LPNMTTDISPINFO)pnmh;
01326 
01327         SYSTEMTIME systime;
01328         TCHAR buffer[64];
01329 
01330         GetLocalTime(&systime);
01331 
01332         if (GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systime, NULL, buffer, 64))
01333             _tcscpy(pdi->szText, buffer);
01334         else
01335             pdi->szText[0] = '\0';
01336     }
01337 
01338     return 0;
01339 }
01340 
01341 void ClockWindow::TimerTick()
01342 {
01343     if (FormatTime())
01344         InvalidateRect(_hwnd, NULL, TRUE);  // refresh displayed time
01345 }
01346 
01347 bool ClockWindow::FormatTime()
01348 {
01349     TCHAR buffer[16];
01350 
01351     if (GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, NULL, NULL, buffer, sizeof(buffer)/sizeof(TCHAR)))
01352         if (_tcscmp(buffer, _time)) {
01353             _tcscpy(_time, buffer);
01354             return true;    // The text to display has changed.
01355         }
01356 
01357     return false;   // no change
01358 }
01359 
01360 void ClockWindow::Paint()
01361 {
01362     PaintCanvas canvas(_hwnd);
01363 
01364     FillRect(canvas, &canvas.rcPaint, GetSysColorBrush(COLOR_BTNFACE));
01365 
01366     BkMode bkmode(canvas, TRANSPARENT);
01367     FontSelection font(canvas, GetStockFont(ANSI_VAR_FONT));
01368 
01369     DrawText(canvas, _time, -1, ClientRect(_hwnd), DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX);
01370 }

Generated on Sun May 27 2012 04:18:40 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.