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