xref: /haiku/src/apps/deskbar/BarApp.cpp (revision 70d5966963513ff47a456ba70b7d2eec0f99648d)
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 kStateChanged:
338 			fPreferencesWindow->PostMessage(kStateChanged);
339 			break;
340 
341 		case kShowBeMenu:
342 			if (fBarWindow->Lock()) {
343 				fBarWindow->ShowBeMenu();
344 				fBarWindow->Unlock();
345 			}
346 			break;
347 
348 		case kShowTeamMenu:
349 			if (fBarWindow->Lock()) {
350 				fBarWindow->ShowTeamMenu();
351 				fBarWindow->Unlock();
352 			}
353 			break;
354 
355 		case kUpdateRecentCounts:
356 			if (message->FindInt32("applications", &count) == B_OK)
357 				fSettings.recentAppsCount = count;
358 			if (message->FindBool("applicationsEnabled", &enabled) == B_OK)
359 				fSettings.recentAppsEnabled = enabled && count > 0;
360 
361 			if (message->FindInt32("folders", &count) == B_OK)
362 				fSettings.recentFoldersCount = count;
363 			if (message->FindBool("foldersEnabled", &enabled) == B_OK)
364 				fSettings.recentFoldersEnabled = enabled && count > 0;
365 
366 			if (message->FindInt32("documents", &count) == B_OK)
367 				fSettings.recentDocsCount = count;
368 			if (message->FindBool("documentsEnabled", &enabled) == B_OK)
369 				fSettings.recentDocsEnabled = enabled && count > 0;
370 			break;
371 
372 		case kConfigClose:
373 			fPreferencesWindow = NULL;
374 			break;
375 
376 		case B_SOME_APP_LAUNCHED:
377 		{
378 			team_id team = -1;
379 			message->FindInt32("be:team", &team);
380 
381 			uint32 flags = 0;
382 			message->FindInt32("be:flags", (long*)&flags);
383 
384 			const char* sig = NULL;
385 			message->FindString("be:signature", &sig);
386 
387 			entry_ref ref;
388 			message->FindRef("be:ref", &ref);
389 
390 			AddTeam(team, flags, sig, &ref);
391 			break;
392 		}
393 
394 		case B_SOME_APP_QUIT:
395 		{
396 			team_id team = -1;
397 			message->FindInt32("be:team", &team);
398 			RemoveTeam(team);
399 			break;
400 		}
401 
402 		case B_ARCHIVED_OBJECT:
403 			// TODO: what's this???
404 			message->AddString("special", "Alex Osadzinski");
405 			fStatusViewMessenger.SendMessage(message);
406 			break;
407 
408 		case kToggleDraggers:
409 			if (BDragger::AreDraggersDrawn())
410 				BDragger::HideAllDraggers();
411 			else
412 				BDragger::ShowAllDraggers();
413 			break;
414 
415 		case kAlwaysTop:
416  			fSettings.alwaysOnTop = !fSettings.alwaysOnTop;
417 
418  			fBarWindow->SetFeel(fSettings.alwaysOnTop ?
419  				B_FLOATING_ALL_WINDOW_FEEL : B_NORMAL_WINDOW_FEEL);
420  			break;
421 
422 		case kAutoRaise:
423 		{
424 			fSettings.autoRaise = !fSettings.autoRaise;
425 
426 			TBarView* barView = static_cast<TBarApp*>(be_app)->BarView();
427 			fBarWindow->Lock();
428 			barView->UpdateAutoRaise();
429 			fBarWindow->Unlock();
430 			break;
431 		}
432 
433 		case kTrackerFirst:
434 		{
435 			fSettings.trackerAlwaysFirst = !fSettings.trackerAlwaysFirst;
436 
437 			TBarView* barView = static_cast<TBarApp*>(be_app)->BarView();
438 			fBarWindow->Lock();
439 			barView->UpdatePlacement();
440 			fBarWindow->Unlock();
441 			break;
442 		}
443 
444 		case kSortRunningApps:
445 		{
446 			fSettings.sortRunningApps = !fSettings.sortRunningApps;
447 
448 			TBarView* barView = static_cast<TBarApp*>(be_app)->BarView();
449 			fBarWindow->Lock();
450 			barView->UpdatePlacement();
451 			fBarWindow->Unlock();
452 			break;
453 		}
454 
455 		case kUnsubscribe:
456 		{
457 			BMessenger messenger;
458 			if (message->FindMessenger("messenger", &messenger) == B_OK)
459 				Unsubscribe(messenger);
460 			break;
461 		}
462 
463 		case kSuperExpando:
464 		{
465 			fSettings.superExpando = !fSettings.superExpando;
466 
467 			TBarView* barView = static_cast<TBarApp*>(be_app)->BarView();
468 			fBarWindow->Lock();
469 			barView->UpdatePlacement();
470 			fBarWindow->Unlock();
471 			break;
472 		}
473 
474 		case kExpandNewTeams:
475 		{
476 			fSettings.expandNewTeams = !fSettings.expandNewTeams;
477 
478 			TBarView* barView = static_cast<TBarApp*>(be_app)->BarView();
479 			fBarWindow->Lock();
480 			barView->UpdatePlacement();
481 			fBarWindow->Unlock();
482 			break;
483 		}
484 
485 		case 'TASK':
486 			fSwitcherMessenger.SendMessage(message);
487 			break;
488 
489 		case kSuspendSystem:
490 			// TODO: Call BRoster?
491 			break;
492 
493 		case kRebootSystem:
494 		case kShutdownSystem:
495 		{
496 			bool reboot = (message->what == kRebootSystem);
497 			bool confirm;
498 			message->FindBool("confirm", &confirm);
499 
500 			BRoster roster;
501 			BRoster::Private rosterPrivate(roster);
502 			status_t error = rosterPrivate.ShutDown(reboot, confirm, false);
503 			if (error != B_OK)
504 				fprintf(stderr, "Shutdown failed: %s\n", strerror(error));
505 
506 			break;
507 		}
508 
509 		case kShowSplash:
510 			run_be_about();
511 			break;
512 
513 		case kRestartTracker:
514 		{
515 			BRoster roster;
516 			roster.Launch(kTrackerSignature);
517 			break;
518 		}
519 
520 		case B_LOCALE_CHANGED:
521 		{
522 			BLocaleRoster::Default()->Refresh();
523 
524 			BMessenger(fBarWindow->FindView("_deskbar_tv_")).SendMessage(
525 				message);
526 				// Notify the TimeView that the format has changed and it should
527 				// recompute its size
528 			break;
529 		}
530 
531 		default:
532 			BApplication::MessageReceived(message);
533 			break;
534 	}
535 }
536 
537 
538 void
539 TBarApp::RefsReceived(BMessage* refs)
540 {
541 	entry_ref ref;
542 	for (int32 i = 0; refs->FindRef("refs", i, &ref) == B_OK; i++) {
543 		BMessage refsReceived(B_REFS_RECEIVED);
544 		refsReceived.AddRef("refs", &ref);
545 
546 		BEntry entry(&ref);
547 		if (!entry.IsDirectory())
548 			TrackerLaunch(&refsReceived, false);
549 	}
550 }
551 
552 
553 void
554 TBarApp::Subscribe(const BMessenger &subscriber, BList* list)
555 {
556 	// called when ExpandoMenuBar, TeamMenu or Switcher are built/rebuilt
557 	list->MakeEmpty();
558 
559 	BAutolock autolock(sSubscriberLock);
560 	if (!autolock.IsLocked())
561 		return;
562 
563 	int32 numTeams = sBarTeamInfoList.CountItems();
564 	for (int32 i = 0; i < numTeams; i++) {
565 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
566 		BarTeamInfo* newBarInfo = new (std::nothrow) BarTeamInfo(*barInfo);
567 		if (newBarInfo != NULL)
568 			list->AddItem(newBarInfo);
569 	}
570 
571 	int32 subsCount = sSubscribers.CountItems();
572 	for (int32 i = 0; i < subsCount; i++) {
573 		BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
574 		if (*messenger == subscriber)
575 			return;
576 	}
577 
578 	sSubscribers.AddItem(new BMessenger(subscriber));
579 }
580 
581 
582 void
583 TBarApp::Unsubscribe(const BMessenger &subscriber)
584 {
585 	BAutolock autolock(sSubscriberLock);
586 	if (!autolock.IsLocked())
587 		return;
588 
589 	int32 count = sSubscribers.CountItems();
590 	for (int32 i = 0; i < count; i++) {
591 		BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
592 		if (*messenger == subscriber) {
593 			sSubscribers.RemoveItem(i);
594 			delete messenger;
595 			break;
596 		}
597 	}
598 }
599 
600 
601 void
602 TBarApp::AddTeam(team_id team, uint32 flags, const char* sig, entry_ref* ref)
603 {
604 	BAutolock autolock(sSubscriberLock);
605 	if (!autolock.IsLocked())
606 		return;
607 
608 	// have we already seen this team, is this another instance of
609 	// a known app?
610 	BarTeamInfo* multiLaunchTeam = NULL;
611 	int32 teamCount = sBarTeamInfoList.CountItems();
612 	for (int32 i = 0; i < teamCount; i++) {
613 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
614 		if (barInfo->teams->HasItem((void*)team))
615 			return;
616 		if (strcasecmp(barInfo->sig, sig) == 0)
617 			multiLaunchTeam = barInfo;
618 	}
619 
620 	if (multiLaunchTeam != NULL) {
621 		multiLaunchTeam->teams->AddItem((void*)team);
622 
623 		int32 subsCount = sSubscribers.CountItems();
624 		if (subsCount > 0) {
625 			BMessage message(kAddTeam);
626 			message.AddInt32("team", team);
627 			message.AddString("sig", multiLaunchTeam->sig);
628 
629 			for (int32 i = 0; i < subsCount; i++)
630 				((BMessenger*)sSubscribers.ItemAt(i))->SendMessage(&message);
631 		}
632 		return;
633 	}
634 
635 	BFile file(ref, B_READ_ONLY);
636 	BAppFileInfo appMime(&file);
637 
638 	BarTeamInfo* barInfo = new BarTeamInfo(new BList(), flags, strdup(sig),
639 		new BBitmap(kIconSize, kIconFormat), strdup(ref->name));
640 
641 	barInfo->teams->AddItem((void*)team);
642 	if (appMime.GetIcon(barInfo->icon, B_MINI_ICON) != B_OK)
643 		appMime.GetTrackerIcon(barInfo->icon, B_MINI_ICON);
644 
645 	sBarTeamInfoList.AddItem(barInfo);
646 
647 	int32 subsCount = sSubscribers.CountItems();
648 	if (subsCount > 0) {
649 		for (int32 i = 0; i < subsCount; i++) {
650 			BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
651 			BMessage message(B_SOME_APP_LAUNCHED);
652 
653 			BList* tList = new BList(*(barInfo->teams));
654 			message.AddPointer("teams", tList);
655 
656 			BBitmap* icon = new BBitmap(barInfo->icon);
657 			ASSERT(icon);
658 
659 			message.AddPointer("icon", icon);
660 
661 			message.AddInt32("flags", static_cast<int32>(barInfo->flags));
662 			message.AddString("name", barInfo->name);
663 			message.AddString("sig", barInfo->sig);
664 
665 			messenger->SendMessage(&message);
666 		}
667 	}
668 }
669 
670 
671 void
672 TBarApp::RemoveTeam(team_id team)
673 {
674 	BAutolock autolock(sSubscriberLock);
675 	if (!autolock.IsLocked())
676 		return;
677 
678 	int32 teamCount = sBarTeamInfoList.CountItems();
679 	for (int32 i = 0; i < teamCount; i++) {
680 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
681 		if (barInfo->teams->HasItem((void*)team)) {
682 			int32 subsCount = sSubscribers.CountItems();
683 			if (subsCount > 0) {
684 				BMessage message((barInfo->teams->CountItems() == 1) ?
685 					 B_SOME_APP_QUIT : kRemoveTeam);
686 
687 				message.AddInt32("team", team);
688 				for (int32 i = 0; i < subsCount; i++) {
689 					BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
690 					messenger->SendMessage(&message);
691 				}
692 			}
693 
694 			barInfo->teams->RemoveItem((void*)team);
695 			if (barInfo->teams->CountItems() < 1) {
696 				delete (BarTeamInfo*)sBarTeamInfoList.RemoveItem(i);
697 				return;
698 			}
699 		}
700 	}
701 }
702 
703 
704 void
705 TBarApp::ShowPreferencesWindow()
706 {
707 	if (fPreferencesWindow)
708 		fPreferencesWindow->Activate();
709  	else {
710 		fPreferencesWindow = new PreferencesWindow(BRect(0, 0, 320, 240));
711 		fPreferencesWindow->Show();
712 	}
713 }
714 
715 
716 //	#pragma mark -
717 
718 
719 BarTeamInfo::BarTeamInfo(BList* teams, uint32 flags, char* sig, BBitmap* icon,
720 	char* name)
721 	:	teams(teams),
722 		flags(flags),
723 		sig(sig),
724 		icon(icon),
725 		name(name)
726 {
727 }
728 
729 
730 BarTeamInfo::BarTeamInfo(const BarTeamInfo &info)
731 	:	teams(new BList(*info.teams)),
732 		flags(info.flags),
733 		sig(strdup(info.sig)),
734 		icon(new BBitmap(*info.icon)),
735 		name(strdup(info.name))
736 {
737 }
738 
739 
740 BarTeamInfo::~BarTeamInfo()
741 {
742 	delete teams;
743 	free(sig);
744 	delete icon;
745 	free(name);
746 }
747 
748