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 'gloc': 172 GetLocation(message); 173 break; 174 175 case 'sloc': 176 SetLocation(message); 177 break; 178 179 case 'gexp': 180 IsExpanded(message); 181 break; 182 183 case 'sexp': 184 Expand(message); 185 break; 186 187 case 'info': 188 ItemInfo(message); 189 break; 190 191 case 'exst': 192 ItemExists(message); 193 break; 194 195 case 'cwnt': 196 CountItems(message); 197 break; 198 199 case 'adon': 200 case 'icon': 201 AddItem(message); 202 break; 203 204 case 'remv': 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 // update width setting 247 static_cast<TBarApp*>(be_app)->Settings()->width = newWidth; 248 } 249 250 if (Lock()) { 251 fBarView->ResizeTo(width, fBarView->Bounds().Height()); 252 if (fBarView->Vertical() && fBarView->ExpandoState()) 253 fBarView->ExpandoMenuBar()->SetMaxContentWidth(width); 254 255 Unlock(); 256 } 257 } 258 259 260 void 261 TBarWindow::SaveSettings() 262 { 263 fBarView->SaveSettings(); 264 } 265 266 267 bool 268 TBarWindow::QuitRequested() 269 { 270 be_app->PostMessage(B_QUIT_REQUESTED); 271 272 return BWindow::QuitRequested(); 273 } 274 275 276 void 277 TBarWindow::WorkspaceActivated(int32 workspace, bool active) 278 { 279 BWindow::WorkspaceActivated(workspace, active); 280 281 if (active && !(fBarView->ExpandoState() && fBarView->Vertical())) 282 fBarView->UpdatePlacement(); 283 else { 284 BRect screenFrame = (BScreen(fBarView->Window())).Frame(); 285 fBarView->SizeWindow(screenFrame); 286 fBarView->PositionWindow(screenFrame); 287 fBarView->Invalidate(); 288 } 289 } 290 291 292 void 293 TBarWindow::ScreenChanged(BRect size, color_space depth) 294 { 295 BWindow::ScreenChanged(size, depth); 296 297 fBarView->UpdatePlacement(); 298 } 299 300 301 void 302 TBarWindow::SetDeskbarMenu(TDeskbarMenu* menu) 303 { 304 sDeskbarMenu = menu; 305 } 306 307 308 TDeskbarMenu* 309 TBarWindow::DeskbarMenu() 310 { 311 return sDeskbarMenu; 312 } 313 314 315 void 316 TBarWindow::ShowDeskbarMenu() 317 { 318 BMenuBar* menuBar = fBarView->BarMenuBar(); 319 if (menuBar == NULL) 320 menuBar = KeyMenuBar(); 321 322 if (menuBar == NULL) 323 return; 324 325 BMenuBar_StartMenuBar_Hack(menuBar, 0, true, true, NULL); 326 } 327 328 329 void 330 TBarWindow::ShowTeamMenu() 331 { 332 int32 index = 0; 333 if (fBarView->BarMenuBar() == NULL) 334 index = 2; 335 336 if (KeyMenuBar() == NULL) 337 return; 338 339 BMenuBar_StartMenuBar_Hack(KeyMenuBar(), index, true, true, NULL); 340 } 341 342 343 // determines the actual location of the window 344 345 deskbar_location 346 TBarWindow::DeskbarLocation() const 347 { 348 bool left = fBarView->Left(); 349 bool top = fBarView->Top(); 350 351 if (fBarView->AcrossTop()) 352 return B_DESKBAR_TOP; 353 354 if (fBarView->AcrossBottom()) 355 return B_DESKBAR_BOTTOM; 356 357 if (left && top) 358 return B_DESKBAR_LEFT_TOP; 359 360 if (!left && top) 361 return B_DESKBAR_RIGHT_TOP; 362 363 if (left && !top) 364 return B_DESKBAR_LEFT_BOTTOM; 365 366 return B_DESKBAR_RIGHT_BOTTOM; 367 } 368 369 370 void 371 TBarWindow::GetLocation(BMessage* message) 372 { 373 BMessage reply('rply'); 374 reply.AddInt32("location", (int32)DeskbarLocation()); 375 reply.AddBool("expanded", fBarView->ExpandoState()); 376 377 message->SendReply(&reply); 378 } 379 380 381 void 382 TBarWindow::SetDeskbarLocation(deskbar_location location, bool newExpandState) 383 { 384 // left top and right top are the only two that 385 // currently pay attention to expand, ignore for all others 386 387 bool left = false, top = true, vertical, expand; 388 389 switch (location) { 390 case B_DESKBAR_TOP: 391 left = true; 392 top = true; 393 vertical = false; 394 expand = true; 395 break; 396 397 case B_DESKBAR_BOTTOM: 398 left = true; 399 top = false; 400 vertical = false; 401 expand = true; 402 break; 403 404 case B_DESKBAR_LEFT_TOP: 405 left = true; 406 top = true; 407 vertical = true; 408 expand = newExpandState; 409 break; 410 411 case B_DESKBAR_RIGHT_TOP: 412 left = false; 413 top = true; 414 vertical = true; 415 expand = newExpandState; 416 break; 417 418 case B_DESKBAR_LEFT_BOTTOM: 419 left = true; 420 top = false; 421 vertical = true; 422 expand = false; 423 break; 424 425 case B_DESKBAR_RIGHT_BOTTOM: 426 left = false; 427 top = false; 428 vertical = true; 429 expand = false; 430 break; 431 432 default: 433 left = true; 434 top = true; 435 vertical = false; 436 expand = true; 437 break; 438 } 439 440 fBarView->ChangeState(expand, vertical, left, top); 441 } 442 443 444 void 445 TBarWindow::SetLocation(BMessage* message) 446 { 447 deskbar_location location; 448 bool expand; 449 if (message->FindInt32("location", (int32*)&location) == B_OK 450 && message->FindBool("expand", &expand) == B_OK) 451 SetDeskbarLocation(location, expand); 452 } 453 454 455 void 456 TBarWindow::IsExpanded(BMessage* message) 457 { 458 BMessage reply('rply'); 459 reply.AddBool("expanded", fBarView->ExpandoState()); 460 message->SendReply(&reply); 461 } 462 463 464 void 465 TBarWindow::Expand(BMessage* message) 466 { 467 bool expand; 468 if (message->FindBool("expand", &expand) == B_OK) { 469 bool vertical = fBarView->Vertical(); 470 bool left = fBarView->Left(); 471 bool top = fBarView->Top(); 472 fBarView->ChangeState(expand, vertical, left, top); 473 } 474 } 475 476 477 void 478 TBarWindow::ItemInfo(BMessage* message) 479 { 480 BMessage replyMsg; 481 const char* name; 482 int32 id; 483 DeskbarShelf shelf; 484 if (message->FindInt32("id", &id) == B_OK) { 485 if (fBarView->ItemInfo(id, &name, &shelf) == B_OK) { 486 replyMsg.AddString("name", name); 487 #if SHELF_AWARE 488 replyMsg.AddInt32("shelf", (int32)shelf); 489 #endif 490 } 491 } else if (message->FindString("name", &name) == B_OK) { 492 if (fBarView->ItemInfo(name, &id, &shelf) == B_OK) { 493 replyMsg.AddInt32("id", id); 494 #if SHELF_AWARE 495 replyMsg.AddInt32("shelf", (int32)shelf); 496 #endif 497 } 498 } 499 500 message->SendReply(&replyMsg); 501 } 502 503 504 void 505 TBarWindow::ItemExists(BMessage* message) 506 { 507 BMessage replyMsg; 508 const char* name; 509 int32 id; 510 DeskbarShelf shelf; 511 512 #if SHELF_AWARE 513 if (message->FindInt32("shelf", (int32*)&shelf) != B_OK) 514 #endif 515 shelf = B_DESKBAR_TRAY; 516 517 bool exists = false; 518 if (message->FindInt32("id", &id) == B_OK) 519 exists = fBarView->ItemExists(id, shelf); 520 else if (message->FindString("name", &name) == B_OK) 521 exists = fBarView->ItemExists(name, shelf); 522 523 replyMsg.AddBool("exists", exists); 524 message->SendReply(&replyMsg); 525 } 526 527 528 void 529 TBarWindow::CountItems(BMessage* message) 530 { 531 DeskbarShelf shelf; 532 533 #if SHELF_AWARE 534 if (message->FindInt32("shelf", (int32*)&shelf) != B_OK) 535 #endif 536 shelf = B_DESKBAR_TRAY; 537 538 BMessage reply('rply'); 539 reply.AddInt32("count", fBarView->CountItems(shelf)); 540 message->SendReply(&reply); 541 } 542 543 544 void 545 TBarWindow::AddItem(BMessage* message) 546 { 547 DeskbarShelf shelf = B_DESKBAR_TRAY; 548 entry_ref ref; 549 int32 id = 999; 550 BMessage reply; 551 status_t err = B_ERROR; 552 553 BMessage* archivedView = new BMessage(); 554 ObjectDeleter<BMessage> deleter(archivedView); 555 if (message->FindMessage("view", archivedView) == B_OK) { 556 #if SHELF_AWARE 557 message->FindInt32("shelf", &shelf); 558 #endif 559 err = fBarView->AddItem(archivedView, shelf, &id); 560 if (err == B_OK) { 561 // Detach the deleter since AddReplicant is taking ownership 562 // on success. This should be changed on server side. 563 deleter.Detach(); 564 } 565 } else if (message->FindRef("addon", &ref) == B_OK) { 566 BEntry entry(&ref); 567 err = entry.InitCheck(); 568 if (err == B_OK) 569 err = fBarView->AddItem(&entry, shelf, &id); 570 } 571 572 if (err == B_OK) 573 reply.AddInt32("id", id); 574 else 575 reply.AddInt32("error", err); 576 577 message->SendReply(&reply); 578 } 579 580 581 void 582 TBarWindow::RemoveItem(BMessage* message) 583 { 584 int32 id; 585 const char* name; 586 587 // ids ought to be unique across all shelves, assuming, of course, 588 // that sometime in the future there may be more than one 589 #if SHELF_AWARE 590 if (message->FindInt32("shelf", (int32*)&shelf) == B_OK) { 591 if (message->FindString("name", &name) == B_OK) 592 fBarView->RemoveItem(name, shelf); 593 } else { 594 #endif 595 if (message->FindInt32("id", &id) == B_OK) { 596 fBarView->RemoveItem(id); 597 // remove the following two lines if and when the 598 // shelf option returns 599 } else if (message->FindString("name", &name) == B_OK) 600 fBarView->RemoveItem(name, B_DESKBAR_TRAY); 601 602 #if SHELF_AWARE 603 } 604 #endif 605 } 606 607 608 void 609 TBarWindow::GetIconFrame(BMessage* message) 610 { 611 BRect frame(0, 0, 0, 0); 612 613 const char* name; 614 int32 id; 615 if (message->FindInt32("id", &id) == B_OK) 616 frame = fBarView->IconFrame(id); 617 else if (message->FindString("name", &name) == B_OK) 618 frame = fBarView->IconFrame(name); 619 620 BMessage reply('rply'); 621 reply.AddRect("frame", frame); 622 message->SendReply(&reply); 623 } 624 625 626 bool 627 TBarWindow::IsShowingMenu() const 628 { 629 return fShowingMenu; 630 } 631 632 633 bool 634 TBarWindow::_IsFocusMessage(BMessage* message) 635 { 636 BMessage::Private messagePrivate(message); 637 if (!messagePrivate.UsePreferredTarget()) 638 return false; 639 640 bool feedFocus; 641 if (message->HasInt32("_token") 642 && (message->FindBool("_feed_focus", &feedFocus) != B_OK || !feedFocus)) 643 return false; 644 645 return true; 646 } 647