xref: /haiku/src/apps/deskbar/BarApp.cpp (revision 5f4f984a94d150153bcb00a2ed780d0437859543)
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 	BServer(kDeskbarSignature, true, NULL),
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 = gMinimumWindowWidth;
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 		// constrain width setting within limits
338 		if (settings.width < gMinimumWindowWidth)
339 			settings.width = gMinimumWindowWidth;
340 		else if (settings.width > gMaximumWindowWidth)
341 			settings.width = gMaximumWindowWidth;
342 
343 		filePath = dirPath;
344 		filePath.Append(clockSettingsFileName);
345 		fClockSettingsFile = new BFile(filePath.Path(), O_RDWR);
346 		if (fClockSettingsFile->InitCheck() != B_OK) {
347 			BDirectory theDir(dirPath.Path());
348 			if (theDir.InitCheck() == B_OK)
349 				theDir.CreateFile(clockSettingsFileName, fClockSettingsFile);
350 		}
351 
352 		if (fClockSettingsFile->InitCheck() == B_OK
353 			&& prefs.Unflatten(fClockSettingsFile) == B_OK) {
354 			clock.showSeconds = prefs.GetBool("showSeconds", false);
355 			clock.showDayOfWeek = prefs.GetBool("showDayOfWeek", false);
356 			clock.showTimeZone = prefs.GetBool("showTimeZone", false);
357 		}
358 	}
359 
360 	fSettings = settings;
361 	fClockSettings = clock;
362 }
363 
364 
365 void
366 TBarApp::MessageReceived(BMessage* message)
367 {
368 	switch (message->what) {
369 		case 'gloc':
370 		case 'sloc':
371 		case 'gexp':
372 		case 'sexp':
373 		case 'info':
374 		case 'exst':
375 		case 'cwnt':
376 		case 'icon':
377 		case 'remv':
378 		case 'adon':
379 			// pass any BDeskbar originating messages on to the window
380 			fBarWindow->PostMessage(message);
381 			break;
382 
383 		case kConfigShow:
384 			ShowPreferencesWindow();
385 			break;
386 
387 		case kConfigQuit:
388 			QuitPreferencesWindow();
389 			break;
390 
391 		case kStateChanged:
392 			if (fPreferencesWindow != NULL)
393 				fPreferencesWindow->PostMessage(kStateChanged);
394 			break;
395 
396 		case kShowDeskbarMenu:
397 			if (fBarWindow->Lock()) {
398 				fBarWindow->ShowDeskbarMenu();
399 				fBarWindow->Unlock();
400 			}
401 			break;
402 
403 		case kShowTeamMenu:
404 			if (fBarWindow->Lock()) {
405 				fBarWindow->ShowTeamMenu();
406 				fBarWindow->Unlock();
407 			}
408 			break;
409 
410 		case kUpdateRecentCounts:
411 			int32 count;
412 			bool enabled;
413 
414 			if (message->FindInt32("applications", &count) == B_OK)
415 				fSettings.recentAppsCount = count;
416 			if (message->FindBool("applicationsEnabled", &enabled) == B_OK)
417 				fSettings.recentAppsEnabled = enabled && count > 0;
418 
419 			if (message->FindInt32("folders", &count) == B_OK)
420 				fSettings.recentFoldersCount = count;
421 			if (message->FindBool("foldersEnabled", &enabled) == B_OK)
422 				fSettings.recentFoldersEnabled = enabled && count > 0;
423 
424 			if (message->FindInt32("documents", &count) == B_OK)
425 				fSettings.recentDocsCount = count;
426 			if (message->FindBool("documentsEnabled", &enabled) == B_OK)
427 				fSettings.recentDocsEnabled = enabled && count > 0;
428 
429 			if (fPreferencesWindow != NULL)
430 				fPreferencesWindow->PostMessage(kUpdatePreferences);
431 			break;
432 
433 		case B_SOME_APP_LAUNCHED:
434 		{
435 			team_id team = -1;
436 			message->FindInt32("be:team", &team);
437 
438 			uint32 flags = 0;
439 			message->FindInt32("be:flags", (int32*)&flags);
440 
441 			const char* signature = NULL;
442 			message->FindString("be:signature", &signature);
443 
444 			entry_ref ref;
445 			message->FindRef("be:ref", &ref);
446 
447 			AddTeam(team, flags, signature, &ref);
448 			break;
449 		}
450 
451 		case B_SOME_APP_QUIT:
452 		{
453 			team_id team = -1;
454 			message->FindInt32("be:team", &team);
455 			RemoveTeam(team);
456 			break;
457 		}
458 
459 		case B_ARCHIVED_OBJECT:
460 			// TODO: what's this???
461 			message->AddString("special", "Alex Osadzinski");
462 			fStatusViewMessenger.SendMessage(message);
463 			break;
464 
465 		case kToggleDraggers:
466 			if (BDragger::AreDraggersDrawn())
467 				BDragger::HideAllDraggers();
468 			else
469 				BDragger::ShowAllDraggers();
470 			break;
471 
472 		case kAlwaysTop:
473 			fSettings.alwaysOnTop = !fSettings.alwaysOnTop;
474 
475 			if (fPreferencesWindow != NULL)
476 				fPreferencesWindow->PostMessage(kUpdatePreferences);
477 
478 			fBarWindow->SetFeel(fSettings.alwaysOnTop
479 				? B_FLOATING_ALL_WINDOW_FEEL
480 				: B_NORMAL_WINDOW_FEEL);
481 			break;
482 
483 		case kAutoRaise:
484 			fSettings.autoRaise = fSettings.alwaysOnTop ? false
485 				: !fSettings.autoRaise;
486 
487 			if (fPreferencesWindow != NULL)
488 				fPreferencesWindow->PostMessage(kUpdatePreferences);
489 			break;
490 
491 		case kAutoHide:
492 			fSettings.autoHide = !fSettings.autoHide;
493 
494 			if (fPreferencesWindow != NULL)
495 				fPreferencesWindow->PostMessage(kUpdatePreferences);
496 
497 			fBarWindow->Lock();
498 			fBarView->HideDeskbar(fSettings.autoHide);
499 			fBarWindow->Unlock();
500 			break;
501 
502 		case kTrackerFirst:
503 			fSettings.trackerAlwaysFirst = !fSettings.trackerAlwaysFirst;
504 
505 			if (fPreferencesWindow != NULL)
506 				fPreferencesWindow->PostMessage(kUpdatePreferences);
507 
508 			// if mini mode we don't need to update the view
509 			if (fBarView->MiniState())
510 				break;
511 
512 			fBarWindow->Lock();
513 			fBarView->PlaceApplicationBar();
514 			fBarWindow->Unlock();
515 			break;
516 
517 		case kSortRunningApps:
518 			fSettings.sortRunningApps = !fSettings.sortRunningApps;
519 
520 			if (fPreferencesWindow != NULL)
521 				fPreferencesWindow->PostMessage(kUpdatePreferences);
522 
523 			// if mini mode we don't need to update the view
524 			if (fBarView->MiniState())
525 				break;
526 
527 			fBarWindow->Lock();
528 			fBarView->PlaceApplicationBar();
529 			fBarWindow->Unlock();
530 			break;
531 
532 		case kUnsubscribe:
533 		{
534 			BMessenger messenger;
535 			if (message->FindMessenger("messenger", &messenger) == B_OK)
536 				Unsubscribe(messenger);
537 			break;
538 		}
539 
540 		case kSuperExpando:
541 			fSettings.superExpando = !fSettings.superExpando;
542 
543 			if (fPreferencesWindow != NULL)
544 				fPreferencesWindow->PostMessage(kUpdatePreferences);
545 
546 			// if mini mode we don't need to update the view
547 			if (fBarView->MiniState())
548 				break;
549 
550 			fBarWindow->Lock();
551 			fBarView->PlaceApplicationBar();
552 			fBarWindow->Unlock();
553 			break;
554 
555 		case kExpandNewTeams:
556 			fSettings.expandNewTeams = !fSettings.expandNewTeams;
557 
558 			if (fPreferencesWindow != NULL)
559 				fPreferencesWindow->PostMessage(kUpdatePreferences);
560 
561 			// if mini mode we don't need to update the view
562 			if (fBarView->MiniState())
563 				break;
564 
565 			fBarWindow->Lock();
566 			fBarView->PlaceApplicationBar();
567 			fBarWindow->Unlock();
568 			break;
569 
570 		case kHideLabels:
571 			fSettings.hideLabels = !fSettings.hideLabels;
572 
573 			if (fPreferencesWindow != NULL)
574 				fPreferencesWindow->PostMessage(kUpdatePreferences);
575 
576 			// if mini mode we don't need to update the view
577 			if (fBarView->MiniState())
578 				break;
579 
580 			fBarWindow->Lock();
581 			fBarView->PlaceApplicationBar();
582 			fBarWindow->Unlock();
583 			break;
584 
585 		case kResizeTeamIcons:
586 		{
587 			int32 oldIconSize = fSettings.iconSize;
588 			int32 iconSize;
589 			if (message->FindInt32("be:value", &iconSize) != B_OK)
590 				break;
591 
592 			fSettings.iconSize = iconSize * kIconSizeInterval;
593 
594 			// pin icon size between min and max values
595 			if (fSettings.iconSize < kMinimumIconSize)
596 				fSettings.iconSize = kMinimumIconSize;
597 			else if (fSettings.iconSize > kMaximumIconSize)
598 				fSettings.iconSize = kMaximumIconSize;
599 
600 			// don't resize if icon size hasn't changed
601 			if (fSettings.iconSize == oldIconSize)
602 				break;
603 
604 			ResizeTeamIcons();
605 
606 			if (fPreferencesWindow != NULL)
607 				fPreferencesWindow->PostMessage(kUpdatePreferences);
608 
609 			// if mini mode we don't need to update the view
610 			if (fBarView->MiniState())
611 				break;
612 
613 			fBarWindow->Lock();
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 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 kRealignReplicants:
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 	if ((flags & B_BACKGROUND_APP) != 0
749 		|| strcasecmp(sig, kDeskbarSignature) == 0) {
750 		// don't add if a background app or Deskbar itself
751 		return;
752 	}
753 
754 	BAutolock autolock(sSubscriberLock);
755 	if (!autolock.IsLocked())
756 		return;
757 
758 	// have we already seen this team, is this another instance of
759 	// a known app?
760 	BarTeamInfo* multiLaunchTeam = NULL;
761 	int32 teamCount = sBarTeamInfoList.CountItems();
762 	for (int32 i = 0; i < teamCount; i++) {
763 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
764 		if (barInfo->teams->HasItem((void*)(addr_t)team))
765 			return;
766 		if (strcasecmp(barInfo->sig, sig) == 0)
767 			multiLaunchTeam = barInfo;
768 	}
769 
770 	if (multiLaunchTeam != NULL) {
771 		multiLaunchTeam->teams->AddItem((void*)(addr_t)team);
772 
773 		int32 subsCount = sSubscribers.CountItems();
774 		if (subsCount > 0) {
775 			BMessage message(kAddTeam);
776 			message.AddInt32("team", team);
777 			message.AddString("sig", multiLaunchTeam->sig);
778 
779 			for (int32 i = 0; i < subsCount; i++)
780 				((BMessenger*)sSubscribers.ItemAt(i))->SendMessage(&message);
781 		}
782 		return;
783 	}
784 
785 	BFile file(ref, B_READ_ONLY);
786 	BAppFileInfo appMime(&file);
787 
788 	BString name;
789 	if (!gLocalizedNamePreferred
790 		|| BLocaleRoster::Default()->GetLocalizedFileName(name, *ref)
791 			!= B_OK) {
792 		name = ref->name;
793 	}
794 
795 	BarTeamInfo* barInfo = new BarTeamInfo(new BList(), flags, strdup(sig),
796 		NULL, strdup(name.String()));
797 	FetchAppIcon(barInfo);
798 	barInfo->teams->AddItem((void*)(addr_t)team);
799 	sBarTeamInfoList.AddItem(barInfo);
800 
801 	int32 subsCount = sSubscribers.CountItems();
802 	if (subsCount > 0) {
803 		for (int32 i = 0; i < subsCount; i++) {
804 			BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
805 			BMessage message(B_SOME_APP_LAUNCHED);
806 
807 			BList* tList = new BList(*(barInfo->teams));
808 			message.AddPointer("teams", tList);
809 
810 			BBitmap* icon = new BBitmap(barInfo->icon);
811 			ASSERT(icon);
812 
813 			message.AddPointer("icon", icon);
814 
815 			message.AddInt32("flags", static_cast<int32>(barInfo->flags));
816 			message.AddString("name", barInfo->name);
817 			message.AddString("sig", barInfo->sig);
818 
819 			messenger->SendMessage(&message);
820 		}
821 	}
822 }
823 
824 
825 void
826 TBarApp::RemoveTeam(team_id team)
827 {
828 	BAutolock autolock(sSubscriberLock);
829 	if (!autolock.IsLocked())
830 		return;
831 
832 	int32 teamCount = sBarTeamInfoList.CountItems();
833 	for (int32 i = 0; i < teamCount; i++) {
834 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
835 		if (barInfo->teams->HasItem((void*)(addr_t)team)) {
836 			int32 subsCount = sSubscribers.CountItems();
837 			if (subsCount > 0) {
838 				BMessage message((barInfo->teams->CountItems() == 1)
839 					? B_SOME_APP_QUIT : kRemoveTeam);
840 
841 				message.AddInt32("team", team);
842 				for (int32 i = 0; i < subsCount; i++) {
843 					BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
844 					messenger->SendMessage(&message);
845 				}
846 			}
847 
848 			barInfo->teams->RemoveItem((void*)(addr_t)team);
849 			if (barInfo->teams->CountItems() < 1) {
850 				delete (BarTeamInfo*)sBarTeamInfoList.RemoveItem(i);
851 				return;
852 			}
853 		}
854 	}
855 }
856 
857 
858 void
859 TBarApp::ResizeTeamIcons()
860 {
861 	for (int32 i = sBarTeamInfoList.CountItems() - 1; i >= 0; i--) {
862 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
863 		if ((barInfo->flags & B_BACKGROUND_APP) == 0
864 			&& strcasecmp(barInfo->sig, kDeskbarSignature) != 0) {
865 			FetchAppIcon(barInfo);
866 		}
867 	}
868 }
869 
870 
871 int32
872 TBarApp::IconSize()
873 {
874 	return fSettings.iconSize;
875 }
876 
877 
878 void
879 TBarApp::ShowPreferencesWindow()
880 {
881 	if (fPreferencesWindow == NULL) {
882 		fPreferencesWindow = new PreferencesWindow(BRect(100, 100, 320, 240));
883 		fPreferencesWindow->Show();
884 	} else if (fPreferencesWindow->Lock()) {
885 		if (fPreferencesWindow->IsHidden())
886 			fPreferencesWindow->Show();
887 		else
888 			fPreferencesWindow->Activate();
889 
890 		fPreferencesWindow->Unlock();
891 	}
892 }
893 
894 
895 void
896 TBarApp::QuitPreferencesWindow()
897 {
898 	if (fPreferencesWindow == NULL)
899 		return;
900 
901 	if (fPreferencesWindow->Lock()) {
902 		fPreferencesWindow->Quit();
903 			// Quit() destroys the window so don't unlock
904 		fPreferencesWindow = NULL;
905 	}
906 }
907 
908 
909 void
910 TBarApp::FetchAppIcon(BarTeamInfo* barInfo)
911 {
912 	int32 width = IconSize();
913 	int32 index = (width - kMinimumIconSize) / kIconSizeInterval;
914 
915 	// first look in the icon cache
916 	barInfo->icon = barInfo->iconCache[index];
917 	if (barInfo->icon != NULL)
918 		return;
919 
920 	// icon wasn't in cache, get it from be_roster and cache it
921 	app_info appInfo;
922 	icon_size size = width >= 31 ? B_LARGE_ICON : B_MINI_ICON;
923 	BBitmap* icon = new BBitmap(IconRect(), kIconColorSpace);
924 	if (be_roster->GetAppInfo(barInfo->sig, &appInfo) == B_OK) {
925 		// fetch the app icon
926 		BFile file(&appInfo.ref, B_READ_ONLY);
927 		BAppFileInfo appMime(&file);
928 		if (appMime.GetIcon(icon, size) == B_OK) {
929 			delete barInfo->iconCache[index];
930 			barInfo->iconCache[index] = barInfo->icon = icon;
931 			return;
932 		}
933 	}
934 
935 	// couldn't find the app icon
936 	// fetch the generic 3 boxes icon and cache it
937 	BMimeType defaultAppMime;
938 	defaultAppMime.SetTo(B_APP_MIME_TYPE);
939 	if (defaultAppMime.GetIcon(icon, size) == B_OK) {
940 		delete barInfo->iconCache[index];
941 		barInfo->iconCache[index] = barInfo->icon = icon;
942 		return;
943 	}
944 
945 	// couldn't find generic 3 boxes icon
946 	// fill with transparent
947 	uint8* iconBits = (uint8*)icon->Bits();
948 	if (icon->ColorSpace() == B_RGBA32) {
949 		int32 i = 0;
950 		while (i < icon->BitsLength()) {
951 			iconBits[i++] = B_TRANSPARENT_32_BIT.red;
952 			iconBits[i++] = B_TRANSPARENT_32_BIT.green;
953 			iconBits[i++] = B_TRANSPARENT_32_BIT.blue;
954 			iconBits[i++] = B_TRANSPARENT_32_BIT.alpha;
955 		}
956 	} else {
957 		// Assume B_CMAP8
958 		for (int32 i = 0; i < icon->BitsLength(); i++)
959 			iconBits[i] = B_TRANSPARENT_MAGIC_CMAP8;
960 	}
961 
962 	delete barInfo->iconCache[index];
963 	barInfo->iconCache[index] = barInfo->icon = icon;
964 }
965 
966 
967 BRect
968 TBarApp::IconRect()
969 {
970 	int32 iconSize = IconSize();
971 	return BRect(0, 0, iconSize - 1, iconSize - 1);
972 }
973 
974 
975 //	#pragma mark -
976 
977 
978 BarTeamInfo::BarTeamInfo(BList* teams, uint32 flags, char* sig, BBitmap* icon,
979 	char* name)
980 	:
981 	teams(teams),
982 	flags(flags),
983 	sig(sig),
984 	icon(icon),
985 	name(name)
986 {
987 	_Init();
988 }
989 
990 
991 BarTeamInfo::BarTeamInfo(const BarTeamInfo &info)
992 	:
993 	teams(new BList(*info.teams)),
994 	flags(info.flags),
995 	sig(strdup(info.sig)),
996 	icon(new BBitmap(*info.icon)),
997 	name(strdup(info.name))
998 {
999 	_Init();
1000 }
1001 
1002 
1003 BarTeamInfo::~BarTeamInfo()
1004 {
1005 	delete teams;
1006 	free(sig);
1007 	free(name);
1008 	for (int32 i = 0; i < kIconCacheCount; i++)
1009 		delete iconCache[i];
1010 }
1011 
1012 
1013 void
1014 BarTeamInfo::_Init()
1015 {
1016 	for (int32 i = 0; i < kIconCacheCount; i++)
1017 		iconCache[i] = NULL;
1018 }
1019