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