xref: /haiku/src/apps/autoraise/AutoRaiseIcon.cpp (revision 9760dcae2038d47442f4658c2575844c6cf92c40)
1 /* this is for the DANO hack (new, simpler version than the BStringIO hack) */
2 #include <BeBuild.h>
3 #ifdef B_BEOS_VERSION_DANO
4 #define private public
5 #include <Messenger.h>
6 #undef private
7 #endif
8 
9 #include "AutoRaiseIcon.h"
10 #include <stdlib.h>
11 #include <DataIO.h>
12 #include <Screen.h>
13 #include <View.h>
14 #include <Debug.h>
15 
16 
17 extern "C" _EXPORT BView *instantiate_deskbar_item(void)
18 {
19 	puts("Instanciating AutoRaise TrayView...");
20 	return (new TrayView);
21 }
22 
23 
24 long removeFromDeskbar(void *)
25 {
26 	BDeskbar db;
27 	if (db.RemoveItem(APP_NAME) != B_OK)
28 		printf("Unable to remove AutoRaise from BDeskbar\n");
29 
30 	return 0;
31 }
32 
33 //**************************************************
34 
35 ConfigMenu::ConfigMenu(TrayView *tv, bool useMag)
36 	:BPopUpMenu("config_popup", false, false){
37 
38 	BMenu *tmpm;
39 	BMenuItem *tmpi;
40 	BMessage *msg;
41 	bigtime_t delay;
42 
43 	AutoRaiseSettings *s = tv->Settings();
44 
45 	SetFont(be_plain_font);
46 
47 
48 	BMenuItem *active = new BMenuItem("Active", new BMessage(MSG_TOOGLE_ACTIVE));
49 	active->SetMarked(s->Active());
50 	AddItem(active);
51 
52 	tmpm = new BMenu("Mode");
53 	tmpm->SetFont(be_plain_font);
54 
55 	msg = new BMessage(MSG_SET_MODE);
56 	msg->AddInt32(AR_MODE, Mode_All);
57 	tmpi = new BMenuItem("Default (all windows)", msg);
58 	tmpi->SetMarked(s->Mode() == Mode_All);
59 	tmpm->AddItem(tmpi);
60 
61 	msg = new BMessage(MSG_SET_MODE);
62 	msg->AddInt32(AR_MODE, Mode_DeskbarOver);
63 	tmpi = new BMenuItem("Deskbar only (over its area)", msg);
64 	tmpi->SetMarked(s->Mode() == Mode_DeskbarOver);
65 #ifdef USE_DANO_HACK
66 	tmpi->SetEnabled(false);
67 #endif
68 	tmpm->AddItem(tmpi);
69 
70 	msg = new BMessage(MSG_SET_MODE);
71 	msg->AddInt32(AR_MODE, Mode_DeskbarTouch);
72 	tmpi = new BMenuItem("Deskbar only (touch)", msg);
73 	tmpi->SetMarked(s->Mode() == Mode_DeskbarTouch);
74 	tmpm->AddItem(tmpi);
75 
76 
77 	tmpm->SetTargetForItems(tv);
78 	BMenuItem *modem = new BMenuItem(tmpm);
79 	modem->SetEnabled(s->Active());
80 	AddItem(modem);
81 
82 	tmpm = new BMenu("Inactive behaviour");
83 	tmpm->SetFont(be_plain_font);
84 
85 	msg = new BMessage(MSG_SET_BEHAVIOUR);
86 	msg->AddInt32(AR_BEHAVIOUR, B_NORMAL_MOUSE);
87 	tmpi = new BMenuItem("Normal", msg);
88 	tmpi->SetMarked(tv->fNormalMM == B_NORMAL_MOUSE);
89 	tmpm->AddItem(tmpi);
90 
91 	msg = new BMessage(MSG_SET_BEHAVIOUR);
92 	msg->AddInt32(AR_BEHAVIOUR, B_FOCUS_FOLLOWS_MOUSE);
93 	tmpi = new BMenuItem("Focus follows mouse", msg);
94 	tmpi->SetMarked(tv->fNormalMM == B_FOCUS_FOLLOWS_MOUSE);
95 	tmpm->AddItem(tmpi);
96 
97 	msg = new BMessage(MSG_SET_BEHAVIOUR);
98 	msg->AddInt32(AR_BEHAVIOUR, B_WARP_FOCUS_FOLLOWS_MOUSE);
99 	tmpi = new BMenuItem("Warping (ffm)", msg);
100 	tmpi->SetMarked(tv->fNormalMM == B_WARP_FOCUS_FOLLOWS_MOUSE);
101 	tmpm->AddItem(tmpi);
102 
103 	msg = new BMessage(MSG_SET_BEHAVIOUR);
104 	msg->AddInt32(AR_BEHAVIOUR, B_INSTANT_WARP_FOCUS_FOLLOWS_MOUSE);
105 	tmpi = new BMenuItem("Instant warping (ffm)", msg);
106 	tmpi->SetMarked(tv->fNormalMM == B_INSTANT_WARP_FOCUS_FOLLOWS_MOUSE);
107 	tmpm->AddItem(tmpi);
108 
109 	tmpm->SetTargetForItems(tv);
110 	BMenuItem *behavm = new BMenuItem(tmpm);
111 	AddItem(behavm);
112 
113 
114 	tmpm = new BMenu("Delay");
115 	tmpm->SetFont(be_plain_font);
116 
117 	msg = new BMessage(MSG_SET_DELAY);
118 	msg->AddInt64(AR_DELAY, 100000LL);
119 	tmpi = new BMenuItem("0.1 s", msg);
120 	tmpi->SetMarked(tv->raise_delay == 100000LL);
121 	tmpm->AddItem(tmpi);
122 
123 	msg = new BMessage(MSG_SET_DELAY);
124 	msg->AddInt64(AR_DELAY, 200000LL);
125 	tmpi = new BMenuItem("0.2 s", msg);
126 	tmpi->SetMarked(tv->raise_delay == 200000LL);
127 	tmpm->AddItem(tmpi);
128 
129 	msg = new BMessage(MSG_SET_DELAY);
130 	msg->AddInt64(AR_DELAY, 500000LL);
131 	tmpi = new BMenuItem("0.5 s", msg);
132 	tmpi->SetMarked(tv->raise_delay == 500000LL);
133 	tmpm->AddItem(tmpi);
134 
135 	msg = new BMessage(MSG_SET_DELAY);
136 	msg->AddInt64(AR_DELAY, 1000000LL);
137 	tmpi = new BMenuItem("1 s", msg);
138 	tmpi->SetMarked(tv->raise_delay == 1000000LL);
139 	tmpm->AddItem(tmpi);
140 
141 	msg = new BMessage(MSG_SET_DELAY);
142 	msg->AddInt64(AR_DELAY, 2000000LL);
143 	tmpi = new BMenuItem("2 s", msg);
144 	tmpi->SetMarked(tv->raise_delay == 2000000LL);
145 	tmpm->AddItem(tmpi);
146 
147 	msg = new BMessage(MSG_SET_DELAY);
148 	msg->AddInt64(AR_DELAY, 3000000LL);
149 	tmpi = new BMenuItem("3 s", msg);
150 	tmpi->SetMarked(tv->raise_delay == 3000000LL);
151 	tmpm->AddItem(tmpi);
152 
153 	msg = new BMessage(MSG_SET_DELAY);
154 	msg->AddInt64(AR_DELAY, 4000000LL);
155 	tmpi = new BMenuItem("4 s", msg);
156 	tmpi->SetMarked(tv->raise_delay == 4000000LL);
157 	tmpm->AddItem(tmpi);
158 
159 	msg = new BMessage(MSG_SET_DELAY);
160 	msg->AddInt64(AR_DELAY, 5000000LL);
161 	tmpi = new BMenuItem("5 s", msg);
162 	tmpi->SetMarked(tv->raise_delay == 5000000LL);
163 	tmpm->AddItem(tmpi);
164 
165 	tmpm->SetTargetForItems(tv);
166 	BMenuItem *delaym = new BMenuItem(tmpm);
167 	delaym->SetEnabled(s->Active());
168 
169 	AddItem(delaym);
170 
171 	AddSeparatorItem();
172 //	AddItem(new BMenuItem("Settings...", new BMessage(OPEN_SETTINGS)));
173 
174 	AddItem(new BMenuItem("About "APP_NAME B_UTF8_ELLIPSIS,
175 		new BMessage(B_ABOUT_REQUESTED)));
176 	AddItem(new BMenuItem("Remove from tray", new BMessage(REMOVE_FROM_TRAY)));
177 
178 	SetTargetForItems(tv);
179 	SetAsyncAutoDestruct(true);
180 }
181 
182 ConfigMenu::~ConfigMenu() {}
183 
184 //************************************************
185 
186 TrayView::TrayView()
187 	:BView(BRect(0, 0, B_MINI_ICON, B_MINI_ICON -1), "AutoRaise", B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW){
188 	_init(); 	//Initialization common to both constructors
189 }
190 
191 //Rehydratable constructor
192 TrayView::TrayView(BMessage *mdArchive):BView(mdArchive){
193 	_init();		//As above
194 }
195 
196 void TrayView::GetPreferredSize(float *w, float *h)
197 {
198 	*w = B_MINI_ICON;
199 	*h = B_MINI_ICON - 1;
200 }
201 
202 void TrayView::_init()
203 {
204 	thread_info ti;
205 	status_t err;
206 
207 	watching = false;
208 	_settings = new AutoRaiseSettings;
209 
210 	_appPath = _settings->AppPath();
211 
212 	raise_delay = _settings->Delay();
213 	current_window = 0;
214 	polling_delay = 100000;
215 	fPollerSem = create_sem(0, "AutoRaise poller sync");
216 	last_raiser_thread = 0;
217 	fNormalMM = mouse_mode();
218 
219 	_activeIcon = NULL;
220 	_inactiveIcon = NULL;
221 
222 	get_thread_info(find_thread(NULL), &ti);
223 	fDeskbarTeam = ti.team;
224 
225 #ifndef USE_DANO_HACK
226 	resume_thread(poller_thread = spawn_thread(poller, "AutoRaise desktop "
227 		"poller", B_NORMAL_PRIORITY, (void *)this));
228 #endif
229 
230 	//determine paths to icon files based on app path in settings file
231 
232 	BResources res;
233 	BFile theapp(&_appPath, B_READ_ONLY);
234 	if ((err = res.SetTo(&theapp)) != B_OK) {
235 
236 		printf("Unable to find the app to get the resources !!!\n");
237 //		removeFromDeskbar(NULL);
238 //		delete _settings;
239 //		return;
240 	}
241 
242 	size_t bmsz;
243 	char *p;
244 
245 	p = (char *)res.LoadResource('MICN', ACTIVE_ICON, &bmsz);
246 	_activeIcon = new BBitmap(BRect(0, 0, B_MINI_ICON-1, B_MINI_ICON -1),
247 		B_CMAP8);
248 	if (!p)
249 		puts("ERROR loading active icon");
250 	else
251 		_activeIcon->SetBits(p, B_MINI_ICON*B_MINI_ICON, 0, B_CMAP8);
252 
253 	p = (char *)res.LoadResource('MICN', INACTIVE_ICON, &bmsz);
254 	_inactiveIcon = new BBitmap(BRect(0, 0, B_MINI_ICON-1, B_MINI_ICON -1),
255 		B_CMAP8);
256 	if (!p)
257 		puts("ERROR loading inactive icon");
258 	else
259 		_inactiveIcon->SetBits(p, B_MINI_ICON*B_MINI_ICON, 0, B_CMAP8);
260 
261 
262 	SetDrawingMode(B_OP_ALPHA);
263 	SetFlags(Flags() | B_WILL_DRAW);
264 
265 	// begin watching if we want
266 	// (doesn't work here, better do it in AttachedToWindow())
267 }
268 
269 TrayView::~TrayView(){
270 	status_t ret;
271 
272 	if (watching) {
273 #ifdef USE_DANO_HACK
274 		be_roster->StopWatching(this);
275 #else
276 //		acquire_sem(fPollerSem);
277 #endif
278 		set_mouse_mode(fNormalMM);
279 		watching = false;
280 	}
281 	delete_sem(fPollerSem);
282 #ifndef USE_DANO_HACK
283 	wait_for_thread(poller_thread, &ret);
284 #endif
285 	if (_activeIcon) delete _activeIcon;
286 	if (_inactiveIcon) delete _inactiveIcon;
287 	if (_settings) delete _settings;
288 
289 	return;
290 }
291 
292 //Dehydrate into a message (called by the DeskBar)
293 status_t TrayView::Archive(BMessage *data, bool deep = true) const {
294 //	BEntry appentry(&_appPath, true);
295 //	BPath appPath(&appentry);
296 	status_t error=BView::Archive(data, deep);
297 	data->AddString("add_on", APP_SIG);
298 //	data->AddFlat("_appPath", (BFlattenable *) &_appPath);
299 	data->AddRef("_appPath", &_appPath);
300 
301 	return B_NO_ERROR;
302 }
303 
304 //Rehydrate the View from a given message (called by the DeskBar)
305 TrayView *TrayView::Instantiate(BMessage *data) {
306 
307 	if (!validate_instantiation(data, "TrayView"))
308 	{
309 		return NULL;
310 	}
311 
312 	return (new TrayView(data));
313 }
314 
315 void TrayView::AttachedToWindow() {
316 	if(Parent())
317 		SetViewColor(Parent()->ViewColor());
318 		if (_settings->Active()) {
319 			fNormalMM = mouse_mode();
320 			set_mouse_mode(B_FOCUS_FOLLOWS_MOUSE);
321 #ifdef USE_DANO_HACK
322 			be_roster->StartWatching(this, B_REQUEST_WINDOW_ACTIVATED);
323 #else
324 			release_sem(fPollerSem);
325 #endif
326 			watching = true;
327 		}
328 }
329 
330 void TrayView::Draw(BRect updaterect) {
331 	BRect bnds(Bounds());
332 
333 	if (Parent()) SetHighColor(Parent()->ViewColor());
334 	else SetHighColor(189, 186, 189, 255);
335 	FillRect(bnds);
336 
337 	if (_settings->Active())
338 	{
339 		if (_activeIcon) DrawBitmap(_activeIcon);
340 	}
341 	else
342 	{
343 		if (_inactiveIcon) DrawBitmap(_inactiveIcon);
344 	}
345 }
346 
347 void TrayView::MouseDown(BPoint where) {
348 	BWindow *window = Window();	/*To handle the MouseDown message*/
349 	if (!window)	/*Check for proper instantiation*/
350 		return;
351 
352 	BMessage *mouseMsg = window->CurrentMessage();
353 	if (!mouseMsg)	/*Check for existence*/
354 		return;
355 
356 	if (mouseMsg->what == B_MOUSE_DOWN) {
357 		/*Variables for storing the button pressed / modifying key*/
358 		uint32 	buttons = 0;
359 		uint32  modifiers = 0;
360 
361 		/*Get the button pressed*/
362 		mouseMsg->FindInt32("buttons", (int32 *) &buttons);
363 		/*Get modifier key (if any)*/
364 		mouseMsg->FindInt32("modifiers", (int32 *) &modifiers);
365 
366 		/*Now perform action*/
367 		switch(buttons) {
368 			case B_PRIMARY_MOUSE_BUTTON:
369 			{
370 				SetActive(!_settings->Active());
371 
372 				break;
373 			}
374 			case B_SECONDARY_MOUSE_BUTTON:
375 			{
376 				ConvertToScreen(&where);
377 
378 				//menu will delete itself (see constructor of ConfigMenu),
379 				//so all we're concerned about is calling Go() asynchronously
380 				ConfigMenu *menu = new ConfigMenu(this, false);
381 				menu->Go(where, true, true, ConvertToScreen(Bounds()), true);
382 
383 				break;
384 			}
385 		}
386 	}
387 }
388 
389 
390 int32 fronter(void *arg)
391 {
392 	TrayView *tv = (TrayView *)arg;
393 	int32 tok = tv->current_window;
394 	int32 ws = current_workspace();
395 	sem_id sem = tv->fPollerSem;
396 	int32 *tl, tlc;
397 	window_info *wi;
398 
399 	snooze(tv->raise_delay);
400 
401 #ifndef USE_DANO_HACK
402 	if (acquire_sem(sem) != B_OK)
403 		return B_OK; // this really needs a better locking model...
404 #endif
405 	if (ws != current_workspace())
406 		goto end; // don't touch windows if we changed workspace
407 	if (tv->last_raiser_thread != find_thread(NULL))
408 		goto end; // seems a newer one has been spawn, exit
409 PRINT(("tok = %ld cw = %ld\n", tok, tv->current_window));
410 	if (tok == tv->current_window) {
411 		bool doZoom = false;
412 		BRect zoomRect(0.0f, 0.0f, 10.0f, 10.0f);
413 		do_window_action(tok, B_BRING_TO_FRONT, zoomRect, doZoom);
414 	}
415 
416 	end:
417 	release_sem(sem);
418 	return B_OK;
419 }
420 
421 #ifndef USE_DANO_HACK
422 
423 int32 poller(void *arg)
424 {
425 	TrayView *tv = (TrayView *)arg;
426 	volatile int32 tok = tv->current_window;
427 	int32 *tl = NULL;
428 	int32 i, tlc;
429 	window_info *wi = NULL;
430 
431 	int pass=0;
432 	BPoint mouse;
433 	uint32 buttons;
434 
435 	while (acquire_sem(tv->fPollerSem) == B_OK) {
436 		release_sem(tv->fPollerSem);
437 		pass++;
438 		BLooper *l = tv->Looper();
439 		if (!l || l->LockWithTimeout(500000) != B_OK)
440 			continue;
441 		tv->GetMouse(&mouse, &buttons);
442 		tv->ConvertToScreen(&mouse);
443 		tv->Looper()->Unlock();
444 		if (buttons) // we don't want to interfere when the user is moving a window or something...
445 			goto zzz;
446 
447 		tl = get_token_list(-1, &tlc);
448 		for (i=0; i<tlc; i++) {
449 			wi = get_window_info(tl[i]);
450 			if (wi) {
451 				if (wi->layer < 3) // we hit the desktop or a window not on this WS
452 					goto zzz;
453 				if ((wi->window_left > wi->window_right) || (wi->window_top > wi->window_bottom))
454 					goto zzz; // invalid window ?
455 /*
456 printf("if (!%s && (%li, %li)isin(%li)(%li, %li, %li, %li) && (%li != %li) ", wi->is_mini?"true":"false",
457 	(long)mouse.x, (long)mouse.y, i, wi->window_left, wi->window_right, wi->window_top, wi->window_bottom, wi->id, tok);
458 */
459 
460 
461 				if ((!wi->is_mini)
462 						&& (((long)mouse.x) > wi->window_left) && (((long)mouse.x) < wi->window_right)
463 						&& (((long)mouse.y) > wi->window_top) && (((long)mouse.y) < wi->window_bottom)) {
464 //((tv->_settings->Mode() != Mode_DeskbarOver) || (wi->team == tv->fDeskbarTeam))
465 
466 					if ((tv->_settings->Mode() == Mode_All) && (wi->id == tv->current_window))
467 						goto zzz; // already raised
468 
469 					if ((tv->_settings->Mode() == Mode_All) || (wi->team == tv->fDeskbarTeam)) {
470 						tv->current_window = wi->id;
471 						tok = wi->id;
472 						resume_thread(tv->last_raiser_thread = spawn_thread(fronter, "fronter", B_NORMAL_PRIORITY, (void *)tv));
473 						goto zzz;
474 					} else if (tv->_settings->Mode() == Mode_DeskbarTouch) // give up, before we find Deskbar under it
475 						goto zzz;
476 				}
477 				free(wi);
478 				wi=NULL;
479 			} else
480 				goto zzz;
481 		}
482 	zzz:
483 //		puts("");
484 		if (wi) free(wi);
485 		wi = NULL;
486 		if (tl) free(tl);
487 		tl = NULL;
488 		snooze(tv->polling_delay);
489 	}
490 	return B_OK;
491 }
492 
493 #endif
494 
495 void TrayView::MessageReceived(BMessage* message)
496 {
497 	BMessenger msgr;
498 	int32 *tl, tlc;
499 	port_id pi;
500 	int32 tok;
501 	window_info *wi;
502 
503 	BAlert *alert;
504 	bigtime_t delay;
505 	int32 mode;
506 	bool wasactive;
507 	BPoint mouse;
508 	uint32 buttons;
509 
510 	switch(message->what)
511 	{
512 		case MSG_TOOGLE_ACTIVE:
513 			SetActive(!_settings->Active());
514 			break;
515 		case MSG_SET_ACTIVE:
516 			SetActive(true);
517 			break;
518 		case MSG_SET_INACTIVE:
519 			SetActive(false);
520 			break;
521 		case MSG_SET_DELAY:
522 			delay = DEFAULT_DELAY;
523 			message->FindInt64(AR_DELAY, &delay);
524 			raise_delay = delay;
525 			_settings->SetDelay(delay);
526 			break;
527 		case MSG_SET_MODE:
528 			mode = Mode_All;
529 			message->FindInt32(AR_MODE, &mode);
530 			_settings->SetMode(mode);
531 			break;
532 		case MSG_SET_BEHAVIOUR:
533 			message->FindInt32(AR_BEHAVIOUR, &mode);
534 			wasactive = _settings->Active();
535 			if (wasactive)
536 				SetActive(false);
537 			fNormalMM = (mode_mouse)mode;
538 			set_mouse_mode(fNormalMM);
539 			if (wasactive)
540 				SetActive(true);
541 			break;
542 		case REMOVE_FROM_TRAY:
543 		{
544 			thread_id tid = spawn_thread(removeFromDeskbar, "RemoveFromDeskbar", B_NORMAL_PRIORITY, NULL);
545 			if (tid) resume_thread(tid);
546 
547 			break;
548 		}
549 		case B_ABOUT_REQUESTED:
550 			alert = new BAlert("about box", "AutoRaise, (c) 2002, mmu_man\nEnjoy :-)", "OK", NULL, NULL,
551                 B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_INFO_ALERT);
552 	        alert->SetShortcut(0, B_ENTER);
553     	    alert->Go(NULL); // use asynchronous version
554 			break;
555 		case OPEN_SETTINGS:
556 
557 			break;
558 #ifdef USE_DANO_HACK
559 		case B_SOME_WINDOW_ACTIVATED:
560 //			printf("Window Activated\n");
561 //			message->PrintToStream();
562 			GetMouse(&mouse, &buttons);
563 			if (buttons)
564 				break;
565 			if (message->FindMessenger("be:window", &msgr) < B_OK)
566 				puts("BMsgr ERROR");
567 			else {
568 				bool doZoom = false;
569                 BRect zoomRect(0.0f, 0.0f, 0.0f, 0.0f);
570 				pi = msgr.fPort;
571 //				printf("port:%li (%lx)\n", pi, pi);
572 
573 				tl = get_token_list(msgr.Team(), &tlc);
574 //				printf("tokens (team %li): (%li) ", msgr.Team(), tlc);
575 				for (tlc; tlc; tlc--) {
576 //					printf("%li ", tl[tlc-1]);
577 					wi = get_window_info(tl[tlc-1]);
578 					if (wi) {
579 						if (wi->client_port == pi) {
580 							if ((wi->layer < 3) // we hit the desktop or a window not on this WS
581 									|| (wi->window_left > wi->window_right) || (wi->window_top > wi->window_bottom)
582 									|| (wi->is_mini)
583 									|| (/*(_settings->Mode() == Mode_All) && */(wi->id == current_window))) {
584 								// already raised
585 								free(wi);
586 								break;
587 							}
588 
589 							if ((_settings->Mode() == Mode_All) || (wi->team == fDeskbarTeam)) {
590 								PRINT(("raising wi=%li, cp=%ld, pi=%ld team=%ld DBteam=%ld\n", wi->id, wi->client_port, pi, wi->team, fDeskbarTeam));
591 								current_window = wi->id;
592 								tok = wi->id;
593 								resume_thread(last_raiser_thread = spawn_thread(fronter, "fronter", B_NORMAL_PRIORITY, (void *)this));
594 							} else {
595 								current_window = wi->id;
596 							}
597 						}
598 						free(wi);
599 					}
600 				}
601 //				puts("");
602 				free(tl);
603 			}
604 			break;
605 #endif
606 		default:
607 			BView::MessageReceived(message);
608 	}
609 }
610 
611 AutoRaiseSettings *TrayView::Settings() const
612 {
613 	return _settings;
614 }
615 
616 void TrayView::SetActive(bool st)
617 {
618 	_settings->SetActive(st);
619 	if (_settings->Active())
620 	{
621 		if (!watching) {
622 			fNormalMM = mouse_mode();
623 			set_mouse_mode(B_FOCUS_FOLLOWS_MOUSE);
624 #ifdef USE_DANO_HACK
625 			be_roster->StartWatching(this, B_REQUEST_WINDOW_ACTIVATED);
626 #else
627 			release_sem(fPollerSem);
628 #endif
629 			watching = true;
630 		}
631 	}
632 	else
633 	{
634 		if (watching) {
635 #ifdef USE_DANO_HACK
636 			be_roster->StopWatching(this);
637 #else
638 			acquire_sem(fPollerSem);
639 #endif
640 			set_mouse_mode(fNormalMM);
641 			watching = false;
642 		}
643 	}
644 	Invalidate();
645 }
646 
647