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 "BarApp.h" 56 #include "BarMenuBar.h" 57 #include "BarView.h" 58 #include "DeskbarUtils.h" 59 #include "DeskbarMenu.h" 60 #include "ExpandoMenuBar.h" 61 #include "StatusView.h" 62 63 #include "tracker_private.h" 64 65 #undef B_TRANSLATION_CONTEXT 66 #define B_TRANSLATION_CONTEXT "MainWindow" 67 68 69 // This is a very ugly hack to be able to call the private 70 // BMenuBar::StartMenuBar() method from the TBarWindow::ShowBeMenu() method. 71 // Don't do this at home -- but why the hell is this method private? 72 #if __MWERKS__ 73 #define BMenuBar_StartMenuBar_Hack StartMenuBar__8BMenuBarFlbbP5BRect 74 #elif __GNUC__ <= 2 75 #define BMenuBar_StartMenuBar_Hack StartMenuBar__8BMenuBarlbT2P5BRect 76 #elif __GNUC__ > 2 77 #if B_HAIKU_64_BIT 78 #define BMenuBar_StartMenuBar_Hack _ZN8BMenuBar12StartMenuBarEibbP5BRect 79 #else 80 #define BMenuBar_StartMenuBar_Hack _ZN8BMenuBar12StartMenuBarElbbP5BRect 81 #endif 82 #else 83 # error "You may want to port this ugly hack to your compiler ABI" 84 #endif 85 extern "C" void 86 BMenuBar_StartMenuBar_Hack(BMenuBar*, int32, bool, bool, BRect*); 87 88 89 TDeskbarMenu* TBarWindow::sDeskbarMenu = NULL; 90 91 92 TBarWindow::TBarWindow() 93 : 94 BWindow(BRect(-1000.0f, -1000.0f, -1000.0f, -1000.0f), 95 B_TRANSLATE_SYSTEM_NAME("Deskbar"), B_BORDERED_WINDOW, 96 B_WILL_ACCEPT_FIRST_CLICK | B_NOT_ZOOMABLE | B_NOT_CLOSABLE 97 | B_NOT_MINIMIZABLE | B_NOT_MOVABLE | B_NOT_V_RESIZABLE 98 | B_AVOID_FRONT | B_ASYNCHRONOUS_CONTROLS, 99 B_ALL_WORKSPACES), 100 fShowingMenu(false) 101 { 102 desk_settings* settings = ((TBarApp*)be_app)->Settings(); 103 if (settings->alwaysOnTop) 104 SetFeel(B_FLOATING_ALL_WINDOW_FEEL); 105 106 fBarView = new TBarView(Bounds(), settings->vertical, settings->left, 107 settings->top, settings->state, settings->width); 108 AddChild(fBarView); 109 110 RemoveShortcut('H', B_COMMAND_KEY | B_CONTROL_KEY); 111 AddShortcut('F', B_COMMAND_KEY, new BMessage(kFindButton)); 112 } 113 114 115 void 116 TBarWindow::MenusBeginning() 117 { 118 BPath path; 119 entry_ref ref; 120 BEntry entry; 121 122 if (GetDeskbarSettingsDirectory(path) == B_OK 123 && path.Append(kDeskbarMenuEntriesFileName) == B_OK 124 && entry.SetTo(path.Path(), true) == B_OK 125 && entry.Exists() 126 && entry.GetRef(&ref) == B_OK) { 127 sDeskbarMenu->SetNavDir(&ref); 128 } else if (GetDeskbarDataDirectory(path) == B_OK 129 && path.Append(kDeskbarMenuEntriesFileName) == B_OK 130 && entry.SetTo(path.Path(), true) == B_OK 131 && entry.Exists() 132 && entry.GetRef(&ref) == B_OK) { 133 sDeskbarMenu->SetNavDir(&ref); 134 } else { 135 // this really should never happen 136 TRESPASS(); 137 return; 138 } 139 140 sDeskbarMenu->ResetTargets(); 141 142 fShowingMenu = true; 143 BWindow::MenusBeginning(); 144 } 145 146 147 void 148 TBarWindow::MenusEnded() 149 { 150 fShowingMenu = false; 151 BWindow::MenusEnded(); 152 153 if (sDeskbarMenu->LockLooper()) { 154 sDeskbarMenu->ForceRebuild(); 155 sDeskbarMenu->UnlockLooper(); 156 } 157 } 158 159 160 void 161 TBarWindow::MessageReceived(BMessage* message) 162 { 163 switch (message->what) { 164 case kFindButton: 165 { 166 BMessenger tracker(kTrackerSignature); 167 tracker.SendMessage(message); 168 break; 169 } 170 171 case kMsgLocation: 172 GetLocation(message); 173 break; 174 175 case kMsgSetLocation: 176 SetLocation(message); 177 break; 178 179 case kMsgIsExpanded: 180 IsExpanded(message); 181 break; 182 183 case kMsgExpand: 184 Expand(message); 185 break; 186 187 case kMsgGetItemInfo: 188 ItemInfo(message); 189 break; 190 191 case kMsgHasItem: 192 ItemExists(message); 193 break; 194 195 case kMsgCountItems: 196 CountItems(message); 197 break; 198 199 case kMsgAddAddOn: 200 case kMsgAddView: 201 AddItem(message); 202 break; 203 204 case kMsgRemoveItem: 205 RemoveItem(message); 206 break; 207 208 case 'iloc': 209 GetIconFrame(message); 210 break; 211 212 default: 213 BWindow::MessageReceived(message); 214 break; 215 } 216 } 217 218 219 void 220 TBarWindow::Minimize(bool minimize) 221 { 222 // Don't allow the Deskbar to be minimized 223 if (!minimize) 224 BWindow::Minimize(false); 225 } 226 227 228 void 229 TBarWindow::FrameResized(float width, float height) 230 { 231 if (!fBarView->Vertical()) 232 return BWindow::FrameResized(width, height); 233 234 bool setToHiddenSize = static_cast<TBarApp*>(be_app)->Settings()->autoHide 235 && fBarView->IsHidden() && !fBarView->DragRegion()->IsDragging(); 236 if (!setToHiddenSize) { 237 // constrain within limits 238 float newWidth; 239 if (width < gMinimumWindowWidth) 240 newWidth = gMinimumWindowWidth; 241 else if (width > gMaximumWindowWidth) 242 newWidth = gMaximumWindowWidth; 243 else 244 newWidth = width; 245 246 float oldWidth = static_cast<TBarApp*>(be_app)->Settings()->width; 247 248 // update width setting 249 static_cast<TBarApp*>(be_app)->Settings()->width = newWidth; 250 251 if (oldWidth != newWidth) { 252 fBarView->ResizeTo(width, fBarView->Bounds().Height()); 253 if (fBarView->Vertical() && fBarView->ExpandoState()) 254 fBarView->ExpandoMenuBar()->SetMaxContentWidth(width); 255 256 fBarView->UpdatePlacement(); 257 } 258 } 259 } 260 261 262 void 263 TBarWindow::SaveSettings() 264 { 265 fBarView->SaveSettings(); 266 } 267 268 269 bool 270 TBarWindow::QuitRequested() 271 { 272 be_app->PostMessage(B_QUIT_REQUESTED); 273 274 return BWindow::QuitRequested(); 275 } 276 277 278 void 279 TBarWindow::WorkspaceActivated(int32 workspace, bool active) 280 { 281 BWindow::WorkspaceActivated(workspace, active); 282 283 if (active && !(fBarView->ExpandoState() && fBarView->Vertical())) 284 fBarView->UpdatePlacement(); 285 else { 286 BRect screenFrame = (BScreen(fBarView->Window())).Frame(); 287 fBarView->SizeWindow(screenFrame); 288 fBarView->PositionWindow(screenFrame); 289 fBarView->Invalidate(); 290 } 291 } 292 293 294 void 295 TBarWindow::ScreenChanged(BRect size, color_space depth) 296 { 297 BWindow::ScreenChanged(size, depth); 298 299 fBarView->UpdatePlacement(); 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 BMenuBar* menuBar = fBarView->BarMenuBar(); 321 if (menuBar == NULL) 322 menuBar = KeyMenuBar(); 323 324 if (menuBar == NULL) 325 return; 326 327 BMenuBar_StartMenuBar_Hack(menuBar, 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 BMenuBar_StartMenuBar_Hack(KeyMenuBar(), 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::AddItem(BMessage* message) 548 { 549 DeskbarShelf shelf = B_DESKBAR_TRAY; 550 entry_ref ref; 551 int32 id = 999; 552 BMessage reply; 553 status_t err = B_ERROR; 554 555 BMessage* archivedView = new BMessage(); 556 ObjectDeleter<BMessage> deleter(archivedView); 557 if (message->FindMessage("view", archivedView) == B_OK) { 558 #if SHELF_AWARE 559 message->FindInt32("shelf", &shelf); 560 #endif 561 err = fBarView->AddItem(archivedView, shelf, &id); 562 if (err == B_OK) { 563 // Detach the deleter since AddReplicant is taking ownership 564 // on success. This should be changed on server side. 565 deleter.Detach(); 566 } 567 } else if (message->FindRef("addon", &ref) == B_OK) { 568 BEntry entry(&ref); 569 err = entry.InitCheck(); 570 if (err == B_OK) 571 err = fBarView->AddItem(&entry, shelf, &id); 572 } 573 574 if (err == B_OK) 575 reply.AddInt32("id", id); 576 else 577 reply.AddInt32("error", err); 578 579 message->SendReply(&reply); 580 } 581 582 583 void 584 TBarWindow::RemoveItem(BMessage* message) 585 { 586 int32 id; 587 const char* name; 588 589 // ids ought to be unique across all shelves, assuming, of course, 590 // that sometime in the future there may be more than one 591 #if SHELF_AWARE 592 if (message->FindInt32("shelf", (int32*)&shelf) == B_OK) { 593 if (message->FindString("name", &name) == B_OK) 594 fBarView->RemoveItem(name, shelf); 595 } else { 596 #endif 597 if (message->FindInt32("id", &id) == B_OK) { 598 fBarView->RemoveItem(id); 599 // remove the following two lines if and when the 600 // shelf option returns 601 } else if (message->FindString("name", &name) == B_OK) 602 fBarView->RemoveItem(name, B_DESKBAR_TRAY); 603 604 #if SHELF_AWARE 605 } 606 #endif 607 } 608 609 610 void 611 TBarWindow::GetIconFrame(BMessage* message) 612 { 613 BRect frame(0, 0, 0, 0); 614 615 const char* name; 616 int32 id; 617 if (message->FindInt32("id", &id) == B_OK) 618 frame = fBarView->IconFrame(id); 619 else if (message->FindString("name", &name) == B_OK) 620 frame = fBarView->IconFrame(name); 621 622 BMessage reply('rply'); 623 reply.AddRect("frame", frame); 624 message->SendReply(&reply); 625 } 626 627 628 bool 629 TBarWindow::IsShowingMenu() const 630 { 631 return fShowingMenu; 632 } 633 634 635 bool 636 TBarWindow::_IsFocusMessage(BMessage* message) 637 { 638 BMessage::Private messagePrivate(message); 639 if (!messagePrivate.UsePreferredTarget()) 640 return false; 641 642 bool feedFocus; 643 if (message->HasInt32("_token") 644 && (message->FindBool("_feed_focus", &feedFocus) != B_OK || !feedFocus)) 645 return false; 646 647 return true; 648 } 649