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 "BarWindow.h" 38 39 #include <stdio.h> 40 41 #include <Application.h> 42 #include <AutoDeleter.h> 43 #include <Catalog.h> 44 #include <ControlLook.h> 45 #include <Directory.h> 46 #include <FindDirectory.h> 47 #include <Path.h> 48 #include <Debug.h> 49 #include <File.h> 50 #include <Locale.h> 51 #include <MenuItem.h> 52 #include <MessageFilter.h> 53 #include <MessagePrivate.h> 54 #include <Screen.h> 55 56 #include <DeskbarPrivate.h> 57 #include <tracker_private.h> 58 59 #include "BarApp.h" 60 #include "BarMenuBar.h" 61 #include "BarView.h" 62 #include "DeskbarUtils.h" 63 #include "DeskbarMenu.h" 64 #include "ExpandoMenuBar.h" 65 #include "StatusView.h" 66 67 68 #undef B_TRANSLATION_CONTEXT 69 #define B_TRANSLATION_CONTEXT "MainWindow" 70 71 72 // This is a bit of a hack to be able to call BMenuBar::StartMenuBar(), which 73 // is private. Don't do this at home! 74 class TStartableMenuBar : public BMenuBar { 75 public: 76 TStartableMenuBar(); 77 void StartMenuBar(int32 menuIndex, bool sticky = true, bool showMenu = false, 78 BRect* special_rect = NULL) { BMenuBar::StartMenuBar(menuIndex, sticky, showMenu, 79 special_rect); } 80 }; 81 82 83 TDeskbarMenu* TBarWindow::sDeskbarMenu = NULL; 84 85 86 TBarWindow::TBarWindow() 87 : 88 BWindow(BRect(-1000.0f, -1000.0f, -1000.0f, -1000.0f), 89 "Deskbar", /* no B_TRANSLATE_SYSTEM_NAME, for binary compatibility */ 90 B_BORDERED_WINDOW, 91 B_WILL_ACCEPT_FIRST_CLICK | B_NOT_ZOOMABLE | B_NOT_CLOSABLE 92 | B_NOT_MINIMIZABLE | B_NOT_MOVABLE | B_NOT_V_RESIZABLE 93 | B_AVOID_FRONT | B_ASYNCHRONOUS_CONTROLS, 94 B_ALL_WORKSPACES), 95 fBarApp(static_cast<TBarApp*>(be_app)), 96 fBarView(NULL), 97 fMenusShown(0) 98 { 99 desk_settings* settings = fBarApp->Settings(); 100 if (settings->alwaysOnTop) 101 SetFeel(B_FLOATING_ALL_WINDOW_FEEL); 102 103 fBarView = new TBarView(Bounds(), settings->vertical, settings->left, 104 settings->top, settings->state, settings->width); 105 AddChild(fBarView); 106 107 RemoveShortcut('H', B_COMMAND_KEY | B_CONTROL_KEY); 108 AddShortcut('F', B_COMMAND_KEY, new BMessage(kFindButton)); 109 110 SetSizeLimits(); 111 } 112 113 114 void 115 TBarWindow::MenusBeginning() 116 { 117 BPath path; 118 entry_ref ref; 119 BEntry entry; 120 121 if (GetDeskbarSettingsDirectory(path) == B_OK 122 && path.Append(kDeskbarMenuEntriesFileName) == B_OK 123 && entry.SetTo(path.Path(), true) == B_OK 124 && entry.Exists() 125 && entry.GetRef(&ref) == B_OK) { 126 sDeskbarMenu->SetNavDir(&ref); 127 } else if (GetDeskbarDataDirectory(path) == B_OK 128 && path.Append(kDeskbarMenuEntriesFileName) == B_OK 129 && entry.SetTo(path.Path(), true) == B_OK 130 && entry.Exists() 131 && entry.GetRef(&ref) == B_OK) { 132 sDeskbarMenu->SetNavDir(&ref); 133 } else { 134 // this really should never happen 135 TRESPASS(); 136 return; 137 } 138 139 // raise Deskbar on menu open in auto-raise mode unless always-on-top 140 desk_settings* settings = fBarApp->Settings(); 141 bool alwaysOnTop = settings->alwaysOnTop; 142 bool autoRaise = settings->autoRaise; 143 if (!alwaysOnTop && autoRaise) 144 fBarView->RaiseDeskbar(true); 145 146 sDeskbarMenu->ResetTargets(); 147 148 fMenusShown++; 149 BWindow::MenusBeginning(); 150 } 151 152 153 void 154 TBarWindow::MenusEnded() 155 { 156 fMenusShown--; 157 BWindow::MenusEnded(); 158 159 // lower Deskbar back down again on menu close in auto-raise mode 160 // unless another menu is open or always-on-top. 161 desk_settings* settings = fBarApp->Settings(); 162 bool alwaysOnTop = settings->alwaysOnTop; 163 bool autoRaise = settings->autoRaise; 164 if (!alwaysOnTop && autoRaise && fMenusShown <= 0) 165 fBarView->RaiseDeskbar(false); 166 167 if (sDeskbarMenu->LockLooper()) { 168 sDeskbarMenu->ForceRebuild(); 169 sDeskbarMenu->UnlockLooper(); 170 } 171 } 172 173 174 void 175 TBarWindow::MessageReceived(BMessage* message) 176 { 177 switch (message->what) { 178 case kFindButton: 179 { 180 BMessenger tracker(kTrackerSignature); 181 tracker.SendMessage(message); 182 break; 183 } 184 185 case kMsgLocation: 186 GetLocation(message); 187 break; 188 189 case kMsgSetLocation: 190 SetLocation(message); 191 break; 192 193 case kMsgIsExpanded: 194 IsExpanded(message); 195 break; 196 197 case kMsgExpand: 198 Expand(message); 199 break; 200 201 case kMsgGetItemInfo: 202 ItemInfo(message); 203 break; 204 205 case kMsgHasItem: 206 ItemExists(message); 207 break; 208 209 case kMsgCountItems: 210 CountItems(message); 211 break; 212 213 case kMsgMaxItemSize: 214 MaxItemSize(message); 215 break; 216 217 case kMsgAddAddOn: 218 case kMsgAddView: 219 AddItem(message); 220 break; 221 222 case kMsgRemoveItem: 223 RemoveItem(message); 224 break; 225 226 case 'iloc': 227 GetIconFrame(message); 228 break; 229 230 default: 231 BWindow::MessageReceived(message); 232 break; 233 } 234 } 235 236 237 void 238 TBarWindow::Minimize(bool minimize) 239 { 240 // Don't allow the Deskbar to be minimized 241 if (!minimize) 242 BWindow::Minimize(false); 243 } 244 245 246 void 247 TBarWindow::FrameResized(float width, float height) 248 { 249 if (!fBarView->Vertical()) 250 return BWindow::FrameResized(width, height); 251 252 bool setToHiddenSize = fBarApp->Settings()->autoHide 253 && fBarView->IsHidden() && !fBarView->DragRegion()->IsDragging(); 254 if (!setToHiddenSize) { 255 // constrain within limits 256 float newWidth; 257 if (width < gMinimumWindowWidth) 258 newWidth = gMinimumWindowWidth; 259 else if (width > gMaximumWindowWidth) 260 newWidth = gMaximumWindowWidth; 261 else 262 newWidth = width; 263 264 float oldWidth = fBarApp->Settings()->width; 265 266 // update width setting 267 fBarApp->Settings()->width = newWidth; 268 269 if (oldWidth != newWidth) { 270 fBarView->ResizeTo(width, fBarView->Bounds().Height()); 271 if (fBarView->Vertical() && fBarView->ExpandoMenuBar() != NULL) 272 fBarView->ExpandoMenuBar()->SetMaxContentWidth(width); 273 274 fBarView->UpdatePlacement(); 275 } 276 } 277 } 278 279 280 void 281 TBarWindow::SaveSettings() 282 { 283 fBarView->SaveSettings(); 284 } 285 286 287 bool 288 TBarWindow::QuitRequested() 289 { 290 be_app->PostMessage(B_QUIT_REQUESTED); 291 292 return BWindow::QuitRequested(); 293 } 294 295 296 void 297 TBarWindow::WorkspaceActivated(int32 workspace, bool active) 298 { 299 BWindow::WorkspaceActivated(workspace, active); 300 301 if (active && !(fBarView->ExpandoState() && fBarView->Vertical())) 302 fBarView->UpdatePlacement(); 303 else { 304 BRect screenFrame = (BScreen(fBarView->Window())).Frame(); 305 fBarView->SizeWindow(screenFrame); 306 fBarView->PositionWindow(screenFrame); 307 fBarView->Invalidate(); 308 } 309 } 310 311 312 void 313 TBarWindow::ScreenChanged(BRect size, color_space depth) 314 { 315 BWindow::ScreenChanged(size, depth); 316 317 SetSizeLimits(); 318 319 if (fBarView != NULL) { 320 fBarView->DragRegion()->CalculateRegions(); 321 fBarView->UpdatePlacement(); 322 } 323 } 324 325 326 void 327 TBarWindow::SetDeskbarMenu(TDeskbarMenu* menu) 328 { 329 sDeskbarMenu = menu; 330 } 331 332 333 TDeskbarMenu* 334 TBarWindow::DeskbarMenu() 335 { 336 return sDeskbarMenu; 337 } 338 339 340 void 341 TBarWindow::ShowDeskbarMenu() 342 { 343 TStartableMenuBar* menuBar = (TStartableMenuBar*)fBarView->BarMenuBar(); 344 if (menuBar == NULL) 345 menuBar = (TStartableMenuBar*)KeyMenuBar(); 346 347 if (menuBar == NULL) 348 return; 349 350 menuBar->StartMenuBar(0, true, true, NULL); 351 } 352 353 354 void 355 TBarWindow::ShowTeamMenu() 356 { 357 int32 index = 0; 358 if (fBarView->BarMenuBar() == NULL) 359 index = 2; 360 361 if (KeyMenuBar() == NULL) 362 return; 363 364 ((TStartableMenuBar*)KeyMenuBar())->StartMenuBar(index, true, true, NULL); 365 } 366 367 368 // determines the actual location of the window 369 370 deskbar_location 371 TBarWindow::DeskbarLocation() const 372 { 373 bool left = fBarView->Left(); 374 bool top = fBarView->Top(); 375 376 if (fBarView->AcrossTop()) 377 return B_DESKBAR_TOP; 378 379 if (fBarView->AcrossBottom()) 380 return B_DESKBAR_BOTTOM; 381 382 if (left && top) 383 return B_DESKBAR_LEFT_TOP; 384 385 if (!left && top) 386 return B_DESKBAR_RIGHT_TOP; 387 388 if (left && !top) 389 return B_DESKBAR_LEFT_BOTTOM; 390 391 return B_DESKBAR_RIGHT_BOTTOM; 392 } 393 394 395 void 396 TBarWindow::GetLocation(BMessage* message) 397 { 398 BMessage reply('rply'); 399 reply.AddInt32("location", (int32)DeskbarLocation()); 400 reply.AddBool("expanded", fBarView->ExpandoState()); 401 402 message->SendReply(&reply); 403 } 404 405 406 void 407 TBarWindow::SetDeskbarLocation(deskbar_location location, bool newExpandState) 408 { 409 // left top and right top are the only two that 410 // currently pay attention to expand, ignore for all others 411 412 bool left = false, top = true, vertical, expand; 413 414 switch (location) { 415 case B_DESKBAR_TOP: 416 left = true; 417 top = true; 418 vertical = false; 419 expand = true; 420 break; 421 422 case B_DESKBAR_BOTTOM: 423 left = true; 424 top = false; 425 vertical = false; 426 expand = true; 427 break; 428 429 case B_DESKBAR_LEFT_TOP: 430 left = true; 431 top = true; 432 vertical = true; 433 expand = newExpandState; 434 break; 435 436 case B_DESKBAR_RIGHT_TOP: 437 left = false; 438 top = true; 439 vertical = true; 440 expand = newExpandState; 441 break; 442 443 case B_DESKBAR_LEFT_BOTTOM: 444 left = true; 445 top = false; 446 vertical = true; 447 expand = false; 448 break; 449 450 case B_DESKBAR_RIGHT_BOTTOM: 451 left = false; 452 top = false; 453 vertical = true; 454 expand = false; 455 break; 456 457 default: 458 left = true; 459 top = true; 460 vertical = false; 461 expand = true; 462 break; 463 } 464 465 fBarView->ChangeState(expand, vertical, left, top); 466 } 467 468 469 void 470 TBarWindow::SetLocation(BMessage* message) 471 { 472 deskbar_location location; 473 bool expand; 474 if (message->FindInt32("location", (int32*)&location) == B_OK 475 && message->FindBool("expand", &expand) == B_OK) 476 SetDeskbarLocation(location, expand); 477 } 478 479 480 void 481 TBarWindow::IsExpanded(BMessage* message) 482 { 483 BMessage reply('rply'); 484 reply.AddBool("expanded", fBarView->ExpandoState()); 485 message->SendReply(&reply); 486 } 487 488 489 void 490 TBarWindow::Expand(BMessage* message) 491 { 492 bool expand; 493 if (message->FindBool("expand", &expand) == B_OK) { 494 bool vertical = fBarView->Vertical(); 495 bool left = fBarView->Left(); 496 bool top = fBarView->Top(); 497 fBarView->ChangeState(expand, vertical, left, top); 498 } 499 } 500 501 502 void 503 TBarWindow::ItemInfo(BMessage* message) 504 { 505 BMessage replyMsg; 506 const char* name; 507 int32 id; 508 DeskbarShelf shelf; 509 if (message->FindInt32("id", &id) == B_OK) { 510 if (fBarView->ItemInfo(id, &name, &shelf) == B_OK) { 511 replyMsg.AddString("name", name); 512 #if SHELF_AWARE 513 replyMsg.AddInt32("shelf", (int32)shelf); 514 #endif 515 } 516 } else if (message->FindString("name", &name) == B_OK) { 517 if (fBarView->ItemInfo(name, &id, &shelf) == B_OK) { 518 replyMsg.AddInt32("id", id); 519 #if SHELF_AWARE 520 replyMsg.AddInt32("shelf", (int32)shelf); 521 #endif 522 } 523 } 524 525 message->SendReply(&replyMsg); 526 } 527 528 529 void 530 TBarWindow::ItemExists(BMessage* message) 531 { 532 BMessage replyMsg; 533 const char* name; 534 int32 id; 535 DeskbarShelf shelf; 536 537 #if SHELF_AWARE 538 if (message->FindInt32("shelf", (int32*)&shelf) != B_OK) 539 #endif 540 shelf = B_DESKBAR_TRAY; 541 542 bool exists = false; 543 if (message->FindInt32("id", &id) == B_OK) 544 exists = fBarView->ItemExists(id, shelf); 545 else if (message->FindString("name", &name) == B_OK) 546 exists = fBarView->ItemExists(name, shelf); 547 548 replyMsg.AddBool("exists", exists); 549 message->SendReply(&replyMsg); 550 } 551 552 553 void 554 TBarWindow::CountItems(BMessage* message) 555 { 556 DeskbarShelf shelf; 557 558 #if SHELF_AWARE 559 if (message->FindInt32("shelf", (int32*)&shelf) != B_OK) 560 #endif 561 shelf = B_DESKBAR_TRAY; 562 563 BMessage reply('rply'); 564 reply.AddInt32("count", fBarView->CountItems(shelf)); 565 message->SendReply(&reply); 566 } 567 568 569 void 570 TBarWindow::MaxItemSize(BMessage* message) 571 { 572 DeskbarShelf shelf; 573 #if SHELF_AWARE 574 if (message->FindInt32("shelf", (int32*)&shelf) != B_OK) 575 #endif 576 shelf = B_DESKBAR_TRAY; 577 578 BSize size = fBarView->MaxItemSize(shelf); 579 580 BMessage reply('rply'); 581 reply.AddFloat("width", size.width); 582 reply.AddFloat("height", size.height); 583 message->SendReply(&reply); 584 } 585 586 587 void 588 TBarWindow::AddItem(BMessage* message) 589 { 590 DeskbarShelf shelf = B_DESKBAR_TRAY; 591 entry_ref ref; 592 int32 id = 999; 593 BMessage reply; 594 status_t err = B_ERROR; 595 596 BMessage* archivedView = new BMessage(); 597 ObjectDeleter<BMessage> deleter(archivedView); 598 if (message->FindMessage("view", archivedView) == B_OK) { 599 #if SHELF_AWARE 600 message->FindInt32("shelf", &shelf); 601 #endif 602 err = fBarView->AddItem(archivedView, shelf, &id); 603 if (err == B_OK) { 604 // Detach the deleter since AddReplicant is taking ownership 605 // on success. This should be changed on server side. 606 deleter.Detach(); 607 } 608 } else if (message->FindRef("addon", &ref) == B_OK) { 609 BEntry entry(&ref); 610 err = entry.InitCheck(); 611 if (err == B_OK) 612 err = fBarView->AddItem(&entry, shelf, &id); 613 } 614 615 if (err == B_OK) 616 reply.AddInt32("id", id); 617 else 618 reply.AddInt32("error", err); 619 620 message->SendReply(&reply); 621 } 622 623 624 void 625 TBarWindow::RemoveItem(BMessage* message) 626 { 627 int32 id; 628 const char* name; 629 630 // ids ought to be unique across all shelves, assuming, of course, 631 // that sometime in the future there may be more than one 632 #if SHELF_AWARE 633 if (message->FindInt32("shelf", (int32*)&shelf) == B_OK) { 634 if (message->FindString("name", &name) == B_OK) 635 fBarView->RemoveItem(name, shelf); 636 } else { 637 #endif 638 if (message->FindInt32("id", &id) == B_OK) { 639 fBarView->RemoveItem(id); 640 // remove the following two lines if and when the 641 // shelf option returns 642 } else if (message->FindString("name", &name) == B_OK) 643 fBarView->RemoveItem(name, B_DESKBAR_TRAY); 644 645 #if SHELF_AWARE 646 } 647 #endif 648 } 649 650 651 void 652 TBarWindow::GetIconFrame(BMessage* message) 653 { 654 BRect frame(0, 0, 0, 0); 655 656 const char* name; 657 int32 id; 658 if (message->FindInt32("id", &id) == B_OK) 659 frame = fBarView->IconFrame(id); 660 else if (message->FindString("name", &name) == B_OK) 661 frame = fBarView->IconFrame(name); 662 663 BMessage reply('rply'); 664 reply.AddRect("frame", frame); 665 message->SendReply(&reply); 666 } 667 668 669 bool 670 TBarWindow::IsShowingMenu() const 671 { 672 return fMenusShown > 0; 673 } 674 675 676 void 677 TBarWindow::SetSizeLimits() 678 { 679 BRect screenFrame = (BScreen(this)).Frame(); 680 bool setToHiddenSize = fBarApp->Settings()->autoHide 681 && fBarView->IsHidden() && !fBarView->DragRegion()->IsDragging(); 682 683 if (setToHiddenSize) { 684 if (fBarView->Vertical()) 685 BWindow::SetSizeLimits(0, kHiddenDimension, 0, kHiddenDimension); 686 else { 687 BWindow::SetSizeLimits(screenFrame.Width(), screenFrame.Width(), 688 0, kHiddenDimension); 689 } 690 } else { 691 float minHeight; 692 float maxHeight; 693 float minWidth; 694 float maxWidth; 695 696 if (fBarView->Vertical()) { 697 minHeight = fBarView->TabHeight(); 698 maxHeight = B_SIZE_UNLIMITED; 699 minWidth = gMinimumWindowWidth; 700 maxWidth = gMaximumWindowWidth; 701 } else { 702 // horizontal 703 if (fBarView->MiniState()) { 704 // horizontal mini-mode 705 minWidth = gMinimumWindowWidth; 706 maxWidth = B_SIZE_UNLIMITED; 707 minHeight = fBarView->TabHeight(); 708 maxHeight = std::max(fBarView->TabHeight(), kGutter 709 + fBarView->ReplicantTray()->MaxReplicantHeight() 710 + kGutter); 711 } else { 712 // horizontal expando-mode 713 const int32 max 714 = be_control_look->ComposeIconSize(kMaximumIconSize) 715 .IntegerWidth() + 1; 716 const float iconPadding 717 = be_control_look->ComposeSpacing(kIconPadding); 718 719 minWidth = maxWidth = screenFrame.Width(); 720 minHeight = kMenuBarHeight - 1; 721 maxHeight = max + iconPadding / 2; 722 } 723 } 724 725 BWindow::SetSizeLimits(minWidth, maxWidth, minHeight, maxHeight); 726 } 727 } 728 729 730 bool 731 TBarWindow::_IsFocusMessage(BMessage* message) 732 { 733 BMessage::Private messagePrivate(message); 734 if (!messagePrivate.UsePreferredTarget()) 735 return false; 736 737 bool feedFocus; 738 if (message->HasInt32("_token") 739 && (message->FindBool("_feed_focus", &feedFocus) != B_OK || !feedFocus)) 740 return false; 741 742 return true; 743 } 744