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
30 trademarks of Be Incorporated in the United States and other countries. Other
31 brand product names are registered trademarks or trademarks of their respective
32 holders.
33 All rights reserved.
34 */
35
36
37 #include "BarApp.h"
38
39 #include <locale.h>
40 #include <strings.h>
41
42 #include <AppFileInfo.h>
43 #include <Autolock.h>
44 #include <Bitmap.h>
45 #include <Catalog.h>
46 #include <ControlLook.h>
47 #include <Debug.h>
48 #include <Directory.h>
49 #include <Dragger.h>
50 #include <File.h>
51 #include <FindDirectory.h>
52 #include <IconUtils.h>
53 #include <Locale.h>
54 #include <Message.h>
55 #include <Messenger.h>
56 #include <Mime.h>
57 #include <Path.h>
58 #include <Roster.h>
59
60 #include <DeskbarPrivate.h>
61 #include <RosterPrivate.h>
62 #include "tracker_private.h"
63
64 #include "BarView.h"
65 #include "BarWindow.h"
66 #include "DeskbarUtils.h"
67 #include "FSUtils.h"
68 #include "PreferencesWindow.h"
69 #include "ResourceSet.h"
70 #include "StatusView.h"
71 #include "Switcher.h"
72
73 #include "icons.h"
74
75
76 BLocker TBarApp::sSubscriberLock;
77 BList TBarApp::sBarTeamInfoList;
78 BList TBarApp::sWindowIconCache;
79 BList TBarApp::sSubscribers;
80
81
82 const uint32 kShowDeskbarMenu = 'BeMn';
83 const uint32 kShowTeamMenu = 'TmMn';
84
85
86 int
main()87 main()
88 {
89 setlocale(LC_ALL, "");
90 TBarApp app;
91 app.Run();
92
93 return B_OK;
94 }
95
96
TBarApp()97 TBarApp::TBarApp()
98 :
99 BServer(kDeskbarSignature, true, NULL),
100 fSettingsFile(NULL),
101 fClockSettingsFile(NULL),
102 fPreferencesWindow(NULL)
103 {
104 InitSettings();
105 InitIconPreloader();
106
107 fBarWindow = new TBarWindow();
108 fBarView = fBarWindow->BarView();
109
110 be_roster->StartWatching(this);
111
112 gLocalizedNamePreferred
113 = BLocaleRoster::Default()->IsFilesystemTranslationPreferred();
114
115 sBarTeamInfoList.MakeEmpty();
116
117 BList teamList;
118 int32 numTeams;
119 be_roster->GetAppList(&teamList);
120 numTeams = teamList.CountItems();
121 for (int32 i = 0; i < numTeams; i++) {
122 app_info appInfo;
123 team_id tID = (addr_t)teamList.ItemAt(i);
124 if (be_roster->GetRunningAppInfo(tID, &appInfo) == B_OK) {
125 AddTeam(appInfo.team, appInfo.flags, appInfo.signature,
126 &appInfo.ref);
127 }
128 }
129
130 sWindowIconCache.MakeEmpty();
131 for (int32 id = R_WindowShownIcon; id <= R_WindowHiddenSwitchIcon; id++) {
132 if (id == R_ResizeIcon)
133 continue;
134
135 WindowIconCache* winCache = new WindowIconCache(id);
136 _CacheWindowIcon(winCache);
137 sWindowIconCache.AddItem(winCache);
138 }
139
140 sSubscribers.MakeEmpty();
141 fSwitcherMessenger = BMessenger(new TSwitchManager());
142 fBarWindow->Show();
143
144 fBarWindow->Lock();
145 fBarView->UpdatePlacement();
146 fBarWindow->Unlock();
147
148 // this messenger now targets the barview instead of the
149 // statusview so that all additions to the tray
150 // follow the same path
151 fStatusViewMessenger = BMessenger(fBarWindow->FindView("BarView"));
152 }
153
154
~TBarApp()155 TBarApp::~TBarApp()
156 {
157 be_roster->StopWatching(this);
158
159 int32 teamCount = sBarTeamInfoList.CountItems();
160 for (int32 i = 0; i < teamCount; i++) {
161 BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
162 delete barInfo;
163 }
164
165 int32 subsCount = sSubscribers.CountItems();
166 for (int32 i = 0; i < subsCount; i++) {
167 BMessenger* messenger
168 = static_cast<BMessenger*>(sSubscribers.ItemAt(i));
169 delete messenger;
170 }
171
172 SaveSettings();
173
174 delete fSettingsFile;
175 delete fClockSettingsFile;
176 }
177
178
179 bool
QuitRequested()180 TBarApp::QuitRequested()
181 {
182 // don't allow the user to quit
183 if (CurrentMessage() && CurrentMessage()->FindBool("shortcut")) {
184 // but close the preferences window
185 QuitPreferencesWindow();
186 return false;
187 }
188
189 // system quitting, call inherited to notify all loopers
190 fBarWindow->SaveSettings();
191 BApplication::QuitRequested();
192 return true;
193 }
194
195
196 void
SaveSettings()197 TBarApp::SaveSettings()
198 {
199 if (fSettingsFile->InitCheck() == B_OK) {
200 fSettingsFile->Seek(0, SEEK_SET);
201 BMessage prefs;
202 prefs.AddBool("vertical", fSettings.vertical);
203 prefs.AddBool("left", fSettings.left);
204 prefs.AddBool("top", fSettings.top);
205 prefs.AddInt32("state", fSettings.state);
206 prefs.AddFloat("width", fSettings.width);
207 prefs.AddPoint("switcherLoc", fSettings.switcherLoc);
208 prefs.AddBool("showClock", fSettings.showClock);
209 // applications
210 prefs.AddBool("trackerAlwaysFirst", fSettings.trackerAlwaysFirst);
211 prefs.AddBool("sortRunningApps", fSettings.sortRunningApps);
212 prefs.AddBool("superExpando", fSettings.superExpando);
213 prefs.AddBool("expandNewTeams", fSettings.expandNewTeams);
214 prefs.AddBool("hideLabels", fSettings.hideLabels);
215 prefs.AddInt32("iconSize", fSettings.iconSize);
216 // recent items
217 prefs.AddBool("recentDocsEnabled", fSettings.recentDocsEnabled);
218 prefs.AddBool("recentFoldersEnabled", fSettings.recentFoldersEnabled);
219 prefs.AddBool("recentAppsEnabled", fSettings.recentAppsEnabled);
220 prefs.AddInt32("recentDocsCount", fSettings.recentDocsCount);
221 prefs.AddInt32("recentFoldersCount", fSettings.recentFoldersCount);
222 prefs.AddInt32("recentAppsCount", fSettings.recentAppsCount);
223 // window
224 prefs.AddBool("alwaysOnTop", fSettings.alwaysOnTop);
225 prefs.AddBool("autoRaise", fSettings.autoRaise);
226 prefs.AddBool("autoHide", fSettings.autoHide);
227
228 prefs.Flatten(fSettingsFile);
229 }
230
231 if (fClockSettingsFile->InitCheck() == B_OK) {
232 fClockSettingsFile->Seek(0, SEEK_SET);
233 BMessage prefs;
234 prefs.AddBool("showSeconds", fClockSettings.showSeconds);
235 prefs.AddBool("showDayOfWeek", fClockSettings.showDayOfWeek);
236 prefs.AddBool("showTimeZone", fClockSettings.showTimeZone);
237
238 prefs.Flatten(fClockSettingsFile);
239 }
240 }
241
242
243 void
InitSettings()244 TBarApp::InitSettings()
245 {
246 // compute metrics
247 sIconGap = ceilf(be_control_look->DefaultLabelSpacing() / 3.0f);
248
249 gDragRegionWidth = be_control_look->ComposeSpacing(B_USE_HALF_ITEM_SPACING);
250 gDragWidth = ceilf(gDragRegionWidth * 0.6f);
251
252 gMinReplicantHeight = gMinReplicantWidth =
253 be_control_look->ComposeIconSize(B_MINI_ICON).IntegerWidth() + 1;
254
255 // 1 pixel for left gutter
256 // space for replicant tray (6 items)
257 // 6 pixel drag region
258 gMinimumTrayWidth = sIconGap + gMinReplicantWidth
259 + (kMinimumReplicantCount * sIconGap)
260 + (kMinimumReplicantCount * gMinReplicantWidth) + kGutter;
261
262 gMinimumWindowWidth = kGutter + gMinimumTrayWidth + gDragRegionWidth;
263 gMaximumWindowWidth = gMinimumWindowWidth * 2;
264
265 // defaults
266 desk_settings settings;
267 settings.vertical = fDefaultSettings.vertical = true;
268 settings.left = fDefaultSettings.left = false;
269 settings.top = fDefaultSettings.top = true;
270 settings.state = fDefaultSettings.state = kExpandoState;
271 settings.width = fDefaultSettings.width = gMinimumWindowWidth;
272 settings.switcherLoc = fDefaultSettings.switcherLoc = BPoint(5000, 5000);
273 settings.showClock = fDefaultSettings.showClock = true;
274 // applications
275 settings.trackerAlwaysFirst = fDefaultSettings.trackerAlwaysFirst = true;
276 settings.sortRunningApps = fDefaultSettings.sortRunningApps = false;
277 settings.superExpando = fDefaultSettings.superExpando = false;
278 settings.expandNewTeams = fDefaultSettings.expandNewTeams = false;
279 settings.hideLabels = fDefaultSettings.hideLabels = false;
280 settings.iconSize = fDefaultSettings.iconSize = kMinimumIconSize;
281 // recent items
282 settings.recentDocsEnabled = fDefaultSettings.recentDocsEnabled = true;
283 settings.recentFoldersEnabled
284 = fDefaultSettings.recentFoldersEnabled = true;
285 settings.recentAppsEnabled = fDefaultSettings.recentAppsEnabled = true;
286 settings.recentDocsCount = fDefaultSettings.recentDocsCount = 10;
287 settings.recentFoldersCount = fDefaultSettings.recentFoldersCount = 10;
288 settings.recentAppsCount = fDefaultSettings.recentAppsCount = 10;
289 // window
290 settings.alwaysOnTop = fDefaultSettings.alwaysOnTop = false;
291 settings.autoRaise = fDefaultSettings.autoRaise = false;
292 settings.autoHide = fDefaultSettings.autoHide = false;
293
294 clock_settings clock;
295 clock.showSeconds = false;
296 clock.showDayOfWeek = false;
297 clock.showTimeZone = false;
298
299 BPath dirPath;
300 const char* settingsFileName = "settings";
301 const char* clockSettingsFileName = "clock_settings";
302
303 find_directory(B_USER_DESKBAR_DIRECTORY, &dirPath, true);
304 // just make it
305
306 if (GetDeskbarSettingsDirectory(dirPath, true) == B_OK) {
307 BPath filePath = dirPath;
308 filePath.Append(settingsFileName);
309 fSettingsFile = new BFile(filePath.Path(), O_RDWR);
310 if (fSettingsFile->InitCheck() != B_OK) {
311 BDirectory theDir(dirPath.Path());
312 if (theDir.InitCheck() == B_OK)
313 theDir.CreateFile(settingsFileName, fSettingsFile);
314 }
315
316 BMessage prefs;
317 if (fSettingsFile->InitCheck() == B_OK
318 && prefs.Unflatten(fSettingsFile) == B_OK) {
319 settings.vertical = prefs.GetBool("vertical",
320 fDefaultSettings.vertical);
321 settings.left = prefs.GetBool("left",
322 fDefaultSettings.left);
323 settings.top = prefs.GetBool("top",
324 fDefaultSettings.top);
325 settings.state = prefs.GetInt32("state",
326 fDefaultSettings.state);
327 settings.width = prefs.GetFloat("width",
328 fDefaultSettings.width);
329 settings.switcherLoc = prefs.GetPoint("switcherLoc",
330 fDefaultSettings.switcherLoc);
331 settings.showClock = prefs.GetBool("showClock",
332 fDefaultSettings.showClock);
333 // applications
334 settings.trackerAlwaysFirst = prefs.GetBool("trackerAlwaysFirst",
335 fDefaultSettings.trackerAlwaysFirst);
336 settings.sortRunningApps = prefs.GetBool("sortRunningApps",
337 fDefaultSettings.sortRunningApps);
338 settings.superExpando = prefs.GetBool("superExpando",
339 fDefaultSettings.superExpando);
340 settings.expandNewTeams = prefs.GetBool("expandNewTeams",
341 fDefaultSettings.expandNewTeams);
342 settings.hideLabels = prefs.GetBool("hideLabels",
343 fDefaultSettings.hideLabels);
344 settings.iconSize = prefs.GetInt32("iconSize",
345 fDefaultSettings.iconSize);
346 // recent items
347 settings.recentDocsEnabled = prefs.GetBool("recentDocsEnabled",
348 fDefaultSettings.recentDocsEnabled);
349 settings.recentFoldersEnabled
350 = prefs.GetBool("recentFoldersEnabled",
351 fDefaultSettings.recentFoldersEnabled);
352 settings.recentAppsEnabled = prefs.GetBool("recentAppsEnabled",
353 fDefaultSettings.recentAppsEnabled);
354 settings.recentDocsCount = prefs.GetInt32("recentDocsCount",
355 fDefaultSettings.recentDocsCount);
356 settings.recentFoldersCount = prefs.GetInt32("recentFoldersCount",
357 fDefaultSettings.recentFoldersCount);
358 settings.recentAppsCount = prefs.GetInt32("recentAppsCount",
359 fDefaultSettings.recentAppsCount);
360 // window
361 settings.alwaysOnTop = prefs.GetBool("alwaysOnTop",
362 fDefaultSettings.alwaysOnTop);
363 settings.autoRaise = prefs.GetBool("autoRaise",
364 fDefaultSettings.autoRaise);
365 settings.autoHide = prefs.GetBool("autoHide",
366 fDefaultSettings.autoHide);
367 }
368
369 // constrain width setting within limits
370 if (settings.width < gMinimumWindowWidth)
371 settings.width = gMinimumWindowWidth;
372 else if (settings.width > gMaximumWindowWidth)
373 settings.width = gMaximumWindowWidth;
374
375 filePath = dirPath;
376 filePath.Append(clockSettingsFileName);
377 fClockSettingsFile = new BFile(filePath.Path(), O_RDWR);
378 if (fClockSettingsFile->InitCheck() != B_OK) {
379 BDirectory theDir(dirPath.Path());
380 if (theDir.InitCheck() == B_OK)
381 theDir.CreateFile(clockSettingsFileName, fClockSettingsFile);
382 }
383
384 if (fClockSettingsFile->InitCheck() == B_OK
385 && prefs.Unflatten(fClockSettingsFile) == B_OK) {
386 clock.showSeconds = prefs.GetBool("showSeconds", false);
387 clock.showDayOfWeek = prefs.GetBool("showDayOfWeek", false);
388 clock.showTimeZone = prefs.GetBool("showTimeZone", false);
389 }
390 }
391
392 fSettings = settings;
393 fClockSettings = clock;
394 }
395
396
397 void
MessageReceived(BMessage * message)398 TBarApp::MessageReceived(BMessage* message)
399 {
400 switch (message->what) {
401 // BDeskbar originating messages we can handle
402 case kMsgIsAlwaysOnTop:
403 {
404 BMessage reply('rply');
405 reply.AddBool("always on top", fSettings.alwaysOnTop);
406 message->SendReply(&reply);
407 break;
408 }
409 case kMsgIsAutoRaise:
410 {
411 BMessage reply('rply');
412 reply.AddBool("auto raise", fSettings.autoRaise);
413 message->SendReply(&reply);
414 break;
415 }
416 case kMsgIsAutoHide:
417 {
418 BMessage reply('rply');
419 reply.AddBool("auto hide", fSettings.autoHide);
420 message->SendReply(&reply);
421 break;
422 }
423
424 // pass rest of BDeskbar originating messages onto the window
425 // (except for setters handled below)
426 case kMsgLocation:
427 case kMsgSetLocation:
428 case kMsgIsExpanded:
429 case kMsgExpand:
430 case kMsgGetItemInfo:
431 case kMsgHasItem:
432 case kMsgCountItems:
433 case kMsgMaxItemSize:
434 case kMsgAddView:
435 case kMsgRemoveItem:
436 case kMsgAddAddOn:
437 fBarWindow->PostMessage(message);
438 break;
439
440 case kConfigShow:
441 ShowPreferencesWindow();
442 break;
443
444 case kConfigQuit:
445 QuitPreferencesWindow();
446 break;
447
448 case kStateChanged:
449 if (fPreferencesWindow != NULL)
450 fPreferencesWindow->PostMessage(kStateChanged);
451 break;
452
453 case kShowDeskbarMenu:
454 if (fBarWindow->Lock()) {
455 fBarWindow->ShowDeskbarMenu();
456 fBarWindow->Unlock();
457 }
458 break;
459
460 case kShowTeamMenu:
461 if (fBarWindow->Lock()) {
462 fBarWindow->ShowTeamMenu();
463 fBarWindow->Unlock();
464 }
465 break;
466
467 case kUpdateRecentCounts:
468 int32 count;
469 bool enabled;
470
471 if (message->FindInt32("applications", &count) == B_OK)
472 fSettings.recentAppsCount = count;
473 if (message->FindBool("applicationsEnabled", &enabled) == B_OK)
474 fSettings.recentAppsEnabled = enabled && count > 0;
475
476 if (message->FindInt32("folders", &count) == B_OK)
477 fSettings.recentFoldersCount = count;
478 if (message->FindBool("foldersEnabled", &enabled) == B_OK)
479 fSettings.recentFoldersEnabled = enabled && count > 0;
480
481 if (message->FindInt32("documents", &count) == B_OK)
482 fSettings.recentDocsCount = count;
483 if (message->FindBool("documentsEnabled", &enabled) == B_OK)
484 fSettings.recentDocsEnabled = enabled && count > 0;
485
486 if (fPreferencesWindow != NULL)
487 fPreferencesWindow->PostMessage(kUpdatePreferences);
488 break;
489
490 case B_SOME_APP_LAUNCHED:
491 {
492 team_id team = -1;
493 message->FindInt32("be:team", &team);
494
495 uint32 flags = 0;
496 message->FindInt32("be:flags", (int32*)&flags);
497
498 const char* signature = NULL;
499 message->FindString("be:signature", &signature);
500
501 entry_ref ref;
502 message->FindRef("be:ref", &ref);
503
504 AddTeam(team, flags, signature, &ref);
505 break;
506 }
507
508 case B_SOME_APP_QUIT:
509 {
510 team_id team = -1;
511 message->FindInt32("be:team", &team);
512 RemoveTeam(team);
513 break;
514 }
515
516 case B_ARCHIVED_OBJECT:
517 // TODO: what's this???
518 message->AddString("special", "Alex Osadzinski");
519 fStatusViewMessenger.SendMessage(message);
520 break;
521
522 case kToggleDraggers:
523 if (BDragger::AreDraggersDrawn())
524 BDragger::HideAllDraggers();
525 else
526 BDragger::ShowAllDraggers();
527 break;
528
529 case kMsgAlwaysOnTop: // from BDeskbar
530 case kAlwaysTop:
531 fSettings.alwaysOnTop = !fSettings.alwaysOnTop;
532
533 if (fPreferencesWindow != NULL)
534 fPreferencesWindow->PostMessage(kUpdatePreferences);
535
536 fBarWindow->SetFeel(fSettings.alwaysOnTop
537 ? B_FLOATING_ALL_WINDOW_FEEL
538 : B_NORMAL_WINDOW_FEEL);
539 break;
540
541 case kMsgAutoRaise: // from BDeskbar
542 case kAutoRaise:
543 fSettings.autoRaise = fSettings.alwaysOnTop ? false
544 : !fSettings.autoRaise;
545
546 if (fPreferencesWindow != NULL)
547 fPreferencesWindow->PostMessage(kUpdatePreferences);
548 break;
549
550 case kMsgAutoHide: // from BDeskbar
551 case kAutoHide:
552 fSettings.autoHide = !fSettings.autoHide;
553
554 if (fPreferencesWindow != NULL)
555 fPreferencesWindow->PostMessage(kUpdatePreferences);
556
557 fBarWindow->Lock();
558 fBarView->HideDeskbar(fSettings.autoHide);
559 fBarWindow->Unlock();
560 break;
561
562 case kTrackerFirst:
563 fSettings.trackerAlwaysFirst = !fSettings.trackerAlwaysFirst;
564
565 if (fPreferencesWindow != NULL)
566 fPreferencesWindow->PostMessage(kUpdatePreferences);
567
568 // if mini mode we don't need to update the view
569 if (fBarView->MiniState())
570 break;
571
572 fBarWindow->Lock();
573 fBarView->PlaceApplicationBar();
574 fBarWindow->Unlock();
575 break;
576
577 case kSortRunningApps:
578 fSettings.sortRunningApps = !fSettings.sortRunningApps;
579
580 if (fPreferencesWindow != NULL)
581 fPreferencesWindow->PostMessage(kUpdatePreferences);
582
583 // if mini mode we don't need to update the view
584 if (fBarView->MiniState())
585 break;
586
587 fBarWindow->Lock();
588 fBarView->PlaceApplicationBar();
589 fBarWindow->Unlock();
590 break;
591
592 case kUnsubscribe:
593 {
594 BMessenger messenger;
595 if (message->FindMessenger("messenger", &messenger) == B_OK)
596 Unsubscribe(messenger);
597 break;
598 }
599
600 case kSuperExpando:
601 fSettings.superExpando = !fSettings.superExpando;
602
603 if (fPreferencesWindow != NULL)
604 fPreferencesWindow->PostMessage(kUpdatePreferences);
605
606 // if mini mode we don't need to update the view
607 if (fBarView->MiniState())
608 break;
609
610 fBarWindow->Lock();
611 fBarView->PlaceApplicationBar();
612 fBarWindow->Unlock();
613 break;
614
615 case kExpandNewTeams:
616 fSettings.expandNewTeams = !fSettings.expandNewTeams;
617
618 if (fPreferencesWindow != NULL)
619 fPreferencesWindow->PostMessage(kUpdatePreferences);
620
621 // if mini mode we don't need to update the view
622 if (fBarView->MiniState())
623 break;
624
625 fBarWindow->Lock();
626 fBarView->PlaceApplicationBar();
627 fBarWindow->Unlock();
628 break;
629
630 case kHideLabels:
631 fSettings.hideLabels = !fSettings.hideLabels;
632
633 if (fPreferencesWindow != NULL)
634 fPreferencesWindow->PostMessage(kUpdatePreferences);
635
636 // if mini mode we don't need to update the view
637 if (fBarView->MiniState())
638 break;
639
640 fBarWindow->Lock();
641 fBarView->PlaceApplicationBar();
642 fBarWindow->Unlock();
643 break;
644
645 case kResizeTeamIcons:
646 {
647 int32 oldIconSize = fSettings.iconSize;
648 int32 value;
649 if (message->FindInt32("be:value", &value) != B_OK)
650 break;
651
652 int32 iconSize = value * kIconSizeInterval;
653 fSettings.iconSize = iconSize;
654
655 // pin icon size between min and max values
656 if (fSettings.iconSize < kMinimumIconSize)
657 fSettings.iconSize = kMinimumIconSize;
658 else if (fSettings.iconSize > kMaximumIconSize)
659 fSettings.iconSize = kMaximumIconSize;
660
661 // don't resize if icon size hasn't changed
662 if (fSettings.iconSize == oldIconSize)
663 break;
664
665 ResizeTeamIcons();
666
667 if (fPreferencesWindow != NULL)
668 fPreferencesWindow->PostMessage(kUpdatePreferences);
669
670 // if mini mode we don't need to update the view
671 if (fBarView->MiniState())
672 break;
673
674 fBarWindow->Lock();
675 if (!fBarView->Vertical()) {
676 // Must also resize the Deskbar menu and replicant tray in
677 // horizontal mode
678 fBarView->PlaceDeskbarMenu();
679 fBarView->PlaceTray(false, false);
680 }
681 fBarView->PlaceApplicationBar();
682 fBarWindow->Unlock();
683 break;
684 }
685
686 case 'TASK':
687 fSwitcherMessenger.SendMessage(message);
688 break;
689
690 case kSuspendSystem:
691 // TODO: Call BRoster?
692 break;
693
694 case kRebootSystem:
695 case kShutdownSystem:
696 {
697 bool reboot = (message->what == kRebootSystem);
698 bool confirm;
699 message->FindBool("confirm", &confirm);
700
701 BRoster roster;
702 BRoster::Private rosterPrivate(roster);
703 status_t error = rosterPrivate.ShutDown(reboot, confirm, false);
704 if (error != B_OK)
705 fprintf(stderr, "Shutdown failed: %s\n", strerror(error));
706
707 break;
708 }
709
710 case kShowSplash:
711 run_be_about();
712 break;
713
714 case B_LOCALE_CHANGED:
715 {
716 BLocaleRoster::Default()->Refresh();
717
718 bool localize;
719 if (message->FindBool("filesys", &localize) == B_OK)
720 gLocalizedNamePreferred = localize;
721 }
722 // fall-through
723
724 case kRealignReplicants:
725 case kShowHideTime:
726 case kShowSeconds:
727 case kShowDayOfWeek:
728 case kShowTimeZone:
729 case kGetClockSettings:
730 fStatusViewMessenger.SendMessage(message);
731 // Notify the replicant tray (through BarView) that the time
732 // interval has changed and it should update the time view
733 // and reflow the tray icons.
734 break;
735
736 default:
737 BApplication::MessageReceived(message);
738 break;
739 }
740 }
741
742
743 void
RefsReceived(BMessage * refs)744 TBarApp::RefsReceived(BMessage* refs)
745 {
746 entry_ref ref;
747 for (int32 i = 0; refs->FindRef("refs", i, &ref) == B_OK; i++) {
748 BMessage refsReceived(B_REFS_RECEIVED);
749 refsReceived.AddRef("refs", &ref);
750
751 BEntry entry(&ref);
752 if (!entry.IsDirectory())
753 TrackerLaunch(&refsReceived, false);
754 }
755 }
756
757
758 void
Subscribe(const BMessenger & subscriber,BList * list)759 TBarApp::Subscribe(const BMessenger &subscriber, BList* list)
760 {
761 // called when ExpandoMenuBar, TeamMenu or Switcher are built/rebuilt
762 list->MakeEmpty();
763
764 BAutolock autolock(sSubscriberLock);
765 if (!autolock.IsLocked())
766 return;
767
768 int32 numTeams = sBarTeamInfoList.CountItems();
769 for (int32 i = 0; i < numTeams; i++) {
770 BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
771 BarTeamInfo* newBarInfo = new(std::nothrow) BarTeamInfo(*barInfo);
772 if (newBarInfo != NULL)
773 list->AddItem(newBarInfo);
774 }
775
776 int32 subsCount = sSubscribers.CountItems();
777 for (int32 i = 0; i < subsCount; i++) {
778 BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
779 if (*messenger == subscriber)
780 return;
781 }
782
783 sSubscribers.AddItem(new BMessenger(subscriber));
784 }
785
786
787 void
Unsubscribe(const BMessenger & subscriber)788 TBarApp::Unsubscribe(const BMessenger &subscriber)
789 {
790 BAutolock autolock(sSubscriberLock);
791 if (!autolock.IsLocked())
792 return;
793
794 int32 count = sSubscribers.CountItems();
795 for (int32 i = 0; i < count; i++) {
796 BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
797 if (*messenger == subscriber) {
798 sSubscribers.RemoveItem(i);
799 delete messenger;
800 break;
801 }
802 }
803 }
804
805
806 BBitmap*
FetchTeamIcon(team_id team,int32 size)807 TBarApp::FetchTeamIcon(team_id team, int32 size)
808 {
809 int32 teamCount = sBarTeamInfoList.CountItems();
810 for (int32 i = 0; i < teamCount; i++) {
811 BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
812 if (barInfo->teams->HasItem((void*)(addr_t)team)) {
813 _CacheTeamIcon(barInfo, size);
814 BBitmap* icon = barInfo->icon;
815
816 // restore icon pointer back to setting
817 if (size != fSettings.iconSize) {
818 int32 index = (fSettings.iconSize - kMinimumIconSize)
819 / kIconSizeInterval;
820 barInfo->icon = barInfo->iconCache[index];
821 }
822
823 return icon;
824 }
825 }
826
827 return NULL;
828 }
829
830
831 BBitmap*
FetchWindowIcon(bool local,bool minimized)832 TBarApp::FetchWindowIcon(bool local, bool minimized)
833 {
834 int32 id = R_WindowShownIcon;
835 int32 index = 0;
836
837 if (local) {
838 if (!minimized) {
839 id = R_WindowShownIcon;
840 index = 0;
841 }
842 else {
843 id = R_WindowHiddenIcon;
844 index = 1;
845 }
846 } else {
847 if (!minimized) {
848 id = R_WindowShownSwitchIcon;
849 index = 2;
850 }
851 else {
852 id = R_WindowHiddenSwitchIcon;
853 index = 3;
854 }
855 }
856
857 // create a new cache entry if not found
858 WindowIconCache* winCache
859 = (WindowIconCache*)sWindowIconCache.ItemAt(index);
860 if (winCache == NULL)
861 winCache = new WindowIconCache(id);
862
863 _CacheWindowIcon(winCache);
864
865 return winCache->icon;
866 }
867
868
869 void
AddTeam(team_id team,uint32 flags,const char * sig,entry_ref * ref)870 TBarApp::AddTeam(team_id team, uint32 flags, const char* sig, entry_ref* ref)
871 {
872 if ((flags & B_BACKGROUND_APP) != 0
873 || strcasecmp(sig, kDeskbarSignature) == 0) {
874 // don't add if a background app or Deskbar itself
875 return;
876 }
877
878 BAutolock autolock(sSubscriberLock);
879 if (!autolock.IsLocked())
880 return;
881
882 // have we already seen this team, is this another instance of
883 // a known app?
884 BarTeamInfo* multiLaunchTeam = NULL;
885 int32 teamCount = sBarTeamInfoList.CountItems();
886 for (int32 i = 0; i < teamCount; i++) {
887 BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
888 if (barInfo->teams->HasItem((void*)(addr_t)team))
889 return;
890 if (strcasecmp(barInfo->sig, sig) == 0)
891 multiLaunchTeam = barInfo;
892 }
893
894 if (multiLaunchTeam != NULL) {
895 multiLaunchTeam->teams->AddItem((void*)(addr_t)team);
896
897 int32 subsCount = sSubscribers.CountItems();
898 if (subsCount > 0) {
899 BMessage message(kAddTeam);
900 message.AddInt32("team", team);
901 message.AddString("sig", multiLaunchTeam->sig);
902
903 for (int32 i = 0; i < subsCount; i++)
904 ((BMessenger*)sSubscribers.ItemAt(i))->SendMessage(&message);
905 }
906 return;
907 }
908
909 BString name;
910 if (!gLocalizedNamePreferred
911 || BLocaleRoster::Default()->GetLocalizedFileName(name, *ref)
912 != B_OK) {
913 name = ref->name;
914 }
915
916 BarTeamInfo* barInfo = new BarTeamInfo(new BList(), flags, strdup(sig),
917 strdup(name.String()));
918 _CacheTeamIcon(barInfo);
919 barInfo->teams->AddItem((void*)(addr_t)team);
920 sBarTeamInfoList.AddItem(barInfo);
921
922 int32 subsCount = sSubscribers.CountItems();
923 if (subsCount > 0) {
924 for (int32 i = 0; i < subsCount; i++) {
925 BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
926 BMessage message(B_SOME_APP_LAUNCHED);
927
928 BList* tList = new BList(*(barInfo->teams));
929 message.AddPointer("teams", tList);
930
931 BBitmap* icon = new BBitmap(barInfo->icon);
932 ASSERT(icon);
933
934 message.AddPointer("icon", icon);
935
936 message.AddInt32("flags", static_cast<int32>(barInfo->flags));
937 message.AddString("name", barInfo->name);
938 message.AddString("sig", barInfo->sig);
939
940 messenger->SendMessage(&message);
941 }
942 }
943 }
944
945
946 void
RemoveTeam(team_id team)947 TBarApp::RemoveTeam(team_id team)
948 {
949 BAutolock autolock(sSubscriberLock);
950 if (!autolock.IsLocked())
951 return;
952
953 int32 teamCount = sBarTeamInfoList.CountItems();
954 for (int32 i = 0; i < teamCount; i++) {
955 BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
956 if (barInfo->teams->HasItem((void*)(addr_t)team)) {
957 int32 subsCount = sSubscribers.CountItems();
958 if (subsCount > 0) {
959 BMessage message((barInfo->teams->CountItems() == 1)
960 ? B_SOME_APP_QUIT : kRemoveTeam);
961
962 message.AddInt32("team", team);
963 for (int32 i = 0; i < subsCount; i++) {
964 BMessenger* messenger = (BMessenger*)sSubscribers.ItemAt(i);
965 messenger->SendMessage(&message);
966 }
967 }
968
969 barInfo->teams->RemoveItem((void*)(addr_t)team);
970 if (barInfo->teams->CountItems() < 1) {
971 delete (BarTeamInfo*)sBarTeamInfoList.RemoveItem(i);
972 return;
973 }
974 }
975 }
976 }
977
978
979 void
ResizeTeamIcons()980 TBarApp::ResizeTeamIcons()
981 {
982 for (int32 i = sBarTeamInfoList.CountItems() - 1; i >= 0; i--) {
983 BarTeamInfo* barInfo = (BarTeamInfo*)sBarTeamInfoList.ItemAt(i);
984 if ((barInfo->flags & B_BACKGROUND_APP) == 0
985 && strcasecmp(barInfo->sig, kDeskbarSignature) != 0) {
986 _CacheTeamIcon(barInfo);
987 }
988 }
989 }
990
991
992 int32
TeamIconSize()993 TBarApp::TeamIconSize()
994 {
995 static int32 iconSize = 0, composed = 0;
996 int32 saved = fSettings.iconSize;
997 if (iconSize != saved) {
998 composed = be_control_look->ComposeIconSize(saved).IntegerWidth() + 1;
999 iconSize = saved;
1000 }
1001
1002 return composed;
1003 }
1004
1005
1006 void
ShowPreferencesWindow()1007 TBarApp::ShowPreferencesWindow()
1008 {
1009 if (fPreferencesWindow == NULL) {
1010 fPreferencesWindow = new PreferencesWindow(BRect(100, 100, 320, 240));
1011 fPreferencesWindow->Show();
1012 } else if (fPreferencesWindow->Lock()) {
1013 if (fPreferencesWindow->IsHidden())
1014 fPreferencesWindow->Show();
1015 else
1016 fPreferencesWindow->Activate();
1017
1018 fPreferencesWindow->Unlock();
1019 }
1020 }
1021
1022
1023 void
QuitPreferencesWindow()1024 TBarApp::QuitPreferencesWindow()
1025 {
1026 if (fPreferencesWindow == NULL)
1027 return;
1028
1029 if (fPreferencesWindow->Lock()) {
1030 fPreferencesWindow->Quit();
1031 // Quit() destroys the window so don't unlock
1032 fPreferencesWindow = NULL;
1033 }
1034 }
1035
1036
1037 status_t
_CacheTeamIcon(BarTeamInfo * barInfo)1038 TBarApp::_CacheTeamIcon(BarTeamInfo* barInfo)
1039 {
1040 if (barInfo == NULL)
1041 return B_BAD_VALUE;
1042
1043 return _CacheTeamIcon(barInfo, fSettings.iconSize);
1044 }
1045
1046
1047 status_t
_CacheTeamIcon(BarTeamInfo * barInfo,int32 size)1048 TBarApp::_CacheTeamIcon(BarTeamInfo* barInfo, int32 size)
1049 {
1050 if (barInfo == NULL || size < kMinimumIconSize)
1051 return B_BAD_VALUE;
1052
1053 // icon index based on icon size
1054 const int32 index = (size - kMinimumIconSize) / kIconSizeInterval;
1055
1056 // first look in the icon cache
1057 barInfo->icon = barInfo->iconCache[index];
1058 if (barInfo->icon != NULL)
1059 return B_OK;
1060
1061 int32 composed = be_control_look->ComposeIconSize(size).IntegerWidth() + 1;
1062 BRect iconRect = BRect(0, 0, composed - 1, composed - 1);
1063 BBitmap* icon = new BBitmap(iconRect, B_RGBA32);
1064
1065 // icon wasn't in cache, get it from be_roster and cache it
1066 app_info appInfo;
1067 if (be_roster->GetAppInfo(barInfo->sig, &appInfo) == B_OK) {
1068 // fetch the app icon
1069 BFile file(&appInfo.ref, B_READ_ONLY);
1070 BAppFileInfo appMime(&file);
1071 if (appMime.GetIcon(icon, (icon_size)size) == B_OK) {
1072 barInfo->iconCache[index] = barInfo->icon = icon;
1073
1074 return B_OK;
1075 }
1076 }
1077
1078 // couldn't find the app icon
1079 // fetch the generic 3 boxes icon and cache it
1080 BMimeType defaultAppMime;
1081 defaultAppMime.SetTo(B_APP_MIME_TYPE);
1082 if (defaultAppMime.GetIcon(icon, (icon_size)size) == B_OK) {
1083 barInfo->iconCache[index] = barInfo->icon = icon;
1084
1085 return B_OK;
1086 }
1087
1088 // couldn't find generic 3 boxes icon
1089 // fill with transparent
1090 uint8* iconBits = (uint8*)icon->Bits();
1091 if (icon->ColorSpace() == B_RGBA32) {
1092 int32 i = 0;
1093 while (i < icon->BitsLength()) {
1094 iconBits[i++] = B_TRANSPARENT_32_BIT.red;
1095 iconBits[i++] = B_TRANSPARENT_32_BIT.green;
1096 iconBits[i++] = B_TRANSPARENT_32_BIT.blue;
1097 iconBits[i++] = B_TRANSPARENT_32_BIT.alpha;
1098 }
1099 } else {
1100 // Assume B_CMAP8
1101 for (int32 i = 0; i < icon->BitsLength(); i++)
1102 iconBits[i] = B_TRANSPARENT_MAGIC_CMAP8;
1103 }
1104
1105 barInfo->iconCache[index] = barInfo->icon = icon;
1106
1107 return B_OK;
1108 }
1109
1110
1111 status_t
_CacheWindowIcon(WindowIconCache * winCache)1112 TBarApp::_CacheWindowIcon(WindowIconCache* winCache)
1113 {
1114 if (winCache == NULL)
1115 return B_BAD_VALUE;
1116
1117 // clip font size
1118 int32 fontSize = (int32)floorf(be_plain_font->Size());
1119 if (fontSize < kMinimumFontSize)
1120 fontSize = kMinimumFontSize;
1121 if (fontSize > kMaximumFontSize)
1122 fontSize = kMaximumFontSize;
1123
1124 // icon index based on font size
1125 const int32 index = (fontSize - kMinimumFontSize) / kFontSizeInterval;
1126
1127 // first look in the icon cache
1128 winCache->icon = winCache->iconCache[index];
1129 if (winCache->icon != NULL)
1130 return B_OK;
1131
1132 int32 id = winCache->id;
1133 uint8* data;
1134 size_t size;
1135
1136 // icon wasn't in cache, get vector icon from resource and cache it
1137 data = (uint8*)AppResSet()->FindResource(B_VECTOR_ICON_TYPE, id, &size);
1138 if (data != NULL && size > 0) {
1139 // seems valid, scale bitmap according to font size
1140 BBitmap* icon = new(std::nothrow) BBitmap(
1141 BRect(B_ORIGIN, be_control_look->ComposeIconSize(B_MINI_ICON)),
1142 B_RGBA32);
1143 if (icon != NULL && icon->InitCheck() == B_OK
1144 && BIconUtils::GetVectorIcon(const_cast<const uint8*>(data),
1145 size, icon) == B_OK) {
1146 winCache->iconCache[index] = winCache->icon = icon;
1147
1148 return B_OK;
1149 } else if (icon != NULL) {
1150 // ran out of memory allocating bitmap, this should never happen
1151 delete icon;
1152 delete winCache->iconCache[index];
1153 winCache->iconCache[index] = winCache->icon = NULL;
1154
1155 return B_NO_MEMORY;
1156 }
1157 }
1158
1159 return B_ERROR;
1160 }
1161
1162
1163 // #pragma mark - BarTeamInfo
1164
1165
BarTeamInfo(BList * teams,uint32 flags,char * sig,char * name,BBitmap * icon)1166 BarTeamInfo::BarTeamInfo(BList* teams, uint32 flags, char* sig, char* name,
1167 BBitmap* icon)
1168 :
1169 teams(teams),
1170 flags(flags),
1171 sig(sig),
1172 name(name),
1173 icon(icon)
1174 {
1175 _Init();
1176 }
1177
1178
BarTeamInfo(const BarTeamInfo & info)1179 BarTeamInfo::BarTeamInfo(const BarTeamInfo &info)
1180 :
1181 teams(new BList(*info.teams)),
1182 flags(info.flags),
1183 sig(strdup(info.sig)),
1184 name(strdup(info.name)),
1185 icon(new BBitmap(*info.icon))
1186 {
1187 _Init();
1188 }
1189
1190
~BarTeamInfo()1191 BarTeamInfo::~BarTeamInfo()
1192 {
1193 delete teams;
1194 free(sig);
1195 free(name);
1196 for (int32 i = 0; i < kIconCacheCount; i++)
1197 delete iconCache[i];
1198 }
1199
1200
1201 void
_Init()1202 BarTeamInfo::_Init()
1203 {
1204 for (int32 i = 0; i < kIconCacheCount; i++)
1205 iconCache[i] = NULL;
1206 }
1207
1208
1209 // #pragma mark - WindowIconCache
1210
1211
WindowIconCache(int32 id,BBitmap * icon)1212 WindowIconCache::WindowIconCache(int32 id, BBitmap* icon)
1213 :
1214 id(id),
1215 icon(icon)
1216 {
1217 _Init();
1218 }
1219
1220
WindowIconCache(const WindowIconCache & cache)1221 WindowIconCache::WindowIconCache(const WindowIconCache &cache)
1222 :
1223 id(cache.id),
1224 icon(new BBitmap(*cache.icon))
1225 {
1226 _Init();
1227 }
1228
1229
~WindowIconCache()1230 WindowIconCache::~WindowIconCache()
1231 {
1232 for (int32 i = 0; i < kWindowIconCacheCount; i++)
1233 delete iconCache[i];
1234 }
1235
1236
1237 void
_Init()1238 WindowIconCache::_Init()
1239 {
1240 for (int32 i = 0; i < kWindowIconCacheCount; i++)
1241 iconCache[i] = NULL;
1242 }
1243