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