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