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