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