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