2 * Copyright 2002-2016, Haiku, Inc. All rights reserved.
3 * Copyright 2002, François Revol, revol@free.fr.
4 * This file is distributed under the terms of the MIT License.
7 * François Revol, revol@free.fr
8 * Axel Dörfler, axeld@pinc-software.de
9 * Oliver "Madison" Kohl,
11 * Daniel Devine, devine@ddevnet.net
15 #include <AboutWindow.h>
16 #include <Application.h>
22 #include <FindDirectory.h>
26 #include <PopUpMenu.h>
37 #include <InterfacePrivate.h>
38 #include <ViewPrivate.h>
39 #include <WindowPrivate.h>
41 #undef B_TRANSLATION_CONTEXT
42 #define B_TRANSLATION_CONTEXT "Workspaces"
45 static const char* kDeskbarItemName
= "workspaces";
46 static const char* kSignature
= "application/x-vnd.Be-WORK";
47 static const char* kDeskbarSignature
= "application/x-vnd.Be-TSKB";
48 static const char* kScreenPrefletSignature
= "application/x-vnd.Haiku-Screen";
49 static const char* kOldSettingFile
= "Workspace_data";
50 static const char* kSettingsFile
= "Workspaces_settings";
52 static const uint32 kMsgChangeCount
= 'chWC';
53 static const uint32 kMsgToggleTitle
= 'tgTt';
54 static const uint32 kMsgToggleBorder
= 'tgBd';
55 static const uint32 kMsgToggleAutoRaise
= 'tgAR';
56 static const uint32 kMsgToggleAlwaysOnTop
= 'tgAT';
57 static const uint32 kMsgToggleLiveInDeskbar
= 'tgDb';
58 static const uint32 kMsgToggleSwitchOnWheel
= 'tgWh';
61 extern "C" _EXPORT BView
* instantiate_deskbar_item();
65 OpenSettingsFile(BFile
& file
, int mode
)
68 status_t status
= find_directory(B_USER_SETTINGS_DIRECTORY
, &path
);
70 status
= find_directory(B_SYSTEM_SETTINGS_DIRECTORY
, &path
);
74 status
= path
.Append(kSettingsFile
);
78 status
= file
.SetTo(path
.Path(), mode
);
79 if (mode
== B_READ_ONLY
&& status
== B_ENTRY_NOT_FOUND
) {
80 if (find_directory(B_SYSTEM_SETTINGS_DIRECTORY
, &path
) == B_OK
81 && path
.Append(kSettingsFile
) == B_OK
) {
82 status
= file
.SetTo(path
.Path(), mode
);
90 class WorkspacesSettings
{
93 virtual ~WorkspacesSettings();
95 BRect
WindowFrame() const { return fWindowFrame
; }
96 BRect
ScreenFrame() const { return fScreenFrame
; }
98 bool AutoRaising() const { return fAutoRaising
; }
99 bool AlwaysOnTop() const { return fAlwaysOnTop
; }
100 bool HasTitle() const { return fHasTitle
; }
101 bool HasBorder() const { return fHasBorder
; }
102 bool SettingsLoaded() const { return fLoaded
; }
104 void UpdateFramesForScreen(BRect screenFrame
);
105 void UpdateScreenFrame();
107 void SetWindowFrame(BRect
);
108 void SetAutoRaising(bool enable
) { fAutoRaising
= enable
; }
109 void SetAlwaysOnTop(bool enable
) { fAlwaysOnTop
= enable
; }
110 void SetHasTitle(bool enable
) { fHasTitle
= enable
; }
111 void SetHasBorder(bool enable
) { fHasBorder
= enable
; }
123 class WorkspacesView
: public BView
{
125 WorkspacesView(BRect frame
, bool showDragger
);
126 WorkspacesView(BMessage
* archive
);
129 static WorkspacesView
* Instantiate(BMessage
* archive
);
130 virtual status_t
Archive(BMessage
* archive
, bool deep
= true) const;
132 virtual void AttachedToWindow();
133 virtual void DetachedFromWindow();
134 virtual void FrameMoved(BPoint newPosition
);
135 virtual void FrameResized(float newWidth
, float newHeight
);
136 virtual void MessageReceived(BMessage
* message
);
137 virtual void MouseMoved(BPoint where
, uint32 transit
,
138 const BMessage
* dragMessage
);
139 virtual void MouseDown(BPoint where
);
141 bool SwitchOnWheel() const { return fSwitchOnWheel
; }
142 void SetSwitchOnWheel(bool enable
);
145 void _AboutRequested();
147 void _UpdateParentClipping();
148 void _ExcludeFromParentClipping();
149 void _CleanupParentClipping();
151 friend class WorkspacesWindow
;
153 void _LoadSettings();
154 void _SaveSettings();
156 BView
* fParentWhichDrawsOnChildren
;
161 class WorkspacesWindow
: public BWindow
{
163 WorkspacesWindow(WorkspacesSettings
*settings
);
164 virtual ~WorkspacesWindow();
166 virtual void ScreenChanged(BRect frame
, color_space mode
);
167 virtual void FrameMoved(BPoint origin
);
168 virtual void FrameResized(float width
, float height
);
169 virtual void Zoom(BPoint origin
, float width
, float height
);
171 virtual void MessageReceived(BMessage
*msg
);
172 virtual bool QuitRequested();
174 void SetAutoRaise(bool enable
);
175 bool IsAutoRaising() const { return fSettings
->AutoRaising(); }
177 float GetTabHeight() { return fSettings
->HasTitle() ? fTabHeight
: 0; }
178 float GetBorderWidth() { return fBorderWidth
; }
179 float GetScreenBorderOffset() { return 2.0 * fBorderWidth
; }
182 WorkspacesSettings
*fSettings
;
183 WorkspacesView
*fWorkspacesView
;
188 class WorkspacesApp
: public BApplication
{
191 virtual ~WorkspacesApp();
193 virtual void AboutRequested();
194 virtual void ArgvReceived(int32 argc
, char **argv
);
195 virtual void ReadyToRun();
197 void Usage(const char *programName
);
200 WorkspacesWindow
* fWindow
;
204 // #pragma mark - WorkspacesSettings
207 WorkspacesSettings::WorkspacesSettings()
220 if (OpenSettingsFile(file
, B_READ_ONLY
) == B_OK
) {
222 if (settings
.Unflatten(&file
) == B_OK
) {
223 fLoaded
= settings
.FindRect("window", &fWindowFrame
) == B_OK
224 && settings
.FindRect("screen", &fScreenFrame
) == B_OK
;
225 settings
.FindBool("auto-raise", &fAutoRaising
);
226 settings
.FindBool("always on top", &fAlwaysOnTop
);
227 if (settings
.FindBool("has title", &fHasTitle
) != B_OK
)
229 if (settings
.FindBool("has border", &fHasBorder
) != B_OK
)
233 // try reading BeOS compatible settings
235 if (find_directory(B_USER_SETTINGS_DIRECTORY
, &path
) == B_OK
) {
236 path
.Append(kOldSettingFile
);
237 BFile
file(path
.Path(), B_READ_ONLY
);
238 if (file
.InitCheck() == B_OK
239 && file
.Read(&fWindowFrame
, sizeof(BRect
)) == sizeof(BRect
)) {
240 // we now also store the frame of the screen to know
241 // in which context the window frame has been chosen
243 if (file
.Read(&frame
, sizeof(BRect
)) == sizeof(BRect
))
244 fScreenFrame
= frame
;
246 fScreenFrame
= screen
.Frame();
254 // if the current screen frame is different from the one
255 // just loaded, we need to alter the window frame accordingly
256 if (fScreenFrame
!= screen
.Frame())
257 UpdateFramesForScreen(screen
.Frame());
262 WorkspacesSettings::~WorkspacesSettings()
265 if (OpenSettingsFile(file
, B_WRITE_ONLY
| B_ERASE_FILE
| B_CREATE_FILE
)
270 // switch on wheel saved by view later on
272 BMessage
settings('wksp');
273 if (settings
.AddRect("window", fWindowFrame
) == B_OK
274 && settings
.AddRect("screen", fScreenFrame
) == B_OK
275 && settings
.AddBool("auto-raise", fAutoRaising
) == B_OK
276 && settings
.AddBool("always on top", fAlwaysOnTop
) == B_OK
277 && settings
.AddBool("has title", fHasTitle
) == B_OK
278 && settings
.AddBool("has border", fHasBorder
) == B_OK
) {
279 settings
.Flatten(&file
);
285 WorkspacesSettings::UpdateFramesForScreen(BRect newScreenFrame
)
287 // don't change the position if the screen frame hasn't changed
288 if (newScreenFrame
== fScreenFrame
)
291 // adjust horizontal position
292 if (fWindowFrame
.right
> fScreenFrame
.right
/ 2) {
293 fWindowFrame
.OffsetTo(newScreenFrame
.right
294 - (fScreenFrame
.right
- fWindowFrame
.left
), fWindowFrame
.top
);
297 // adjust vertical position
298 if (fWindowFrame
.bottom
> fScreenFrame
.bottom
/ 2) {
299 fWindowFrame
.OffsetTo(fWindowFrame
.left
,
300 newScreenFrame
.bottom
- (fScreenFrame
.bottom
- fWindowFrame
.top
));
303 fScreenFrame
= newScreenFrame
;
308 WorkspacesSettings::UpdateScreenFrame()
311 fScreenFrame
= screen
.Frame();
316 WorkspacesSettings::SetWindowFrame(BRect frame
)
318 fWindowFrame
= frame
;
322 // #pragma mark - WorkspacesView
325 WorkspacesView::WorkspacesView(BRect frame
, bool showDragger
= true)
327 BView(frame
, kDeskbarItemName
, B_FOLLOW_ALL
,
328 kWorkspacesViewFlag
| B_FRAME_EVENTS
),
329 fParentWhichDrawsOnChildren(NULL
),
330 fCurrentFrame(frame
),
331 fSwitchOnWheel(false)
336 frame
.OffsetTo(B_ORIGIN
);
337 frame
.top
= frame
.bottom
- 7;
338 frame
.left
= frame
.right
- 7;
339 BDragger
* dragger
= new BDragger(frame
, this,
340 B_FOLLOW_RIGHT
| B_FOLLOW_BOTTOM
);
346 WorkspacesView::WorkspacesView(BMessage
* archive
)
349 fParentWhichDrawsOnChildren(NULL
),
350 fCurrentFrame(Frame()),
351 fSwitchOnWheel(false)
355 // Just in case we are instantiated from an older archive...
356 SetFlags(Flags() | B_FRAME_EVENTS
);
357 // Make sure the auto-raise feature didn't leave any artifacts - this is
358 // not a good idea to keep enabled for a replicant.
359 if (EventMask() != 0)
364 WorkspacesView::~WorkspacesView()
370 /*static*/ WorkspacesView
*
371 WorkspacesView::Instantiate(BMessage
* archive
)
373 if (!validate_instantiation(archive
, "WorkspacesView"))
376 return new WorkspacesView(archive
);
381 WorkspacesView::Archive(BMessage
* archive
, bool deep
) const
383 status_t status
= BView::Archive(archive
, deep
);
385 status
= archive
->AddString("add_on", kSignature
);
387 status
= archive
->AddString("class", "WorkspacesView");
394 WorkspacesView::_AboutRequested()
396 BAboutWindow
* window
= new BAboutWindow(
397 B_TRANSLATE_SYSTEM_NAME("Workspaces"), kSignature
);
399 const char* authors
[] = {
401 "Oliver \"Madison\" Kohl",
407 const char* extraCopyrights
[] = {
408 "2002 François Revol",
412 const char* extraInfo
= "Send windows behind using the Option key. "
413 "Move windows to front using the Control key.\n";
415 window
->AddCopyright(2002, "Haiku, Inc.",
417 window
->AddAuthors(authors
);
418 window
->AddExtraInfo(extraInfo
);
425 WorkspacesView::AttachedToWindow()
427 BView
* parent
= Parent();
428 if (parent
!= NULL
&& (parent
->Flags() & B_DRAW_ON_CHILDREN
) != 0) {
429 fParentWhichDrawsOnChildren
= parent
;
430 _ExcludeFromParentClipping();
436 WorkspacesView::DetachedFromWindow()
438 if (fParentWhichDrawsOnChildren
!= NULL
)
439 _CleanupParentClipping();
444 WorkspacesView::FrameMoved(BPoint newPosition
)
446 _UpdateParentClipping();
451 WorkspacesView::FrameResized(float newWidth
, float newHeight
)
453 _UpdateParentClipping();
458 WorkspacesView::_UpdateParentClipping()
460 if (fParentWhichDrawsOnChildren
!= NULL
) {
461 _CleanupParentClipping();
462 _ExcludeFromParentClipping();
463 fParentWhichDrawsOnChildren
->Invalidate(fCurrentFrame
);
464 fCurrentFrame
= Frame();
470 WorkspacesView::_ExcludeFromParentClipping()
472 // Prevent the parent view to draw over us. Do so in a way that allows
473 // restoring the parent to the previous state.
474 fParentWhichDrawsOnChildren
->PushState();
476 BRegion
clipping(fParentWhichDrawsOnChildren
->Bounds());
477 clipping
.Exclude(Frame());
478 fParentWhichDrawsOnChildren
->ConstrainClippingRegion(&clipping
);
483 WorkspacesView::_CleanupParentClipping()
485 // Restore the previous parent state. NOTE: This relies on views
486 // being detached in exactly the opposite order as them being
487 // attached. Otherwise we would mess up states if a sibbling view did
488 // the same thing we did in AttachedToWindow()...
489 fParentWhichDrawsOnChildren
->PopState();
494 WorkspacesView::_LoadSettings()
497 if (OpenSettingsFile(file
, B_READ_ONLY
) == B_OK
) {
499 if (settings
.Unflatten(&file
) == B_OK
)
500 settings
.FindBool("switch on wheel", &fSwitchOnWheel
);
506 WorkspacesView::_SaveSettings()
509 if (OpenSettingsFile(file
, B_READ_ONLY
| B_CREATE_FILE
) != B_OK
)
512 BMessage
settings('wksp');
513 settings
.Unflatten(&file
);
515 if (OpenSettingsFile(file
, B_WRITE_ONLY
| B_ERASE_FILE
) != B_OK
)
518 if (settings
.ReplaceBool("switch on wheel", fSwitchOnWheel
) != B_OK
)
519 settings
.AddBool("switch on wheel", fSwitchOnWheel
);
521 settings
.Flatten(&file
);
526 WorkspacesView::MessageReceived(BMessage
* message
)
528 switch (message
->what
) {
529 case B_ABOUT_REQUESTED
:
533 case B_MOUSE_WHEEL_CHANGED
:
538 float deltaY
= message
->FindFloat("be:wheel_delta_y");
540 activate_workspace(current_workspace() + 1);
541 else if (deltaY
< -0.1)
542 activate_workspace(current_workspace() - 1);
546 case kMsgChangeCount
:
547 be_roster
->Launch(kScreenPrefletSignature
);
550 case kMsgToggleLiveInDeskbar
:
552 // only actually used from the replicant itself
553 // since HasItem() locks up we just remove directly.
555 // we shouldn't do this here actually, but it works for now...
556 deskbar
.RemoveItem(kDeskbarItemName
);
560 case kMsgToggleSwitchOnWheel
:
562 fSwitchOnWheel
= !fSwitchOnWheel
;
567 BView::MessageReceived(message
);
574 WorkspacesView::MouseMoved(BPoint where
, uint32 transit
,
575 const BMessage
* dragMessage
)
577 WorkspacesWindow
* window
= dynamic_cast<WorkspacesWindow
*>(Window());
578 if (window
== NULL
|| !window
->IsAutoRaising())
583 where
= ConvertToScreen(where
);
584 BScreen
screen(window
);
585 BRect screenFrame
= screen
.Frame();
586 BRect windowFrame
= window
->Frame();
587 float tabHeight
= window
->GetTabHeight();
588 float borderWidth
= window
->GetBorderWidth();
590 if (where
.x
== screenFrame
.left
|| where
.x
== screenFrame
.right
591 || where
.y
== screenFrame
.top
|| where
.y
== screenFrame
.bottom
) {
592 // cursor is on screen edge
594 // Stretch frame to also accept mouse moves over the window borders
595 windowFrame
.InsetBy(-borderWidth
, -(tabHeight
+ borderWidth
));
597 if (windowFrame
.Contains(where
))
604 WorkspacesView::MouseDown(BPoint where
)
606 // With enabled auto-raise feature, we'll get mouse messages we don't
607 // want to handle here.
608 if (!Bounds().Contains(where
))
612 if (Window() != NULL
&& Window()->CurrentMessage() != NULL
)
613 Window()->CurrentMessage()->FindInt32("buttons", &buttons
);
615 if ((buttons
& B_SECONDARY_MOUSE_BUTTON
) == 0)
620 BPopUpMenu
*menu
= new BPopUpMenu(B_EMPTY_STRING
, false, false);
621 menu
->SetFont(be_plain_font
);
623 // TODO: alternatively change the count here directly?
624 BMenuItem
* changeItem
= new BMenuItem(B_TRANSLATE("Change workspace count"
625 B_UTF8_ELLIPSIS
), new BMessage(kMsgChangeCount
));
626 menu
->AddItem(changeItem
);
628 BMenuItem
* switchItem
= new BMenuItem(B_TRANSLATE("Switch on mouse wheel"),
629 new BMessage(kMsgToggleSwitchOnWheel
));
630 menu
->AddItem(switchItem
);
631 switchItem
->SetMarked(fSwitchOnWheel
);
633 WorkspacesWindow
*window
= dynamic_cast<WorkspacesWindow
*>(Window());
634 if (window
!= NULL
) {
635 // inside Workspaces app
638 menu
->AddSeparatorItem();
639 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Show window tab"),
640 new BMessage(kMsgToggleTitle
)));
641 if (window
->Look() == B_TITLED_WINDOW_LOOK
)
642 item
->SetMarked(true);
643 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Show window border"),
644 new BMessage(kMsgToggleBorder
)));
645 if (window
->Look() == B_TITLED_WINDOW_LOOK
646 || window
->Look() == B_MODAL_WINDOW_LOOK
) {
647 item
->SetMarked(true);
650 menu
->AddSeparatorItem();
651 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Always on top"),
652 new BMessage(kMsgToggleAlwaysOnTop
)));
653 if (window
->Feel() == B_FLOATING_ALL_WINDOW_FEEL
)
654 item
->SetMarked(true);
655 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Auto-raise"),
656 new BMessage(kMsgToggleAutoRaise
)));
657 if (window
->IsAutoRaising())
658 item
->SetMarked(true);
659 if (be_roster
->IsRunning(kDeskbarSignature
)) {
660 menu
->AddItem(item
= new BMenuItem(
661 B_TRANSLATE("Live in the Deskbar"),
662 new BMessage(kMsgToggleLiveInDeskbar
)));
664 item
->SetMarked(deskbar
.HasItem(kDeskbarItemName
));
667 menu
->AddSeparatorItem();
668 menu
->AddItem(new BMenuItem(B_TRANSLATE("Quit"),
669 new BMessage(B_QUIT_REQUESTED
)));
670 menu
->SetTargetForItems(window
);
672 // we're replicated in some way...
675 menu
->AddSeparatorItem();
678 BDragger
*dragger
= dynamic_cast<BDragger
*>(ChildAt(0));
681 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Remove replicant"),
682 new BMessage(B_TRASH_TARGET
)));
683 item
->SetTarget(dragger
);
686 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Remove replicant"),
687 new BMessage(kMsgToggleLiveInDeskbar
)));
688 item
->SetTarget(this);
692 changeItem
->SetTarget(this);
693 switchItem
->SetTarget(this);
695 ConvertToScreen(&where
);
696 menu
->Go(where
, true, true, true);
701 WorkspacesView::SetSwitchOnWheel(bool enable
)
703 if (enable
== fSwitchOnWheel
)
706 fSwitchOnWheel
= enable
;
710 // #pragma mark - WorkspacesWindow
713 WorkspacesWindow::WorkspacesWindow(WorkspacesSettings
*settings
)
715 BWindow(settings
->WindowFrame(), B_TRANSLATE_SYSTEM_NAME("Workspaces"),
716 B_TITLED_WINDOW_LOOK
, B_NORMAL_WINDOW_FEEL
,
717 B_AVOID_FRONT
| B_WILL_ACCEPT_FIRST_CLICK
| B_CLOSE_ON_ESCAPE
,
720 fWorkspacesView(NULL
)
722 // Turn window decor on to grab decor widths.
723 BMessage windowSettings
;
724 float borderWidth
= 0;
726 SetLook(B_TITLED_WINDOW_LOOK
);
727 if (GetDecoratorSettings(&windowSettings
) == B_OK
) {
728 BRect tabFrame
= windowSettings
.FindRect("tab frame");
729 borderWidth
= windowSettings
.FindFloat("border width");
730 fTabHeight
= tabFrame
.Height();
731 fBorderWidth
= borderWidth
;
734 if (!fSettings
->SettingsLoaded()) {
735 // No settings, compute a reasonable default frame.
736 // We aim for previews at 10% of actual screen size, and matching the
737 // aspect ratio. We then scale that down, until it fits the screen.
738 // Finally, we put the window on the bottom right of the screen so the
739 // auto-raise mode can be used.
743 float screenWidth
= screen
.Frame().Width();
744 float screenHeight
= screen
.Frame().Height();
745 float aspectRatio
= screenWidth
/ screenHeight
;
747 uint32 columns
, rows
;
748 BPrivate::get_workspaces_layout(&columns
, &rows
);
750 // default size of ~1/10 of screen width
751 float workspaceWidth
= screenWidth
/ 10;
752 float workspaceHeight
= workspaceWidth
/ aspectRatio
;
754 float width
= floor(workspaceWidth
* columns
);
755 float height
= floor(workspaceHeight
* rows
);
757 // If you have too many workspaces to fit on the screen, shrink until
759 while (width
+ 2 * borderWidth
> screenWidth
760 || height
+ 2 * borderWidth
+ GetTabHeight() > screenHeight
) {
761 width
= floor(0.95 * width
);
762 height
= floor(0.95 * height
);
765 BRect frame
= fSettings
->ScreenFrame();
766 frame
.OffsetBy(-2.0 * borderWidth
, -2.0 * borderWidth
);
767 frame
.left
= frame
.right
- width
;
768 frame
.top
= frame
.bottom
- height
;
769 ResizeTo(frame
.Width(), frame
.Height());
771 // Put it in bottom corner by default.
772 MoveTo(screenWidth
- frame
.Width() - borderWidth
,
773 screenHeight
- frame
.Height() - borderWidth
);
775 fSettings
->SetWindowFrame(frame
);
778 if (!fSettings
->HasBorder())
779 SetLook(B_NO_BORDER_WINDOW_LOOK
);
780 else if (!fSettings
->HasTitle())
781 SetLook(B_MODAL_WINDOW_LOOK
);
783 fWorkspacesView
= new WorkspacesView(Bounds());
784 AddChild(fWorkspacesView
);
786 if (fSettings
->AlwaysOnTop())
787 SetFeel(B_FLOATING_ALL_WINDOW_FEEL
);
789 SetAutoRaise(fSettings
->AutoRaising());
793 WorkspacesWindow::~WorkspacesWindow()
800 WorkspacesWindow::ScreenChanged(BRect rect
, color_space mode
)
802 fSettings
->UpdateFramesForScreen(rect
);
803 MoveTo(fSettings
->WindowFrame().LeftTop());
808 WorkspacesWindow::FrameMoved(BPoint origin
)
810 fSettings
->SetWindowFrame(Frame());
815 WorkspacesWindow::FrameResized(float width
, float height
)
817 if (!(modifiers() & B_SHIFT_KEY
)) {
818 BWindow::FrameResized(width
, height
);
822 uint32 columns
, rows
;
823 BPrivate::get_workspaces_layout(&columns
, &rows
);
826 float screenWidth
= screen
.Frame().Width();
827 float screenHeight
= screen
.Frame().Height();
829 float windowAspectRatio
830 = (columns
* screenWidth
) / (rows
* screenHeight
);
832 float newHeight
= width
/ windowAspectRatio
;
834 if (height
!= newHeight
)
835 ResizeTo(width
, newHeight
);
837 fSettings
->SetWindowFrame(Frame());
842 WorkspacesWindow::Zoom(BPoint origin
, float width
, float height
)
845 float screenWidth
= screen
.Frame().Width();
846 float screenHeight
= screen
.Frame().Height();
847 float aspectRatio
= screenWidth
/ screenHeight
;
849 uint32 columns
, rows
;
850 BPrivate::get_workspaces_layout(&columns
, &rows
);
852 float workspaceWidth
= Frame().Width() / columns
;
853 float workspaceHeight
= workspaceWidth
/ aspectRatio
;
855 width
= floor(workspaceWidth
* columns
);
856 height
= floor(workspaceHeight
* rows
);
858 while (width
+ 2 * GetScreenBorderOffset() > screenWidth
859 || height
+ 2 * GetScreenBorderOffset() + GetTabHeight()
861 width
= floor(0.95 * width
);
862 height
= floor(0.95 * height
);
865 ResizeTo(width
, height
);
867 if (fSettings
->AutoRaising()) {
868 // The auto-raising mode makes sense only if the window is positionned
869 // exactly in the bottom-right corner. If the setting is enabled, move
871 origin
= screen
.Frame().RightBottom();
872 origin
.x
-= GetScreenBorderOffset() + width
;
873 origin
.y
-= GetScreenBorderOffset() + height
;
881 WorkspacesWindow::MessageReceived(BMessage
*message
)
883 switch (message
->what
) {
888 for (int i
= 0; (message
->FindRef("refs", i
, &ref
) == B_OK
); i
++)
889 be_roster
->Launch(&ref
);
893 case B_ABOUT_REQUESTED
:
894 PostMessage(message
, ChildAt(0));
897 case kMsgToggleBorder
:
900 if (Look() == B_NO_BORDER_WINDOW_LOOK
)
904 if (fSettings
->HasTitle())
905 SetLook(B_TITLED_WINDOW_LOOK
);
907 SetLook(B_MODAL_WINDOW_LOOK
);
909 SetLook(B_NO_BORDER_WINDOW_LOOK
);
911 fSettings
->SetHasBorder(enable
);
915 case kMsgToggleTitle
:
918 if (Look() == B_MODAL_WINDOW_LOOK
919 || Look() == B_NO_BORDER_WINDOW_LOOK
)
923 SetLook(B_TITLED_WINDOW_LOOK
);
925 SetLook(B_MODAL_WINDOW_LOOK
);
927 // No matter what the setting for title, we must force the border on
928 fSettings
->SetHasBorder(true);
929 fSettings
->SetHasTitle(enable
);
933 case kMsgToggleAutoRaise
:
934 SetAutoRaise(!IsAutoRaising());
935 SetFeel(B_NORMAL_WINDOW_FEEL
);
938 case kMsgToggleAlwaysOnTop
:
941 if (Feel() != B_FLOATING_ALL_WINDOW_FEEL
)
945 SetFeel(B_FLOATING_ALL_WINDOW_FEEL
);
947 SetFeel(B_NORMAL_WINDOW_FEEL
);
949 fSettings
->SetAlwaysOnTop(enable
);
953 case kMsgToggleLiveInDeskbar
:
956 if (deskbar
.HasItem(kDeskbarItemName
))
957 deskbar
.RemoveItem(kDeskbarItemName
);
959 fWorkspacesView
->_SaveSettings();
960 // save "switch on wheel" setting for replicant to load
962 be_roster
->FindApp(kSignature
, &ref
);
963 deskbar
.AddItem(&ref
);
969 BWindow::MessageReceived(message
);
976 WorkspacesWindow::QuitRequested()
978 be_app
->PostMessage(B_QUIT_REQUESTED
);
984 WorkspacesWindow::SetAutoRaise(bool enable
)
986 fSettings
->SetAutoRaising(enable
);
989 ChildAt(0)->SetEventMask(B_POINTER_EVENTS
, B_NO_POINTER_HISTORY
);
991 ChildAt(0)->SetEventMask(0);
995 // #pragma mark - WorkspacesApp
998 WorkspacesApp::WorkspacesApp()
999 : BApplication(kSignature
)
1001 fWindow
= new WorkspacesWindow(new WorkspacesSettings());
1005 WorkspacesApp::~WorkspacesApp()
1011 WorkspacesApp::AboutRequested()
1013 fWindow
->PostMessage(B_ABOUT_REQUESTED
);
1018 WorkspacesApp::Usage(const char *programName
)
1020 printf(B_TRANSLATE("Usage: %s [options] [workspace]\n"
1021 "where \"options\" are:\n"
1022 " --notitle\t\ttitle bar removed, border and resize kept\n"
1023 " --noborder\t\ttitle, border, and resize removed\n"
1024 " --avoidfocus\t\tprevents the window from being the target of "
1026 " --alwaysontop\t\tkeeps window on top\n"
1027 " --notmovable\t\twindow can't be moved around\n"
1028 " --autoraise\t\tauto-raise the workspace window when it's at the "
1030 " --help\t\tdisplay this help and exit\n"
1031 "and \"workspace\" is the number of the Workspace to which to switch "
1035 // quit only if we aren't running already
1042 WorkspacesApp::ArgvReceived(int32 argc
, char **argv
)
1044 for (int i
= 1; i
< argc
; i
++) {
1045 if (argv
[i
][0] == '-' && argv
[i
][1] == '-') {
1046 // evaluate --arguments
1047 if (!strcmp(argv
[i
], "--notitle"))
1048 fWindow
->SetLook(B_MODAL_WINDOW_LOOK
);
1049 else if (!strcmp(argv
[i
], "--noborder"))
1050 fWindow
->SetLook(B_NO_BORDER_WINDOW_LOOK
);
1051 else if (!strcmp(argv
[i
], "--avoidfocus"))
1052 fWindow
->SetFlags(fWindow
->Flags() | B_AVOID_FOCUS
);
1053 else if (!strcmp(argv
[i
], "--notmovable"))
1054 fWindow
->SetFlags(fWindow
->Flags() | B_NOT_MOVABLE
);
1055 else if (!strcmp(argv
[i
], "--alwaysontop"))
1056 fWindow
->SetFeel(B_FLOATING_ALL_WINDOW_FEEL
);
1057 else if (!strcmp(argv
[i
], "--autoraise"))
1058 fWindow
->SetAutoRaise(true);
1060 const char *programName
= strrchr(argv
[0], '/');
1061 programName
= programName
? programName
+ 1 : argv
[0];
1065 } else if (isdigit(*argv
[i
])) {
1066 // check for a numeric arg, if not already given
1067 activate_workspace(atoi(argv
[i
]));
1069 // if the app is running, don't quit
1070 // but if it isn't, cancel the complete run, so it doesn't
1074 } else if (!strcmp(argv
[i
], "-")) {
1075 activate_workspace(current_workspace() - 1);
1079 } else if (!strcmp(argv
[i
], "+")) {
1080 activate_workspace(current_workspace() + 1);
1085 // some unknown arguments were specified
1086 fprintf(stderr
, B_TRANSLATE("Invalid argument: %s\n"), argv
[i
]);
1095 BView
* instantiate_deskbar_item()
1097 // Calculate the correct size of the Deskbar replicant first
1100 float screenWidth
= screen
.Frame().Width();
1101 float screenHeight
= screen
.Frame().Height();
1102 float aspectRatio
= screenWidth
/ screenHeight
;
1103 uint32 columns
, rows
;
1104 BPrivate::get_workspaces_layout(&columns
, &rows
);
1106 // ╔═╤═╕ A Deskbar replicant can be 16px tall and 129px wide at most.
1107 // ║ │ │ We use 1px for the top and left borders (shown as double)
1108 // ╟─┼─┤ and divide the remainder equally. However, we keep in mind
1109 // ║ │ │ that the actual width and height of each workspace is smaller
1110 // ╙─┴─┘ by 1px, because of bottom/right borders (shown as single).
1111 // When calculating workspace width, we must ensure that the assumed
1112 // actual workspace height is not negative. Zero is OK.
1115 float rowHeight
= floor((height
- 1) / rows
);
1119 float columnWidth
= floor((rowHeight
- 1) * aspectRatio
) + 1;
1121 float width
= columnWidth
* columns
+ 1;
1125 return new WorkspacesView(BRect (0, 0, width
- 1, height
- 1), false);
1130 WorkspacesApp::ReadyToRun()
1140 main(int argc
, char **argv
)