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