xref: /haiku/src/apps/deskbar/BarApp.cpp (revision 922e7ba1f3228e6f28db69b0ded8f86eb32dea17)
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 #include <Debug.h>
37 #include <stdlib.h>
38 #include <string.h>
39 
40 #include <AppFileInfo.h>
41 #include <Autolock.h>
42 #include <Bitmap.h>
43 #include <Catalog.h>
44 #include <Directory.h>
45 #include <Dragger.h>
46 #include <File.h>
47 #include <FindDirectory.h>
48 #include <Locale.h>
49 #include <Mime.h>
50 #include <Path.h>
51 #include <Roster.h>
52 #include <RosterPrivate.h>
53 
54 #include "icons.h"
55 #include "tracker_private.h"
56 #include "BarApp.h"
57 #include "BarView.h"
58 #include "BarWindow.h"
59 #include "DeskbarUtils.h"
60 #include "FSUtils.h"
61 #include "PublicCommands.h"
62 #include "ResourceSet.h"
63 #include "Switcher.h"
64 #include "Utilities.h"
65 
66 
67 BLocker TBarApp::sSubscriberLock;
68 BList TBarApp::sBarTeamInfoList;
69 BList TBarApp::sSubscribers;
70 
71 
72 const uint32 kShowDeskbarMenu = 'BeMn';
73 const uint32 kShowTeamMenu = 'TmMn';
74 
75 
76 const BRect kIconRect(0.0f, 0.0f, 15.0f, 15.0f);
77 static const color_space kIconFormat = B_RGBA32;
78 
79 
80 int
81 main()
82 {
83 	TBarApp app;
84 	app.Run();
85 
86 	return B_OK;
87 }
88 
89 
90 TBarApp::TBarApp()
91 	:	BApplication(kDeskbarSignature),
92 		fSettingsFile(NULL),
93 		fPreferencesWindow(NULL)
94 {
95 	InitSettings();
96 	InitIconPreloader();
97 
98 	be_roster->StartWatching(this);
99 
100 	gLocalizedNamePreferred
101 		= BLocaleRoster::Default()->IsFilesystemTranslationPreferred();
102 
103 	sBarTeamInfoList.MakeEmpty();
104 
105 	BList teamList;
106 	int32 numTeams;
107 	be_roster->GetAppList(&teamList);
108 	numTeams = teamList.CountItems();
109 	for (int32 i = 0; i < numTeams; i++) {
110 		app_info appInfo;
111 		team_id tID = (team_id)teamList.ItemAt(i);
112 		if (be_roster->GetRunningAppInfo(tID, &appInfo) == B_OK) {
113 			AddTeam(appInfo.team, appInfo.flags, appInfo.signature,
114 				&appInfo.ref);
115 		}
116 	}
117 
118 	sSubscribers.MakeEmpty();
119 
120 	fSwitcherMessenger = BMessenger(new TSwitchManager(fSettings.switcherLoc));
121 
122 	fBarWindow = new TBarWindow();
123 	fBarWindow->Show();
124 
125 	// this messenger now targets the barview instead of the
126 	// statusview so that all additions to the tray
127 	// follow the same path
128 	fStatusViewMessenger = BMessenger(fBarWindow->FindView("BarView"));
129 }
130 
131 
132 TBarApp::~TBarApp()
133 {
134 	be_roster->StopWatching(this);
135 
136 	int32 teamCount = sBarTeamInfoList.CountItems();
137 	for (int32 i = 0; i < teamCount; i++) {
138 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
139 		delete barInfo;
140 	}
141 
142 	int32 subsCount = sSubscribers.CountItems();
143 	for (int32 i = 0; i < subsCount; i++) {
144 		BMessenger* messenger
145 			= static_cast<BMessenger*>(sSubscribers.ItemAt(i));
146 		delete messenger;
147 	}
148 	SaveSettings();
149 	delete fSettingsFile;
150 }
151 
152 
153 bool
154 TBarApp::QuitRequested()
155 {
156 	// don't allow user quitting
157 	if (CurrentMessage() && CurrentMessage()->FindBool("shortcut")) {
158 		// but allow quitting to hide fPreferencesWindow
159 		int32 index = 0;
160 		BWindow* window = NULL;
161 		while ((window = WindowAt(index++)) != NULL) {
162 			if (window == fPreferencesWindow) {
163 				if (fPreferencesWindow->Lock()) {
164 					if (fPreferencesWindow->IsActive())
165 						fPreferencesWindow->PostMessage(B_QUIT_REQUESTED);
166 					fPreferencesWindow->Unlock();
167 				}
168 				break;
169 			}
170 		}
171 		return false;
172 	}
173 
174 	// system quitting, call inherited to notify all loopers
175 	fBarWindow->SaveSettings();
176 	BApplication::QuitRequested();
177 	return true;
178 }
179 
180 
181 void
182 TBarApp::SaveSettings()
183 {
184 	if (fSettingsFile->InitCheck() == B_OK) {
185 		fSettingsFile->Seek(0, SEEK_SET);
186 		BMessage storedSettings;
187 		storedSettings.AddBool("vertical", fSettings.vertical);
188 		storedSettings.AddBool("left", fSettings.left);
189 		storedSettings.AddBool("top", fSettings.top);
190 		storedSettings.AddBool("ampmMode", fSettings.ampmMode);
191 
192 		storedSettings.AddInt32("state", fSettings.state);
193 		storedSettings.AddFloat("width", fSettings.width);
194 		storedSettings.AddBool("showTime", fSettings.showTime);
195 		storedSettings.AddPoint("switcherLoc", fSettings.switcherLoc);
196 		storedSettings.AddInt32("recentAppsCount", fSettings.recentAppsCount);
197 		storedSettings.AddInt32("recentDocsCount", fSettings.recentDocsCount);
198 		storedSettings.AddBool("timeShowSeconds", fSettings.timeShowSeconds);
199 		storedSettings.AddInt32("recentFoldersCount",
200 			fSettings.recentFoldersCount);
201 		storedSettings.AddBool("alwaysOnTop", fSettings.alwaysOnTop);
202 		storedSettings.AddBool("timeFullDate", fSettings.timeFullDate);
203 		storedSettings.AddBool("trackerAlwaysFirst",
204 			fSettings.trackerAlwaysFirst);
205 		storedSettings.AddBool("sortRunningApps", fSettings.sortRunningApps);
206 		storedSettings.AddBool("superExpando", fSettings.superExpando);
207 		storedSettings.AddBool("expandNewTeams", fSettings.expandNewTeams);
208 		storedSettings.AddBool("autoRaise", fSettings.autoRaise);
209 		storedSettings.AddBool("autoHide", fSettings.autoHide);
210 		storedSettings.AddBool("recentAppsEnabled",
211 			fSettings.recentAppsEnabled);
212 		storedSettings.AddBool("recentDocsEnabled",
213 			fSettings.recentDocsEnabled);
214 		storedSettings.AddBool("recentFoldersEnabled",
215 			fSettings.recentFoldersEnabled);
216 
217 		storedSettings.Flatten(fSettingsFile);
218 	}
219 }
220 
221 
222 void
223 TBarApp::InitSettings()
224 {
225 	desk_settings settings;
226 	settings.vertical = true;
227 	settings.left = false;
228 	settings.top = true;
229 	settings.ampmMode = true;
230 	settings.showTime = true;
231 	settings.state = kExpandoState;
232 	settings.width = 0;
233 	settings.switcherLoc = BPoint(5000, 5000);
234 	settings.recentAppsCount = 10;
235 	settings.recentDocsCount = 10;
236 	settings.timeShowSeconds = false;
237 	settings.recentFoldersCount = 10;
238 	settings.alwaysOnTop = false;
239 	settings.timeFullDate = false;
240 	settings.trackerAlwaysFirst = false;
241 	settings.sortRunningApps = false;
242 	settings.superExpando = false;
243 	settings.expandNewTeams = false;
244 	settings.autoRaise = false;
245 	settings.autoHide = false;
246 	settings.recentAppsEnabled = true;
247 	settings.recentDocsEnabled = true;
248 	settings.recentFoldersEnabled = true;
249 
250 	BPath dirPath;
251 	const char* settingsFileName = "Deskbar_settings";
252 
253 	find_directory(B_USER_DESKBAR_DIRECTORY, &dirPath, true);
254 	// just make it
255 
256 	if (find_directory (B_USER_SETTINGS_DIRECTORY, &dirPath, true) == B_OK) {
257 		BPath filePath = dirPath;
258 		filePath.Append(settingsFileName);
259 		fSettingsFile = new BFile(filePath.Path(), O_RDWR);
260 		if (fSettingsFile->InitCheck() != B_OK) {
261 			BDirectory theDir(dirPath.Path());
262 			if (theDir.InitCheck() == B_OK)
263 				theDir.CreateFile(settingsFileName, fSettingsFile);
264 		}
265 
266 		BMessage storedSettings;
267 		if (fSettingsFile->InitCheck() == B_OK
268 			&& storedSettings.Unflatten(fSettingsFile) == B_OK) {
269 			storedSettings.FindBool("vertical", &settings.vertical);
270 			storedSettings.FindBool("left", &settings.left);
271 			storedSettings.FindBool("top", &settings.top);
272 			storedSettings.FindBool("ampmMode", &settings.ampmMode);
273 
274 			storedSettings.FindInt32("state", (int32*)&settings.state);
275 			storedSettings.FindFloat("width", &settings.width);
276 			storedSettings.FindBool("showTime", &settings.showTime);
277 			storedSettings.FindPoint("switcherLoc", &settings.switcherLoc);
278 			storedSettings.FindInt32("recentAppsCount",
279 				&settings.recentAppsCount);
280 			storedSettings.FindInt32("recentDocsCount",
281 				&settings.recentDocsCount);
282 			storedSettings.FindBool("timeShowSeconds",
283 				&settings.timeShowSeconds);
284 			storedSettings.FindInt32("recentFoldersCount",
285 				&settings.recentFoldersCount);
286 			storedSettings.FindBool("alwaysOnTop", &settings.alwaysOnTop);
287 			storedSettings.FindBool("timeFullDate", &settings.timeFullDate);
288 			storedSettings.FindBool("trackerAlwaysFirst",
289 				&settings.trackerAlwaysFirst);
290 			storedSettings.FindBool("sortRunningApps",
291 				&settings.sortRunningApps);
292 			storedSettings.FindBool("superExpando", &settings.superExpando);
293 			storedSettings.FindBool("expandNewTeams", &settings.expandNewTeams);
294 			storedSettings.FindBool("autoRaise", &settings.autoRaise);
295 			storedSettings.FindBool("autoHide", &settings.autoHide);
296 			storedSettings.FindBool("recentAppsEnabled",
297 				&settings.recentAppsEnabled);
298 			storedSettings.FindBool("recentDocsEnabled",
299 				&settings.recentDocsEnabled);
300 			storedSettings.FindBool("recentFoldersEnabled",
301 				&settings.recentFoldersEnabled);
302 		}
303 	}
304 
305 	fSettings = settings;
306 }
307 
308 
309 void
310 TBarApp::MessageReceived(BMessage* message)
311 {
312 	switch (message->what) {
313 		case 'gloc':
314 		case 'sloc':
315 		case 'gexp':
316 		case 'sexp':
317 		case 'info':
318 		case 'exst':
319 		case 'cwnt':
320 		case 'icon':
321 		case 'remv':
322 		case 'adon':
323 			// pass any BDeskbar originating messages on to the window
324 			fBarWindow->PostMessage(message);
325 			break;
326 
327 		case kConfigShow:
328 			ShowPreferencesWindow();
329 			break;
330 
331 		case kStateChanged:
332 			fPreferencesWindow->PostMessage(kStateChanged);
333 			break;
334 
335 		case kShowDeskbarMenu:
336 			if (fBarWindow->Lock()) {
337 				fBarWindow->ShowDeskbarMenu();
338 				fBarWindow->Unlock();
339 			}
340 			break;
341 
342 		case kShowTeamMenu:
343 			if (fBarWindow->Lock()) {
344 				fBarWindow->ShowTeamMenu();
345 				fBarWindow->Unlock();
346 			}
347 			break;
348 
349 		case kUpdateRecentCounts:
350 			int32 count;
351 			bool enabled;
352 
353 			if (message->FindInt32("applications", &count) == B_OK)
354 				fSettings.recentAppsCount = count;
355 			if (message->FindBool("applicationsEnabled", &enabled) == B_OK)
356 				fSettings.recentAppsEnabled = enabled && count > 0;
357 
358 			if (message->FindInt32("folders", &count) == B_OK)
359 				fSettings.recentFoldersCount = count;
360 			if (message->FindBool("foldersEnabled", &enabled) == B_OK)
361 				fSettings.recentFoldersEnabled = enabled && count > 0;
362 
363 			if (message->FindInt32("documents", &count) == B_OK)
364 				fSettings.recentDocsCount = count;
365 			if (message->FindBool("documentsEnabled", &enabled) == B_OK)
366 				fSettings.recentDocsEnabled = enabled && count > 0;
367 			break;
368 
369 		case kConfigClose:
370 			fPreferencesWindow = NULL;
371 			break;
372 
373 		case B_SOME_APP_LAUNCHED:
374 		{
375 			team_id team = -1;
376 			message->FindInt32("be:team", &team);
377 
378 			uint32 flags = 0;
379 			message->FindInt32("be:flags", (long*)&flags);
380 
381 			const char* sig = NULL;
382 			message->FindString("be:signature", &sig);
383 
384 			entry_ref ref;
385 			message->FindRef("be:ref", &ref);
386 
387 			AddTeam(team, flags, sig, &ref);
388 			break;
389 		}
390 
391 		case B_SOME_APP_QUIT:
392 		{
393 			team_id team = -1;
394 			message->FindInt32("be:team", &team);
395 			RemoveTeam(team);
396 			break;
397 		}
398 
399 		case B_ARCHIVED_OBJECT:
400 			// TODO: what's this???
401 			message->AddString("special", "Alex Osadzinski");
402 			fStatusViewMessenger.SendMessage(message);
403 			break;
404 
405 		case kToggleDraggers:
406 			if (BDragger::AreDraggersDrawn())
407 				BDragger::HideAllDraggers();
408 			else
409 				BDragger::ShowAllDraggers();
410 			break;
411 
412 		case kAlwaysTop:
413 			fSettings.alwaysOnTop = !fSettings.alwaysOnTop;
414 			fBarWindow->SetFeel(fSettings.alwaysOnTop ?
415 				B_FLOATING_ALL_WINDOW_FEEL : B_NORMAL_WINDOW_FEEL);
416 			fPreferencesWindow->PostMessage(kStateChanged);
417 			break;
418 
419 		case kAutoRaise:
420 			fSettings.autoRaise = fSettings.alwaysOnTop ? false :
421 				!fSettings.autoRaise;
422 
423 			fBarWindow->Lock();
424 			BarView()->UpdateEventMask();
425 			fBarWindow->Unlock();
426 			break;
427 
428 		case kAutoHide:
429 			fSettings.autoHide = !fSettings.autoHide;
430 
431 			fBarWindow->Lock();
432 			BarView()->UpdateEventMask();
433 			BarView()->HideDeskbar(fSettings.autoHide);
434 			fBarWindow->Unlock();
435 			break;
436 
437 		case kTrackerFirst:
438 			fSettings.trackerAlwaysFirst = !fSettings.trackerAlwaysFirst;
439 
440 			fBarWindow->Lock();
441 			BarView()->UpdatePlacement();
442 			fBarWindow->Unlock();
443 			break;
444 
445 		case kSortRunningApps:
446 			fSettings.sortRunningApps = !fSettings.sortRunningApps;
447 
448 			fBarWindow->Lock();
449 			BarView()->UpdatePlacement();
450 			fBarWindow->Unlock();
451 			break;
452 
453 		case kUnsubscribe:
454 		{
455 			BMessenger messenger;
456 			if (message->FindMessenger("messenger", &messenger) == B_OK)
457 				Unsubscribe(messenger);
458 			break;
459 		}
460 
461 		case kSuperExpando:
462 			fSettings.superExpando = !fSettings.superExpando;
463 
464 			fBarWindow->Lock();
465 			BarView()->UpdatePlacement();
466 			fBarWindow->Unlock();
467 			break;
468 
469 		case kExpandNewTeams:
470 			fSettings.expandNewTeams = !fSettings.expandNewTeams;
471 
472 			fBarWindow->Lock();
473 			BarView()->UpdatePlacement();
474 			fBarWindow->Unlock();
475 			break;
476 
477 		case 'TASK':
478 			fSwitcherMessenger.SendMessage(message);
479 			break;
480 
481 		case kSuspendSystem:
482 			// TODO: Call BRoster?
483 			break;
484 
485 		case kRebootSystem:
486 		case kShutdownSystem:
487 		{
488 			bool reboot = (message->what == kRebootSystem);
489 			bool confirm;
490 			message->FindBool("confirm", &confirm);
491 
492 			BRoster roster;
493 			BRoster::Private rosterPrivate(roster);
494 			status_t error = rosterPrivate.ShutDown(reboot, confirm, false);
495 			if (error != B_OK)
496 				fprintf(stderr, "Shutdown failed: %s\n", strerror(error));
497 
498 			break;
499 		}
500 
501 		case kShowSplash:
502 			run_be_about();
503 			break;
504 
505 		case kRestartTracker:
506 		{
507 			BRoster roster;
508 			roster.Launch(kTrackerSignature);
509 			break;
510 		}
511 
512 		case B_LOCALE_CHANGED:
513 		{
514 			BLocaleRoster::Default()->Refresh();
515 
516 			bool localize;
517 			if (message->FindBool("filesys", &localize) == B_OK)
518 				gLocalizedNamePreferred = localize;
519 
520 			BMessenger(fBarWindow->FindView("_deskbar_tv_")).SendMessage(
521 				message);
522 				// Notify the TimeView that the format has changed and it should
523 				// recompute its size
524 			break;
525 		}
526 
527 		default:
528 			BApplication::MessageReceived(message);
529 			break;
530 	}
531 }
532 
533 
534 void
535 TBarApp::RefsReceived(BMessage* refs)
536 {
537 	entry_ref ref;
538 	for (int32 i = 0; refs->FindRef("refs", i, &ref) == B_OK; i++) {
539 		BMessage refsReceived(B_REFS_RECEIVED);
540 		refsReceived.AddRef("refs", &ref);
541 
542 		BEntry entry(&ref);
543 		if (!entry.IsDirectory())
544 			TrackerLaunch(&refsReceived, false);
545 	}
546 }
547 
548 
549 void
550 TBarApp::Subscribe(const BMessenger &subscriber, BList* list)
551 {
552 	// called when ExpandoMenuBar, TeamMenu or Switcher are built/rebuilt
553 	list->MakeEmpty();
554 
555 	BAutolock autolock(sSubscriberLock);
556 	if (!autolock.IsLocked())
557 		return;
558 
559 	int32 numTeams = sBarTeamInfoList.CountItems();
560 	for (int32 i = 0; i < numTeams; i++) {
561 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
562 		BarTeamInfo* newBarInfo = new (std::nothrow) BarTeamInfo(*barInfo);
563 		if (newBarInfo != NULL)
564 			list->AddItem(newBarInfo);
565 	}
566 
567 	int32 subsCount = sSubscribers.CountItems();
568 	for (int32 i = 0; i < subsCount; i++) {
569 		BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
570 		if (*messenger == subscriber)
571 			return;
572 	}
573 
574 	sSubscribers.AddItem(new BMessenger(subscriber));
575 }
576 
577 
578 void
579 TBarApp::Unsubscribe(const BMessenger &subscriber)
580 {
581 	BAutolock autolock(sSubscriberLock);
582 	if (!autolock.IsLocked())
583 		return;
584 
585 	int32 count = sSubscribers.CountItems();
586 	for (int32 i = 0; i < count; i++) {
587 		BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
588 		if (*messenger == subscriber) {
589 			sSubscribers.RemoveItem(i);
590 			delete messenger;
591 			break;
592 		}
593 	}
594 }
595 
596 
597 void
598 TBarApp::AddTeam(team_id team, uint32 flags, const char* sig, entry_ref* ref)
599 {
600 	BAutolock autolock(sSubscriberLock);
601 	if (!autolock.IsLocked())
602 		return;
603 
604 	// have we already seen this team, is this another instance of
605 	// a known app?
606 	BarTeamInfo* multiLaunchTeam = NULL;
607 	int32 teamCount = sBarTeamInfoList.CountItems();
608 	for (int32 i = 0; i < teamCount; i++) {
609 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
610 		if (barInfo->teams->HasItem((void*)team))
611 			return;
612 		if (strcasecmp(barInfo->sig, sig) == 0)
613 			multiLaunchTeam = barInfo;
614 	}
615 
616 	if (multiLaunchTeam != NULL) {
617 		multiLaunchTeam->teams->AddItem((void*)team);
618 
619 		int32 subsCount = sSubscribers.CountItems();
620 		if (subsCount > 0) {
621 			BMessage message(kAddTeam);
622 			message.AddInt32("team", team);
623 			message.AddString("sig", multiLaunchTeam->sig);
624 
625 			for (int32 i = 0; i < subsCount; i++)
626 				((BMessenger*)sSubscribers.ItemAt(i))->SendMessage(&message);
627 		}
628 		return;
629 	}
630 
631 	BFile file(ref, B_READ_ONLY);
632 	BAppFileInfo appMime(&file);
633 
634 	BString name;
635 	if (!gLocalizedNamePreferred
636 		|| BLocaleRoster::Default()->GetLocalizedFileName(name, *ref) != B_OK)
637 		name = ref->name;
638 
639 	BarTeamInfo* barInfo = new BarTeamInfo(new BList(), flags, strdup(sig),
640 		new BBitmap(kIconRect, kIconFormat), strdup(name.String()));
641 
642 	barInfo->teams->AddItem((void*)team);
643 	if (appMime.GetIcon(barInfo->icon, B_MINI_ICON) != B_OK)
644 		appMime.GetTrackerIcon(barInfo->icon, B_MINI_ICON);
645 
646 	sBarTeamInfoList.AddItem(barInfo);
647 
648 	int32 subsCount = sSubscribers.CountItems();
649 	if (subsCount > 0) {
650 		for (int32 i = 0; i < subsCount; i++) {
651 			BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
652 			BMessage message(B_SOME_APP_LAUNCHED);
653 
654 			BList* tList = new BList(*(barInfo->teams));
655 			message.AddPointer("teams", tList);
656 
657 			BBitmap* icon = new BBitmap(barInfo->icon);
658 			ASSERT(icon);
659 
660 			message.AddPointer("icon", icon);
661 
662 			message.AddInt32("flags", static_cast<int32>(barInfo->flags));
663 			message.AddString("name", barInfo->name);
664 			message.AddString("sig", barInfo->sig);
665 
666 			messenger->SendMessage(&message);
667 		}
668 	}
669 }
670 
671 
672 void
673 TBarApp::RemoveTeam(team_id team)
674 {
675 	BAutolock autolock(sSubscriberLock);
676 	if (!autolock.IsLocked())
677 		return;
678 
679 	int32 teamCount = sBarTeamInfoList.CountItems();
680 	for (int32 i = 0; i < teamCount; i++) {
681 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
682 		if (barInfo->teams->HasItem((void*)team)) {
683 			int32 subsCount = sSubscribers.CountItems();
684 			if (subsCount > 0) {
685 				BMessage message((barInfo->teams->CountItems() == 1) ?
686 					B_SOME_APP_QUIT : kRemoveTeam);
687 
688 				message.AddInt32("team", team);
689 				for (int32 i = 0; i < subsCount; i++) {
690 					BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
691 					messenger->SendMessage(&message);
692 				}
693 			}
694 
695 			barInfo->teams->RemoveItem((void*)team);
696 			if (barInfo->teams->CountItems() < 1) {
697 				delete (BarTeamInfo*)sBarTeamInfoList.RemoveItem(i);
698 				return;
699 			}
700 		}
701 	}
702 }
703 
704 
705 void
706 TBarApp::ShowPreferencesWindow()
707 {
708 	if (fPreferencesWindow)
709 		fPreferencesWindow->Activate();
710 	else {
711 		fPreferencesWindow = new PreferencesWindow(BRect(0, 0, 320, 240));
712 		fPreferencesWindow->Show();
713 	}
714 }
715 
716 
717 //	#pragma mark -
718 
719 
720 BarTeamInfo::BarTeamInfo(BList* teams, uint32 flags, char* sig, BBitmap* icon,
721 	char* name)
722 	:	teams(teams),
723 		flags(flags),
724 		sig(sig),
725 		icon(icon),
726 		name(name)
727 {
728 }
729 
730 
731 BarTeamInfo::BarTeamInfo(const BarTeamInfo &info)
732 	:	teams(new BList(*info.teams)),
733 		flags(info.flags),
734 		sig(strdup(info.sig)),
735 		icon(new BBitmap(*info.icon)),
736 		name(strdup(info.name))
737 {
738 }
739 
740 
741 BarTeamInfo::~BarTeamInfo()
742 {
743 	delete teams;
744 	free(sig);
745 	delete icon;
746 	free(name);
747 }
748 
749