xref: /haiku/src/apps/deskbar/BarApp.cpp (revision 9760dcae2038d47442f4658c2575844c6cf92c40)
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 	}
203 }
204 
205 
206 void
207 TBarApp::InitSettings()
208 {
209 	desk_settings settings;
210 	settings.vertical = true;
211 	settings.left = false;
212 	settings.top = true;
213 	settings.ampmMode = true;
214 	settings.showTime = true;
215 	settings.state = kExpandoState;
216 	settings.width = 0;
217 	settings.switcherLoc = BPoint(5000, 5000);
218 	settings.recentAppsCount = 10;
219 	settings.recentDocsCount = 10;
220 	settings.timeShowSeconds = false;
221 	settings.timeShowMil = false;
222 	settings.recentFoldersCount = 10;
223 	settings.timeShowEuro = false;
224 	settings.alwaysOnTop = false;
225 	settings.timeFullDate = false;
226 	settings.trackerAlwaysFirst = false;
227 	settings.sortRunningApps = false;
228 	settings.superExpando = false;
229 	settings.expandNewTeams = false;
230 	settings.autoRaise = false;
231 
232 	BPath dirPath;
233 	const char* settingsFileName = "Deskbar_settings";
234 
235 	find_directory(B_USER_DESKBAR_DIRECTORY, &dirPath, true);
236 	// just make it
237 
238 	if (find_directory (B_USER_SETTINGS_DIRECTORY, &dirPath, true) == B_OK) {
239 		BPath filePath = dirPath;
240 		filePath.Append(settingsFileName);
241 		fSettingsFile = new BFile(filePath.Path(), O_RDWR);
242 		if (fSettingsFile->InitCheck() != B_OK) {
243 			BDirectory theDir(dirPath.Path());
244 			if (theDir.InitCheck() == B_OK)
245 				theDir.CreateFile(settingsFileName, fSettingsFile);
246 		}
247 
248 		if (fSettingsFile->InitCheck() == B_OK) {
249 			off_t size = 0;
250 			fSettingsFile->GetSize(&size);
251 
252 			if (size >= kValidSettingsSize1) {
253 				fSettingsFile->Seek(0, SEEK_SET);
254 				fSettingsFile->Read(&settings.vertical, sizeof(bool));
255 				fSettingsFile->Read(&settings.left, sizeof(bool));
256 				fSettingsFile->Read(&settings.top, sizeof(bool));
257 				fSettingsFile->Read(&settings.ampmMode, sizeof(bool));
258 				fSettingsFile->Read(&settings.state, sizeof(uint32));
259 				fSettingsFile->Read(&settings.width, sizeof(float));
260 				fSettingsFile->Read(&settings.showTime, sizeof(bool));
261 			}
262 			if (size >= kValidSettingsSize2)
263 				fSettingsFile->Read(&settings.switcherLoc, sizeof(BPoint));
264 			if (size >= kValidSettingsSize3) {
265 				fSettingsFile->Read(&settings.recentAppsCount, sizeof(int32));
266 				fSettingsFile->Read(&settings.recentDocsCount, sizeof(int32));
267 			}
268 			if (size >= kValidSettingsSize4) {
269 				fSettingsFile->Read(&settings.timeShowSeconds, sizeof(bool));
270 				fSettingsFile->Read(&settings.timeShowMil, sizeof(bool));
271 			}
272 			if (size >= kValidSettingsSize5)
273 				fSettingsFile->Read(&settings.recentFoldersCount,
274 					sizeof(int32));
275 			if (size >= kValidSettingsSize6) {
276 				fSettingsFile->Read(&settings.timeShowEuro, sizeof(bool));
277 				fSettingsFile->Read(&settings.alwaysOnTop, sizeof(bool));
278 			}
279 			if (size >= kValidSettingsSize7)
280 				fSettingsFile->Read(&settings.timeFullDate, sizeof(bool));
281 			if (size >= kValidSettingsSize8) {
282 				fSettingsFile->Read(&settings.trackerAlwaysFirst, sizeof(bool));
283 				fSettingsFile->Read(&settings.sortRunningApps, sizeof(bool));
284 			}
285 			if (size >= kValidSettingsSize9) {
286 				fSettingsFile->Read(&settings.superExpando, sizeof(bool));
287 				fSettingsFile->Read(&settings.expandNewTeams, sizeof(bool));
288 			}
289 			if (size >= kValidSettingsSize10)
290 				fSettingsFile->Read(&settings.autoRaise, sizeof(bool));
291 		}
292 	}
293 
294 	fSettings = settings;
295 }
296 
297 
298 void
299 TBarApp::MessageReceived(BMessage* message)
300 {
301 	int32 count;
302 	switch (message->what) {
303 		case 'gloc':
304 		case 'sloc':
305 		case 'gexp':
306 		case 'sexp':
307 		case 'info':
308 		case 'exst':
309 		case 'cwnt':
310 		case 'icon':
311 		case 'remv':
312 		case 'adon':
313 			// pass any BDeskbar originating messages on to the window
314 			fBarWindow->PostMessage(message);
315 			break;
316 
317 		case kConfigShow:
318 			ShowPreferencesWindow();
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 kUpdateRecentCounts:
336 			if (message->FindInt32("applications", &count) == B_OK)
337 				fSettings.recentAppsCount = count;
338 			if (message->FindInt32("folders", &count) == B_OK)
339 				fSettings.recentFoldersCount = count;
340 			if (message->FindInt32("documents", &count) == B_OK)
341 				fSettings.recentDocsCount = count;
342 			break;
343 
344 		case kConfigClose:
345 			fPreferencesWindow = NULL;
346 			break;
347 
348 		case B_SOME_APP_LAUNCHED:
349 		{
350 			team_id team = -1;
351 			message->FindInt32("be:team", &team);
352 
353 			uint32 flags = 0;
354 			message->FindInt32("be:flags", (long*)&flags);
355 
356 			const char* sig = NULL;
357 			message->FindString("be:signature", &sig);
358 
359 			entry_ref ref;
360 			message->FindRef("be:ref", &ref);
361 
362 			AddTeam(team, flags, sig, &ref);
363 			break;
364 		}
365 
366 		case B_SOME_APP_QUIT:
367 		{
368 			team_id team = -1;
369 			message->FindInt32("be:team", &team);
370 			RemoveTeam(team);
371 			break;
372 		}
373 
374 		case B_ARCHIVED_OBJECT:
375 			// TODO: what's this???
376 			message->AddString("special", "Alex Osadzinski");
377 			fStatusViewMessenger.SendMessage(message);
378 			break;
379 
380 		case kToggleDraggers:
381 			if (BDragger::AreDraggersDrawn())
382 				BDragger::HideAllDraggers();
383 			else
384 				BDragger::ShowAllDraggers();
385 			break;
386 
387 		case kAlwaysTop:
388  			fSettings.alwaysOnTop = !fSettings.alwaysOnTop;
389 
390  			fBarWindow->SetFeel(fSettings.alwaysOnTop ?
391  				B_FLOATING_ALL_WINDOW_FEEL : B_NORMAL_WINDOW_FEEL);
392  			break;
393 
394 		case kAutoRaise:
395 		{
396 			fSettings.autoRaise = !fSettings.autoRaise;
397 
398 			TBarView* barView = static_cast<TBarApp*>(be_app)->BarView();
399 			fBarWindow->Lock();
400 			barView->UpdateAutoRaise();
401 			fBarWindow->Unlock();
402 			break;
403 		}
404 
405 		case kTrackerFirst:
406 		{
407 			fSettings.trackerAlwaysFirst = !fSettings.trackerAlwaysFirst;
408 
409 			TBarView* barView = static_cast<TBarApp*>(be_app)->BarView();
410 			fBarWindow->Lock();
411 			barView->UpdatePlacement();
412 			fBarWindow->Unlock();
413 			break;
414 		}
415 
416 		case kSortRunningApps:
417 		{
418 			fSettings.sortRunningApps = !fSettings.sortRunningApps;
419 
420 			TBarView* barView = static_cast<TBarApp*>(be_app)->BarView();
421 			fBarWindow->Lock();
422 			barView->UpdatePlacement();
423 			fBarWindow->Unlock();
424 			break;
425 		}
426 
427 		case kUnsubscribe:
428 		{
429 			BMessenger messenger;
430 			if (message->FindMessenger("messenger", &messenger) == B_OK)
431 				Unsubscribe(messenger);
432 			break;
433 		}
434 
435 		case kSuperExpando:
436 		{
437 			fSettings.superExpando = !fSettings.superExpando;
438 
439 			TBarView* barView = static_cast<TBarApp*>(be_app)->BarView();
440 			fBarWindow->Lock();
441 			barView->UpdatePlacement();
442 			fBarWindow->Unlock();
443 			break;
444 		}
445 
446 		case kExpandNewTeams:
447 		{
448 			fSettings.expandNewTeams = !fSettings.expandNewTeams;
449 
450 			TBarView* barView = static_cast<TBarApp*>(be_app)->BarView();
451 			fBarWindow->Lock();
452 			barView->UpdatePlacement();
453 			fBarWindow->Unlock();
454 			break;
455 		}
456 
457 		case 'TASK':
458 			fSwitcherMessenger.SendMessage(message);
459 			break;
460 
461 		case kSuspendSystem:
462 			// TODO: Call BRoster?
463 			break;
464 
465 		case kRebootSystem:
466 		case kShutdownSystem:
467 		{
468 			bool reboot = (message->what == kRebootSystem);
469 			bool confirm;
470 			message->FindBool("confirm", &confirm);
471 
472 			BRoster roster;
473 			BRoster::Private rosterPrivate(roster);
474 			status_t error = rosterPrivate.ShutDown(reboot, confirm, false);
475 			if (error != B_OK)
476 				fprintf(stderr, "Shutdown failed: %s\n", strerror(error));
477 
478 			break;
479 		}
480 
481 		case kShowSplash:
482 			run_be_about();
483 			break;
484 
485 		default:
486 			BApplication::MessageReceived(message);
487 			break;
488 	}
489 }
490 
491 
492 void
493 TBarApp::RefsReceived(BMessage* refs)
494 {
495 	entry_ref ref;
496 	for (int32 i = 0; refs->FindRef("refs", i, &ref) == B_OK; i++) {
497 		BMessage refsReceived(B_REFS_RECEIVED);
498 		refsReceived.AddRef("refs", &ref);
499 
500 		BEntry entry(&ref);
501 		if (!entry.IsDirectory())
502 			TrackerLaunch(&refsReceived, true);
503 	}
504 }
505 
506 
507 void
508 TBarApp::Subscribe(const BMessenger &subscriber, BList* list)
509 {
510 	// called when ExpandoMenuBar, TeamMenu or Switcher are built/rebuilt
511 	list->MakeEmpty();
512 
513 	BAutolock autolock(sSubscriberLock);
514 	if (!autolock.IsLocked())
515 		return;
516 
517 	int32 numTeams = sBarTeamInfoList.CountItems();
518 	for (int32 i = 0; i < numTeams; i++) {
519 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
520 		BarTeamInfo* newBarInfo = new (std::nothrow) BarTeamInfo(*barInfo);
521 		if (newBarInfo != NULL)
522 			list->AddItem(newBarInfo);
523 	}
524 
525 	int32 subsCount = sSubscribers.CountItems();
526 	for (int32 i = 0; i < subsCount; i++) {
527 		BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
528 		if (*messenger == subscriber)
529 			return;
530 	}
531 
532 	sSubscribers.AddItem(new BMessenger(subscriber));
533 }
534 
535 
536 void
537 TBarApp::Unsubscribe(const BMessenger &subscriber)
538 {
539 	BAutolock autolock(sSubscriberLock);
540 	if (!autolock.IsLocked())
541 		return;
542 
543 	int32 count = sSubscribers.CountItems();
544 	for (int32 i = 0; i < count; i++) {
545 		BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
546 		if (*messenger == subscriber) {
547 			sSubscribers.RemoveItem(i);
548 			delete messenger;
549 			break;
550 		}
551 	}
552 }
553 
554 
555 void
556 TBarApp::AddTeam(team_id team, uint32 flags, const char* sig, entry_ref* ref)
557 {
558 	BAutolock autolock(sSubscriberLock);
559 	if (!autolock.IsLocked())
560 		return;
561 
562 	// have we already seen this team, is this another instance of
563 	// a known app?
564 	BarTeamInfo* multiLaunchTeam = NULL;
565 	int32 teamCount = sBarTeamInfoList.CountItems();
566 	for (int32 i = 0; i < teamCount; i++) {
567 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
568 		if (barInfo->teams->HasItem((void*)team))
569 			return;
570 		if (strcasecmp(barInfo->sig, sig) == 0)
571 			multiLaunchTeam = barInfo;
572 	}
573 
574 	if (multiLaunchTeam != NULL) {
575 		multiLaunchTeam->teams->AddItem((void*)team);
576 
577 		int32 subsCount = sSubscribers.CountItems();
578 		if (subsCount > 0) {
579 			BMessage message(kAddTeam);
580 			message.AddInt32("team", team);
581 			message.AddString("sig", multiLaunchTeam->sig);
582 
583 			for (int32 i = 0; i < subsCount; i++)
584 				((BMessenger*)sSubscribers.ItemAt(i))->SendMessage(&message);
585 		}
586 		return;
587 	}
588 
589 	BFile file(ref, B_READ_ONLY);
590 	BAppFileInfo appMime(&file);
591 
592 	BarTeamInfo* barInfo = new BarTeamInfo(new BList(), flags, strdup(sig),
593 		new BBitmap(kIconSize, kIconFormat), strdup(ref->name));
594 
595 	barInfo->teams->AddItem((void*)team);
596 	if (appMime.GetIcon(barInfo->icon, B_MINI_ICON) != B_OK)
597 		appMime.GetTrackerIcon(barInfo->icon, B_MINI_ICON);
598 
599 	sBarTeamInfoList.AddItem(barInfo);
600 
601 	int32 subsCount = sSubscribers.CountItems();
602 	if (subsCount > 0) {
603 		for (int32 i = 0; i < subsCount; i++) {
604 			BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
605 			BMessage message(B_SOME_APP_LAUNCHED);
606 
607 			BList* tList = new BList(*(barInfo->teams));
608 			message.AddPointer("teams", tList);
609 
610 			BBitmap* icon = new BBitmap(barInfo->icon);
611 			ASSERT(icon);
612 
613 			message.AddPointer("icon", icon);
614 
615 			message.AddInt32("flags", static_cast<int32>(barInfo->flags));
616 			message.AddString("name", barInfo->name);
617 			message.AddString("sig", barInfo->sig);
618 
619 			messenger->SendMessage(&message);
620 		}
621 	}
622 }
623 
624 
625 void
626 TBarApp::RemoveTeam(team_id team)
627 {
628 	BAutolock autolock(sSubscriberLock);
629 	if (!autolock.IsLocked())
630 		return;
631 
632 	int32 teamCount = sBarTeamInfoList.CountItems();
633 	for (int32 i = 0; i < teamCount; i++) {
634 		BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
635 		if (barInfo->teams->HasItem((void*)team)) {
636 			int32 subsCount = sSubscribers.CountItems();
637 			if (subsCount > 0) {
638 				BMessage message((barInfo->teams->CountItems() == 1) ?
639 					 B_SOME_APP_QUIT : kRemoveTeam);
640 
641 				message.AddInt32("team", team);
642 				for (int32 i = 0; i < subsCount; i++) {
643 					BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
644 					messenger->SendMessage(&message);
645 				}
646 			}
647 
648 			barInfo->teams->RemoveItem((void*)team);
649 			if (barInfo->teams->CountItems() < 1) {
650 				delete (BarTeamInfo*)sBarTeamInfoList.RemoveItem(i);
651 				return;
652 			}
653 		}
654 	}
655 }
656 
657 
658 void
659 TBarApp::ShowPreferencesWindow()
660 {
661 	if (fPreferencesWindow)
662 		fPreferencesWindow->Activate();
663  	else {
664 		fPreferencesWindow = new PreferencesWindow(BRect(0, 0, 320, 240));
665 		fPreferencesWindow->Show();
666 	}
667 }
668 
669 
670 //	#pragma mark -
671 
672 
673 BarTeamInfo::BarTeamInfo(BList* teams, uint32 flags, char* sig, BBitmap* icon,
674 	char* name)
675 	:	teams(teams),
676 		flags(flags),
677 		sig(sig),
678 		icon(icon),
679 		name(name)
680 {
681 }
682 
683 
684 BarTeamInfo::BarTeamInfo(const BarTeamInfo &info)
685 	:	teams(new BList(*info.teams)),
686 		flags(info.flags),
687 		sig(strdup(info.sig)),
688 		icon(new BBitmap(*info.icon)),
689 		name(strdup(info.name))
690 {
691 }
692 
693 
694 BarTeamInfo::~BarTeamInfo()
695 {
696 	delete teams;
697 	free(sig);
698 	delete icon;
699 	free(name);
700 }
701 
702