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