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