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