1 /* 2 * Copyright 2002-2008, Haiku, Inc. 3 * Copyright 2002, François Revol, revol@free.fr. 4 * This file is distributed under the terms of the MIT License. 5 * 6 * Authors: 7 * François Revol, revol@free.fr 8 * Axel Dörfler, axeld@pinc-software.de 9 * Oliver "Madison" Kohl, 10 * Matt Madia 11 */ 12 13 14 #include <Alert.h> 15 #include <Application.h> 16 #include <Dragger.h> 17 #include <Entry.h> 18 #include <File.h> 19 #include <FindDirectory.h> 20 #include <MenuItem.h> 21 #include <Path.h> 22 #include <PopUpMenu.h> 23 #include <Roster.h> 24 #include <Screen.h> 25 #include <TextView.h> 26 #include <Window.h> 27 28 #include <ctype.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 33 #include <InterfacePrivate.h> 34 #include <ViewPrivate.h> 35 #include <WindowPrivate.h> 36 37 38 static const char* kSignature = "application/x-vnd.Be-WORK"; 39 static const char* kOldSettingFile = "Workspace_data"; 40 static const char* kSettingsFile = "Workspaces_settings"; 41 42 static const uint32 kMsgChangeCount = 'chWC'; 43 static const uint32 kMsgToggleTitle = 'tgTt'; 44 static const uint32 kMsgToggleBorder = 'tgBd'; 45 static const uint32 kMsgToggleAutoRaise = 'tgAR'; 46 static const uint32 kMsgToggleAlwaysOnTop = 'tgAT'; 47 48 static const float kScreenBorderOffset = 10.0; 49 50 51 class WorkspacesSettings { 52 public: 53 WorkspacesSettings(); 54 virtual ~WorkspacesSettings(); 55 56 BRect WindowFrame() const { return fWindowFrame; } 57 BRect ScreenFrame() const { return fScreenFrame; } 58 59 bool AutoRaising() const { return fAutoRaising; } 60 bool AlwaysOnTop() const { return fAlwaysOnTop; } 61 bool HasTitle() const { return fHasTitle; } 62 bool HasBorder() const { return fHasBorder; } 63 64 void UpdateFramesForScreen(BRect screenFrame); 65 void UpdateScreenFrame(); 66 67 void SetWindowFrame(BRect); 68 void SetAutoRaising(bool enable) { fAutoRaising = enable; } 69 void SetAlwaysOnTop(bool enable) { fAlwaysOnTop = enable; } 70 void SetHasTitle(bool enable) { fHasTitle = enable; } 71 void SetHasBorder(bool enable) { fHasBorder = enable; } 72 73 private: 74 status_t _Open(BFile& file, int mode); 75 76 BRect fWindowFrame; 77 BRect fScreenFrame; 78 bool fAutoRaising; 79 bool fAlwaysOnTop; 80 bool fHasTitle; 81 bool fHasBorder; 82 }; 83 84 class WorkspacesView : public BView { 85 public: 86 WorkspacesView(BRect frame); 87 WorkspacesView(BMessage* archive); 88 ~WorkspacesView(); 89 90 static WorkspacesView* Instantiate(BMessage* archive); 91 virtual status_t Archive(BMessage* archive, bool deep = true) const; 92 93 virtual void AttachedToWindow(); 94 virtual void DetachedFromWindow(); 95 virtual void FrameMoved(BPoint newPosition); 96 virtual void FrameResized(float newWidth, float newHeight); 97 virtual void MessageReceived(BMessage* message); 98 virtual void MouseMoved(BPoint where, uint32 transit, 99 const BMessage* dragMessage); 100 virtual void MouseDown(BPoint where); 101 102 private: 103 void _AboutRequested(); 104 105 void _UpdateParentClipping(); 106 void _ExcludeFromParentClipping(); 107 void _CleanupParentClipping(); 108 109 BView* fParentWhichDrawsOnChildren; 110 BRect fCurrentFrame; 111 }; 112 113 class WorkspacesWindow : public BWindow { 114 public: 115 WorkspacesWindow(WorkspacesSettings *settings); 116 virtual ~WorkspacesWindow(); 117 118 virtual void ScreenChanged(BRect frame, color_space mode); 119 virtual void FrameMoved(BPoint origin); 120 virtual void FrameResized(float width, float height); 121 virtual void Zoom(BPoint origin, float width, float height); 122 123 virtual void MessageReceived(BMessage *msg); 124 virtual bool QuitRequested(); 125 126 void SetAutoRaise(bool enable); 127 bool IsAutoRaising() const { return fAutoRaising; } 128 129 private: 130 WorkspacesSettings *fSettings; 131 bool fAutoRaising; 132 }; 133 134 class WorkspacesApp : public BApplication { 135 public: 136 WorkspacesApp(); 137 virtual ~WorkspacesApp(); 138 139 virtual void AboutRequested(); 140 virtual void ArgvReceived(int32 argc, char **argv); 141 virtual void ReadyToRun(); 142 143 void Usage(const char *programName); 144 145 private: 146 WorkspacesWindow* fWindow; 147 }; 148 149 150 WorkspacesSettings::WorkspacesSettings() 151 : 152 fAutoRaising(false), 153 fAlwaysOnTop(false), 154 fHasTitle(true), 155 fHasBorder(true) 156 { 157 UpdateScreenFrame(); 158 159 bool loaded = false; 160 BScreen screen; 161 162 BFile file; 163 if (_Open(file, B_READ_ONLY) == B_OK) { 164 BMessage settings; 165 if (settings.Unflatten(&file) == B_OK) { 166 if (settings.FindRect("window", &fWindowFrame) == B_OK 167 && settings.FindRect("screen", &fScreenFrame) == B_OK) 168 loaded = true; 169 170 settings.FindBool("auto-raise", &fAutoRaising); 171 settings.FindBool("always on top", &fAlwaysOnTop); 172 173 if (settings.FindBool("has title", &fHasTitle) != B_OK) 174 fHasTitle = true; 175 if (settings.FindBool("has border", &fHasBorder) != B_OK) 176 fHasBorder = true; 177 } 178 } else { 179 // try reading BeOS compatible settings 180 BPath path; 181 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) { 182 path.Append(kOldSettingFile); 183 BFile file(path.Path(), B_READ_ONLY); 184 if (file.InitCheck() == B_OK 185 && file.Read(&fWindowFrame, sizeof(BRect)) == sizeof(BRect)) { 186 // we now also store the frame of the screen to know 187 // in which context the window frame has been chosen 188 BRect frame; 189 if (file.Read(&frame, sizeof(BRect)) == sizeof(BRect)) 190 fScreenFrame = frame; 191 else 192 fScreenFrame = screen.Frame(); 193 194 loaded = true; 195 } 196 } 197 } 198 199 if (loaded) { 200 // if the current screen frame is different from the one 201 // just loaded, we need to alter the window frame accordingly 202 if (fScreenFrame != screen.Frame()) 203 UpdateFramesForScreen(screen.Frame()); 204 } 205 206 if (!loaded 207 || !(screen.Frame().right + 5 >= fWindowFrame.right 208 && screen.Frame().bottom + 5 >= fWindowFrame.bottom 209 && screen.Frame().left - 5 <= fWindowFrame.left 210 && screen.Frame().top - 5 <= fWindowFrame.top)) { 211 // set to some usable defaults 212 float screenWidth = screen.Frame().Width(); 213 float screenHeight = screen.Frame().Height(); 214 float aspectRatio = screenWidth / screenHeight; 215 216 uint32 columns, rows; 217 BPrivate::get_workspaces_layout(&columns, &rows); 218 219 // default size of ~1/10 of screen width 220 float workspaceWidth = screenWidth / 10; 221 float workspaceHeight = workspaceWidth / aspectRatio; 222 223 float width = floor(workspaceWidth * columns); 224 float height = floor(workspaceHeight * rows); 225 226 float tabHeight = 20; 227 // TODO: find tabHeight without being a window 228 229 // shrink to fit more 230 while (width + 2 * kScreenBorderOffset > screenWidth 231 || height + 2 * kScreenBorderOffset + tabHeight > screenHeight) { 232 width = floor(0.95 * width); 233 height = floor(0.95 * height); 234 } 235 236 fWindowFrame = fScreenFrame; 237 fWindowFrame.OffsetBy(-kScreenBorderOffset, -kScreenBorderOffset); 238 fWindowFrame.left = fWindowFrame.right - width; 239 fWindowFrame.top = fWindowFrame.bottom - height; 240 } 241 } 242 243 244 WorkspacesSettings::~WorkspacesSettings() 245 { 246 // write settings file 247 BFile file; 248 if (_Open(file, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE) != B_OK) 249 return; 250 251 BMessage settings('wksp'); 252 253 if (settings.AddRect("window", fWindowFrame) == B_OK 254 && settings.AddRect("screen", fScreenFrame) == B_OK 255 && settings.AddBool("auto-raise", fAutoRaising) == B_OK 256 && settings.AddBool("always on top", fAlwaysOnTop) == B_OK 257 && settings.AddBool("has title", fHasTitle) == B_OK 258 && settings.AddBool("has border", fHasBorder) == B_OK) 259 settings.Flatten(&file); 260 } 261 262 263 status_t 264 WorkspacesSettings::_Open(BFile& file, int mode) 265 { 266 BPath path; 267 status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); 268 if (status != B_OK) 269 status = find_directory(B_COMMON_SETTINGS_DIRECTORY, &path); 270 if (status != B_OK) 271 return status; 272 273 path.Append(kSettingsFile); 274 275 status = file.SetTo(path.Path(), mode); 276 if (mode == B_READ_ONLY && status == B_ENTRY_NOT_FOUND) { 277 if (find_directory(B_COMMON_SETTINGS_DIRECTORY, &path) == B_OK) { 278 path.Append(kSettingsFile); 279 status = file.SetTo(path.Path(), mode); 280 } 281 } 282 283 return status; 284 } 285 286 287 void 288 WorkspacesSettings::UpdateFramesForScreen(BRect newScreenFrame) 289 { 290 // don't change the position if the screen frame hasn't changed 291 if (newScreenFrame == fScreenFrame) 292 return; 293 294 // adjust horizontal position 295 if (fWindowFrame.right > fScreenFrame.right / 2) { 296 fWindowFrame.OffsetTo(newScreenFrame.right 297 - (fScreenFrame.right - fWindowFrame.left), fWindowFrame.top); 298 } 299 300 // adjust vertical position 301 if (fWindowFrame.bottom > fScreenFrame.bottom / 2) { 302 fWindowFrame.OffsetTo(fWindowFrame.left, 303 newScreenFrame.bottom - (fScreenFrame.bottom - fWindowFrame.top)); 304 } 305 306 fScreenFrame = newScreenFrame; 307 } 308 309 310 void 311 WorkspacesSettings::UpdateScreenFrame() 312 { 313 BScreen screen; 314 fScreenFrame = screen.Frame(); 315 } 316 317 318 void 319 WorkspacesSettings::SetWindowFrame(BRect frame) 320 { 321 fWindowFrame = frame; 322 } 323 324 325 // #pragma mark - 326 327 328 WorkspacesView::WorkspacesView(BRect frame) 329 : 330 BView(frame, "workspaces", B_FOLLOW_ALL, 331 kWorkspacesViewFlag | B_FRAME_EVENTS), 332 fParentWhichDrawsOnChildren(NULL), 333 fCurrentFrame(frame) 334 { 335 frame.OffsetTo(B_ORIGIN); 336 frame.top = frame.bottom - 7; 337 frame.left = frame.right - 7; 338 BDragger* dragger = new BDragger(frame, this, 339 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); 340 AddChild(dragger); 341 } 342 343 344 WorkspacesView::WorkspacesView(BMessage* archive) 345 : 346 BView(archive), 347 fParentWhichDrawsOnChildren(NULL), 348 fCurrentFrame(Frame()) 349 { 350 // Just in case we are instantiated from an older archive... 351 SetFlags(Flags() | B_FRAME_EVENTS); 352 // Make sure the auto-raise feature didn't leave any artifacts - this is 353 // not a good idea to keep enabled for a replicant. 354 if (EventMask() != 0) 355 SetEventMask(0); 356 } 357 358 359 WorkspacesView::~WorkspacesView() 360 { 361 } 362 363 364 /*static*/ WorkspacesView* 365 WorkspacesView::Instantiate(BMessage* archive) 366 { 367 if (!validate_instantiation(archive, "WorkspacesView")) 368 return NULL; 369 370 return new WorkspacesView(archive); 371 } 372 373 374 status_t 375 WorkspacesView::Archive(BMessage* archive, bool deep) const 376 { 377 status_t status = BView::Archive(archive, deep); 378 if (status == B_OK) 379 status = archive->AddString("add_on", kSignature); 380 if (status == B_OK) 381 status = archive->AddString("class", "WorkspacesView"); 382 383 return status; 384 } 385 386 387 void 388 WorkspacesView::_AboutRequested() 389 { 390 BAlert *alert = new BAlert("about", "Workspaces\n" 391 "written by François Revol, Axel Dörfler, and Matt Madia.\n\n" 392 "Copyright 2002-2008, Haiku.\n\n" 393 "Send windows behind using the Option key. " 394 "Move windows to front using the Control key.\n", "Ok"); 395 BTextView *view = alert->TextView(); 396 BFont font; 397 398 view->SetStylable(true); 399 400 view->GetFont(&font); 401 font.SetSize(18); 402 font.SetFace(B_BOLD_FACE); 403 view->SetFontAndColor(0, 10, &font); 404 405 alert->Go(); 406 } 407 408 409 void 410 WorkspacesView::AttachedToWindow() 411 { 412 BView* parent = Parent(); 413 if (parent != NULL && (parent->Flags() & B_DRAW_ON_CHILDREN) != 0) { 414 fParentWhichDrawsOnChildren = parent; 415 _ExcludeFromParentClipping(); 416 } 417 } 418 419 420 void 421 WorkspacesView::DetachedFromWindow() 422 { 423 if (fParentWhichDrawsOnChildren != NULL) 424 _CleanupParentClipping(); 425 } 426 427 428 void 429 WorkspacesView::FrameMoved(BPoint newPosition) 430 { 431 _UpdateParentClipping(); 432 } 433 434 435 void 436 WorkspacesView::FrameResized(float newWidth, float newHeight) 437 { 438 _UpdateParentClipping(); 439 } 440 441 442 void 443 WorkspacesView::_UpdateParentClipping() 444 { 445 if (fParentWhichDrawsOnChildren != NULL) { 446 _CleanupParentClipping(); 447 _ExcludeFromParentClipping(); 448 fParentWhichDrawsOnChildren->Invalidate(fCurrentFrame); 449 fCurrentFrame = Frame(); 450 } 451 } 452 453 454 void 455 WorkspacesView::_ExcludeFromParentClipping() 456 { 457 // Prevent the parent view to draw over us. Do so in a way that allows 458 // restoring the parent to the previous state. 459 fParentWhichDrawsOnChildren->PushState(); 460 461 BRegion clipping(fParentWhichDrawsOnChildren->Bounds()); 462 clipping.Exclude(Frame()); 463 fParentWhichDrawsOnChildren->ConstrainClippingRegion(&clipping); 464 } 465 466 467 void 468 WorkspacesView::_CleanupParentClipping() 469 { 470 // Restore the previous parent state. NOTE: This relies on views 471 // being detached in exactly the opposite order as them being 472 // attached. Otherwise we would mess up states if a sibbling view did 473 // the same thing we did in AttachedToWindow()... 474 fParentWhichDrawsOnChildren->PopState(); 475 } 476 477 478 void 479 WorkspacesView::MessageReceived(BMessage* message) 480 { 481 switch (message->what) { 482 case B_ABOUT_REQUESTED: 483 _AboutRequested(); 484 break; 485 486 case kMsgChangeCount: 487 be_roster->Launch("application/x-vnd.Be-SCRN"); 488 break; 489 490 default: 491 BView::MessageReceived(message); 492 break; 493 } 494 } 495 496 497 void 498 WorkspacesView::MouseMoved(BPoint where, uint32 transit, 499 const BMessage* dragMessage) 500 { 501 WorkspacesWindow* window = dynamic_cast<WorkspacesWindow*>(Window()); 502 if (window == NULL || !window->IsAutoRaising()) 503 return; 504 505 // Auto-Raise 506 507 where = ConvertToScreen(where); 508 BScreen screen(window); 509 BRect frame = screen.Frame(); 510 if (where.x == frame.left || where.x == frame.right 511 || where.y == frame.top || where.y == frame.bottom) { 512 // cursor is on screen edge 513 if (window->Frame().Contains(where)) 514 window->Activate(); 515 } 516 } 517 518 519 void 520 WorkspacesView::MouseDown(BPoint where) 521 { 522 // With enabled auto-raise feature, we'll get mouse messages we don't 523 // want to handle here. 524 if (!Bounds().Contains(where)) 525 return; 526 527 int32 buttons = 0; 528 if (Window() != NULL && Window()->CurrentMessage() != NULL) 529 Window()->CurrentMessage()->FindInt32("buttons", &buttons); 530 531 if ((buttons & B_SECONDARY_MOUSE_BUTTON) == 0) 532 return; 533 534 // open context menu 535 536 BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING, false, false); 537 menu->SetFont(be_plain_font); 538 539 // TODO: alternatively change the count here directly? 540 BMenuItem* changeItem = new BMenuItem("Change Workspace Count" 541 B_UTF8_ELLIPSIS, new BMessage(kMsgChangeCount)); 542 menu->AddItem(changeItem); 543 544 WorkspacesWindow* window = dynamic_cast<WorkspacesWindow*>(Window()); 545 if (window != NULL) { 546 BMenuItem* item; 547 548 menu->AddSeparatorItem(); 549 menu->AddItem(item = new BMenuItem("Show Window Title", 550 new BMessage(kMsgToggleTitle))); 551 if (window->Look() == B_TITLED_WINDOW_LOOK) 552 item->SetMarked(true); 553 menu->AddItem(item = new BMenuItem("Show Window Border", 554 new BMessage(kMsgToggleBorder))); 555 if (window->Look() == B_TITLED_WINDOW_LOOK 556 || window->Look() == B_MODAL_WINDOW_LOOK) 557 item->SetMarked(true); 558 559 menu->AddSeparatorItem(); 560 menu->AddItem(item = new BMenuItem("Always On Top", 561 new BMessage(kMsgToggleAlwaysOnTop))); 562 if (window->Feel() == B_FLOATING_ALL_WINDOW_FEEL) 563 item->SetMarked(true); 564 menu->AddItem(item = new BMenuItem("Auto Raise", 565 new BMessage(kMsgToggleAutoRaise))); 566 if (window->IsAutoRaising()) 567 item->SetMarked(true); 568 569 menu->AddSeparatorItem(); 570 menu->AddItem(new BMenuItem("About" B_UTF8_ELLIPSIS, 571 new BMessage(B_ABOUT_REQUESTED))); 572 menu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED))); 573 menu->SetTargetForItems(window); 574 } 575 576 changeItem->SetTarget(this); 577 ConvertToScreen(&where); 578 menu->Go(where, true, true, true); 579 } 580 581 582 // #pragma mark - 583 584 585 WorkspacesWindow::WorkspacesWindow(WorkspacesSettings *settings) 586 : BWindow(settings->WindowFrame(), "Workspaces", B_TITLED_WINDOW_LOOK, 587 B_NORMAL_WINDOW_FEEL, B_AVOID_FRONT | B_WILL_ACCEPT_FIRST_CLICK, 588 B_ALL_WORKSPACES), 589 fSettings(settings), 590 fAutoRaising(false) 591 { 592 AddChild(new WorkspacesView(Bounds())); 593 594 if (!fSettings->HasBorder()) 595 SetLook(B_NO_BORDER_WINDOW_LOOK); 596 else if (!fSettings->HasTitle()) 597 SetLook(B_MODAL_WINDOW_LOOK); 598 599 if (fSettings->AlwaysOnTop()) 600 SetFeel(B_FLOATING_ALL_WINDOW_FEEL); 601 else 602 SetAutoRaise(fSettings->AutoRaising()); 603 } 604 605 606 WorkspacesWindow::~WorkspacesWindow() 607 { 608 delete fSettings; 609 } 610 611 612 void 613 WorkspacesWindow::ScreenChanged(BRect rect, color_space mode) 614 { 615 fSettings->UpdateFramesForScreen(rect); 616 MoveTo(fSettings->WindowFrame().LeftTop()); 617 } 618 619 620 void 621 WorkspacesWindow::FrameMoved(BPoint origin) 622 { 623 fSettings->SetWindowFrame(Frame()); 624 } 625 626 627 void 628 WorkspacesWindow::FrameResized(float width, float height) 629 { 630 if (!modifiers() & B_SHIFT_KEY) { 631 BWindow::FrameResized(width, height); 632 return; 633 } 634 635 uint32 columns, rows; 636 BPrivate::get_workspaces_layout(&columns, &rows); 637 638 BScreen screen; 639 float screenWidth = screen.Frame().Width(); 640 float screenHeight = screen.Frame().Height(); 641 642 float windowAspectRatio 643 = (columns * screenWidth) / (rows * screenHeight); 644 645 float newHeight = width / windowAspectRatio; 646 647 if (height != newHeight) 648 ResizeTo(width, newHeight); 649 650 fSettings->SetWindowFrame(Frame()); 651 } 652 653 654 void 655 WorkspacesWindow::Zoom(BPoint origin, float width, float height) 656 { 657 BScreen screen; 658 float screenWidth = screen.Frame().Width(); 659 float screenHeight = screen.Frame().Height(); 660 float aspectRatio = screenWidth / screenHeight; 661 662 uint32 columns, rows; 663 BPrivate::get_workspaces_layout(&columns, &rows); 664 665 float workspaceWidth = screenWidth / 10; 666 float workspaceHeight = workspaceWidth / aspectRatio; 667 668 width = floor(workspaceWidth * columns); 669 height = floor(workspaceHeight * rows); 670 671 float tabHeight = Frame().top - DecoratorFrame().top; 672 673 while (width + 2 * kScreenBorderOffset > screenWidth 674 || height + 2 * kScreenBorderOffset + tabHeight > screenHeight) { 675 width = floor(0.95 * width); 676 height = floor(0.95 * height); 677 } 678 679 ResizeTo(width, height); 680 681 origin = screen.Frame().RightBottom(); 682 origin.x -= kScreenBorderOffset + width; 683 origin.y -= kScreenBorderOffset + height; 684 685 MoveTo(origin); 686 } 687 688 689 void 690 WorkspacesWindow::MessageReceived(BMessage *message) 691 { 692 switch (message->what) { 693 case B_SIMPLE_DATA: 694 { 695 // Drop from Tracker 696 entry_ref ref; 697 for (int i = 0; (message->FindRef("refs", i, &ref) == B_OK); i++) 698 be_roster->Launch(&ref); 699 break; 700 } 701 702 case B_ABOUT_REQUESTED: 703 PostMessage(message, ChildAt(0)); 704 break; 705 706 case kMsgToggleBorder: 707 { 708 bool enable = false; 709 if (Look() == B_NO_BORDER_WINDOW_LOOK) 710 enable = true; 711 712 if (enable) 713 if (fSettings->HasTitle()) 714 SetLook(B_TITLED_WINDOW_LOOK); 715 else 716 SetLook(B_MODAL_WINDOW_LOOK); 717 else 718 SetLook(B_NO_BORDER_WINDOW_LOOK); 719 720 fSettings->SetHasBorder(enable); 721 break; 722 } 723 724 case kMsgToggleTitle: 725 { 726 bool enable = false; 727 if (Look() == B_MODAL_WINDOW_LOOK 728 || Look() == B_NO_BORDER_WINDOW_LOOK) 729 enable = true; 730 731 if (enable) 732 SetLook(B_TITLED_WINDOW_LOOK); 733 else 734 SetLook(B_MODAL_WINDOW_LOOK); 735 736 // No matter what the setting for title, we must force the border on 737 fSettings->SetHasBorder(true); 738 fSettings->SetHasTitle(enable); 739 break; 740 } 741 742 case kMsgToggleAutoRaise: 743 SetAutoRaise(!IsAutoRaising()); 744 SetFeel(B_NORMAL_WINDOW_FEEL); 745 break; 746 747 case kMsgToggleAlwaysOnTop: 748 { 749 bool enable = false; 750 if (Feel() != B_FLOATING_ALL_WINDOW_FEEL) 751 enable = true; 752 753 if (enable) 754 SetFeel(B_FLOATING_ALL_WINDOW_FEEL); 755 else 756 SetFeel(B_NORMAL_WINDOW_FEEL); 757 758 fSettings->SetAlwaysOnTop(enable); 759 break; 760 } 761 762 default: 763 BWindow::MessageReceived(message); 764 break; 765 } 766 } 767 768 769 bool 770 WorkspacesWindow::QuitRequested() 771 { 772 be_app->PostMessage(B_QUIT_REQUESTED); 773 return true; 774 } 775 776 777 void 778 WorkspacesWindow::SetAutoRaise(bool enable) 779 { 780 if (enable == fAutoRaising) 781 return; 782 783 fAutoRaising = enable; 784 fSettings->SetAutoRaising(enable); 785 786 if (enable) 787 ChildAt(0)->SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY); 788 else 789 ChildAt(0)->SetEventMask(0); 790 } 791 792 793 // #pragma mark - 794 795 796 WorkspacesApp::WorkspacesApp() 797 : BApplication(kSignature) 798 { 799 fWindow = new WorkspacesWindow(new WorkspacesSettings()); 800 } 801 802 803 WorkspacesApp::~WorkspacesApp() 804 { 805 } 806 807 808 void 809 WorkspacesApp::AboutRequested() 810 { 811 fWindow->PostMessage(B_ABOUT_REQUESTED); 812 } 813 814 815 void 816 WorkspacesApp::Usage(const char *programName) 817 { 818 printf("Usage: %s [options] [workspace]\n" 819 "where \"options\" is one of:\n" 820 " --notitle\t\ttitle bar removed. border and resize kept.\n" 821 " --noborder\t\ttitle, border, and resize removed.\n" 822 " --avoidfocus\t\tprevents the window from being the target of keyboard events.\n" 823 " --alwaysontop\t\tkeeps window on top\n" 824 " --notmovable\t\twindow can't be moved around\n" 825 " --autoraise\t\tauto-raise the workspace window when it's at the screen corner\n" 826 " --help\t\tdisplay this help and exit\n" 827 "and \"workspace\" is the number of the Workspace to which to switch (0-31)\n", 828 programName); 829 830 // quit only if we aren't running already 831 if (IsLaunching()) 832 Quit(); 833 } 834 835 836 void 837 WorkspacesApp::ArgvReceived(int32 argc, char **argv) 838 { 839 for (int i = 1; i < argc; i++) { 840 if (argv[i][0] == '-' && argv[i][1] == '-') { 841 // evaluate --arguments 842 if (!strcmp(argv[i], "--notitle")) 843 fWindow->SetLook(B_MODAL_WINDOW_LOOK); 844 else if (!strcmp(argv[i], "--noborder")) 845 fWindow->SetLook(B_NO_BORDER_WINDOW_LOOK); 846 else if (!strcmp(argv[i], "--avoidfocus")) 847 fWindow->SetFlags(fWindow->Flags() | B_AVOID_FOCUS); 848 else if (!strcmp(argv[i], "--notmovable")) 849 fWindow->SetFlags(fWindow->Flags() | B_NOT_MOVABLE); 850 else if (!strcmp(argv[i], "--alwaysontop")) 851 fWindow->SetFeel(B_FLOATING_ALL_WINDOW_FEEL); 852 else if (!strcmp(argv[i], "--autoraise")) 853 fWindow->SetAutoRaise(true); 854 else { 855 const char *programName = strrchr(argv[0], '/'); 856 programName = programName ? programName + 1 : argv[0]; 857 858 Usage(programName); 859 } 860 } else if (isdigit(*argv[i])) { 861 // check for a numeric arg, if not already given 862 activate_workspace(atoi(argv[i])); 863 864 // if the app is running, don't quit 865 // but if it isn't, cancel the complete run, so it doesn't 866 // open any window 867 if (IsLaunching()) 868 Quit(); 869 } else if (!strcmp(argv[i], "-")) { 870 activate_workspace(current_workspace() - 1); 871 872 if (IsLaunching()) 873 Quit(); 874 } else if (!strcmp(argv[i], "+")) { 875 activate_workspace(current_workspace() + 1); 876 877 if (IsLaunching()) 878 Quit(); 879 } else { 880 // some unknown arguments were specified 881 fprintf(stderr, "Invalid argument: %s\n", argv[i]); 882 883 if (IsLaunching()) 884 Quit(); 885 } 886 } 887 } 888 889 890 void 891 WorkspacesApp::ReadyToRun() 892 { 893 fWindow->Show(); 894 } 895 896 897 // #pragma mark - 898 899 900 int 901 main(int argc, char **argv) 902 { 903 WorkspacesApp app; 904 app.Run(); 905 906 return 0; 907 } 908