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

Generated on Fri Nov 6 00:18:45 2009 for synergy-plus by  doxygen 1.4.7