00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "CArchTaskBarWindows.h"
00020 #include "CArchMiscWindows.h"
00021 #include "IArchTaskBarReceiver.h"
00022 #include "CArch.h"
00023 #include "XArch.h"
00024 #include <string.h>
00025 #include <shellapi.h>
00026 #include "CAppUtilWindows.h"
00027
00028 static const UINT kAddReceiver = WM_USER + 10;
00029 static const UINT kRemoveReceiver = WM_USER + 11;
00030 static const UINT kUpdateReceiver = WM_USER + 12;
00031 static const UINT kNotifyReceiver = WM_USER + 13;
00032 static const UINT kFirstReceiverID = WM_USER + 14;
00033
00034
00035
00036
00037
00038 CArchTaskBarWindows* CArchTaskBarWindows::s_instance = NULL;
00039
00040 CArchTaskBarWindows::CArchTaskBarWindows() :
00041 m_nextID(kFirstReceiverID)
00042 {
00043
00044 s_instance = this;
00045 }
00046
00047 CArchTaskBarWindows::~CArchTaskBarWindows()
00048 {
00049 if (m_thread != NULL) {
00050 PostMessage(m_hwnd, WM_QUIT, 0, 0);
00051 ARCH->wait(m_thread, -1.0);
00052 ARCH->closeThread(m_thread);
00053 }
00054 ARCH->closeCondVar(m_condVar);
00055 ARCH->closeMutex(m_mutex);
00056 s_instance = NULL;
00057 }
00058
00059 void
00060 CArchTaskBarWindows::init()
00061 {
00062
00063 m_mutex = ARCH->newMutex();
00064
00065
00066 m_ready = false;
00067 m_condVar = ARCH->newCondVar();
00068
00069
00070
00071
00072 ARCH->lockMutex(m_mutex);
00073
00074
00075
00076
00077
00078
00079 m_thread = ARCH->newThread(&CArchTaskBarWindows::threadEntry, this);
00080
00081
00082 while (!m_ready) {
00083 ARCH->waitCondVar(m_condVar, m_mutex, -1.0);
00084 }
00085
00086
00087 ARCH->unlockMutex(m_mutex);
00088 }
00089
00090 void
00091 CArchTaskBarWindows::addDialog(HWND hwnd)
00092 {
00093 CArchMiscWindows::addDialog(hwnd);
00094 }
00095
00096 void
00097 CArchTaskBarWindows::removeDialog(HWND hwnd)
00098 {
00099 CArchMiscWindows::removeDialog(hwnd);
00100 }
00101
00102 void
00103 CArchTaskBarWindows::addReceiver(IArchTaskBarReceiver* receiver)
00104 {
00105
00106 if (receiver == NULL) {
00107 return;
00108 }
00109
00110
00111 CReceiverToInfoMap::iterator index = m_receivers.find(receiver);
00112 if (index == m_receivers.end()) {
00113
00114 CReceiverInfo info;
00115 info.m_id = getNextID();
00116 index = m_receivers.insert(std::make_pair(receiver, info)).first;
00117
00118
00119 m_idTable.insert(std::make_pair(info.m_id, index));
00120 }
00121
00122
00123 PostMessage(m_hwnd, kAddReceiver, index->second.m_id, 0);
00124 }
00125
00126 void
00127 CArchTaskBarWindows::removeReceiver(IArchTaskBarReceiver* receiver)
00128 {
00129
00130 CReceiverToInfoMap::iterator index = m_receivers.find(receiver);
00131 if (index == m_receivers.end()) {
00132 return;
00133 }
00134
00135
00136 SendMessage(m_hwnd, kRemoveReceiver, index->second.m_id, 0);
00137
00138
00139 recycleID(index->second.m_id);
00140
00141
00142 m_idTable.erase(index->second.m_id);
00143 m_receivers.erase(index);
00144 }
00145
00146 void
00147 CArchTaskBarWindows::updateReceiver(IArchTaskBarReceiver* receiver)
00148 {
00149
00150 CReceiverToInfoMap::const_iterator index = m_receivers.find(receiver);
00151 if (index == m_receivers.end()) {
00152 return;
00153 }
00154
00155
00156 PostMessage(m_hwnd, kUpdateReceiver, index->second.m_id, 0);
00157 }
00158
00159 UINT
00160 CArchTaskBarWindows::getNextID()
00161 {
00162 if (m_oldIDs.empty()) {
00163 return m_nextID++;
00164 }
00165 UINT id = m_oldIDs.back();
00166 m_oldIDs.pop_back();
00167 return id;
00168 }
00169
00170 void
00171 CArchTaskBarWindows::recycleID(UINT id)
00172 {
00173 m_oldIDs.push_back(id);
00174 }
00175
00176 void
00177 CArchTaskBarWindows::addIcon(UINT id)
00178 {
00179 ARCH->lockMutex(m_mutex);
00180 CIDToReceiverMap::const_iterator index = m_idTable.find(id);
00181 if (index != m_idTable.end()) {
00182 modifyIconNoLock(index->second, NIM_ADD);
00183 }
00184 ARCH->unlockMutex(m_mutex);
00185 }
00186
00187 void
00188 CArchTaskBarWindows::removeIcon(UINT id)
00189 {
00190 ARCH->lockMutex(m_mutex);
00191 removeIconNoLock(id);
00192 ARCH->unlockMutex(m_mutex);
00193 }
00194
00195 void
00196 CArchTaskBarWindows::updateIcon(UINT id)
00197 {
00198 ARCH->lockMutex(m_mutex);
00199 CIDToReceiverMap::const_iterator index = m_idTable.find(id);
00200 if (index != m_idTable.end()) {
00201 modifyIconNoLock(index->second, NIM_MODIFY);
00202 }
00203 ARCH->unlockMutex(m_mutex);
00204 }
00205
00206 void
00207 CArchTaskBarWindows::addAllIcons()
00208 {
00209 ARCH->lockMutex(m_mutex);
00210 for (CReceiverToInfoMap::const_iterator index = m_receivers.begin();
00211 index != m_receivers.end(); ++index) {
00212 modifyIconNoLock(index, NIM_ADD);
00213 }
00214 ARCH->unlockMutex(m_mutex);
00215 }
00216
00217 void
00218 CArchTaskBarWindows::removeAllIcons()
00219 {
00220 ARCH->lockMutex(m_mutex);
00221 for (CReceiverToInfoMap::const_iterator index = m_receivers.begin();
00222 index != m_receivers.end(); ++index) {
00223 removeIconNoLock(index->second.m_id);
00224 }
00225 ARCH->unlockMutex(m_mutex);
00226 }
00227
00228 void
00229 CArchTaskBarWindows::modifyIconNoLock(
00230 CReceiverToInfoMap::const_iterator index, DWORD taskBarMessage)
00231 {
00232
00233 UINT id = index->second.m_id;
00234 IArchTaskBarReceiver* receiver = index->first;
00235
00236
00237 receiver->lock();
00238
00239
00240 HICON icon = reinterpret_cast<HICON>(
00241 const_cast<IArchTaskBarReceiver::Icon>(receiver->getIcon()));
00242
00243
00244 std::string toolTip = receiver->getToolTip();
00245
00246
00247 receiver->unlock();
00248
00249
00250 NOTIFYICONDATA data;
00251 data.cbSize = sizeof(NOTIFYICONDATA);
00252 data.hWnd = m_hwnd;
00253 data.uID = id;
00254 data.uFlags = NIF_MESSAGE;
00255 data.uCallbackMessage = kNotifyReceiver;
00256 data.hIcon = icon;
00257 if (icon != NULL) {
00258 data.uFlags |= NIF_ICON;
00259 }
00260 if (!toolTip.empty()) {
00261 strncpy(data.szTip, toolTip.c_str(), sizeof(data.szTip));
00262 data.szTip[sizeof(data.szTip) - 1] = '\0';
00263 data.uFlags |= NIF_TIP;
00264 }
00265 else {
00266 data.szTip[0] = '\0';
00267 }
00268
00269
00270 if (Shell_NotifyIcon(taskBarMessage, &data) == 0) {
00271
00272 }
00273 }
00274
00275 void
00276 CArchTaskBarWindows::removeIconNoLock(UINT id)
00277 {
00278 NOTIFYICONDATA data;
00279 data.cbSize = sizeof(NOTIFYICONDATA);
00280 data.hWnd = m_hwnd;
00281 data.uID = id;
00282 if (Shell_NotifyIcon(NIM_DELETE, &data) == 0) {
00283
00284 }
00285 }
00286
00287 void
00288 CArchTaskBarWindows::handleIconMessage(
00289 IArchTaskBarReceiver* receiver, LPARAM lParam)
00290 {
00291
00292 switch (lParam) {
00293 case WM_LBUTTONDOWN:
00294 receiver->showStatus();
00295 break;
00296
00297 case WM_LBUTTONDBLCLK:
00298 receiver->primaryAction();
00299 break;
00300
00301 case WM_RBUTTONUP: {
00302 POINT p;
00303 GetCursorPos(&p);
00304 receiver->runMenu(p.x, p.y);
00305 break;
00306 }
00307
00308 case WM_MOUSEMOVE:
00309
00310 break;
00311
00312 default:
00313
00314 break;
00315 }
00316 }
00317
00318 bool
00319 CArchTaskBarWindows::processDialogs(MSG* msg)
00320 {
00321
00322
00323
00324
00325 ARCH->lockMutex(m_mutex);
00326
00327
00328 m_dialogs.erase(false);
00329
00330
00331 for (CDialogs::const_iterator index = m_addedDialogs.begin();
00332 index != m_addedDialogs.end(); ++index) {
00333 m_dialogs.insert(std::make_pair(index->first, index->second));
00334 }
00335 m_addedDialogs.clear();
00336
00337 ARCH->unlockMutex(m_mutex);
00338
00339
00340
00341
00342
00343
00344
00345 ARCH->lockMutex(m_mutex);
00346 for (CDialogs::const_iterator index = m_dialogs.begin();
00347 index != m_dialogs.end(); ++index) {
00348 if (index->second) {
00349 ARCH->unlockMutex(m_mutex);
00350 if (IsDialogMessage(index->first, msg)) {
00351 return true;
00352 }
00353 ARCH->lockMutex(m_mutex);
00354 }
00355 }
00356 ARCH->unlockMutex(m_mutex);
00357
00358 return false;
00359 }
00360
00361 LRESULT
00362 CArchTaskBarWindows::wndProc(HWND hwnd,
00363 UINT msg, WPARAM wParam, LPARAM lParam)
00364 {
00365 switch (msg) {
00366 case kNotifyReceiver: {
00367
00368 CIDToReceiverMap::const_iterator index = m_idTable.find((UINT)wParam);
00369 if (index != m_idTable.end()) {
00370 IArchTaskBarReceiver* receiver = index->second->first;
00371 handleIconMessage(receiver, lParam);
00372 return 0;
00373 }
00374 break;
00375 }
00376
00377 case kAddReceiver:
00378 addIcon((UINT)wParam);
00379 break;
00380
00381 case kRemoveReceiver:
00382 removeIcon((UINT)wParam);
00383 break;
00384
00385 case kUpdateReceiver:
00386 updateIcon((UINT)wParam);
00387 break;
00388
00389 default:
00390 if (msg == m_taskBarRestart) {
00391
00392 addAllIcons();
00393 }
00394 break;
00395 }
00396
00397 return DefWindowProc(hwnd, msg, wParam, lParam);
00398 }
00399
00400 LRESULT CALLBACK
00401 CArchTaskBarWindows::staticWndProc(HWND hwnd, UINT msg,
00402 WPARAM wParam, LPARAM lParam)
00403 {
00404
00405
00406 CArchTaskBarWindows* self = NULL;
00407 if (msg == WM_NCCREATE) {
00408 CREATESTRUCT* createInfo;
00409 createInfo = reinterpret_cast<CREATESTRUCT*>(lParam);
00410 self = reinterpret_cast<CArchTaskBarWindows*>(
00411 createInfo->lpCreateParams);
00412 SetWindowLong(hwnd, 0, reinterpret_cast<LONG>(self));
00413 }
00414 else {
00415
00416 LONG data = GetWindowLong(hwnd, 0);
00417 if (data != 0) {
00418 self = reinterpret_cast<CArchTaskBarWindows*>(
00419 reinterpret_cast<void*>(data));
00420 }
00421 }
00422
00423
00424 if (self != NULL) {
00425 return self->wndProc(hwnd, msg, wParam, lParam);
00426 }
00427 else {
00428 return DefWindowProc(hwnd, msg, wParam, lParam);
00429 }
00430 }
00431
00432 void
00433 CArchTaskBarWindows::threadMainLoop()
00434 {
00435
00436 m_taskBarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
00437
00438
00439 WNDCLASSEX classInfo;
00440 classInfo.cbSize = sizeof(classInfo);
00441 classInfo.style = CS_NOCLOSE;
00442 classInfo.lpfnWndProc = &CArchTaskBarWindows::staticWndProc;
00443 classInfo.cbClsExtra = 0;
00444 classInfo.cbWndExtra = sizeof(CArchTaskBarWindows*);
00445 classInfo.hInstance = instanceWin32();
00446 classInfo.hIcon = NULL;
00447 classInfo.hCursor = NULL;
00448 classInfo.hbrBackground = NULL;
00449 classInfo.lpszMenuName = NULL;
00450 classInfo.lpszClassName = TEXT("SynergyTaskBar");
00451 classInfo.hIconSm = NULL;
00452 ATOM windowClass = RegisterClassEx(&classInfo);
00453
00454
00455 m_hwnd = CreateWindowEx(WS_EX_TOOLWINDOW,
00456 reinterpret_cast<LPCTSTR>(windowClass),
00457 TEXT("Synergy Task Bar"),
00458 WS_POPUP,
00459 0, 0, 1, 1,
00460 NULL,
00461 NULL,
00462 instanceWin32(),
00463 reinterpret_cast<void*>(this));
00464
00465
00466 ARCH->lockMutex(m_mutex);
00467 m_ready = true;
00468 ARCH->broadcastCondVar(m_condVar);
00469 ARCH->unlockMutex(m_mutex);
00470
00471
00472 if (m_hwnd == NULL) {
00473 UnregisterClass(reinterpret_cast<LPCTSTR>(windowClass), instanceWin32());
00474 return;
00475 }
00476
00477
00478 MSG msg;
00479 while (GetMessage(&msg, NULL, 0, 0)) {
00480 if (!processDialogs(&msg)) {
00481 TranslateMessage(&msg);
00482 DispatchMessage(&msg);
00483 }
00484 }
00485
00486
00487 removeAllIcons();
00488 DestroyWindow(m_hwnd);
00489 UnregisterClass(reinterpret_cast<LPCTSTR>(windowClass), instanceWin32());
00490 }
00491
00492 void*
00493 CArchTaskBarWindows::threadEntry(void* self)
00494 {
00495 reinterpret_cast<CArchTaskBarWindows*>(self)->threadMainLoop();
00496 return NULL;
00497 }
00498
00499 HINSTANCE CArchTaskBarWindows::instanceWin32()
00500 {
00501 return CArchMiscWindows::instanceWin32();
00502 }