Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members

CMSWindowsClientTaskBarReceiver.cpp

00001 /*
00002  * synergy -- mouse and keyboard sharing utility
00003  * Copyright (C) 2003 Chris Schoeneman
00004  * 
00005  * This package is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * found in the file COPYING that should have accompanied this file.
00008  * 
00009  * This package 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
00012  * GNU General Public License for more details.
00013  */
00014 
00015 #include "CMSWindowsClientTaskBarReceiver.h"
00016 #include "CClient.h"
00017 #include "CMSWindowsClipboard.h"
00018 #include "LogOutputters.h"
00019 #include "BasicTypes.h"
00020 #include "CArch.h"
00021 #include "CArchTaskBarWindows.h"
00022 #include "resource.h"
00023 
00024 //
00025 // CMSWindowsClientTaskBarReceiver
00026 //
00027 
00028 const UINT CMSWindowsClientTaskBarReceiver::s_stateToIconID[kMaxState] =
00029 {
00030     IDI_TASKBAR_NOT_RUNNING,
00031     IDI_TASKBAR_NOT_WORKING,
00032     IDI_TASKBAR_NOT_CONNECTED,
00033     IDI_TASKBAR_NOT_CONNECTED,
00034     IDI_TASKBAR_CONNECTED
00035 };
00036 
00037 CMSWindowsClientTaskBarReceiver::CMSWindowsClientTaskBarReceiver(
00038                 HINSTANCE appInstance, const CBufferedLogOutputter* logBuffer) :
00039     CClientTaskBarReceiver(),
00040     m_appInstance(appInstance),
00041     m_window(NULL),
00042     m_logBuffer(logBuffer)
00043 {
00044     for (UInt32 i = 0; i < kMaxState; ++i) {
00045         m_icon[i] = loadIcon(s_stateToIconID[i]);
00046     }
00047     m_menu = LoadMenu(m_appInstance, MAKEINTRESOURCE(IDR_TASKBAR));
00048 
00049     // don't create the window yet.  we'll create it on demand.  this
00050     // has the side benefit of being created in the thread used for
00051     // the task bar.  that's good because it means the existence of
00052     // the window won't prevent changing the main thread's desktop.
00053 
00054     // add ourself to the task bar
00055     ARCH->addReceiver(this);
00056 }
00057 
00058 CMSWindowsClientTaskBarReceiver::~CMSWindowsClientTaskBarReceiver()
00059 {
00060     ARCH->removeReceiver(this);
00061     for (UInt32 i = 0; i < kMaxState; ++i) {
00062         deleteIcon(m_icon[i]);
00063     }
00064     DestroyMenu(m_menu);
00065     destroyWindow();
00066 }
00067 
00068 void
00069 CMSWindowsClientTaskBarReceiver::showStatus()
00070 {
00071     // create the window
00072     createWindow();
00073 
00074     // lock self while getting status
00075     lock();
00076 
00077     // get the current status
00078     std::string status = getToolTip();
00079 
00080     // done getting status
00081     unlock();
00082 
00083     // update dialog
00084     HWND child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_STATUS);
00085     SendMessage(child, WM_SETTEXT, 0, (LPARAM)status.c_str());
00086 
00087     if (!IsWindowVisible(m_window)) {
00088         // position it by the mouse
00089         POINT cursorPos;
00090         GetCursorPos(&cursorPos);
00091         RECT windowRect;
00092         GetWindowRect(m_window, &windowRect);
00093         int  x = cursorPos.x;
00094         int  y = cursorPos.y;
00095         int fw = GetSystemMetrics(SM_CXDLGFRAME);
00096         int fh = GetSystemMetrics(SM_CYDLGFRAME);
00097         int ww = windowRect.right  - windowRect.left;
00098         int wh = windowRect.bottom - windowRect.top;
00099         int sw = GetSystemMetrics(SM_CXFULLSCREEN);
00100         int sh = GetSystemMetrics(SM_CYFULLSCREEN);
00101         if (fw < 1) {
00102             fw = 1;
00103         }
00104         if (fh < 1) {
00105             fh = 1;
00106         }
00107         if (x + ww - fw > sw) {
00108             x -= ww - fw;
00109         }
00110         else {
00111             x -= fw;
00112         }
00113         if (x < 0) {
00114             x = 0;
00115         }
00116         if (y + wh - fh > sh) {
00117             y -= wh - fh;
00118         }
00119         else {
00120             y -= fh;
00121         }
00122         if (y < 0) {
00123             y = 0;
00124         }
00125         SetWindowPos(m_window, HWND_TOPMOST, x, y, ww, wh,
00126                             SWP_SHOWWINDOW);
00127     }
00128 }
00129 
00130 void
00131 CMSWindowsClientTaskBarReceiver::runMenu(int x, int y)
00132 {
00133     // do popup menu.  we need a window to pass to TrackPopupMenu().
00134     // the SetForegroundWindow() and SendMessage() calls around
00135     // TrackPopupMenu() are to get the menu to be dismissed when
00136     // another window gets activated and are just one of those
00137     // win32 weirdnesses.
00138     createWindow();
00139     SetForegroundWindow(m_window);
00140     HMENU menu = GetSubMenu(m_menu, 0);
00141     SetMenuDefaultItem(menu, IDC_TASKBAR_STATUS, FALSE);
00142     HMENU logLevelMenu = GetSubMenu(menu, 3);
00143     CheckMenuRadioItem(logLevelMenu, 0, 6,
00144                             CLOG->getFilter() - CLog::kERROR, MF_BYPOSITION);
00145     int n = TrackPopupMenu(menu,
00146                             TPM_NONOTIFY |
00147                             TPM_RETURNCMD |
00148                             TPM_LEFTBUTTON |
00149                             TPM_RIGHTBUTTON,
00150                             x, y, 0, m_window, NULL);
00151     SendMessage(m_window, WM_NULL, 0, 0);
00152 
00153     // perform the requested operation
00154     switch (n) {
00155     case IDC_TASKBAR_STATUS:
00156         showStatus();
00157         break;
00158 
00159     case IDC_TASKBAR_LOG:
00160         copyLog();
00161         break;
00162 
00163     case IDC_TASKBAR_SHOW_LOG:
00164         ARCH->showConsole(true);
00165         break;
00166 
00167     case IDC_TASKBAR_LOG_LEVEL_ERROR:
00168         CLOG->setFilter(CLog::kERROR);
00169         break;
00170 
00171     case IDC_TASKBAR_LOG_LEVEL_WARNING:
00172         CLOG->setFilter(CLog::kWARNING);
00173         break;
00174 
00175     case IDC_TASKBAR_LOG_LEVEL_NOTE:
00176         CLOG->setFilter(CLog::kNOTE);
00177         break;
00178 
00179     case IDC_TASKBAR_LOG_LEVEL_INFO:
00180         CLOG->setFilter(CLog::kINFO);
00181         break;
00182 
00183     case IDC_TASKBAR_LOG_LEVEL_DEBUG:
00184         CLOG->setFilter(CLog::kDEBUG);
00185         break;
00186 
00187     case IDC_TASKBAR_LOG_LEVEL_DEBUG1:
00188         CLOG->setFilter(CLog::kDEBUG1);
00189         break;
00190 
00191     case IDC_TASKBAR_LOG_LEVEL_DEBUG2:
00192         CLOG->setFilter(CLog::kDEBUG2);
00193         break;
00194 
00195     case IDC_TASKBAR_QUIT:
00196         quit();
00197         break;
00198     }
00199 }
00200 
00201 void
00202 CMSWindowsClientTaskBarReceiver::primaryAction()
00203 {
00204     showStatus();
00205 }
00206 
00207 const IArchTaskBarReceiver::Icon
00208 CMSWindowsClientTaskBarReceiver::getIcon() const
00209 {
00210     return reinterpret_cast<Icon>(m_icon[getStatus()]);
00211 }
00212 
00213 void
00214 CMSWindowsClientTaskBarReceiver::copyLog() const
00215 {
00216     if (m_logBuffer != NULL) {
00217         // collect log buffer
00218         CString data;
00219         for (CBufferedLogOutputter::const_iterator index = m_logBuffer->begin();
00220                                 index != m_logBuffer->end(); ++index) {
00221             data += *index;
00222             data += "\n";
00223         }
00224 
00225         // copy log to clipboard
00226         if (!data.empty()) {
00227             CMSWindowsClipboard clipboard(m_window);
00228             clipboard.open(0);
00229             clipboard.emptyUnowned();
00230             clipboard.add(IClipboard::kText, data);
00231             clipboard.close();
00232         }
00233     }
00234 }
00235 
00236 void
00237 CMSWindowsClientTaskBarReceiver::onStatusChanged()
00238 {
00239     if (IsWindowVisible(m_window)) {
00240         showStatus();
00241     }
00242 }
00243 
00244 HICON
00245 CMSWindowsClientTaskBarReceiver::loadIcon(UINT id)
00246 {
00247     HANDLE icon = LoadImage(m_appInstance,
00248                             MAKEINTRESOURCE(id),
00249                             IMAGE_ICON,
00250                             0, 0,
00251                             LR_DEFAULTCOLOR);
00252     return reinterpret_cast<HICON>(icon);
00253 }
00254 
00255 void
00256 CMSWindowsClientTaskBarReceiver::deleteIcon(HICON icon)
00257 {
00258     if (icon != NULL) {
00259         DestroyIcon(icon);
00260     }
00261 }
00262 
00263 void
00264 CMSWindowsClientTaskBarReceiver::createWindow()
00265 {
00266     // ignore if already created
00267     if (m_window != NULL) {
00268         return;
00269     }
00270 
00271     // get the status dialog
00272     m_window = CreateDialogParam(m_appInstance,
00273                             MAKEINTRESOURCE(IDD_TASKBAR_STATUS),
00274                             NULL,
00275                             (DLGPROC)&CMSWindowsClientTaskBarReceiver::staticDlgProc,
00276                             reinterpret_cast<LPARAM>(
00277                                 reinterpret_cast<void*>(this)));
00278 
00279     // window should appear on top of everything, including (especially)
00280     // the task bar.
00281     LONG_PTR style = GetWindowLongPtr(m_window, GWL_EXSTYLE);
00282     style |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
00283     SetWindowLongPtr(m_window, GWL_EXSTYLE, style);
00284 
00285     // tell the task bar about this dialog
00286     CArchTaskBarWindows::addDialog(m_window);
00287 }
00288 
00289 void
00290 CMSWindowsClientTaskBarReceiver::destroyWindow()
00291 {
00292     if (m_window != NULL) {
00293         CArchTaskBarWindows::removeDialog(m_window);
00294         DestroyWindow(m_window);
00295         m_window = NULL;
00296     }
00297 }
00298 
00299 BOOL
00300 CMSWindowsClientTaskBarReceiver::dlgProc(HWND hwnd,
00301                             UINT msg, WPARAM wParam, LPARAM)
00302 {
00303     switch (msg) {
00304     case WM_INITDIALOG:
00305         // use default focus
00306         return TRUE;
00307 
00308     case WM_ACTIVATE:
00309         // hide when another window is activated
00310         if (LOWORD(wParam) == WA_INACTIVE) {
00311             ShowWindow(hwnd, SW_HIDE);
00312         }
00313         break;
00314     }
00315     return FALSE;
00316 }
00317 
00318 BOOL CALLBACK
00319 CMSWindowsClientTaskBarReceiver::staticDlgProc(HWND hwnd,
00320                             UINT msg, WPARAM wParam, LPARAM lParam)
00321 {
00322     // if msg is WM_INITDIALOG, extract the CMSWindowsClientTaskBarReceiver*
00323     // and put it in the extra window data then forward the call.
00324     CMSWindowsClientTaskBarReceiver* self = NULL;
00325     if (msg == WM_INITDIALOG) {
00326         self = reinterpret_cast<CMSWindowsClientTaskBarReceiver*>(
00327                             reinterpret_cast<void*>(lParam));
00328         SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) lParam);
00329     }
00330     else {
00331         // get the extra window data and forward the call
00332         LONG_PTR data = GetWindowLongPtr(hwnd, GWLP_USERDATA);
00333         if (data != 0) {
00334             self = (CMSWindowsClientTaskBarReceiver*) data;
00335         }
00336     }
00337 
00338     // forward the message
00339     if (self != NULL) {
00340         return self->dlgProc(hwnd, msg, wParam, lParam);
00341     }
00342     else {
00343         return (msg == WM_INITDIALOG) ? TRUE : FALSE;
00344     }
00345 }

Generated on Fri Nov 6 00:21:14 2009 for synergy-plus by  doxygen 1.3.9.1