source: trunk/synergy/lib/arch/CArchTaskBarOS2.cpp@ 2752

Last change on this file since 2752 was 2752, checked in by bird, 19 years ago

Two classes (CPMScreen and CPMKeyState) + the hook dll left (and debugging of course).

File size: 11.6 KB
Line 
1/*
2 * synergy -- mouse and keyboard sharing utility
3 * Copyright (C) 2003 Chris Schoeneman
4 *
5 * This package is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * found in the file COPYING that should have accompanied this file.
8 *
9 * This package is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include "CArchTaskBarOS2.h"
16#include "IArchTaskBarReceiver.h"
17#include "CArch.h"
18#include "XArch.h"
19#include <string.h>
20/** @todo xwp */
21
22static const ULONG kAddReceiver = WM_USER + 10;
23static const ULONG kRemoveReceiver = WM_USER + 11;
24static const ULONG kUpdateReceiver = WM_USER + 12;
25static const ULONG kNotifyReceiver = WM_USER + 13;
26static const ULONG kFirstReceiverID = WM_USER + 14;
27
28//
29// CArchTaskBarWindows
30//
31
32CArchTaskBarOS2* CArchTaskBarOS2::s_instance = NULL;
33
34CArchTaskBarOS2::CArchTaskBarOS2(void* appInstance) :
35 m_nextID(kFirstReceiverID)
36{
37 // we need a mutex
38 m_mutex = ARCH->newMutex();
39
40 // and a condition variable which uses the above mutex
41 m_ready = false;
42 m_condVar = ARCH->newCondVar();
43
44 // we're going to want to get a result from the thread we're
45 // about to create to know if it initialized successfully.
46 // so we lock the condition variable.
47 ARCH->lockMutex(m_mutex);
48
49#if 0 /* later */
50 // open a window and run an event loop in a separate thread.
51 // this has to happen in a separate thread because if we
52 // create a window on the current desktop with the current
53 // thread then the current thread won't be able to switch
54 // desktops if it needs to.
55 m_thread = ARCH->newThread(&CArchTaskBarOS2::threadEntry, this);
56
57 // wait for child thread
58 while (!m_ready) {
59 ARCH->waitCondVar(m_condVar, m_mutex, -1.0);
60 }
61#else
62 m_thread = NULL;
63#endif /* later */
64
65 // ready
66 ARCH->unlockMutex(m_mutex);
67}
68
69CArchTaskBarOS2::~CArchTaskBarOS2()
70{
71 if (m_thread != NULL) {
72 WinPostMsg(m_hwnd, WM_QUIT, 0, 0);
73 ARCH->wait(m_thread, -1.0);
74 ARCH->closeThread(m_thread);
75 }
76 ARCH->closeCondVar(m_condVar);
77 ARCH->closeMutex(m_mutex);
78}
79
80void
81CArchTaskBarOS2::addDialog(HWND hwnd)
82{
83//later CArchMiscWindows::addDialog(hwnd);
84}
85
86void
87CArchTaskBarOS2::removeDialog(HWND hwnd)
88{
89//later CArchMiscWindows::removeDialog(hwnd);
90}
91
92void
93CArchTaskBarOS2::addReceiver(IArchTaskBarReceiver* receiver)
94{
95 // ignore bogus receiver
96 if (receiver == NULL) {
97 return;
98 }
99
100 // add receiver if necessary
101 CReceiverToInfoMap::iterator index = m_receivers.find(receiver);
102 if (index == m_receivers.end()) {
103 // add it, creating a new message ID for it
104 CReceiverInfo info;
105 info.m_id = getNextID();
106 index = m_receivers.insert(std::make_pair(receiver, info)).first;
107
108 // add ID to receiver mapping
109 m_idTable.insert(std::make_pair(info.m_id, index));
110 }
111
112 // add receiver
113 WinPostMsg(m_hwnd, kAddReceiver, (MPARAM)index->second.m_id, 0);
114}
115
116void
117CArchTaskBarOS2::removeReceiver(IArchTaskBarReceiver* receiver)
118{
119 // find receiver
120 CReceiverToInfoMap::iterator index = m_receivers.find(receiver);
121 if (index == m_receivers.end()) {
122 return;
123 }
124
125 // remove icon. wait for this to finish before returning.
126 WinSendMsg(m_hwnd, kRemoveReceiver, (MPARAM)index->second.m_id, 0);
127
128 // recycle the ID
129 recycleID(index->second.m_id);
130
131 // discard
132 m_idTable.erase(index->second.m_id);
133 m_receivers.erase(index);
134}
135
136void
137CArchTaskBarOS2::updateReceiver(IArchTaskBarReceiver* receiver)
138{
139 // find receiver
140 CReceiverToInfoMap::const_iterator index = m_receivers.find(receiver);
141 if (index == m_receivers.end()) {
142 return;
143 }
144
145 // update icon and tool tip
146 WinPostMsg(m_hwnd, kUpdateReceiver, (MPARAM)index->second.m_id, 0);
147}
148
149ULONG
150CArchTaskBarOS2::getNextID()
151{
152 if (m_oldIDs.empty()) {
153 return m_nextID++;
154 }
155 ULONG id = m_oldIDs.back();
156 m_oldIDs.pop_back();
157 return id;
158}
159
160void
161CArchTaskBarOS2::recycleID(ULONG id)
162{
163 m_oldIDs.push_back(id);
164}
165
166void
167CArchTaskBarOS2::addIcon(ULONG id)
168{
169 ARCH->lockMutex(m_mutex);
170 CIDToReceiverMap::const_iterator index = m_idTable.find(id);
171 if (index != m_idTable.end()) {
172//later modifyIconNoLock(index->second, NIM_ADD);
173 }
174 ARCH->unlockMutex(m_mutex);
175}
176
177void
178CArchTaskBarOS2::removeIcon(ULONG id)
179{
180 ARCH->lockMutex(m_mutex);
181 removeIconNoLock(id);
182 ARCH->unlockMutex(m_mutex);
183}
184
185void
186CArchTaskBarOS2::updateIcon(ULONG id)
187{
188 ARCH->lockMutex(m_mutex);
189 CIDToReceiverMap::const_iterator index = m_idTable.find(id);
190 if (index != m_idTable.end()) {
191//later modifyIconNoLock(index->second, NIM_MODIFY);
192 }
193 ARCH->unlockMutex(m_mutex);
194}
195
196void
197CArchTaskBarOS2::addAllIcons()
198{
199 ARCH->lockMutex(m_mutex);
200 for (CReceiverToInfoMap::const_iterator index = m_receivers.begin();
201 index != m_receivers.end(); ++index) {
202//later modifyIconNoLock(index, NIM_ADD);
203 }
204 ARCH->unlockMutex(m_mutex);
205}
206
207void
208CArchTaskBarOS2::removeAllIcons()
209{
210 ARCH->lockMutex(m_mutex);
211 for (CReceiverToInfoMap::const_iterator index = m_receivers.begin();
212 index != m_receivers.end(); ++index) {
213 removeIconNoLock(index->second.m_id);
214 }
215 ARCH->unlockMutex(m_mutex);
216}
217
218void
219CArchTaskBarOS2::modifyIconNoLock(
220 CReceiverToInfoMap::const_iterator index, ULONG taskBarMessage)
221{
222#if 0
223 // get receiver
224 ULONG id = index->second.m_id;
225 IArchTaskBarReceiver* receiver = index->first;
226
227 // lock receiver so icon and tool tip are guaranteed to be consistent
228 receiver->lock();
229
230 // get icon data
231 HICON icon = reinterpret_cast<HICON>(
232 const_cast<IArchTaskBarReceiver::Icon>(receiver->getIcon()));
233
234 // get tool tip
235 std::string toolTip = receiver->getToolTip();
236
237 // done querying
238 receiver->unlock();
239
240 // prepare to add icon
241 NOTIFYICONDATA data;
242 data.cbSize = sizeof(NOTIFYICONDATA);
243 data.hWnd = m_hwnd;
244 data.uID = id;
245 data.uFlags = NIF_MESSAGE;
246 data.uCallbackMessage = kNotifyReceiver;
247 data.hIcon = icon;
248 if (icon != NULL) {
249 data.uFlags |= NIF_ICON;
250 }
251 if (!toolTip.empty()) {
252 strncpy(data.szTip, toolTip.c_str(), sizeof(data.szTip));
253 data.szTip[sizeof(data.szTip) - 1] = '\0';
254 data.uFlags |= NIF_TIP;
255 }
256 else {
257 data.szTip[0] = '\0';
258 }
259
260 // add icon
261 if (Shell_NotifyIcon(taskBarMessage, &data) == 0) {
262 // failed
263 }
264#endif
265}
266
267void
268CArchTaskBarOS2::removeIconNoLock(ULONG id)
269{
270#if 0 /*later*/
271 NOTIFYICONDATA data;
272 data.cbSize = sizeof(NOTIFYICONDATA);
273 data.hWnd = m_hwnd;
274 data.uID = id;
275 if (Shell_NotifyIcon(NIM_DELETE, &data) == 0) {
276 // failed
277 }
278#endif
279}
280
281void
282CArchTaskBarOS2::handleIconMessage(
283 IArchTaskBarReceiver* receiver, MPARAM lParam)
284{
285 // process message
286 switch ((ULONG)lParam) {
287 case WM_BUTTON2DOWN:
288 receiver->showStatus();
289 break;
290
291 case WM_BUTTON2DBLCLK:
292 receiver->primaryAction();
293 break;
294
295 case WM_BUTTON2UP: {
296 CURSORINFO info;
297 if (!WinQueryCursorInfo(HWND_DESKTOP, &info)) {
298 info.x = 10;
299 info.y = 10;
300 }
301 receiver->runMenu(info.x, info.y);
302 break;
303 }
304
305 case WM_MOUSEMOVE:
306 // currently unused
307 break;
308
309 default:
310 // unused
311 break;
312 }
313}
314
315bool
316CArchTaskBarOS2::processDialogs(QMSG * msg)
317{
318#if 0 /* later */
319 // only one thread can be in this method on any particular object
320 // at any given time. that's not a problem since only our event
321 // loop calls this method and there's just one of those.
322
323 ARCH->lockMutex(m_mutex);
324
325 // remove removed dialogs
326 m_dialogs.erase(false);
327
328 // merge added dialogs into the dialog list
329 for (CDialogs::const_iterator index = m_addedDialogs.begin();
330 index != m_addedDialogs.end(); ++index) {
331 m_dialogs.insert(std::make_pair(index->first, index->second));
332 }
333 m_addedDialogs.clear();
334
335 ARCH->unlockMutex(m_mutex);
336
337 // check message against all dialogs until one handles it.
338 // note that we don't hold a lock while checking because
339 // the message is processed and may make calls to this
340 // object. that's okay because addDialog() and
341 // removeDialog() don't change the map itself (just the
342 // values of some elements).
343 ARCH->lockMutex(m_mutex);
344 for (CDialogs::const_iterator index = m_dialogs.begin();
345 index != m_dialogs.end(); ++index) {
346 if (index->second) {
347 ARCH->unlockMutex(m_mutex);
348 if (IsDialogMessage(index->first, msg)) {
349 return true;
350 }
351 ARCH->lockMutex(m_mutex);
352 }
353 }
354 ARCH->unlockMutex(m_mutex);
355#endif /* later */
356 return false;
357}
358
359MRESULT
360CArchTaskBarOS2::wndProc(HWND hwnd,
361 ULONG msg, MPARAM wParam, MPARAM lParam)
362{
363 switch (msg) {
364 case kNotifyReceiver: {
365 // lookup receiver
366 CIDToReceiverMap::const_iterator index = m_idTable.find((ULONG)wParam);
367 if (index != m_idTable.end()) {
368 IArchTaskBarReceiver* receiver = index->second->first;
369 handleIconMessage(receiver, lParam);
370 return 0;
371 }
372 break;
373 }
374
375 case kAddReceiver:
376 addIcon((ULONG)wParam);
377 break;
378
379 case kRemoveReceiver:
380 removeIcon((ULONG)wParam);
381 break;
382
383 case kUpdateReceiver:
384 updateIcon((ULONG)wParam);
385 break;
386
387 default:
388 if (msg == m_taskBarRestart) {
389 // task bar was recreated so re-add our icons
390 addAllIcons();
391 }
392 break;
393 }
394
395 return WinDefWindowProc(hwnd, msg, wParam, lParam);
396}
397
398MRESULT EXPENTRY
399CArchTaskBarOS2::staticWndProc(HWND hwnd, ULONG msg,
400 MPARAM wParam, MPARAM lParam)
401{
402#if 0 /*later*/
403 // if msg is WM_NCCREATE, extract the CArchTaskBarOS2* and put
404 // it in the extra window data then forward the call.
405 CArchTaskBarOS2* self = NULL;
406 if (msg == WM_CREATE) {
407 CREATESTRUCT* createInfo;
408 createInfo = reinterpret_cast<CREATESTRUCT*>(lParam);
409 self = reinterpret_cast<CArchTaskBarOS2*>(
410 createInfo->lpCreateParams);
411 SetWindowLong(hwnd, 0, reinterpret_cast<LONG>(self));
412 }
413 else {
414 // get the extra window data and forward the call
415 LONG data = GetWindowLong(hwnd, 0);
416 if (data != 0) {
417 self = reinterpret_cast<CArchTaskBarOS2*>(
418 reinterpret_cast<void*>(data));
419 }
420 }
421
422 // forward the message
423 if (self != NULL) {
424 return self->wndProc(hwnd, msg, wParam, lParam);
425 }
426 else {
427 return DefWindowProc(hwnd, msg, wParam, lParam);
428 }
429#endif
430}
431
432void
433CArchTaskBarOS2::threadMainLoop()
434{
435#if 0 /*later*/
436 // register the task bar restart message
437 m_taskBarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
438
439 // register a window class
440 WNDCLASSEX classInfo;
441 classInfo.cbSize = sizeof(classInfo);
442 classInfo.style = CS_NOCLOSE;
443 classInfo.lpfnWndProc = &CArchTaskBarOS2::staticWndProc;
444 classInfo.cbClsExtra = 0;
445 classInfo.cbWndExtra = sizeof(CArchTaskBarOS2*);
446 classInfo.hInstance = s_appInstance;
447 classInfo.hIcon = NULL;
448 classInfo.hCursor = NULL;
449 classInfo.hbrBackground = NULL;
450 classInfo.lpszMenuName = NULL;
451 classInfo.lpszClassName = TEXT("SynergyTaskBar");
452 classInfo.hIconSm = NULL;
453 ATOM windowClass = RegisterClassEx(&classInfo);
454
455 // create window
456 m_hwnd = CreateWindowEx(WS_EX_TOOLWINDOW,
457 reinterpret_cast<LPCTSTR>(windowClass),
458 TEXT("Synergy Task Bar"),
459 WS_POPUP,
460 0, 0, 1, 1,
461 NULL,
462 NULL,
463 s_appInstance,
464 reinterpret_cast<void*>(this));
465
466 // signal ready
467 ARCH->lockMutex(m_mutex);
468 m_ready = true;
469 ARCH->broadcastCondVar(m_condVar);
470 ARCH->unlockMutex(m_mutex);
471
472 // handle failure
473 if (m_hwnd == NULL) {
474 UnregisterClass(reinterpret_cast<LPCTSTR>(windowClass), s_appInstance);
475 return;
476 }
477
478 // main loop
479 MSG msg;
480 while (GetMessage(&msg, NULL, 0, 0)) {
481 if (!processDialogs(&msg)) {
482 TranslateMessage(&msg);
483 DispatchMessage(&msg);
484 }
485 }
486
487 // clean up
488 removeAllIcons();
489 DestroyWindow(m_hwnd);
490 UnregisterClass(reinterpret_cast<LPCTSTR>(windowClass), s_appInstance);
491#endif /* later */
492}
493
494void*
495CArchTaskBarOS2::threadEntry(void* self)
496{
497 reinterpret_cast<CArchTaskBarOS2*>(self)->threadMainLoop();
498 return NULL;
499}
Note: See TracBrowser for help on using the repository browser.