Doxygen

taskbar.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  // taskbar.cpp
00024  //
00025  // Martin Fuchs, 16.08.2003
00026  //
00027 
00028 
00029 #include <precomp.h>
00030 
00031 #include "taskbar.h"
00032 #include "traynotify.h" // for NOTIFYAREA_WIDTH_DEF
00033 
00034 
00035 DynamicFct<BOOL (WINAPI*)(HWND hwnd)> g_SetTaskmanWindow(TEXT("user32"), "SetTaskmanWindow");
00036 DynamicFct<BOOL (WINAPI*)(HWND hwnd)> g_RegisterShellHookWindow(TEXT("user32"), "RegisterShellHookWindow");
00037 DynamicFct<BOOL (WINAPI*)(HWND hwnd)> g_DeregisterShellHookWindow(TEXT("user32"), "DeregisterShellHookWindow");
00038 
00039 /*
00040 DynamicFct<BOOL (WINAPI*)(HWND hWnd, DWORD dwType)> g_RegisterShellHook(TEXT("shell32"), (LPCSTR)0xb5);
00041 
00042  // constants for RegisterShellHook()
00043 #define RSH_UNREGISTER          0
00044 #define RSH_REGISTER            1
00045 #define RSH_REGISTER_PROGMAN    2
00046 #define RSH_REGISTER_TASKMAN    3
00047 */
00048 
00049 
00050 TaskBarEntry::TaskBarEntry()
00051 {
00052     _id = 0;
00053     _hbmp = 0;
00054     _bmp_idx = 0;
00055     _used = 0;
00056     _btn_idx = 0;
00057     _fsState = 0;
00058 }
00059 
00060 TaskBarMap::~TaskBarMap()
00061 {
00062     while(!empty()) {
00063         iterator it = begin();
00064         DeleteBitmap(it->second._hbmp);
00065         erase(it);
00066     }
00067 }
00068 
00069 
00070 TaskBar::TaskBar(HWND hwnd)
00071  :  super(hwnd),
00072     WM_SHELLHOOK(RegisterWindowMessage(WINMSG_SHELLHOOK))
00073 {
00074     _last_btn_width = 0;
00075 
00076     _mmMetrics_org.cbSize = sizeof(MINIMIZEDMETRICS);
00077 
00078     SystemParametersInfo(SPI_GETMINIMIZEDMETRICS, sizeof(_mmMetrics_org), &_mmMetrics_org, 0);
00079 
00080      // configure the window manager to hide windows when they are minimized
00081      // This is neccessary to enable shell hook messages.
00082     if (!(_mmMetrics_org.iArrange & ARW_HIDE)) {
00083         MINIMIZEDMETRICS _mmMetrics_new = _mmMetrics_org;
00084 
00085         _mmMetrics_new.iArrange |= ARW_HIDE;
00086 
00087         SystemParametersInfo(SPI_SETMINIMIZEDMETRICS, sizeof(_mmMetrics_new), &_mmMetrics_new, 0);
00088     }
00089 }
00090 
00091 TaskBar::~TaskBar()
00092 {
00093 //  if (g_RegisterShellHook)
00094 //      (*g_RegisterShellHook)(_hwnd, RSH_UNREGISTER);
00095 
00096     if (g_DeregisterShellHookWindow)
00097         (*g_DeregisterShellHookWindow)(_hwnd);
00098     else
00099         KillTimer(_hwnd, 0);
00100 
00101     if (g_SetTaskmanWindow)
00102         (*g_SetTaskmanWindow)(0);
00103 
00104     SystemParametersInfo(SPI_GETMINIMIZEDMETRICS, sizeof(_mmMetrics_org), &_mmMetrics_org, 0);
00105 }
00106 
00107 HWND TaskBar::Create(HWND hwndParent)
00108 {
00109     ClientRect clnt(hwndParent);
00110 
00111     int taskbar_pos = 80;   // This start position will be adjusted in DesktopBar::Resize().
00112 
00113     return Window::Create(WINDOW_CREATOR(TaskBar), 0,
00114                             BtnWindowClass(CLASSNAME_TASKBAR), TITLE_TASKBAR,
00115                             WS_CHILD|WS_VISIBLE | CCS_TOP|CCS_NODIVIDER|CCS_NORESIZE,
00116                             taskbar_pos, 0, clnt.right-taskbar_pos-(NOTIFYAREA_WIDTH_DEF+1), clnt.bottom, hwndParent);
00117 }
00118 
00119 LRESULT TaskBar::Init(LPCREATESTRUCT pcs)
00120 {
00121     if (super::Init(pcs))
00122         return 1;
00123 
00124     /* FIXME: There's an internal padding for non-flat toolbar. Get rid of it somehow. */
00125     _htoolbar = CreateToolbarEx(_hwnd,
00126                                 WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|
00127                                 CCS_TOP|CCS_NODIVIDER|TBSTYLE_LIST|TBSTYLE_TOOLTIPS|TBSTYLE_WRAPABLE,//|TBSTYLE_AUTOSIZE
00128                                 IDW_TASKTOOLBAR, 0, 0, 0, NULL, 0, 0, 0, 16, 16, sizeof(TBBUTTON));
00129 
00130     SendMessage(_htoolbar, TB_SETBUTTONWIDTH, 0, MAKELONG(TASKBUTTONWIDTH_MAX,TASKBUTTONWIDTH_MAX));
00131     //SendMessage(_htoolbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS);
00132     //SendMessage(_htoolbar, TB_SETDRAWTEXTFLAGS, DT_CENTER|DT_VCENTER, DT_CENTER|DT_VCENTER);
00133     //SetWindowFont(_htoolbar, GetStockFont(ANSI_VAR_FONT), FALSE);
00134     //SendMessage(_htoolbar, TB_SETPADDING, 0, MAKELPARAM(8,8));
00135 
00136      // set metrics for the Taskbar toolbar to enable button spacing
00137     TBMETRICS metrics;
00138 
00139     metrics.cbSize = sizeof(TBMETRICS);
00140     metrics.dwMask = TBMF_BARPAD | TBMF_BUTTONSPACING;
00141     metrics.cxBarPad = 0;
00142     metrics.cyBarPad = 0;
00143     metrics.cxButtonSpacing = 3;
00144     metrics.cyButtonSpacing = 3;
00145 
00146     SendMessage(_htoolbar, TB_SETMETRICS, 0, (LPARAM)&metrics);
00147 
00148     _next_id = IDC_FIRST_APP;
00149 
00150      // register the taskbar window as task manager window to make the following call to RegisterShellHookWindow working
00151     if (g_SetTaskmanWindow)
00152         (*g_SetTaskmanWindow)(_hwnd);
00153 
00154     if (g_RegisterShellHookWindow) {
00155         LOG(TEXT("Using shell hooks for notification of shell events."));
00156 
00157         (*g_RegisterShellHookWindow)(_hwnd);
00158     } else {
00159         LOG(TEXT("Shell hooks not available."));
00160 
00161         SetTimer(_hwnd, 0, 200, NULL);
00162     }
00163 
00164 /* Alternatively we could use the RegisterShellHook() function in SHELL32, but this is not yet implemented in the WINE code.
00165     if (g_RegisterShellHook) {
00166         (*g_RegisterShellHook)(0, RSH_REGISTER);
00167 
00168         if ((HIWORD(GetVersion())>>14) == W_VER_NT)
00169             (*g_RegisterShellHook)(_hwnd, RSH_REGISTER_TASKMAN);
00170         else
00171             (*g_RegisterShellHook)(_hwnd, RSH_REGISTER);
00172     }
00173 */
00174     Refresh();
00175 
00176     return 0;
00177 }
00178 
00179 LRESULT TaskBar::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
00180 {
00181     switch(nmsg) {
00182       case WM_SIZE:
00183         SendMessage(_htoolbar, WM_SIZE, 0, 0);
00184         ResizeButtons();
00185         break;
00186 
00187       case WM_TIMER:
00188         Refresh();
00189         return 0;
00190 
00191       case WM_CONTEXTMENU: {
00192         Point pt(lparam);
00193         ScreenToClient(_htoolbar, &pt);
00194 
00195         if ((HWND)wparam==_htoolbar && SendMessage(_htoolbar, TB_HITTEST, 0, (LPARAM)&pt)>=0)
00196             break;  // avoid displaying context menu for application button _and_ desktop bar at the same time
00197 
00198         goto def;}
00199 
00200       case PM_GET_LAST_ACTIVE:
00201         return (LRESULT)(HWND)_last_foreground_wnd;
00202 
00203       case WM_SYSCOLORCHANGE:
00204         SendMessage(_htoolbar, WM_SYSCOLORCHANGE, 0, 0);
00205         break;
00206 
00207       default: def:
00208         if (nmsg == WM_SHELLHOOK) {
00209             switch(wparam) {
00210               case HSHELL_WINDOWCREATED:
00211               case HSHELL_WINDOWDESTROYED:
00212               case HSHELL_WINDOWACTIVATED:
00213               case HSHELL_REDRAW:
00214 #ifdef HSHELL_FLASH
00215               case HSHELL_FLASH:
00216 #endif
00217 #ifdef HSHELL_RUDEAPPACTIVATED
00218               case HSHELL_RUDEAPPACTIVATED:
00219 #endif
00220                 Refresh();
00221                 break;
00222             }
00223         } else {
00224             return super::WndProc(nmsg, wparam, lparam);
00225         }
00226     }
00227 
00228     return 0;
00229 }
00230 
00231 int TaskBar::Command(int id, int code)
00232 {
00233     TaskBarMap::iterator found = _map.find_id(id);
00234 
00235     if (found != _map.end()) {
00236         ActivateApp(found);
00237         return 0;
00238     }
00239 
00240     return super::Command(id, code);
00241 }
00242 
00243 int TaskBar::Notify(int id, NMHDR* pnmh)
00244 {
00245     if (pnmh->hwndFrom == _htoolbar)
00246         switch(pnmh->code) {
00247           case NM_RCLICK: {
00248             TBBUTTONINFO btninfo;
00249             TaskBarMap::iterator it;
00250             Point pt(GetMessagePos());
00251             ScreenToClient(_htoolbar, &pt);
00252 
00253             btninfo.cbSize = sizeof(TBBUTTONINFO);
00254             btninfo.dwMask = TBIF_BYINDEX|TBIF_COMMAND;
00255 
00256             int idx = SendMessage(_htoolbar, TB_HITTEST, 0, (LPARAM)&pt);
00257 
00258             if (idx>=0 &&
00259                 SendMessage(_htoolbar, TB_GETBUTTONINFO, idx, (LPARAM)&btninfo)!=-1 &&
00260                 (it=_map.find_id(btninfo.idCommand))!=_map.end()) {
00261                 //TaskBarEntry& entry = it->second;
00262 
00263                 ActivateApp(it, false, false);  // don't restore minimized windows on right button click
00264 
00265                 static DynamicFct<DWORD(STDAPICALLTYPE*)(RESTRICTIONS)> pSHRestricted(TEXT("SHELL32"), "SHRestricted");
00266 
00267                 if (pSHRestricted && !(*pSHRestricted)(REST_NOTRAYCONTEXTMENU))
00268                     ShowAppSystemMenu(it);
00269             }
00270             break;}
00271 
00272           default:
00273             return super::Notify(id, pnmh);
00274         }
00275 
00276     return 0;
00277 }
00278 
00279 
00280 void TaskBar::ActivateApp(TaskBarMap::iterator it, bool can_minimize, bool can_restore)
00281 {
00282     HWND hwnd = it->first;
00283 
00284     bool minimize_it = can_minimize && !IsIconic(hwnd) &&
00285                         (hwnd==GetForegroundWindow() || hwnd==_last_foreground_wnd);
00286 
00287      // switch to selected application window
00288     if (can_restore && !minimize_it)
00289         if (IsIconic(hwnd))
00290             PostMessage(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
00291 
00292      // In case minimize_it is true, we _have_ to switch to the app before
00293      // posting SW_MINIMIZE to be compatible with some applications (e.g. "Sleipnir")
00294     SetForegroundWindow(hwnd);
00295 
00296     if (minimize_it) {
00297         PostMessage(hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
00298         _last_foreground_wnd = 0;
00299     } else
00300         _last_foreground_wnd = hwnd;
00301 
00302     Refresh();
00303 }
00304 
00305 void TaskBar::ShowAppSystemMenu(TaskBarMap::iterator it)
00306 {
00307     HMENU hmenu = GetSystemMenu(it->first, FALSE);
00308 
00309     if (hmenu) {
00310         POINT pt;
00311 
00312         GetCursorPos(&pt);
00313         int cmd = TrackPopupMenu(hmenu, TPM_LEFTBUTTON|TPM_RIGHTBUTTON|TPM_RETURNCMD, pt.x, pt.y, 0, _hwnd, NULL);
00314 
00315         if (cmd) {
00316             ActivateApp(it, false, false);  // reactivate window after the context menu has closed
00317             PostMessage(it->first, WM_SYSCOMMAND, cmd, 0);
00318         }
00319     }
00320 }
00321 
00322 
00323 HICON get_window_icon_small(HWND hwnd)
00324 {
00325     HICON hIcon = 0;
00326 
00327     SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL2, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
00328 
00329     if (!hIcon)
00330         SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
00331 
00332     if (!hIcon)
00333         SendMessageTimeout(hwnd, WM_GETICON, ICON_BIG, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
00334 
00335     if (!hIcon)
00336         hIcon = (HICON)GetClassLongPtr(hwnd, GCL_HICONSM);
00337 
00338     if (!hIcon)
00339         hIcon = (HICON)GetClassLongPtr(hwnd, GCL_HICON);
00340 
00341     if (!hIcon)
00342         SendMessageTimeout(hwnd, WM_QUERYDRAGICON, 0, 0, 0, 1000, (PDWORD_PTR)&hIcon);
00343 
00344     return hIcon;
00345 }
00346 
00347 HICON get_window_icon_big(HWND hwnd, bool allow_from_class)
00348 {
00349     HICON hIcon = 0;
00350 
00351     SendMessageTimeout(hwnd, WM_GETICON, ICON_BIG, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
00352 
00353     if (!hIcon)
00354         SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL2, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
00355 
00356     if (!hIcon)
00357         SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
00358 
00359     if (allow_from_class) {
00360         if (!hIcon)
00361             hIcon = (HICON)GetClassLongPtr(hwnd, GCL_HICON);
00362 
00363         if (!hIcon)
00364             hIcon = (HICON)GetClassLongPtr(hwnd, GCL_HICONSM);
00365     }
00366 
00367     if (!hIcon)
00368         SendMessageTimeout(hwnd, WM_QUERYDRAGICON, 0, 0, 0, 1000, (PDWORD_PTR)&hIcon);
00369 
00370     return hIcon;
00371 }
00372 
00373  // fill task bar with buttons for enumerated top level windows
00374 BOOL CALLBACK TaskBar::EnumWndProc(HWND hwnd, LPARAM lparam)
00375 {
00376     TaskBar* pThis = (TaskBar*)lparam;
00377 
00378     DWORD style = GetWindowStyle(hwnd);
00379     DWORD ex_style = GetWindowExStyle(hwnd);
00380 
00381     if ((style&WS_VISIBLE) && !(ex_style&WS_EX_TOOLWINDOW) &&
00382         !GetParent(hwnd) && !GetWindow(hwnd,GW_OWNER)) {
00383         TCHAR title[BUFFER_LEN];
00384 
00385         if (!GetWindowText(hwnd, title, BUFFER_LEN))
00386             title[0] = '\0';
00387 
00388         TaskBarMap::iterator found = pThis->_map.find(hwnd);
00389         int last_id = 0;
00390 
00391         if (found != pThis->_map.end()) {
00392             last_id = found->second._id;
00393 
00394             if (!last_id)
00395                 found->second._id = pThis->_next_id++;
00396         } else {
00397             HBITMAP hbmp;
00398             HICON hIcon = get_window_icon_small(hwnd);
00399             BOOL delete_icon = FALSE;
00400 
00401             if (!hIcon) {
00402                 hIcon = LoadIcon(0, IDI_APPLICATION);
00403                 delete_icon = TRUE;
00404             }
00405 
00406             if (hIcon) {
00407                 hbmp = create_bitmap_from_icon(hIcon, GetSysColorBrush(COLOR_BTNFACE), WindowCanvas(pThis->_htoolbar));
00408                 if (delete_icon)
00409                     DestroyIcon(hIcon); // some icons can be freed, some not - so ignore any error return of DestroyIcon()
00410             } else
00411                 hbmp = 0;
00412 
00413             TBADDBITMAP ab = {0, (UINT_PTR)hbmp};
00414             int bmp_idx = SendMessage(pThis->_htoolbar, TB_ADDBITMAP, 1, (LPARAM)&ab);
00415 
00416             TaskBarEntry entry;
00417 
00418             entry._id = pThis->_next_id++;
00419             entry._hbmp = hbmp;
00420             entry._bmp_idx = bmp_idx;
00421             entry._title = title;
00422 
00423             pThis->_map[hwnd] = entry;
00424             found = pThis->_map.find(hwnd);
00425         }
00426 
00427         TBBUTTON btn = {-2/*I_IMAGENONE*/, 0, TBSTATE_ENABLED/*|TBSTATE_ELLIPSES*/, BTNS_BUTTON, {0, 0}, 0, 0};
00428         TaskBarEntry& entry = found->second;
00429 
00430         ++entry._used;
00431         btn.idCommand = entry._id;
00432 
00433         HWND foreground = GetForegroundWindow();
00434         HWND foreground_owner = GetWindow(foreground, GW_OWNER);
00435 
00436         if (hwnd==foreground || hwnd==foreground_owner) {
00437             btn.fsState |= TBSTATE_PRESSED|TBSTATE_CHECKED;
00438             pThis->_last_foreground_wnd = hwnd;
00439         }
00440 
00441         if (!last_id) {
00442              // create new toolbar buttons for new windows
00443             if (title[0])
00444                 btn.iString = (INT_PTR)title;
00445 
00446             btn.iBitmap = entry._bmp_idx;
00447             entry._btn_idx = SendMessage(pThis->_htoolbar, TB_BUTTONCOUNT, 0, 0);
00448 
00449             SendMessage(pThis->_htoolbar, TB_INSERTBUTTON, entry._btn_idx, (LPARAM)&btn);
00450 
00451             pThis->ResizeButtons();
00452         } else {
00453              // refresh attributes of existing buttons
00454             if (btn.fsState != entry._fsState)
00455                 SendMessage(pThis->_htoolbar, TB_SETSTATE, entry._id, MAKELONG(btn.fsState,0));
00456 
00457             if (entry._title != title) {
00458                 TBBUTTONINFO info;
00459 
00460                 info.cbSize = sizeof(TBBUTTONINFO);
00461                 info.dwMask = TBIF_TEXT;
00462                 info.pszText = title;
00463 
00464                 SendMessage(pThis->_htoolbar, TB_SETBUTTONINFO, entry._id, (LPARAM)&info);
00465 
00466                 entry._title = title;
00467             }
00468         }
00469 
00470         entry._fsState = btn.fsState;
00471 
00472 #ifdef __REACTOS__  // now handled by activating the ARW_HIDE flag with SystemParametersInfo(SPI_SETMINIMIZEDMETRICS)
00473          // move minimized windows out of sight
00474         if (IsIconic(hwnd)) {
00475             RECT rect;
00476 
00477             GetWindowRect(hwnd, &rect);
00478 
00479             if (rect.bottom > 0)
00480                 SetWindowPos(hwnd, 0, -32000, -32000, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
00481         }
00482 #endif
00483     }
00484 
00485     return TRUE;
00486 }
00487 
00488 void TaskBar::Refresh()
00489 {
00490     for(TaskBarMap::iterator it=_map.begin(); it!=_map.end(); ++it)
00491         it->second._used = 0;
00492 
00493     EnumWindows(EnumWndProc, (LPARAM)this);
00494     //EnumDesktopWindows(GetThreadDesktop(GetCurrentThreadId()), EnumWndProc, (LPARAM)_htoolbar);
00495 
00496     set<int> btn_idx_to_delete;
00497     set<HBITMAP> hbmp_to_delete;
00498 
00499     for(TaskBarMap::iterator it=_map.begin(); it!=_map.end(); ++it) {
00500         TaskBarEntry& entry = it->second;
00501 
00502         if (!entry._used && entry._id) {
00503              // store button indexes to remove
00504             btn_idx_to_delete.insert(entry._btn_idx);
00505             hbmp_to_delete.insert(entry._hbmp);
00506             entry._id = 0;
00507         }
00508     }
00509 
00510     if (!btn_idx_to_delete.empty()) {
00511          // remove buttons from right to left
00512         for(set<int>::reverse_iterator it=btn_idx_to_delete.rbegin(); it!=btn_idx_to_delete.rend(); ++it) {
00513             int idx = *it;
00514 
00515             if (!SendMessage(_htoolbar, TB_DELETEBUTTON, idx, 0))
00516                 MessageBoxW(NULL, L"failed to delete button", NULL, MB_OK);
00517 
00518 
00519             for(TaskBarMap::iterator it2=_map.begin(); it2!=_map.end(); ++it2) {
00520                 TaskBarEntry& entry = it2->second;
00521 
00522                  // adjust button indexes
00523                 if (entry._btn_idx > idx) {
00524                     --entry._btn_idx;
00525 #if 0
00526                     --entry._bmp_idx;
00527 
00528                     TBBUTTONINFO info;
00529 
00530                     info.cbSize = sizeof(TBBUTTONINFO);
00531                     info.dwMask = TBIF_IMAGE;
00532                     info.iImage = entry._bmp_idx;
00533 
00534                     if (!SendMessage(_htoolbar, TB_SETBUTTONINFO, entry._id, (LPARAM)&info))
00535                         MessageBoxW(NULL, L"failed to set button info", NULL, MB_OK);
00536 #endif
00537                 }
00538             }
00539 
00540         }
00541 
00542         for(set<HBITMAP>::iterator it=hbmp_to_delete.begin(); it!=hbmp_to_delete.end(); ++it) {
00543             HBITMAP hbmp = *it;
00544 #if 0
00545             TBREPLACEBITMAP tbrepl = {0, (UINT_PTR)hbmp, 0, 0};
00546             SendMessage(_htoolbar, TB_REPLACEBITMAP, 0, (LPARAM)&tbrepl);
00547 #endif
00548             DeleteObject(hbmp);
00549 
00550             for(TaskBarMap::iterator it=_map.begin(); it!=_map.end(); ++it)
00551                 if (it->second._hbmp == hbmp) {
00552                     _map.erase(it);
00553                     break;
00554                 }
00555         }
00556 
00557         ResizeButtons();
00558     }
00559 }
00560 
00561 TaskBarMap::iterator TaskBarMap::find_id(int id)
00562 {
00563     for(iterator it=begin(); it!=end(); ++it)
00564         if (it->second._id == id)
00565             return it;
00566 
00567     return end();
00568 }
00569 
00570 void TaskBar::ResizeButtons()
00571 {
00572     int btns = _map.size();
00573 
00574     if (btns > 0) {
00575         int bar_width = ClientRect(_hwnd).right;
00576         int btn_width = (bar_width / btns) - 3;
00577 
00578         if (btn_width < TASKBUTTONWIDTH_MIN)
00579             btn_width = TASKBUTTONWIDTH_MIN;
00580         else if (btn_width > TASKBUTTONWIDTH_MAX)
00581             btn_width = TASKBUTTONWIDTH_MAX;
00582 
00583         if (btn_width != _last_btn_width) {
00584             _last_btn_width = btn_width;
00585 
00586             SendMessage(_htoolbar, TB_SETBUTTONWIDTH, 0, MAKELONG(btn_width,btn_width));
00587             SendMessage(_htoolbar, TB_AUTOSIZE, 0, 0);
00588         }
00589     }
00590 }