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