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