1/* 2Open Tracker License 3 4Terms and Conditions 5 6Copyright (c) 1991-2000, Be Incorporated. All rights reserved. 7 8Permission is hereby granted, free of charge, to any person obtaining a copy of 9this software and associated documentation files (the "Software"), to deal in 10the Software without restriction, including without limitation the rights to 11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12of the Software, and to permit persons to whom the Software is furnished to do 13so, subject to the following conditions: 14 15The above copyright notice and this permission notice applies to all licensees 16and shall be included in all copies or substantial portions of the Software. 17 18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, 20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION 23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25Except as contained in this notice, the name of Be Incorporated shall not be 26used in advertising or otherwise to promote the sale, use or other dealings in 27this Software without prior written authorization from Be Incorporated. 28 29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered 30trademarks of Be Incorporated in the United States and other countries. Other 31brand product names are registered trademarks or trademarks of their respective 32holders. 33All 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! 74class TStartableMenuBar : public BMenuBar { 75public: 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 83TDeskbarMenu* TBarWindow::sDeskbarMenu = NULL; 84 85 86TBarWindow::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 114void 115TBarWindow::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 153void 154TBarWindow::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 174void 175TBarWindow::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 237void 238TBarWindow::Minimize(bool minimize) 239{ 240 // Don't allow the Deskbar to be minimized 241 if (!minimize) 242 BWindow::Minimize(false); 243} 244 245 246void 247TBarWindow::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 280void 281TBarWindow::SaveSettings() 282{ 283 fBarView->SaveSettings(); 284} 285 286 287bool 288TBarWindow::QuitRequested() 289{ 290 be_app->PostMessage(B_QUIT_REQUESTED); 291 292 return BWindow::QuitRequested(); 293} 294 295 296void 297TBarWindow::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 312void 313TBarWindow::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 326void 327TBarWindow::SetDeskbarMenu(TDeskbarMenu* menu) 328{ 329 sDeskbarMenu = menu; 330} 331 332 333TDeskbarMenu* 334TBarWindow::DeskbarMenu() 335{ 336 return sDeskbarMenu; 337} 338 339 340void 341TBarWindow::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 354void 355TBarWindow::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 370deskbar_location 371TBarWindow::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 395void 396TBarWindow::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 406void 407TBarWindow::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 469void 470TBarWindow::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 480void 481TBarWindow::IsExpanded(BMessage* message) 482{ 483 BMessage reply('rply'); 484 reply.AddBool("expanded", fBarView->ExpandoState()); 485 message->SendReply(&reply); 486} 487 488 489void 490TBarWindow::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 502void 503TBarWindow::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 529void 530TBarWindow::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 553void 554TBarWindow::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 569void 570TBarWindow::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 587void 588TBarWindow::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 624void 625TBarWindow::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 651void 652TBarWindow::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 669bool 670TBarWindow::IsShowingMenu() const 671{ 672 return fMenusShown > 0; 673} 674 675 676void 677TBarWindow::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 730bool 731TBarWindow::_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