xref: /haiku/src/apps/deskbar/BarApp.cpp (revision 37c7d5d83a2372a6971e383411d5bacbeef0ebdc)
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_locale->GetAppCatalog(&fCatalog);
99 	be_roster->StartWatching(this);
100 
101 	sBarTeamInfoList.MakeEmpty();
102 
103 	BList teamList;
104 	int32 numTeams;
105 	be_roster->GetAppList(&teamList);
106 	numTeams = teamList.CountItems();
107 	for (int32 i = 0; i < numTeams; i++) {
108 		app_info appInfo;
109 		team_id tID = (team_id)teamList.ItemAt(i);
110 		if (be_roster->GetRunningAppInfo(tID, &appInfo) == B_OK) {
111 			AddTeam(appInfo.team, appInfo.flags, appInfo.signature,
112 				&appInfo.ref);
113 		}
114 	}
115 
116 	sSubscribers.MakeEmpty();
117 
118 	fSwitcherMessenger = BMessenger(new TSwitchManager(fSettings.switcherLoc));
119 
120 	fBarWindow = new TBarWindow();
121 	fBarWindow->Show();
122 
123 	// this messenger now targets the barview instead of the
124 	// statusview so that all additions to the tray
125 	// follow the same path
126 	fStatusViewMessenger = BMessenger(fBarWindow->FindView("BarView"));
127 }
128 
129 
130 TBarApp::~TBarApp()
131 {
132 	be_roster->StopWatching(this);
133 
134 	int32 teamCount = sBarTeamInfoList.CountItems();
135 	for (int32 i = 0; i < teamCount; i++) {
136 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
137 		delete barInfo;
138 	}
139 
140 	int32 subsCount = sSubscribers.CountItems();
141 	for (int32 i = 0; i < subsCount; i++) {
142 		BMessenger* messenger
143 			= static_cast<BMessenger*>(sSubscribers.ItemAt(i));
144 		delete messenger;
145 	}
146 	SaveSettings();
147 	delete fSettingsFile;
148 }
149 
150 
151 bool
152 TBarApp::QuitRequested()
153 {
154 	// don't allow user quitting
155 	if (CurrentMessage() && CurrentMessage()->FindBool("shortcut")) {
156 		// but allow quitting to hide fPreferencesWindow
157 		int32 index = 0;
158 		BWindow* window = NULL;
159 		while ((window = WindowAt(index++)) != NULL) {
160 			if (window == fPreferencesWindow) {
161 				if (fPreferencesWindow->Lock()) {
162 					if (fPreferencesWindow->IsActive())
163 						fPreferencesWindow->PostMessage(B_QUIT_REQUESTED);
164 					fPreferencesWindow->Unlock();
165 				}
166 				break;
167 			}
168 		}
169 		return false;
170 	}
171 
172 	// system quitting, call inherited to notify all loopers
173 	fBarWindow->SaveSettings();
174 	BApplication::QuitRequested();
175 	return true;
176 }
177 
178 
179 void
180 TBarApp::SaveSettings()
181 {
182 	if (fSettingsFile->InitCheck() == B_OK) {
183 		fSettingsFile->Seek(0, SEEK_SET);
184 		fSettingsFile->Write(&fSettings.vertical, sizeof(bool));
185 		fSettingsFile->Write(&fSettings.left, sizeof(bool));
186 		fSettingsFile->Write(&fSettings.top, sizeof(bool));
187 		fSettingsFile->Write(&fSettings.ampmMode, sizeof(bool));
188 		fSettingsFile->Write(&fSettings.state, sizeof(uint32));
189 		fSettingsFile->Write(&fSettings.width, sizeof(float));
190 		fSettingsFile->Write(&fSettings.showTime, sizeof(bool));
191 		fSettingsFile->Write(&fSettings.switcherLoc, sizeof(BPoint));
192 		fSettingsFile->Write(&fSettings.recentAppsCount, sizeof(int32));
193 		fSettingsFile->Write(&fSettings.recentDocsCount, sizeof(int32));
194 		fSettingsFile->Write(&fSettings.timeShowSeconds, sizeof(bool));
195 		fSettingsFile->Write(&fSettings.timeShowMil, sizeof(bool));
196 		fSettingsFile->Write(&fSettings.recentFoldersCount, sizeof(int32));
197 		fSettingsFile->Write(&fSettings.timeShowEuro, sizeof(bool));
198 		fSettingsFile->Write(&fSettings.alwaysOnTop, sizeof(bool));
199 		fSettingsFile->Write(&fSettings.timeFullDate, sizeof(bool));
200 		fSettingsFile->Write(&fSettings.trackerAlwaysFirst, sizeof(bool));
201 		fSettingsFile->Write(&fSettings.sortRunningApps, sizeof(bool));
202 		fSettingsFile->Write(&fSettings.superExpando, sizeof(bool));
203 		fSettingsFile->Write(&fSettings.expandNewTeams, sizeof(bool));
204 		fSettingsFile->Write(&fSettings.autoRaise, sizeof(bool));
205 		fSettingsFile->Write(&fSettings.recentAppsEnabled, sizeof(bool));
206 		fSettingsFile->Write(&fSettings.recentDocsEnabled, sizeof(bool));
207 		fSettingsFile->Write(&fSettings.recentFoldersEnabled, sizeof(bool));
208 	}
209 }
210 
211 
212 void
213 TBarApp::InitSettings()
214 {
215 	desk_settings settings;
216 	settings.vertical = true;
217 	settings.left = false;
218 	settings.top = true;
219 	settings.ampmMode = true;
220 	settings.showTime = true;
221 	settings.state = kExpandoState;
222 	settings.width = 0;
223 	settings.switcherLoc = BPoint(5000, 5000);
224 	settings.recentAppsCount = 10;
225 	settings.recentDocsCount = 10;
226 	settings.timeShowSeconds = false;
227 	settings.timeShowMil = false;
228 	settings.recentFoldersCount = 10;
229 	settings.timeShowEuro = false;
230 	settings.alwaysOnTop = false;
231 	settings.timeFullDate = false;
232 	settings.trackerAlwaysFirst = false;
233 	settings.sortRunningApps = false;
234 	settings.superExpando = false;
235 	settings.expandNewTeams = false;
236 	settings.autoRaise = false;
237 	settings.recentAppsEnabled = true;
238 	settings.recentDocsEnabled = true;
239 	settings.recentFoldersEnabled = true;
240 
241 	BPath dirPath;
242 	const char* settingsFileName = "Deskbar_settings";
243 
244 	find_directory(B_USER_DESKBAR_DIRECTORY, &dirPath, true);
245 	// just make it
246 
247 	if (find_directory (B_USER_SETTINGS_DIRECTORY, &dirPath, true) == B_OK) {
248 		BPath filePath = dirPath;
249 		filePath.Append(settingsFileName);
250 		fSettingsFile = new BFile(filePath.Path(), O_RDWR);
251 		if (fSettingsFile->InitCheck() != B_OK) {
252 			BDirectory theDir(dirPath.Path());
253 			if (theDir.InitCheck() == B_OK)
254 				theDir.CreateFile(settingsFileName, fSettingsFile);
255 		}
256 
257 		if (fSettingsFile->InitCheck() == B_OK) {
258 			off_t size = 0;
259 			fSettingsFile->GetSize(&size);
260 
261 			if (size >= kValidSettingsSize1) {
262 				fSettingsFile->Seek(0, SEEK_SET);
263 				fSettingsFile->Read(&settings.vertical, sizeof(bool));
264 				fSettingsFile->Read(&settings.left, sizeof(bool));
265 				fSettingsFile->Read(&settings.top, sizeof(bool));
266 				fSettingsFile->Read(&settings.ampmMode, sizeof(bool));
267 				fSettingsFile->Read(&settings.state, sizeof(uint32));
268 				fSettingsFile->Read(&settings.width, sizeof(float));
269 				fSettingsFile->Read(&settings.showTime, sizeof(bool));
270 			}
271 			if (size >= kValidSettingsSize2)
272 				fSettingsFile->Read(&settings.switcherLoc, sizeof(BPoint));
273 			if (size >= kValidSettingsSize3) {
274 				fSettingsFile->Read(&settings.recentAppsCount, sizeof(int32));
275 				fSettingsFile->Read(&settings.recentDocsCount, sizeof(int32));
276 			}
277 			if (size >= kValidSettingsSize4) {
278 				fSettingsFile->Read(&settings.timeShowSeconds, sizeof(bool));
279 				fSettingsFile->Read(&settings.timeShowMil, sizeof(bool));
280 			}
281 			if (size >= kValidSettingsSize5)
282 				fSettingsFile->Read(&settings.recentFoldersCount,
283 					sizeof(int32));
284 			if (size >= kValidSettingsSize6) {
285 				fSettingsFile->Read(&settings.timeShowEuro, sizeof(bool));
286 				fSettingsFile->Read(&settings.alwaysOnTop, sizeof(bool));
287 			}
288 			if (size >= kValidSettingsSize7)
289 				fSettingsFile->Read(&settings.timeFullDate, sizeof(bool));
290 			if (size >= kValidSettingsSize8) {
291 				fSettingsFile->Read(&settings.trackerAlwaysFirst, sizeof(bool));
292 				fSettingsFile->Read(&settings.sortRunningApps, sizeof(bool));
293 			}
294 			if (size >= kValidSettingsSize9) {
295 				fSettingsFile->Read(&settings.superExpando, sizeof(bool));
296 				fSettingsFile->Read(&settings.expandNewTeams, sizeof(bool));
297 			}
298 			if (size >= kValidSettingsSize10)
299 				fSettingsFile->Read(&settings.autoRaise, sizeof(bool));
300 
301 			if (size >= kValidSettingsSize11) {
302 				fSettingsFile->Read(&settings.recentAppsEnabled, sizeof(bool));
303 				fSettingsFile->Read(&settings.recentDocsEnabled, sizeof(bool));
304 				fSettingsFile->Read(&settings.recentFoldersEnabled, sizeof(bool));
305 			} else {
306 				settings.recentAppsEnabled = settings.recentAppsCount > 0;
307 				settings.recentDocsEnabled = settings.recentDocsCount > 0;
308 				settings.recentFoldersEnabled = settings.recentFoldersCount > 0;
309 			}
310 		}
311 	}
312 
313 	fSettings = settings;
314 }
315 
316 
317 void
318 TBarApp::MessageReceived(BMessage* message)
319 {
320 	int32 count;
321 	bool enabled;
322 	switch (message->what) {
323 		case 'gloc':
324 		case 'sloc':
325 		case 'gexp':
326 		case 'sexp':
327 		case 'info':
328 		case 'exst':
329 		case 'cwnt':
330 		case 'icon':
331 		case 'remv':
332 		case 'adon':
333 			// pass any BDeskbar originating messages on to the window
334 			fBarWindow->PostMessage(message);
335 			break;
336 
337 		case kConfigShow:
338 			ShowPreferencesWindow();
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 		default:
521 			BApplication::MessageReceived(message);
522 			break;
523 	}
524 }
525 
526 
527 void
528 TBarApp::RefsReceived(BMessage* refs)
529 {
530 	entry_ref ref;
531 	for (int32 i = 0; refs->FindRef("refs", i, &ref) == B_OK; i++) {
532 		BMessage refsReceived(B_REFS_RECEIVED);
533 		refsReceived.AddRef("refs", &ref);
534 
535 		BEntry entry(&ref);
536 		if (!entry.IsDirectory())
537 			TrackerLaunch(&refsReceived, false);
538 	}
539 }
540 
541 
542 void
543 TBarApp::Subscribe(const BMessenger &subscriber, BList* list)
544 {
545 	// called when ExpandoMenuBar, TeamMenu or Switcher are built/rebuilt
546 	list->MakeEmpty();
547 
548 	BAutolock autolock(sSubscriberLock);
549 	if (!autolock.IsLocked())
550 		return;
551 
552 	int32 numTeams = sBarTeamInfoList.CountItems();
553 	for (int32 i = 0; i < numTeams; i++) {
554 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
555 		BarTeamInfo* newBarInfo = new (std::nothrow) BarTeamInfo(*barInfo);
556 		if (newBarInfo != NULL)
557 			list->AddItem(newBarInfo);
558 	}
559 
560 	int32 subsCount = sSubscribers.CountItems();
561 	for (int32 i = 0; i < subsCount; i++) {
562 		BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
563 		if (*messenger == subscriber)
564 			return;
565 	}
566 
567 	sSubscribers.AddItem(new BMessenger(subscriber));
568 }
569 
570 
571 void
572 TBarApp::Unsubscribe(const BMessenger &subscriber)
573 {
574 	BAutolock autolock(sSubscriberLock);
575 	if (!autolock.IsLocked())
576 		return;
577 
578 	int32 count = sSubscribers.CountItems();
579 	for (int32 i = 0; i < count; i++) {
580 		BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
581 		if (*messenger == subscriber) {
582 			sSubscribers.RemoveItem(i);
583 			delete messenger;
584 			break;
585 		}
586 	}
587 }
588 
589 
590 void
591 TBarApp::AddTeam(team_id team, uint32 flags, const char* sig, entry_ref* ref)
592 {
593 	BAutolock autolock(sSubscriberLock);
594 	if (!autolock.IsLocked())
595 		return;
596 
597 	// have we already seen this team, is this another instance of
598 	// a known app?
599 	BarTeamInfo* multiLaunchTeam = NULL;
600 	int32 teamCount = sBarTeamInfoList.CountItems();
601 	for (int32 i = 0; i < teamCount; i++) {
602 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
603 		if (barInfo->teams->HasItem((void*)team))
604 			return;
605 		if (strcasecmp(barInfo->sig, sig) == 0)
606 			multiLaunchTeam = barInfo;
607 	}
608 
609 	if (multiLaunchTeam != NULL) {
610 		multiLaunchTeam->teams->AddItem((void*)team);
611 
612 		int32 subsCount = sSubscribers.CountItems();
613 		if (subsCount > 0) {
614 			BMessage message(kAddTeam);
615 			message.AddInt32("team", team);
616 			message.AddString("sig", multiLaunchTeam->sig);
617 
618 			for (int32 i = 0; i < subsCount; i++)
619 				((BMessenger*)sSubscribers.ItemAt(i))->SendMessage(&message);
620 		}
621 		return;
622 	}
623 
624 	BFile file(ref, B_READ_ONLY);
625 	BAppFileInfo appMime(&file);
626 
627 	BarTeamInfo* barInfo = new BarTeamInfo(new BList(), flags, strdup(sig),
628 		new BBitmap(kIconSize, kIconFormat), strdup(ref->name));
629 
630 	barInfo->teams->AddItem((void*)team);
631 	if (appMime.GetIcon(barInfo->icon, B_MINI_ICON) != B_OK)
632 		appMime.GetTrackerIcon(barInfo->icon, B_MINI_ICON);
633 
634 	sBarTeamInfoList.AddItem(barInfo);
635 
636 	int32 subsCount = sSubscribers.CountItems();
637 	if (subsCount > 0) {
638 		for (int32 i = 0; i < subsCount; i++) {
639 			BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
640 			BMessage message(B_SOME_APP_LAUNCHED);
641 
642 			BList* tList = new BList(*(barInfo->teams));
643 			message.AddPointer("teams", tList);
644 
645 			BBitmap* icon = new BBitmap(barInfo->icon);
646 			ASSERT(icon);
647 
648 			message.AddPointer("icon", icon);
649 
650 			message.AddInt32("flags", static_cast<int32>(barInfo->flags));
651 			message.AddString("name", barInfo->name);
652 			message.AddString("sig", barInfo->sig);
653 
654 			messenger->SendMessage(&message);
655 		}
656 	}
657 }
658 
659 
660 void
661 TBarApp::RemoveTeam(team_id team)
662 {
663 	BAutolock autolock(sSubscriberLock);
664 	if (!autolock.IsLocked())
665 		return;
666 
667 	int32 teamCount = sBarTeamInfoList.CountItems();
668 	for (int32 i = 0; i < teamCount; i++) {
669 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
670 		if (barInfo->teams->HasItem((void*)team)) {
671 			int32 subsCount = sSubscribers.CountItems();
672 			if (subsCount > 0) {
673 				BMessage message((barInfo->teams->CountItems() == 1) ?
674 					 B_SOME_APP_QUIT : kRemoveTeam);
675 
676 				message.AddInt32("team", team);
677 				for (int32 i = 0; i < subsCount; i++) {
678 					BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
679 					messenger->SendMessage(&message);
680 				}
681 			}
682 
683 			barInfo->teams->RemoveItem((void*)team);
684 			if (barInfo->teams->CountItems() < 1) {
685 				delete (BarTeamInfo*)sBarTeamInfoList.RemoveItem(i);
686 				return;
687 			}
688 		}
689 	}
690 }
691 
692 
693 void
694 TBarApp::ShowPreferencesWindow()
695 {
696 	if (fPreferencesWindow)
697 		fPreferencesWindow->Activate();
698  	else {
699 		fPreferencesWindow = new PreferencesWindow(BRect(0, 0, 320, 240));
700 		fPreferencesWindow->Show();
701 	}
702 }
703 
704 
705 //	#pragma mark -
706 
707 
708 BarTeamInfo::BarTeamInfo(BList* teams, uint32 flags, char* sig, BBitmap* icon,
709 	char* name)
710 	:	teams(teams),
711 		flags(flags),
712 		sig(sig),
713 		icon(icon),
714 		name(name)
715 {
716 }
717 
718 
719 BarTeamInfo::BarTeamInfo(const BarTeamInfo &info)
720 	:	teams(new BList(*info.teams)),
721 		flags(info.flags),
722 		sig(strdup(info.sig)),
723 		icon(new BBitmap(*info.icon)),
724 		name(strdup(info.name))
725 {
726 }
727 
728 
729 BarTeamInfo::~BarTeamInfo()
730 {
731 	delete teams;
732 	free(sig);
733 	delete icon;
734 	free(name);
735 }
736 
737