xref: /haiku/src/apps/deskbar/BarApp.cpp (revision 776c58b2b56d8bcf33638a2ecb6c697f95a1cbf3)
1 /*
2 Open Tracker License
3 
4 Terms and Conditions
5 
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7 
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
14 
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
28 
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered
30 trademarks of Be Incorporated in the United States and other countries. Other
31 brand product names are registered trademarks or trademarks of their respective
32 holders.
33 All rights reserved.
34 */
35 
36 
37 #include "BarApp.h"
38 
39 #include <locale.h>
40 #include <stdlib.h>
41 #include <string.h>
42 
43 #include <AppFileInfo.h>
44 #include <Autolock.h>
45 #include <Bitmap.h>
46 #include <Catalog.h>
47 #include <Debug.h>
48 #include <Directory.h>
49 #include <Dragger.h>
50 #include <File.h>
51 #include <FindDirectory.h>
52 #include <Locale.h>
53 #include <Mime.h>
54 #include <Message.h>
55 #include <Messenger.h>
56 #include <Path.h>
57 #include <Roster.h>
58 #include <RosterPrivate.h>
59 
60 #include "icons.h"
61 #include "tracker_private.h"
62 #include "BarView.h"
63 #include "BarWindow.h"
64 #include "PreferencesWindow.h"
65 #include "DeskbarUtils.h"
66 #include "FSUtils.h"
67 #include "PublicCommands.h"
68 #include "ResourceSet.h"
69 #include "StatusView.h"
70 #include "Switcher.h"
71 #include "Utilities.h"
72 
73 
74 BLocker TBarApp::sSubscriberLock;
75 BList TBarApp::sBarTeamInfoList;
76 BList TBarApp::sSubscribers;
77 
78 
79 const uint32 kShowDeskbarMenu		= 'BeMn';
80 const uint32 kShowTeamMenu			= 'TmMn';
81 
82 static const color_space kIconColorSpace = B_RGBA32;
83 
84 
85 int
86 main()
87 {
88 	setlocale(LC_ALL, "");
89 	TBarApp app;
90 	app.Run();
91 
92 	return B_OK;
93 }
94 
95 
96 TBarApp::TBarApp()
97 	:	BApplication(kDeskbarSignature),
98 		fSettingsFile(NULL),
99 		fClockSettingsFile(NULL),
100 		fPreferencesWindow(NULL)
101 {
102 	InitSettings();
103 	InitIconPreloader();
104 
105 	fBarWindow = new TBarWindow();
106 	fBarView = fBarWindow->BarView();
107 
108 	be_roster->StartWatching(this);
109 
110 	gLocalizedNamePreferred
111 		= BLocaleRoster::Default()->IsFilesystemTranslationPreferred();
112 
113 	sBarTeamInfoList.MakeEmpty();
114 
115 	BList teamList;
116 	int32 numTeams;
117 	be_roster->GetAppList(&teamList);
118 	numTeams = teamList.CountItems();
119 	for (int32 i = 0; i < numTeams; i++) {
120 		app_info appInfo;
121 		team_id tID = (addr_t)teamList.ItemAt(i);
122 		if (be_roster->GetRunningAppInfo(tID, &appInfo) == B_OK) {
123 			AddTeam(appInfo.team, appInfo.flags, appInfo.signature,
124 				&appInfo.ref);
125 		}
126 	}
127 
128 	sSubscribers.MakeEmpty();
129 
130 	fSwitcherMessenger = BMessenger(new TSwitchManager(fSettings.switcherLoc));
131 
132 	fBarWindow->Show();
133 
134 	// Call UpdatePlacement() after the window is shown because expanded apps
135 	// need to resize the window.
136 	if (fBarWindow->Lock()) {
137 		fBarView->UpdatePlacement();
138 		fBarWindow->Unlock();
139 	}
140 
141 	// this messenger now targets the barview instead of the
142 	// statusview so that all additions to the tray
143 	// follow the same path
144 	fStatusViewMessenger = BMessenger(fBarWindow->FindView("BarView"));
145 }
146 
147 
148 TBarApp::~TBarApp()
149 {
150 	be_roster->StopWatching(this);
151 
152 	int32 teamCount = sBarTeamInfoList.CountItems();
153 	for (int32 i = 0; i < teamCount; i++) {
154 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
155 		delete barInfo;
156 	}
157 
158 	int32 subsCount = sSubscribers.CountItems();
159 	for (int32 i = 0; i < subsCount; i++) {
160 		BMessenger* messenger
161 			= static_cast<BMessenger*>(sSubscribers.ItemAt(i));
162 		delete messenger;
163 	}
164 
165 	SaveSettings();
166 
167 	delete fSettingsFile;
168 	delete fClockSettingsFile;
169 }
170 
171 
172 bool
173 TBarApp::QuitRequested()
174 {
175 	// don't allow user quitting
176 	if (CurrentMessage() && CurrentMessage()->FindBool("shortcut")) {
177 		// but allow quitting to hide fPreferencesWindow
178 		int32 index = 0;
179 		BWindow* window = NULL;
180 		while ((window = WindowAt(index++)) != NULL) {
181 			if (window == fPreferencesWindow) {
182 				if (fPreferencesWindow->Lock()) {
183 					if (fPreferencesWindow->IsActive())
184 						fPreferencesWindow->PostMessage(B_QUIT_REQUESTED);
185 					fPreferencesWindow->Unlock();
186 				}
187 				break;
188 			}
189 		}
190 		return false;
191 	}
192 
193 	// system quitting, call inherited to notify all loopers
194 	fBarWindow->SaveSettings();
195 	BApplication::QuitRequested();
196 	return true;
197 }
198 
199 
200 void
201 TBarApp::SaveSettings()
202 {
203 	if (fSettingsFile->InitCheck() == B_OK) {
204 		fSettingsFile->Seek(0, SEEK_SET);
205 		BMessage storedSettings;
206 		storedSettings.AddBool("vertical", fSettings.vertical);
207 		storedSettings.AddBool("left", fSettings.left);
208 		storedSettings.AddBool("top", fSettings.top);
209 		storedSettings.AddInt32("state", fSettings.state);
210 		storedSettings.AddFloat("width", fSettings.width);
211 
212 		storedSettings.AddPoint("switcherLoc", fSettings.switcherLoc);
213 		storedSettings.AddInt32("recentAppsCount", fSettings.recentAppsCount);
214 		storedSettings.AddInt32("recentDocsCount", fSettings.recentDocsCount);
215 		storedSettings.AddBool("timeShowSeconds", fSettings.timeShowSeconds);
216 		storedSettings.AddInt32("recentFoldersCount",
217 			fSettings.recentFoldersCount);
218 		storedSettings.AddBool("alwaysOnTop", fSettings.alwaysOnTop);
219 		storedSettings.AddBool("timeFullDate", fSettings.timeFullDate);
220 		storedSettings.AddBool("trackerAlwaysFirst",
221 			fSettings.trackerAlwaysFirst);
222 		storedSettings.AddBool("sortRunningApps", fSettings.sortRunningApps);
223 		storedSettings.AddBool("superExpando", fSettings.superExpando);
224 		storedSettings.AddBool("expandNewTeams", fSettings.expandNewTeams);
225 		storedSettings.AddBool("hideLabels", fSettings.hideLabels);
226 		storedSettings.AddInt32("iconSize", fSettings.iconSize);
227 		storedSettings.AddBool("autoRaise", fSettings.autoRaise);
228 		storedSettings.AddBool("autoHide", fSettings.autoHide);
229 		storedSettings.AddBool("recentAppsEnabled",
230 			fSettings.recentAppsEnabled);
231 		storedSettings.AddBool("recentDocsEnabled",
232 			fSettings.recentDocsEnabled);
233 		storedSettings.AddBool("recentFoldersEnabled",
234 			fSettings.recentFoldersEnabled);
235 
236 		storedSettings.Flatten(fSettingsFile);
237 	}
238 
239 	if (fClockSettingsFile->InitCheck() == B_OK) {
240 		fClockSettingsFile->Seek(0, SEEK_SET);
241 		BMessage storedSettings;
242 
243 		storedSettings.AddBool("showSeconds",
244 			fClockSettings.showSeconds);
245 		storedSettings.AddBool("showDayOfWeek",
246 			fClockSettings.showDayOfWeek);
247 		storedSettings.AddBool("showTimeZone",
248 			fClockSettings.showTimeZone);
249 
250 		storedSettings.Flatten(fClockSettingsFile);
251 	}
252 }
253 
254 
255 void
256 TBarApp::InitSettings()
257 {
258 	desk_settings settings;
259 	settings.vertical = true;
260 	settings.left = false;
261 	settings.top = true;
262 	settings.state = kExpandoState;
263 	settings.width = 0;
264 	settings.switcherLoc = BPoint(5000, 5000);
265 	settings.recentAppsCount = 10;
266 	settings.recentDocsCount = 10;
267 	settings.timeShowSeconds = false;
268 	settings.recentFoldersCount = 10;
269 	settings.alwaysOnTop = false;
270 	settings.timeFullDate = false;
271 	settings.trackerAlwaysFirst = false;
272 	settings.sortRunningApps = false;
273 	settings.superExpando = false;
274 	settings.expandNewTeams = false;
275 	settings.hideLabels = false;
276 	settings.iconSize = kMinimumIconSize;
277 	settings.autoRaise = false;
278 	settings.autoHide = false;
279 	settings.recentAppsEnabled = true;
280 	settings.recentDocsEnabled = true;
281 	settings.recentFoldersEnabled = true;
282 
283 	clock_settings clock;
284 	clock.showSeconds = false;
285 	clock.showDayOfWeek = false;
286 	clock.showTimeZone = false;
287 
288 	BPath dirPath;
289 	const char* settingsFileName = "Deskbar_settings";
290 	const char* clockSettingsFileName = "Deskbar_clock_settings";
291 
292 	find_directory(B_USER_DESKBAR_DIRECTORY, &dirPath, true);
293 		// just make it
294 
295 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &dirPath, true) == B_OK) {
296 		BPath filePath = dirPath;
297 		filePath.Append(settingsFileName);
298 		fSettingsFile = new BFile(filePath.Path(), O_RDWR);
299 		if (fSettingsFile->InitCheck() != B_OK) {
300 			BDirectory theDir(dirPath.Path());
301 			if (theDir.InitCheck() == B_OK)
302 				theDir.CreateFile(settingsFileName, fSettingsFile);
303 		}
304 
305 		fClockSettingsFile = new BFile(filePath.Path(), O_RDWR);
306 		if (fClockSettingsFile->InitCheck() != B_OK) {
307 			BDirectory theDir(dirPath.Path());
308 			if (theDir.InitCheck() == B_OK)
309 				theDir.CreateFile(clockSettingsFileName, fClockSettingsFile);
310 		}
311 
312 		BMessage storedSettings;
313 		if (fSettingsFile->InitCheck() == B_OK
314 			&& storedSettings.Unflatten(fSettingsFile) == B_OK) {
315 			if (storedSettings.FindBool("vertical", &settings.vertical)
316 					!= B_OK) {
317 				settings.vertical = true;
318 			}
319 			if (storedSettings.FindBool("left", &settings.left) != B_OK)
320 				settings.left = false;
321 			if (storedSettings.FindBool("top", &settings.top) != B_OK)
322 				settings.top = true;
323 			if (storedSettings.FindInt32("state", (int32*)&settings.state)
324 					!= B_OK) {
325 				settings.state = kExpandoState;
326 			}
327 			if (storedSettings.FindFloat("width", &settings.width) != B_OK)
328 				settings.width = 0;
329 			if (storedSettings.FindPoint("switcherLoc", &settings.switcherLoc)
330 					!= B_OK) {
331 				settings.switcherLoc = BPoint(5000, 5000);
332 			}
333 			if (storedSettings.FindInt32("recentAppsCount",
334 					&settings.recentAppsCount) != B_OK) {
335 				settings.recentAppsCount = 10;
336 			}
337 			if (storedSettings.FindInt32("recentDocsCount",
338 					&settings.recentDocsCount) != B_OK) {
339 				settings.recentDocsCount = 10;
340 			}
341 			if (storedSettings.FindBool("timeShowSeconds",
342 					&settings.timeShowSeconds) != B_OK) {
343 				settings.timeShowSeconds = false;
344 			}
345 			if (storedSettings.FindInt32("recentFoldersCount",
346 					&settings.recentFoldersCount) != B_OK) {
347 				settings.recentFoldersCount = 10;
348 			}
349 			if (storedSettings.FindBool("alwaysOnTop", &settings.alwaysOnTop)
350 					!= B_OK) {
351 				settings.alwaysOnTop = false;
352 			}
353 			if (storedSettings.FindBool("timeFullDate", &settings.timeFullDate)
354 					!= B_OK) {
355 				settings.timeFullDate = false;
356 			}
357 			if (storedSettings.FindBool("trackerAlwaysFirst",
358 					&settings.trackerAlwaysFirst) != B_OK) {
359 				settings.trackerAlwaysFirst = false;
360 			}
361 			if (storedSettings.FindBool("sortRunningApps",
362 					&settings.sortRunningApps) != B_OK) {
363 				settings.sortRunningApps = false;
364 			}
365 			if (storedSettings.FindBool("superExpando", &settings.superExpando)
366 					!= B_OK) {
367 				settings.superExpando = false;
368 			}
369 			if (storedSettings.FindBool("expandNewTeams",
370 					&settings.expandNewTeams) != B_OK) {
371 				settings.expandNewTeams = false;
372 			}
373 			if (storedSettings.FindBool("hideLabels", &settings.hideLabels)
374 					!= B_OK) {
375 				settings.hideLabels = false;
376 			}
377 			if (storedSettings.FindInt32("iconSize", (int32*)&settings.iconSize)
378 					!= B_OK) {
379 				settings.iconSize = kMinimumIconSize;
380 			}
381 			if (storedSettings.FindBool("autoRaise", &settings.autoRaise)
382 					!= B_OK) {
383 				settings.autoRaise = false;
384 			}
385 			if (storedSettings.FindBool("autoHide", &settings.autoHide) != B_OK)
386 				settings.autoHide = false;
387 			if (storedSettings.FindBool("recentAppsEnabled",
388 					&settings.recentAppsEnabled) != B_OK) {
389 				settings.recentAppsEnabled = true;
390 			}
391 			if (storedSettings.FindBool("recentDocsEnabled",
392 					&settings.recentDocsEnabled) != B_OK) {
393 				settings.recentDocsEnabled = true;
394 			}
395 			if (storedSettings.FindBool("recentFoldersEnabled",
396 					&settings.recentFoldersEnabled) != B_OK) {
397 				settings.recentFoldersEnabled = true;
398 			}
399 		}
400 
401 		if (fClockSettingsFile->InitCheck() == B_OK
402 			&& storedSettings.Unflatten(fClockSettingsFile) == B_OK) {
403 			if (storedSettings.FindBool("showSeconds", &clock.showSeconds)
404 					!= B_OK) {
405 				clock.showSeconds = false;
406 			}
407 			if (storedSettings.FindBool("showDayOfWeek",
408 					&clock.showDayOfWeek) != B_OK) {
409 				clock.showDayOfWeek = false;
410 			}
411 			if (storedSettings.FindBool("showTimeZone",
412 					&clock.showTimeZone) != B_OK) {
413 				clock.showDayOfWeek = false;
414 			}
415 		}
416 	}
417 
418 	fSettings = settings;
419 	fClockSettings = clock;
420 }
421 
422 
423 void
424 TBarApp::MessageReceived(BMessage* message)
425 {
426 	switch (message->what) {
427 		case 'gloc':
428 		case 'sloc':
429 		case 'gexp':
430 		case 'sexp':
431 		case 'info':
432 		case 'exst':
433 		case 'cwnt':
434 		case 'icon':
435 		case 'remv':
436 		case 'adon':
437 			// pass any BDeskbar originating messages on to the window
438 			fBarWindow->PostMessage(message);
439 			break;
440 
441 		case kConfigShow:
442 			ShowPreferencesWindow();
443 			break;
444 
445 		case kStateChanged:
446 			fPreferencesWindow->PostMessage(kStateChanged);
447 			break;
448 
449 		case kShowDeskbarMenu:
450 			if (fBarWindow->Lock()) {
451 				fBarWindow->ShowDeskbarMenu();
452 				fBarWindow->Unlock();
453 			}
454 			break;
455 
456 		case kShowTeamMenu:
457 			if (fBarWindow->Lock()) {
458 				fBarWindow->ShowTeamMenu();
459 				fBarWindow->Unlock();
460 			}
461 			break;
462 
463 		case kUpdateRecentCounts:
464 			int32 count;
465 			bool enabled;
466 
467 			if (message->FindInt32("applications", &count) == B_OK)
468 				fSettings.recentAppsCount = count;
469 			if (message->FindBool("applicationsEnabled", &enabled) == B_OK)
470 				fSettings.recentAppsEnabled = enabled && count > 0;
471 
472 			if (message->FindInt32("folders", &count) == B_OK)
473 				fSettings.recentFoldersCount = count;
474 			if (message->FindBool("foldersEnabled", &enabled) == B_OK)
475 				fSettings.recentFoldersEnabled = enabled && count > 0;
476 
477 			if (message->FindInt32("documents", &count) == B_OK)
478 				fSettings.recentDocsCount = count;
479 			if (message->FindBool("documentsEnabled", &enabled) == B_OK)
480 				fSettings.recentDocsEnabled = enabled && count > 0;
481 			break;
482 
483 		case B_SOME_APP_LAUNCHED:
484 		{
485 			team_id team = -1;
486 			message->FindInt32("be:team", &team);
487 
488 			uint32 flags = 0;
489 			message->FindInt32("be:flags", (int32*)&flags);
490 
491 			const char* sig = NULL;
492 			message->FindString("be:signature", &sig);
493 
494 			entry_ref ref;
495 			message->FindRef("be:ref", &ref);
496 
497 			AddTeam(team, flags, sig, &ref);
498 			break;
499 		}
500 
501 		case B_SOME_APP_QUIT:
502 		{
503 			team_id team = -1;
504 			message->FindInt32("be:team", &team);
505 			RemoveTeam(team);
506 			break;
507 		}
508 
509 		case B_ARCHIVED_OBJECT:
510 			// TODO: what's this???
511 			message->AddString("special", "Alex Osadzinski");
512 			fStatusViewMessenger.SendMessage(message);
513 			break;
514 
515 		case kToggleDraggers:
516 			if (BDragger::AreDraggersDrawn())
517 				BDragger::HideAllDraggers();
518 			else
519 				BDragger::ShowAllDraggers();
520 			break;
521 
522 		case kAlwaysTop:
523 			fSettings.alwaysOnTop = !fSettings.alwaysOnTop;
524 			fBarWindow->SetFeel(fSettings.alwaysOnTop ?
525 				B_FLOATING_ALL_WINDOW_FEEL : B_NORMAL_WINDOW_FEEL);
526 			fPreferencesWindow->PostMessage(kStateChanged);
527 			break;
528 
529 		case kAutoRaise:
530 			fSettings.autoRaise = fSettings.alwaysOnTop ? false :
531 				!fSettings.autoRaise;
532 			break;
533 
534 		case kAutoHide:
535 			fSettings.autoHide = !fSettings.autoHide;
536 
537 			fBarWindow->Lock();
538 			fBarView->HideDeskbar(fSettings.autoHide);
539 			fBarWindow->Unlock();
540 			break;
541 
542 		case kTrackerFirst:
543 			fSettings.trackerAlwaysFirst = !fSettings.trackerAlwaysFirst;
544 
545 			fBarWindow->Lock();
546 			fBarView->PlaceApplicationBar();
547 			fBarWindow->Unlock();
548 			break;
549 
550 		case kSortRunningApps:
551 			fSettings.sortRunningApps = !fSettings.sortRunningApps;
552 
553 			fBarWindow->Lock();
554 			fBarView->PlaceApplicationBar();
555 			fBarWindow->Unlock();
556 			break;
557 
558 		case kUnsubscribe:
559 		{
560 			BMessenger messenger;
561 			if (message->FindMessenger("messenger", &messenger) == B_OK)
562 				Unsubscribe(messenger);
563 			break;
564 		}
565 
566 		case kSuperExpando:
567 			fSettings.superExpando = !fSettings.superExpando;
568 
569 			fBarWindow->Lock();
570 			fBarView->PlaceApplicationBar();
571 			fBarWindow->Unlock();
572 			break;
573 
574 		case kExpandNewTeams:
575 			fSettings.expandNewTeams = !fSettings.expandNewTeams;
576 
577 			fBarWindow->Lock();
578 			fBarView->PlaceApplicationBar();
579 			fBarWindow->Unlock();
580 			break;
581 
582 		case kHideLabels:
583 			fSettings.hideLabels = !fSettings.hideLabels;
584 
585 			fBarWindow->Lock();
586 			fBarView->PlaceApplicationBar();
587 			fBarWindow->Unlock();
588 			break;
589 
590 		case kResizeTeamIcons:
591 		{
592 			int32 iconSize;
593 
594 			if (message->FindInt32("be:value", &iconSize) != B_OK)
595 				break;
596 
597 			fSettings.iconSize = iconSize * kIconSizeInterval;
598 
599 			if (fSettings.iconSize < kMinimumIconSize)
600 				fSettings.iconSize = kMinimumIconSize;
601 			else if (fSettings.iconSize > kMaximumIconSize)
602 				fSettings.iconSize = kMaximumIconSize;
603 
604 			ResizeTeamIcons();
605 
606 			if (fBarView->MiniState())
607 				break;
608 
609 			fBarWindow->Lock();
610 			if (fBarView->Vertical())
611 				fBarView->PlaceApplicationBar();
612 			else
613 				fBarView->UpdatePlacement();
614 
615 			fBarWindow->Unlock();
616 			break;
617 		}
618 
619 		case 'TASK':
620 			fSwitcherMessenger.SendMessage(message);
621 			break;
622 
623 		case kSuspendSystem:
624 			// TODO: Call BRoster?
625 			break;
626 
627 		case kRebootSystem:
628 		case kShutdownSystem:
629 		{
630 			bool reboot = (message->what == kRebootSystem);
631 			bool confirm;
632 			message->FindBool("confirm", &confirm);
633 
634 			BRoster roster;
635 			BRoster::Private rosterPrivate(roster);
636 			status_t error = rosterPrivate.ShutDown(reboot, confirm, false);
637 			if (error != B_OK)
638 				fprintf(stderr, "Shutdown failed: %s\n", strerror(error));
639 
640 			break;
641 		}
642 
643 		case kShowSplash:
644 			run_be_about();
645 			break;
646 
647 		case kRestartTracker:
648 		{
649 			BRoster roster;
650 			roster.Launch(kTrackerSignature);
651 			break;
652 		}
653 
654 		case B_LOCALE_CHANGED:
655 		{
656 			BLocaleRoster::Default()->Refresh();
657 
658 			bool localize;
659 			if (message->FindBool("filesys", &localize) == B_OK)
660 				gLocalizedNamePreferred = localize;
661 		}
662 		// fall-through
663 
664 		case kShowHideTime:
665 		case kShowSeconds:
666 		case kShowDayOfWeek:
667 		case kShowTimeZone:
668 		case kGetClockSettings:
669 			fStatusViewMessenger.SendMessage(message);
670 				// Notify the replicant tray (through BarView) that the time
671 				// interval has changed and it should update the time view
672 				// and reflow the tray icons.
673 			break;
674 
675 		default:
676 			BApplication::MessageReceived(message);
677 			break;
678 	}
679 }
680 
681 
682 void
683 TBarApp::RefsReceived(BMessage* refs)
684 {
685 	entry_ref ref;
686 	for (int32 i = 0; refs->FindRef("refs", i, &ref) == B_OK; i++) {
687 		BMessage refsReceived(B_REFS_RECEIVED);
688 		refsReceived.AddRef("refs", &ref);
689 
690 		BEntry entry(&ref);
691 		if (!entry.IsDirectory())
692 			TrackerLaunch(&refsReceived, false);
693 	}
694 }
695 
696 
697 void
698 TBarApp::Subscribe(const BMessenger &subscriber, BList* list)
699 {
700 	// called when ExpandoMenuBar, TeamMenu or Switcher are built/rebuilt
701 	list->MakeEmpty();
702 
703 	BAutolock autolock(sSubscriberLock);
704 	if (!autolock.IsLocked())
705 		return;
706 
707 	int32 numTeams = sBarTeamInfoList.CountItems();
708 	for (int32 i = 0; i < numTeams; i++) {
709 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
710 		BarTeamInfo* newBarInfo = new (std::nothrow) BarTeamInfo(*barInfo);
711 		if (newBarInfo != NULL)
712 			list->AddItem(newBarInfo);
713 	}
714 
715 	int32 subsCount = sSubscribers.CountItems();
716 	for (int32 i = 0; i < subsCount; i++) {
717 		BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
718 		if (*messenger == subscriber)
719 			return;
720 	}
721 
722 	sSubscribers.AddItem(new BMessenger(subscriber));
723 }
724 
725 
726 void
727 TBarApp::Unsubscribe(const BMessenger &subscriber)
728 {
729 	BAutolock autolock(sSubscriberLock);
730 	if (!autolock.IsLocked())
731 		return;
732 
733 	int32 count = sSubscribers.CountItems();
734 	for (int32 i = 0; i < count; i++) {
735 		BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
736 		if (*messenger == subscriber) {
737 			sSubscribers.RemoveItem(i);
738 			delete messenger;
739 			break;
740 		}
741 	}
742 }
743 
744 
745 void
746 TBarApp::AddTeam(team_id team, uint32 flags, const char* sig, entry_ref* ref)
747 {
748 	BAutolock autolock(sSubscriberLock);
749 	if (!autolock.IsLocked())
750 		return;
751 
752 	// have we already seen this team, is this another instance of
753 	// a known app?
754 	BarTeamInfo* multiLaunchTeam = NULL;
755 	int32 teamCount = sBarTeamInfoList.CountItems();
756 	for (int32 i = 0; i < teamCount; i++) {
757 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
758 		if (barInfo->teams->HasItem((void*)(addr_t)team))
759 			return;
760 		if (strcasecmp(barInfo->sig, sig) == 0)
761 			multiLaunchTeam = barInfo;
762 	}
763 
764 	if (multiLaunchTeam != NULL) {
765 		multiLaunchTeam->teams->AddItem((void*)(addr_t)team);
766 
767 		int32 subsCount = sSubscribers.CountItems();
768 		if (subsCount > 0) {
769 			BMessage message(kAddTeam);
770 			message.AddInt32("team", team);
771 			message.AddString("sig", multiLaunchTeam->sig);
772 
773 			for (int32 i = 0; i < subsCount; i++)
774 				((BMessenger*)sSubscribers.ItemAt(i))->SendMessage(&message);
775 		}
776 		return;
777 	}
778 
779 	BFile file(ref, B_READ_ONLY);
780 	BAppFileInfo appMime(&file);
781 
782 	BString name;
783 	if (!gLocalizedNamePreferred
784 		|| BLocaleRoster::Default()->GetLocalizedFileName(name, *ref)
785 			!= B_OK) {
786 		name = ref->name;
787 	}
788 
789 	BarTeamInfo* barInfo = new BarTeamInfo(new BList(), flags, strdup(sig),
790 		new BBitmap(IconRect(), kIconColorSpace), strdup(name.String()));
791 
792 	if ((barInfo->flags & B_BACKGROUND_APP) == 0
793 		&& strcasecmp(barInfo->sig, kDeskbarSignature) != 0) {
794 		FetchAppIcon(barInfo->sig, barInfo->icon);
795 	}
796 
797 	barInfo->teams->AddItem((void*)(addr_t)team);
798 
799 	sBarTeamInfoList.AddItem(barInfo);
800 
801 	if (fSettings.expandNewTeams)
802 		fBarView->AddExpandedItem(sig);
803 
804 	int32 subsCount = sSubscribers.CountItems();
805 	if (subsCount > 0) {
806 		for (int32 i = 0; i < subsCount; i++) {
807 			BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
808 			BMessage message(B_SOME_APP_LAUNCHED);
809 
810 			BList* tList = new BList(*(barInfo->teams));
811 			message.AddPointer("teams", tList);
812 
813 			BBitmap* icon = new BBitmap(barInfo->icon);
814 			ASSERT(icon);
815 
816 			message.AddPointer("icon", icon);
817 
818 			message.AddInt32("flags", static_cast<int32>(barInfo->flags));
819 			message.AddString("name", barInfo->name);
820 			message.AddString("sig", barInfo->sig);
821 
822 			messenger->SendMessage(&message);
823 		}
824 	}
825 }
826 
827 
828 void
829 TBarApp::RemoveTeam(team_id team)
830 {
831 	BAutolock autolock(sSubscriberLock);
832 	if (!autolock.IsLocked())
833 		return;
834 
835 	int32 teamCount = sBarTeamInfoList.CountItems();
836 	for (int32 i = 0; i < teamCount; i++) {
837 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
838 		if (barInfo->teams->HasItem((void*)(addr_t)team)) {
839 			int32 subsCount = sSubscribers.CountItems();
840 			if (subsCount > 0) {
841 				BMessage message((barInfo->teams->CountItems() == 1)
842 					? B_SOME_APP_QUIT : kRemoveTeam);
843 
844 				message.AddInt32("team", team);
845 				for (int32 i = 0; i < subsCount; i++) {
846 					BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
847 					messenger->SendMessage(&message);
848 				}
849 			}
850 
851 			barInfo->teams->RemoveItem((void*)(addr_t)team);
852 			if (barInfo->teams->CountItems() < 1) {
853 				delete (BarTeamInfo*)sBarTeamInfoList.RemoveItem(i);
854 				return;
855 			}
856 		}
857 	}
858 }
859 
860 
861 void
862 TBarApp::ResizeTeamIcons()
863 {
864 	for (int32 i = 0; i < sBarTeamInfoList.CountItems(); i++) {
865 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
866 		if ((barInfo->flags & B_BACKGROUND_APP) == 0
867 			&& strcasecmp(barInfo->sig, kDeskbarSignature) != 0) {
868 			delete barInfo->icon;
869 			barInfo->icon = new BBitmap(IconRect(), kIconColorSpace);
870 			FetchAppIcon(barInfo->sig, barInfo->icon);
871 		}
872 	}
873 }
874 
875 
876 int32
877 TBarApp::IconSize()
878 {
879 	return fSettings.iconSize;
880 }
881 
882 
883 void
884 TBarApp::ShowPreferencesWindow()
885 {
886 	if (fPreferencesWindow == NULL) {
887 		fPreferencesWindow = new PreferencesWindow(BRect(0, 0, 320, 240));
888 		fPreferencesWindow->Show();
889 	} else {
890 		if (fPreferencesWindow->Lock()) {
891 			if (fPreferencesWindow->IsHidden())
892 				fPreferencesWindow->Show();
893 			else
894 				fPreferencesWindow->Activate();
895 
896 			fPreferencesWindow->Unlock();
897 		}
898 	}
899 }
900 
901 
902 void
903 TBarApp::FetchAppIcon(const char* signature, BBitmap* icon)
904 {
905 	app_info appInfo;
906 	icon_size size = icon->Bounds().IntegerHeight() >= 31
907 		? B_LARGE_ICON : B_MINI_ICON;
908 
909 	if (be_roster->GetAppInfo(signature, &appInfo) == B_OK) {
910 		// fetch the app icon
911 		BFile file(&appInfo.ref, B_READ_ONLY);
912 		BAppFileInfo appMime(&file);
913 		if (appMime.GetIcon(icon, size) == B_OK)
914 			return;
915 	}
916 
917 	// couldn't find the app icon
918 	// fetch the generic 3 boxes icon
919 	BMimeType defaultAppMime;
920 	defaultAppMime.SetTo(B_APP_MIME_TYPE);
921 	if (defaultAppMime.GetIcon(icon, size) == B_OK)
922 		return;
923 
924 	// couldn't find generic 3 boxes icon
925 	// fill with transparent
926 	uint8* iconBits = (uint8*)icon->Bits();
927 	if (icon->ColorSpace() == B_RGBA32) {
928 		int32 i = 0;
929 		while (i < icon->BitsLength()) {
930 			iconBits[i++] = B_TRANSPARENT_32_BIT.red;
931 			iconBits[i++] = B_TRANSPARENT_32_BIT.green;
932 			iconBits[i++] = B_TRANSPARENT_32_BIT.blue;
933 			iconBits[i++] = B_TRANSPARENT_32_BIT.alpha;
934 		}
935 	} else {
936 		// Assume B_CMAP8
937 		for (int32 i = 0; i < icon->BitsLength(); i++)
938 			iconBits[i] = B_TRANSPARENT_MAGIC_CMAP8;
939 	}
940 }
941 
942 
943 BRect
944 TBarApp::IconRect()
945 {
946 	int32 iconSize = IconSize();
947 	return BRect(0, 0, iconSize - 1, iconSize - 1);
948 }
949 
950 
951 //	#pragma mark -
952 
953 
954 BarTeamInfo::BarTeamInfo(BList* teams, uint32 flags, char* sig, BBitmap* icon,
955 	char* name)
956 	:	teams(teams),
957 		flags(flags),
958 		sig(sig),
959 		icon(icon),
960 		name(name)
961 {
962 }
963 
964 
965 BarTeamInfo::BarTeamInfo(const BarTeamInfo &info)
966 	:	teams(new BList(*info.teams)),
967 		flags(info.flags),
968 		sig(strdup(info.sig)),
969 		icon(new BBitmap(*info.icon)),
970 		name(strdup(info.name))
971 {
972 }
973 
974 
975 BarTeamInfo::~BarTeamInfo()
976 {
977 	delete teams;
978 	free(sig);
979 	delete icon;
980 	free(name);
981 }
982