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