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