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