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->ExpandoState()) 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 fBarView->UpdatePlacement(); 316 SetSizeLimits(); 317 } 318 319 320 void 321 TBarWindow::SetDeskbarMenu(TDeskbarMenu* menu) 322 { 323 sDeskbarMenu = menu; 324 } 325 326 327 TDeskbarMenu* 328 TBarWindow::DeskbarMenu() 329 { 330 return sDeskbarMenu; 331 } 332 333 334 void 335 TBarWindow::ShowDeskbarMenu() 336 { 337 TStartableMenuBar* menuBar = (TStartableMenuBar*)fBarView->BarMenuBar(); 338 if (menuBar == NULL) 339 menuBar = (TStartableMenuBar*)KeyMenuBar(); 340 341 if (menuBar == NULL) 342 return; 343 344 menuBar->StartMenuBar(0, true, true, NULL); 345 } 346 347 348 void 349 TBarWindow::ShowTeamMenu() 350 { 351 int32 index = 0; 352 if (fBarView->BarMenuBar() == NULL) 353 index = 2; 354 355 if (KeyMenuBar() == NULL) 356 return; 357 358 ((TStartableMenuBar*)KeyMenuBar())->StartMenuBar(index, true, true, NULL); 359 } 360 361 362 // determines the actual location of the window 363 364 deskbar_location 365 TBarWindow::DeskbarLocation() const 366 { 367 bool left = fBarView->Left(); 368 bool top = fBarView->Top(); 369 370 if (fBarView->AcrossTop()) 371 return B_DESKBAR_TOP; 372 373 if (fBarView->AcrossBottom()) 374 return B_DESKBAR_BOTTOM; 375 376 if (left && top) 377 return B_DESKBAR_LEFT_TOP; 378 379 if (!left && top) 380 return B_DESKBAR_RIGHT_TOP; 381 382 if (left && !top) 383 return B_DESKBAR_LEFT_BOTTOM; 384 385 return B_DESKBAR_RIGHT_BOTTOM; 386 } 387 388 389 void 390 TBarWindow::GetLocation(BMessage* message) 391 { 392 BMessage reply('rply'); 393 reply.AddInt32("location", (int32)DeskbarLocation()); 394 reply.AddBool("expanded", fBarView->ExpandoState()); 395 396 message->SendReply(&reply); 397 } 398 399 400 void 401 TBarWindow::SetDeskbarLocation(deskbar_location location, bool newExpandState) 402 { 403 // left top and right top are the only two that 404 // currently pay attention to expand, ignore for all others 405 406 bool left = false, top = true, vertical, expand; 407 408 switch (location) { 409 case B_DESKBAR_TOP: 410 left = true; 411 top = true; 412 vertical = false; 413 expand = true; 414 break; 415 416 case B_DESKBAR_BOTTOM: 417 left = true; 418 top = false; 419 vertical = false; 420 expand = true; 421 break; 422 423 case B_DESKBAR_LEFT_TOP: 424 left = true; 425 top = true; 426 vertical = true; 427 expand = newExpandState; 428 break; 429 430 case B_DESKBAR_RIGHT_TOP: 431 left = false; 432 top = true; 433 vertical = true; 434 expand = newExpandState; 435 break; 436 437 case B_DESKBAR_LEFT_BOTTOM: 438 left = true; 439 top = false; 440 vertical = true; 441 expand = false; 442 break; 443 444 case B_DESKBAR_RIGHT_BOTTOM: 445 left = false; 446 top = false; 447 vertical = true; 448 expand = false; 449 break; 450 451 default: 452 left = true; 453 top = true; 454 vertical = false; 455 expand = true; 456 break; 457 } 458 459 fBarView->ChangeState(expand, vertical, left, top); 460 } 461 462 463 void 464 TBarWindow::SetLocation(BMessage* message) 465 { 466 deskbar_location location; 467 bool expand; 468 if (message->FindInt32("location", (int32*)&location) == B_OK 469 && message->FindBool("expand", &expand) == B_OK) 470 SetDeskbarLocation(location, expand); 471 } 472 473 474 void 475 TBarWindow::IsExpanded(BMessage* message) 476 { 477 BMessage reply('rply'); 478 reply.AddBool("expanded", fBarView->ExpandoState()); 479 message->SendReply(&reply); 480 } 481 482 483 void 484 TBarWindow::Expand(BMessage* message) 485 { 486 bool expand; 487 if (message->FindBool("expand", &expand) == B_OK) { 488 bool vertical = fBarView->Vertical(); 489 bool left = fBarView->Left(); 490 bool top = fBarView->Top(); 491 fBarView->ChangeState(expand, vertical, left, top); 492 } 493 } 494 495 496 void 497 TBarWindow::ItemInfo(BMessage* message) 498 { 499 BMessage replyMsg; 500 const char* name; 501 int32 id; 502 DeskbarShelf shelf; 503 if (message->FindInt32("id", &id) == B_OK) { 504 if (fBarView->ItemInfo(id, &name, &shelf) == B_OK) { 505 replyMsg.AddString("name", name); 506 #if SHELF_AWARE 507 replyMsg.AddInt32("shelf", (int32)shelf); 508 #endif 509 } 510 } else if (message->FindString("name", &name) == B_OK) { 511 if (fBarView->ItemInfo(name, &id, &shelf) == B_OK) { 512 replyMsg.AddInt32("id", id); 513 #if SHELF_AWARE 514 replyMsg.AddInt32("shelf", (int32)shelf); 515 #endif 516 } 517 } 518 519 message->SendReply(&replyMsg); 520 } 521 522 523 void 524 TBarWindow::ItemExists(BMessage* message) 525 { 526 BMessage replyMsg; 527 const char* name; 528 int32 id; 529 DeskbarShelf shelf; 530 531 #if SHELF_AWARE 532 if (message->FindInt32("shelf", (int32*)&shelf) != B_OK) 533 #endif 534 shelf = B_DESKBAR_TRAY; 535 536 bool exists = false; 537 if (message->FindInt32("id", &id) == B_OK) 538 exists = fBarView->ItemExists(id, shelf); 539 else if (message->FindString("name", &name) == B_OK) 540 exists = fBarView->ItemExists(name, shelf); 541 542 replyMsg.AddBool("exists", exists); 543 message->SendReply(&replyMsg); 544 } 545 546 547 void 548 TBarWindow::CountItems(BMessage* message) 549 { 550 DeskbarShelf shelf; 551 552 #if SHELF_AWARE 553 if (message->FindInt32("shelf", (int32*)&shelf) != B_OK) 554 #endif 555 shelf = B_DESKBAR_TRAY; 556 557 BMessage reply('rply'); 558 reply.AddInt32("count", fBarView->CountItems(shelf)); 559 message->SendReply(&reply); 560 } 561 562 563 void 564 TBarWindow::MaxItemSize(BMessage* message) 565 { 566 DeskbarShelf shelf; 567 #if SHELF_AWARE 568 if (message->FindInt32("shelf", (int32*)&shelf) != B_OK) 569 #endif 570 shelf = B_DESKBAR_TRAY; 571 572 BSize size = fBarView->MaxItemSize(shelf); 573 574 BMessage reply('rply'); 575 reply.AddFloat("width", size.width); 576 reply.AddFloat("height", size.height); 577 message->SendReply(&reply); 578 } 579 580 581 void 582 TBarWindow::AddItem(BMessage* message) 583 { 584 DeskbarShelf shelf = B_DESKBAR_TRAY; 585 entry_ref ref; 586 int32 id = 999; 587 BMessage reply; 588 status_t err = B_ERROR; 589 590 BMessage* archivedView = new BMessage(); 591 ObjectDeleter<BMessage> deleter(archivedView); 592 if (message->FindMessage("view", archivedView) == B_OK) { 593 #if SHELF_AWARE 594 message->FindInt32("shelf", &shelf); 595 #endif 596 err = fBarView->AddItem(archivedView, shelf, &id); 597 if (err == B_OK) { 598 // Detach the deleter since AddReplicant is taking ownership 599 // on success. This should be changed on server side. 600 deleter.Detach(); 601 } 602 } else if (message->FindRef("addon", &ref) == B_OK) { 603 BEntry entry(&ref); 604 err = entry.InitCheck(); 605 if (err == B_OK) 606 err = fBarView->AddItem(&entry, shelf, &id); 607 } 608 609 if (err == B_OK) 610 reply.AddInt32("id", id); 611 else 612 reply.AddInt32("error", err); 613 614 message->SendReply(&reply); 615 } 616 617 618 void 619 TBarWindow::RemoveItem(BMessage* message) 620 { 621 int32 id; 622 const char* name; 623 624 // ids ought to be unique across all shelves, assuming, of course, 625 // that sometime in the future there may be more than one 626 #if SHELF_AWARE 627 if (message->FindInt32("shelf", (int32*)&shelf) == B_OK) { 628 if (message->FindString("name", &name) == B_OK) 629 fBarView->RemoveItem(name, shelf); 630 } else { 631 #endif 632 if (message->FindInt32("id", &id) == B_OK) { 633 fBarView->RemoveItem(id); 634 // remove the following two lines if and when the 635 // shelf option returns 636 } else if (message->FindString("name", &name) == B_OK) 637 fBarView->RemoveItem(name, B_DESKBAR_TRAY); 638 639 #if SHELF_AWARE 640 } 641 #endif 642 } 643 644 645 void 646 TBarWindow::GetIconFrame(BMessage* message) 647 { 648 BRect frame(0, 0, 0, 0); 649 650 const char* name; 651 int32 id; 652 if (message->FindInt32("id", &id) == B_OK) 653 frame = fBarView->IconFrame(id); 654 else if (message->FindString("name", &name) == B_OK) 655 frame = fBarView->IconFrame(name); 656 657 BMessage reply('rply'); 658 reply.AddRect("frame", frame); 659 message->SendReply(&reply); 660 } 661 662 663 bool 664 TBarWindow::IsShowingMenu() const 665 { 666 return fMenusShown > 0; 667 } 668 669 670 void 671 TBarWindow::SetSizeLimits() 672 { 673 BRect screenFrame = (BScreen(this)).Frame(); 674 bool setToHiddenSize = fBarApp->Settings()->autoHide 675 && fBarView->IsHidden() && !fBarView->DragRegion()->IsDragging(); 676 677 if (setToHiddenSize) { 678 if (fBarView->Vertical()) 679 BWindow::SetSizeLimits(0, kHiddenDimension, 0, kHiddenDimension); 680 else { 681 BWindow::SetSizeLimits(screenFrame.Width(), screenFrame.Width(), 682 0, kHiddenDimension); 683 } 684 } else { 685 if (fBarView->Vertical()) { 686 BWindow::SetSizeLimits(gMinimumWindowWidth, gMaximumWindowWidth, 687 kMenuBarHeight - 1, B_SIZE_UNLIMITED); 688 } else { 689 BWindow::SetSizeLimits(screenFrame.Width(), screenFrame.Width(), 690 kMenuBarHeight - 1, kMaximumIconSize + 4); 691 } 692 } 693 } 694 695 696 bool 697 TBarWindow::_IsFocusMessage(BMessage* message) 698 { 699 BMessage::Private messagePrivate(message); 700 if (!messagePrivate.UsePreferredTarget()) 701 return false; 702 703 bool feedFocus; 704 if (message->HasInt32("_token") 705 && (message->FindBool("_feed_focus", &feedFocus) != B_OK || !feedFocus)) 706 return false; 707 708 return true; 709 } 710