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