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