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