1/*
2Open Tracker License
3
4Terms and Conditions
5
6Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7
8Permission is hereby granted, free of charge, to any person obtaining a copy of
9this software and associated documentation files (the "Software"), to deal in
10the Software without restriction, including without limitation the rights to
11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12of the Software, and to permit persons to whom the Software is furnished to do
13so, subject to the following conditions:
14
15The above copyright notice and this permission notice applies to all licensees
16and shall be included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25Except as contained in this notice, the name of Be Incorporated shall not be
26used in advertising or otherwise to promote the sale, use or other dealings in
27this Software without prior written authorization from Be Incorporated.
28
29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered
30trademarks of Be Incorporated in the United States and other countries. Other
31brand product names are registered trademarks or trademarks of their respective
32holders.
33All 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
76BLocker TBarApp::sSubscriberLock;
77BList TBarApp::sBarTeamInfoList;
78BList TBarApp::sWindowIconCache;
79BList TBarApp::sSubscribers;
80
81
82const uint32 kShowDeskbarMenu		= 'BeMn';
83const uint32 kShowTeamMenu			= 'TmMn';
84
85
86int
87main()
88{
89	setlocale(LC_ALL, "");
90	TBarApp app;
91	app.Run();
92
93	return B_OK;
94}
95
96
97TBarApp::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
155TBarApp::~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
179bool
180TBarApp::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
196void
197TBarApp::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
243void
244TBarApp::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
397void
398TBarApp::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
743void
744TBarApp::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
758void
759TBarApp::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
787void
788TBarApp::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
806BBitmap*
807TBarApp::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
831BBitmap*
832TBarApp::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
869void
870TBarApp::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
946void
947TBarApp::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
979void
980TBarApp::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
992int32
993TBarApp::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
1006void
1007TBarApp::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
1023void
1024TBarApp::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
1037status_t
1038TBarApp::_CacheTeamIcon(BarTeamInfo* barInfo)
1039{
1040	if (barInfo == NULL)
1041		return B_BAD_VALUE;
1042
1043	return _CacheTeamIcon(barInfo, fSettings.iconSize);
1044}
1045
1046
1047status_t
1048TBarApp::_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
1111status_t
1112TBarApp::_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
1166BarTeamInfo::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
1179BarTeamInfo::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
1191BarTeamInfo::~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
1201void
1202BarTeamInfo::_Init()
1203{
1204	for (int32 i = 0; i < kIconCacheCount; i++)
1205		iconCache[i] = NULL;
1206}
1207
1208
1209//	#pragma mark - WindowIconCache
1210
1211
1212WindowIconCache::WindowIconCache(int32 id, BBitmap* icon)
1213	:
1214	id(id),
1215	icon(icon)
1216{
1217	_Init();
1218}
1219
1220
1221WindowIconCache::WindowIconCache(const WindowIconCache &cache)
1222	:
1223	id(cache.id),
1224	icon(new BBitmap(*cache.icon))
1225{
1226	_Init();
1227}
1228
1229
1230WindowIconCache::~WindowIconCache()
1231{
1232	for (int32 i = 0; i < kWindowIconCacheCount; i++)
1233		delete iconCache[i];
1234}
1235
1236
1237void
1238WindowIconCache::_Init()
1239{
1240	for (int32 i = 0; i < kWindowIconCacheCount; i++)
1241		iconCache[i] = NULL;
1242}
1243