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