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