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