xref: /haiku/src/apps/deskbar/BarApp.cpp (revision e0ef64750f3169cd634bb2f7a001e22488b05231)
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 trademarks
30 of Be Incorporated in the United States and other countries. Other brand product
31 names are registered trademarks or trademarks of their respective holders.
32 All rights reserved.
33 */
34 
35 #include <Debug.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 #include <AppFileInfo.h>
40 #include <Autolock.h>
41 #include <Bitmap.h>
42 #include <Catalog.h>
43 #include <Directory.h>
44 #include <Dragger.h>
45 #include <File.h>
46 #include <FindDirectory.h>
47 #include <Locale.h>
48 #include <Mime.h>
49 #include <Path.h>
50 #include <Roster.h>
51 #include <RosterPrivate.h>
52 
53 #include "icons.h"
54 #include "tracker_private.h"
55 #include "BarApp.h"
56 #include "BarView.h"
57 #include "BarWindow.h"
58 #include "DeskBarUtils.h"
59 #include "FSUtils.h"
60 #include "PublicCommands.h"
61 #include "ResourceSet.h"
62 #include "Switcher.h"
63 #include "TeamMenu.h"
64 #include "WindowMenuItem.h"
65 
66 
67 BLocker TBarApp::sSubscriberLock;
68 BList TBarApp::sBarTeamInfoList;
69 BList TBarApp::sSubscribers;
70 
71 
72 const uint32 kShowBeMenu = 'BeMn';
73 const uint32 kShowTeamMenu = 'TmMn';
74 
75 const BRect kIconSize(0.0f, 0.0f, 15.0f, 15.0f);
76 
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 	sBarTeamInfoList.MakeEmpty();
101 
102 	BList teamList;
103 	int32 numTeams;
104 	be_roster->GetAppList(&teamList);
105 	numTeams = teamList.CountItems();
106 	for (int32 i = 0; i < numTeams; i++) {
107 		app_info appInfo;
108 		team_id tID = (team_id)teamList.ItemAt(i);
109 		if (be_roster->GetRunningAppInfo(tID, &appInfo) == B_OK) {
110 			AddTeam(appInfo.team, appInfo.flags, appInfo.signature,
111 				&appInfo.ref);
112 		}
113 	}
114 
115 	sSubscribers.MakeEmpty();
116 
117 	fSwitcherMessenger = BMessenger(new TSwitchManager(fSettings.switcherLoc));
118 
119 	fBarWindow = new TBarWindow();
120 	fBarWindow->Show();
121 
122 	// this messenger now targets the barview instead of the
123 	// statusview so that all additions to the tray
124 	// follow the same path
125 	fStatusViewMessenger = BMessenger(fBarWindow->FindView("BarView"));
126 }
127 
128 
129 TBarApp::~TBarApp()
130 {
131 	be_roster->StopWatching(this);
132 
133 	int32 teamCount = sBarTeamInfoList.CountItems();
134 	for (int32 i = 0; i < teamCount; i++) {
135 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
136 		delete barInfo;
137 	}
138 
139 	int32 subsCount = sSubscribers.CountItems();
140 	for (int32 i = 0; i < subsCount; i++) {
141 		BMessenger* messenger
142 			= static_cast<BMessenger*>(sSubscribers.ItemAt(i));
143 		delete messenger;
144 	}
145 	SaveSettings();
146 	delete fSettingsFile;
147 }
148 
149 
150 bool
151 TBarApp::QuitRequested()
152 {
153 	// don't allow user quitting
154 	if (CurrentMessage() && CurrentMessage()->FindBool("shortcut")) {
155 		// but allow quitting to hide fPreferencesWindow
156 		int32 index = 0;
157 		BWindow* window = NULL;
158 		while ((window = WindowAt(index++)) != NULL) {
159 			if (window == fPreferencesWindow) {
160 				if (fPreferencesWindow->Lock()) {
161 					if (fPreferencesWindow->IsActive())
162 						fPreferencesWindow->PostMessage(B_QUIT_REQUESTED);
163 					fPreferencesWindow->Unlock();
164 				}
165 				break;
166 			}
167 		}
168 		return false;
169 	}
170 
171 	// system quitting, call inherited to notify all loopers
172 	fBarWindow->SaveSettings();
173 	BApplication::QuitRequested();
174 	return true;
175 }
176 
177 
178 void
179 TBarApp::SaveSettings()
180 {
181 	if (fSettingsFile->InitCheck() == B_OK) {
182 		fSettingsFile->Seek(0, SEEK_SET);
183 		BMessage storedSettings;
184 		storedSettings.AddBool("vertical", fSettings.vertical);
185 		storedSettings.AddBool("left", fSettings.left);
186 		storedSettings.AddBool("top", fSettings.top);
187 		storedSettings.AddBool("ampmMode", fSettings.ampmMode);
188 
189 		storedSettings.AddInt32("state", fSettings.state);
190 		storedSettings.AddFloat("width", fSettings.width);
191 		storedSettings.AddBool("showTime", fSettings.showTime);
192 		storedSettings.AddPoint("switcherLoc", fSettings.switcherLoc);
193 		storedSettings.AddInt32("recentAppsCount",
194 			fSettings.recentAppsCount);
195 		storedSettings.AddInt32("recentDocsCount",
196 			fSettings.recentDocsCount);
197 		storedSettings.AddBool("timeShowSeconds",
198 			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",
206 			fSettings.sortRunningApps);
207 		storedSettings.AddBool("superExpando",
208 			fSettings.superExpando);
209 		storedSettings.AddBool("expandNewTeams",
210 			fSettings.expandNewTeams);
211 		storedSettings.AddBool("autoRaise",
212 			fSettings.autoRaise);
213 		storedSettings.AddBool("recentAppsEnabled",
214 			fSettings.recentAppsEnabled);
215 		storedSettings.AddBool("recentDocsEnabled",
216 			fSettings.recentDocsEnabled);
217 		storedSettings.AddBool("recentFoldersEnabled",
218 			fSettings.recentFoldersEnabled);
219 
220 		storedSettings.Flatten(fSettingsFile);
221 	}
222 }
223 
224 
225 void
226 TBarApp::InitSettings()
227 {
228 	desk_settings settings;
229 	settings.vertical = true;
230 	settings.left = false;
231 	settings.top = true;
232 	settings.ampmMode = true;
233 	settings.showTime = true;
234 	settings.state = kExpandoState;
235 	settings.width = 0;
236 	settings.switcherLoc = BPoint(5000, 5000);
237 	settings.recentAppsCount = 10;
238 	settings.recentDocsCount = 10;
239 	settings.timeShowSeconds = false;
240 	settings.recentFoldersCount = 10;
241 	settings.alwaysOnTop = false;
242 	settings.timeFullDate = false;
243 	settings.trackerAlwaysFirst = false;
244 	settings.sortRunningApps = false;
245 	settings.superExpando = false;
246 	settings.expandNewTeams = false;
247 	settings.autoRaise = false;
248 	settings.recentAppsEnabled = true;
249 	settings.recentDocsEnabled = true;
250 	settings.recentFoldersEnabled = true;
251 
252 	BPath dirPath;
253 	const char* settingsFileName = "Deskbar_settings";
254 
255 	find_directory(B_USER_DESKBAR_DIRECTORY, &dirPath, true);
256 	// just make it
257 
258 	if (find_directory (B_USER_SETTINGS_DIRECTORY, &dirPath, true) == B_OK) {
259 		BPath filePath = dirPath;
260 		filePath.Append(settingsFileName);
261 		fSettingsFile = new BFile(filePath.Path(), O_RDWR);
262 		if (fSettingsFile->InitCheck() != B_OK) {
263 			BDirectory theDir(dirPath.Path());
264 			if (theDir.InitCheck() == B_OK)
265 				theDir.CreateFile(settingsFileName, fSettingsFile);
266 		}
267 
268 		BMessage storedSettings;
269 		if (fSettingsFile->InitCheck() == B_OK
270 			&& storedSettings.Unflatten(fSettingsFile) == B_OK) {
271 			storedSettings.FindBool("vertical", &settings.vertical);
272 			storedSettings.FindBool("left", &settings.left);
273 			storedSettings.FindBool("top", &settings.top);
274 			storedSettings.FindBool("ampmMode", &settings.ampmMode);
275 
276 			storedSettings.FindInt32("state", (int32*)&settings.state);
277 			storedSettings.FindFloat("width", &settings.width);
278 			storedSettings.FindBool("showTime", &settings.showTime);
279 			storedSettings.FindPoint("switcherLoc", &settings.switcherLoc);
280 			storedSettings.FindInt32("recentAppsCount",
281 				&settings.recentAppsCount);
282 			storedSettings.FindInt32("recentDocsCount",
283 				&settings.recentDocsCount);
284 			storedSettings.FindBool("timeShowSeconds",
285 				&settings.timeShowSeconds);
286 			storedSettings.FindInt32("recentFoldersCount",
287 				&settings.recentFoldersCount);
288 			storedSettings.FindBool("alwaysOnTop", &settings.alwaysOnTop);
289 			storedSettings.FindBool("timeFullDate", &settings.timeFullDate);
290 			storedSettings.FindBool("trackerAlwaysFirst",
291 				&settings.trackerAlwaysFirst);
292 			storedSettings.FindBool("sortRunningApps",
293 				&settings.sortRunningApps);
294 			storedSettings.FindBool("superExpando",
295 				&settings.superExpando);
296 			storedSettings.FindBool("expandNewTeams",
297 				&settings.expandNewTeams);
298 			storedSettings.FindBool("autoRaise",
299 				&settings.autoRaise);
300 			storedSettings.FindBool("recentAppsEnabled",
301 				&settings.recentAppsEnabled);
302 			storedSettings.FindBool("recentDocsEnabled",
303 				&settings.recentDocsEnabled);
304 			storedSettings.FindBool("recentFoldersEnabled",
305 				&settings.recentFoldersEnabled);
306 		}
307 	}
308 
309 	fSettings = settings;
310 }
311 
312 
313 void
314 TBarApp::MessageReceived(BMessage* message)
315 {
316 	int32 count;
317 	bool enabled;
318 	switch (message->what) {
319 		case 'gloc':
320 		case 'sloc':
321 		case 'gexp':
322 		case 'sexp':
323 		case 'info':
324 		case 'exst':
325 		case 'cwnt':
326 		case 'icon':
327 		case 'remv':
328 		case 'adon':
329 			// pass any BDeskbar originating messages on to the window
330 			fBarWindow->PostMessage(message);
331 			break;
332 
333 		case kConfigShow:
334 			ShowPreferencesWindow();
335 			break;
336 
337 		case kShowBeMenu:
338 			if (fBarWindow->Lock()) {
339 				fBarWindow->ShowBeMenu();
340 				fBarWindow->Unlock();
341 			}
342 			break;
343 
344 		case kShowTeamMenu:
345 			if (fBarWindow->Lock()) {
346 				fBarWindow->ShowTeamMenu();
347 				fBarWindow->Unlock();
348 			}
349 			break;
350 
351 		case kUpdateRecentCounts:
352 			if (message->FindInt32("applications", &count) == B_OK)
353 				fSettings.recentAppsCount = count;
354 			if (message->FindBool("applicationsEnabled", &enabled) == B_OK)
355 				fSettings.recentAppsEnabled = enabled && count > 0;
356 
357 			if (message->FindInt32("folders", &count) == B_OK)
358 				fSettings.recentFoldersCount = count;
359 			if (message->FindBool("foldersEnabled", &enabled) == B_OK)
360 				fSettings.recentFoldersEnabled = enabled && count > 0;
361 
362 			if (message->FindInt32("documents", &count) == B_OK)
363 				fSettings.recentDocsCount = count;
364 			if (message->FindBool("documentsEnabled", &enabled) == B_OK)
365 				fSettings.recentDocsEnabled = enabled && count > 0;
366 			break;
367 
368 		case kConfigClose:
369 			fPreferencesWindow = NULL;
370 			break;
371 
372 		case B_SOME_APP_LAUNCHED:
373 		{
374 			team_id team = -1;
375 			message->FindInt32("be:team", &team);
376 
377 			uint32 flags = 0;
378 			message->FindInt32("be:flags", (long*)&flags);
379 
380 			const char* sig = NULL;
381 			message->FindString("be:signature", &sig);
382 
383 			entry_ref ref;
384 			message->FindRef("be:ref", &ref);
385 
386 			AddTeam(team, flags, sig, &ref);
387 			break;
388 		}
389 
390 		case B_SOME_APP_QUIT:
391 		{
392 			team_id team = -1;
393 			message->FindInt32("be:team", &team);
394 			RemoveTeam(team);
395 			break;
396 		}
397 
398 		case B_ARCHIVED_OBJECT:
399 			// TODO: what's this???
400 			message->AddString("special", "Alex Osadzinski");
401 			fStatusViewMessenger.SendMessage(message);
402 			break;
403 
404 		case kToggleDraggers:
405 			if (BDragger::AreDraggersDrawn())
406 				BDragger::HideAllDraggers();
407 			else
408 				BDragger::ShowAllDraggers();
409 			break;
410 
411 		case kAlwaysTop:
412  			fSettings.alwaysOnTop = !fSettings.alwaysOnTop;
413 
414  			fBarWindow->SetFeel(fSettings.alwaysOnTop ?
415  				B_FLOATING_ALL_WINDOW_FEEL : B_NORMAL_WINDOW_FEEL);
416  			break;
417 
418 		case kAutoRaise:
419 		{
420 			fSettings.autoRaise = !fSettings.autoRaise;
421 
422 			TBarView* barView = static_cast<TBarApp*>(be_app)->BarView();
423 			fBarWindow->Lock();
424 			barView->UpdateAutoRaise();
425 			fBarWindow->Unlock();
426 			break;
427 		}
428 
429 		case kTrackerFirst:
430 		{
431 			fSettings.trackerAlwaysFirst = !fSettings.trackerAlwaysFirst;
432 
433 			TBarView* barView = static_cast<TBarApp*>(be_app)->BarView();
434 			fBarWindow->Lock();
435 			barView->UpdatePlacement();
436 			fBarWindow->Unlock();
437 			break;
438 		}
439 
440 		case kSortRunningApps:
441 		{
442 			fSettings.sortRunningApps = !fSettings.sortRunningApps;
443 
444 			TBarView* barView = static_cast<TBarApp*>(be_app)->BarView();
445 			fBarWindow->Lock();
446 			barView->UpdatePlacement();
447 			fBarWindow->Unlock();
448 			break;
449 		}
450 
451 		case kUnsubscribe:
452 		{
453 			BMessenger messenger;
454 			if (message->FindMessenger("messenger", &messenger) == B_OK)
455 				Unsubscribe(messenger);
456 			break;
457 		}
458 
459 		case kSuperExpando:
460 		{
461 			fSettings.superExpando = !fSettings.superExpando;
462 
463 			TBarView* barView = static_cast<TBarApp*>(be_app)->BarView();
464 			fBarWindow->Lock();
465 			barView->UpdatePlacement();
466 			fBarWindow->Unlock();
467 			break;
468 		}
469 
470 		case kExpandNewTeams:
471 		{
472 			fSettings.expandNewTeams = !fSettings.expandNewTeams;
473 
474 			TBarView* barView = static_cast<TBarApp*>(be_app)->BarView();
475 			fBarWindow->Lock();
476 			barView->UpdatePlacement();
477 			fBarWindow->Unlock();
478 			break;
479 		}
480 
481 		case 'TASK':
482 			fSwitcherMessenger.SendMessage(message);
483 			break;
484 
485 		case kSuspendSystem:
486 			// TODO: Call BRoster?
487 			break;
488 
489 		case kRebootSystem:
490 		case kShutdownSystem:
491 		{
492 			bool reboot = (message->what == kRebootSystem);
493 			bool confirm;
494 			message->FindBool("confirm", &confirm);
495 
496 			BRoster roster;
497 			BRoster::Private rosterPrivate(roster);
498 			status_t error = rosterPrivate.ShutDown(reboot, confirm, false);
499 			if (error != B_OK)
500 				fprintf(stderr, "Shutdown failed: %s\n", strerror(error));
501 
502 			break;
503 		}
504 
505 		case kShowSplash:
506 			run_be_about();
507 			break;
508 
509 		case kRestartTracker:
510 		{
511 			BRoster roster;
512 			roster.Launch(kTrackerSignature);
513 			break;
514 		}
515 
516 		case B_LOCALE_CHANGED:
517 		{
518 			be_locale_roster->Refresh();
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 	BarTeamInfo* barInfo = new BarTeamInfo(new BList(), flags, strdup(sig),
635 		new BBitmap(kIconSize, kIconFormat), strdup(ref->name));
636 
637 	barInfo->teams->AddItem((void*)team);
638 	if (appMime.GetIcon(barInfo->icon, B_MINI_ICON) != B_OK)
639 		appMime.GetTrackerIcon(barInfo->icon, B_MINI_ICON);
640 
641 	sBarTeamInfoList.AddItem(barInfo);
642 
643 	int32 subsCount = sSubscribers.CountItems();
644 	if (subsCount > 0) {
645 		for (int32 i = 0; i < subsCount; i++) {
646 			BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
647 			BMessage message(B_SOME_APP_LAUNCHED);
648 
649 			BList* tList = new BList(*(barInfo->teams));
650 			message.AddPointer("teams", tList);
651 
652 			BBitmap* icon = new BBitmap(barInfo->icon);
653 			ASSERT(icon);
654 
655 			message.AddPointer("icon", icon);
656 
657 			message.AddInt32("flags", static_cast<int32>(barInfo->flags));
658 			message.AddString("name", barInfo->name);
659 			message.AddString("sig", barInfo->sig);
660 
661 			messenger->SendMessage(&message);
662 		}
663 	}
664 }
665 
666 
667 void
668 TBarApp::RemoveTeam(team_id team)
669 {
670 	BAutolock autolock(sSubscriberLock);
671 	if (!autolock.IsLocked())
672 		return;
673 
674 	int32 teamCount = sBarTeamInfoList.CountItems();
675 	for (int32 i = 0; i < teamCount; i++) {
676 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
677 		if (barInfo->teams->HasItem((void*)team)) {
678 			int32 subsCount = sSubscribers.CountItems();
679 			if (subsCount > 0) {
680 				BMessage message((barInfo->teams->CountItems() == 1) ?
681 					 B_SOME_APP_QUIT : kRemoveTeam);
682 
683 				message.AddInt32("team", team);
684 				for (int32 i = 0; i < subsCount; i++) {
685 					BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
686 					messenger->SendMessage(&message);
687 				}
688 			}
689 
690 			barInfo->teams->RemoveItem((void*)team);
691 			if (barInfo->teams->CountItems() < 1) {
692 				delete (BarTeamInfo*)sBarTeamInfoList.RemoveItem(i);
693 				return;
694 			}
695 		}
696 	}
697 }
698 
699 
700 void
701 TBarApp::ShowPreferencesWindow()
702 {
703 	if (fPreferencesWindow)
704 		fPreferencesWindow->Activate();
705  	else {
706 		fPreferencesWindow = new PreferencesWindow(BRect(0, 0, 320, 240));
707 		fPreferencesWindow->Show();
708 	}
709 }
710 
711 
712 //	#pragma mark -
713 
714 
715 BarTeamInfo::BarTeamInfo(BList* teams, uint32 flags, char* sig, BBitmap* icon,
716 	char* name)
717 	:	teams(teams),
718 		flags(flags),
719 		sig(sig),
720 		icon(icon),
721 		name(name)
722 {
723 }
724 
725 
726 BarTeamInfo::BarTeamInfo(const BarTeamInfo &info)
727 	:	teams(new BList(*info.teams)),
728 		flags(info.flags),
729 		sig(strdup(info.sig)),
730 		icon(new BBitmap(*info.icon)),
731 		name(strdup(info.name))
732 {
733 }
734 
735 
736 BarTeamInfo::~BarTeamInfo()
737 {
738 	delete teams;
739 	free(sig);
740 	delete icon;
741 	free(name);
742 }
743 
744