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