From ac2042cb709aeb8451a33b3ad472a28f39653823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Fri, 14 Mar 2008 13:14:23 +0000 Subject: [PATCH] * Moved about window into the view and made it accessible from the replicant as well. * Added a context menu that allows you to change how Workspaces looks and behaves (previously accessible only using command line options). * The settings changes are now remembered; we're now using a new settings file (flattened BMessage), but can still read old settings files if it exists. * Renamed WorkspacesPreferences to WorkspacesSettings. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24389 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/workspaces/Workspaces.cpp | 406 +++++++++++++++++++++++------ 1 file changed, 321 insertions(+), 85 deletions(-) diff --git a/src/apps/workspaces/Workspaces.cpp b/src/apps/workspaces/Workspaces.cpp index 1938457c02..5f0a5f9693 100644 --- a/src/apps/workspaces/Workspaces.cpp +++ b/src/apps/workspaces/Workspaces.cpp @@ -17,7 +17,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -32,26 +34,50 @@ #include -static const char *kSignature = "application/x-vnd.Be-WORK"; -static const char *kWorkspacesSettingFile = "Workspace_data"; +static const char* kSignature = "application/x-vnd.Be-WORK"; +static const char* kOldSettingFile = "Workspace_data"; +static const char* kSettingsFile = "Workspaces_settings"; + +static const uint32 kMsgChangeCount = 'chWC'; +static const uint32 kMsgToggleTitle = 'tgTt'; +static const uint32 kMsgToggleBorder = 'tgBd'; +static const uint32 kMsgToggleAutoRaise = 'tgAR'; +static const uint32 kMsgToggleAlwaysOnTop = 'tgAT'; static const float kScreenBorderOffset = 10.0; -class WorkspacesPreferences { +class WorkspacesSettings { public: - WorkspacesPreferences(); - virtual ~WorkspacesPreferences(); + WorkspacesSettings(); + virtual ~WorkspacesSettings(); BRect WindowFrame() const { return fWindowFrame; } BRect ScreenFrame() const { return fScreenFrame; } + bool AutoRaising() const { return fAutoRaising; } + bool AlwaysOnTop() const { return fAlwaysOnTop; } + bool HasTitle() const { return fHasTitle; } + bool HasBorder() const { return fHasBorder; } + void UpdateFramesForScreen(BRect screenFrame); void UpdateScreenFrame(); + void SetWindowFrame(BRect); + void SetAutoRaising(bool enable) { fAutoRaising = enable; } + void SetAlwaysOnTop(bool enable) { fAlwaysOnTop = enable; } + void SetHasTitle(bool enable) { fHasTitle = enable; } + void SetHasBorder(bool enable) { fHasBorder = enable; } private: - BRect fWindowFrame, fScreenFrame; + status_t _Open(BFile& file, int mode); + + BRect fWindowFrame; + BRect fScreenFrame; + bool fAutoRaising; + bool fAlwaysOnTop; + bool fHasTitle; + bool fHasBorder; }; class WorkspacesView : public BView { @@ -63,14 +89,18 @@ class WorkspacesView : public BView { static WorkspacesView* Instantiate(BMessage* archive); virtual status_t Archive(BMessage* archive, bool deep = true) const; + virtual void MessageReceived(BMessage* message); virtual void MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage); virtual void MouseDown(BPoint where); + + private: + void _AboutRequested(); }; class WorkspacesWindow : public BWindow { public: - WorkspacesWindow(WorkspacesPreferences *fPreferences); + WorkspacesWindow(WorkspacesSettings *settings); virtual ~WorkspacesWindow(); virtual void ScreenChanged(BRect frame, color_space mode); @@ -81,11 +111,13 @@ class WorkspacesWindow : public BWindow { virtual void MessageReceived(BMessage *msg); virtual bool QuitRequested(); - void SetAutoRaise(); + void SetAutoRaise(bool enable); + bool IsAutoRaising() const { return fAutoRaising; } private: - WorkspacesPreferences *fPreferences; + WorkspacesSettings *fSettings; BRect fPreviousFrame; + bool fAutoRaising; }; class WorkspacesApp : public BApplication { @@ -104,40 +136,67 @@ class WorkspacesApp : public BApplication { }; -WorkspacesPreferences::WorkspacesPreferences() +WorkspacesSettings::WorkspacesSettings() + : + fAutoRaising(false), + fAlwaysOnTop(false), + fHasTitle(true), + fHasBorder(true) { UpdateScreenFrame(); - bool settingsValid = false; - BPath path; + bool loaded = false; + BScreen screen; - if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) { - path.Append(kWorkspacesSettingFile); - BFile file(path.Path(), B_READ_ONLY); - if (file.InitCheck() == B_OK - && file.Read(&fWindowFrame, sizeof(BRect)) == sizeof(BRect)) { - // we now also store the frame of the screen to know - // in which context the window frame has been chosen - BScreen screen; - BRect frame; - if (file.Read(&frame, sizeof(BRect)) == sizeof(BRect)) { - fScreenFrame = frame; - // if the current screen frame is different from the one - // just loaded, we need to alter the window frame accordingly - if (fScreenFrame != screen.Frame()) - UpdateFramesForScreen(screen.Frame()); + BFile file; + if (_Open(file, B_READ_ONLY) == B_OK) { + BMessage settings; + if (settings.Unflatten(&file) == B_OK) { + if (settings.FindRect("window", &fWindowFrame) == B_OK + && settings.FindRect("screen", &fScreenFrame) == B_OK) + loaded = true; + + settings.FindBool("auto-raise", &fAutoRaising); + settings.FindBool("always on top", &fAlwaysOnTop); + + if (settings.FindBool("has title", &fHasTitle) != B_OK) + fHasTitle = true; + if (settings.FindBool("has border", &fHasBorder) != B_OK) + fHasBorder = true; + } + } else { + // try reading BeOS compatible settings + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) { + path.Append(kOldSettingFile); + BFile file(path.Path(), B_READ_ONLY); + if (file.InitCheck() == B_OK + && file.Read(&fWindowFrame, sizeof(BRect)) == sizeof(BRect)) { + // we now also store the frame of the screen to know + // in which context the window frame has been chosen + BRect frame; + if (file.Read(&frame, sizeof(BRect)) == sizeof(BRect)) + fScreenFrame = frame; + else + fScreenFrame = screen.Frame(); + + loaded = true; } - - // check if loaded values are valid - if (screen.Frame().right + 5 >= fWindowFrame.right - && screen.Frame().bottom + 5 >= fWindowFrame.bottom - && screen.Frame().left - 5 <= fWindowFrame.left - && screen.Frame().top - 5 <= fWindowFrame.top) - settingsValid = true; } } - if (!settingsValid) { + if (loaded) { + // if the current screen frame is different from the one + // just loaded, we need to alter the window frame accordingly + if (fScreenFrame != screen.Frame()) + UpdateFramesForScreen(screen.Frame()); + } + + if (!loaded + || !(screen.Frame().right + 5 >= fWindowFrame.right + && screen.Frame().bottom + 5 >= fWindowFrame.bottom + && screen.Frame().left - 5 <= fWindowFrame.left + && screen.Frame().top - 5 <= fWindowFrame.top)) { // set to some usable defaults fWindowFrame = fScreenFrame; fWindowFrame.OffsetBy(-kScreenBorderOffset, -kScreenBorderOffset); @@ -147,25 +206,51 @@ WorkspacesPreferences::WorkspacesPreferences() } -WorkspacesPreferences::~WorkspacesPreferences() +WorkspacesSettings::~WorkspacesSettings() { // write settings file - BPath path; - if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) < B_OK) + BFile file; + if (_Open(file, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE) != B_OK) return; - path.Append(kWorkspacesSettingFile); + BMessage settings('wksp'); - BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE); - if (file.InitCheck() == B_OK) { - file.Write(&fWindowFrame, sizeof(BRect)); - file.Write(&fScreenFrame, sizeof(BRect)); + if (settings.AddRect("window", fWindowFrame) == B_OK + && settings.AddRect("screen", fScreenFrame) == B_OK + && settings.AddBool("auto-raise", fAutoRaising) == B_OK + && settings.AddBool("always on top", fAlwaysOnTop) == B_OK + && settings.AddBool("has title", fHasTitle) == B_OK + && settings.AddBool("has border", fHasBorder) == B_OK) + settings.Flatten(&file); +} + + +status_t +WorkspacesSettings::_Open(BFile& file, int mode) +{ + BPath path; + status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); + if (status != B_OK) + status = find_directory(B_COMMON_SETTINGS_DIRECTORY, &path); + if (status != B_OK) + return status; + + path.Append(kSettingsFile); + + status = file.SetTo(path.Path(), mode); + if (mode == B_READ_ONLY && status == B_ENTRY_NOT_FOUND) { + if (find_directory(B_COMMON_SETTINGS_DIRECTORY, &path) == B_OK) { + path.Append(kSettingsFile); + status = file.SetTo(path.Path(), mode); + } } + + return status; } void -WorkspacesPreferences::UpdateFramesForScreen(BRect newScreenFrame) +WorkspacesSettings::UpdateFramesForScreen(BRect newScreenFrame) { // don't change the position if the screen frame hasn't changed if (newScreenFrame == fScreenFrame) @@ -186,7 +271,7 @@ WorkspacesPreferences::UpdateFramesForScreen(BRect newScreenFrame) void -WorkspacesPreferences::UpdateScreenFrame() +WorkspacesSettings::UpdateScreenFrame() { BScreen screen; fScreenFrame = screen.Frame(); @@ -194,7 +279,7 @@ WorkspacesPreferences::UpdateScreenFrame() void -WorkspacesPreferences::SetWindowFrame(BRect frame) +WorkspacesSettings::SetWindowFrame(BRect frame) { fWindowFrame = frame; } @@ -249,6 +334,47 @@ WorkspacesView::Archive(BMessage* archive, bool deep) const } +void +WorkspacesView::_AboutRequested() +{ + BAlert *alert = new BAlert("about", "Workspaces\n" + "written by François Revol, Axel Dörfler, and Matt Madia.\n\n" + "Copyright 2002-2008, Haiku.\n\n" + "Send windows behind using the Option key. " + "Move windows to front using the Control key.\n", "Ok"); + BTextView *view = alert->TextView(); + BFont font; + + view->SetStylable(true); + + view->GetFont(&font); + font.SetSize(18); + font.SetFace(B_BOLD_FACE); + view->SetFontAndColor(0, 10, &font); + + alert->Go(); +} + + +void +WorkspacesView::MessageReceived(BMessage* message) +{ + switch (message->what) { + case B_ABOUT_REQUESTED: + _AboutRequested(); + break; + + case kMsgChangeCount: + be_roster->Launch("application/x-vnd.Be-SCRN"); + break; + + default: + BView::MessageReceived(message); + break; + } +} + + void WorkspacesView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage) @@ -280,38 +406,92 @@ WorkspacesView::MouseDown(BPoint where) if ((buttons & B_SECONDARY_MOUSE_BUTTON) == 0) return; - // TODO: open menu + // open context menu + + BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING, false, false); + menu->SetFont(be_plain_font); + + // TODO: alternatively change the count here directly? + BMenuItem* changeItem = new BMenuItem("Change Workspace Count" + B_UTF8_ELLIPSIS, new BMessage(kMsgChangeCount)); + menu->AddItem(changeItem); + + WorkspacesWindow* window = dynamic_cast(Window()); + if (window != NULL) { + BMenuItem* item; + + menu->AddSeparatorItem(); + menu->AddItem(item = new BMenuItem("No title", + new BMessage(kMsgToggleTitle))); + if (window->Look() == B_MODAL_WINDOW_LOOK) + item->SetMarked(true); + menu->AddItem(item = new BMenuItem("No Border", + new BMessage(kMsgToggleBorder))); + if (window->Look() == B_NO_BORDER_WINDOW_LOOK) + item->SetMarked(true); + + menu->AddSeparatorItem(); + menu->AddItem(item = new BMenuItem("Always On Top", + new BMessage(kMsgToggleAlwaysOnTop))); + if (window->Feel() == B_FLOATING_ALL_WINDOW_FEEL) + item->SetMarked(true); + menu->AddItem(item = new BMenuItem("Auto-Raise", + new BMessage(kMsgToggleAutoRaise))); + if (window->IsAutoRaising()) + item->SetMarked(true); + + menu->AddSeparatorItem(); + menu->AddItem(new BMenuItem("About" B_UTF8_ELLIPSIS, + new BMessage(B_ABOUT_REQUESTED))); + menu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED))); + menu->SetTargetForItems(window); + } + + changeItem->SetTarget(this); + ConvertToScreen(&where); + menu->Go(where, true, false, true); } // #pragma mark - -WorkspacesWindow::WorkspacesWindow(WorkspacesPreferences *preferences) - : BWindow(preferences->WindowFrame(), "Workspaces", B_TITLED_WINDOW_LOOK, +WorkspacesWindow::WorkspacesWindow(WorkspacesSettings *settings) + : BWindow(settings->WindowFrame(), "Workspaces", B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, B_AVOID_FRONT | B_WILL_ACCEPT_FIRST_CLICK, B_ALL_WORKSPACES), - fPreferences(preferences) + fSettings(settings), + fAutoRaising(false) { AddChild(new WorkspacesView(Bounds())); fPreviousFrame = Frame(); + + if (!fSettings->HasTitle()) + SetLook(B_MODAL_WINDOW_LOOK); + else if (!fSettings->HasBorder()) + SetLook(B_NO_BORDER_WINDOW_LOOK); + + if (fSettings->AlwaysOnTop()) + SetFeel(B_FLOATING_ALL_WINDOW_FEEL); + else + SetAutoRaise(fSettings->AutoRaising()); } WorkspacesWindow::~WorkspacesWindow() { - delete fPreferences; + delete fSettings; } void WorkspacesWindow::ScreenChanged(BRect rect, color_space mode) { - fPreviousFrame = fPreferences->WindowFrame(); + fPreviousFrame = fSettings->WindowFrame(); // work-around for a bug in BeOS, see explanation in FrameMoved() - fPreferences->UpdateFramesForScreen(rect); - MoveTo(fPreferences->WindowFrame().LeftTop()); + fSettings->UpdateFramesForScreen(rect); + MoveTo(fSettings->WindowFrame().LeftTop()); } @@ -326,14 +506,14 @@ WorkspacesWindow::FrameMoved(BPoint origin) return; } - fPreferences->SetWindowFrame(Frame()); + fSettings->SetWindowFrame(Frame()); } void WorkspacesWindow::FrameResized(float width, float height) { - fPreferences->SetWindowFrame(Frame()); + fSettings->SetWindowFrame(Frame()); } @@ -342,23 +522,84 @@ WorkspacesWindow::Zoom(BPoint origin, float width, float height) { BScreen screen; origin = screen.Frame().RightBottom(); - origin.x -= kScreenBorderOffset + fPreferences->WindowFrame().Width(); - origin.y -= kScreenBorderOffset + fPreferences->WindowFrame().Height(); + origin.x -= kScreenBorderOffset + fSettings->WindowFrame().Width(); + origin.y -= kScreenBorderOffset + fSettings->WindowFrame().Height(); MoveTo(origin); } void -WorkspacesWindow::MessageReceived(BMessage *msg) +WorkspacesWindow::MessageReceived(BMessage *message) { - if (msg->what == 'DATA') { - // Drop from Tracker - entry_ref ref; - for (int i = 0; (msg->FindRef("refs", i, &ref) == B_OK); i++) - be_roster->Launch(&ref); - } else - BWindow::MessageReceived(msg); + switch (message->what) { + case B_SIMPLE_DATA: + { + // Drop from Tracker + entry_ref ref; + for (int i = 0; (message->FindRef("refs", i, &ref) == B_OK); i++) + be_roster->Launch(&ref); + break; + } + + case B_ABOUT_REQUESTED: + PostMessage(message, ChildAt(0)); + break; + + case kMsgToggleBorder: + { + bool enable = false; + if (Look() == B_NO_BORDER_WINDOW_LOOK) + enable = true; + + if (enable) + SetLook(B_TITLED_WINDOW_LOOK); + else + SetLook(B_NO_BORDER_WINDOW_LOOK); + + fSettings->SetHasBorder(enable); + break; + } + + case kMsgToggleTitle: + { + bool enable = false; + if (Look() == B_MODAL_WINDOW_LOOK) + enable = true; + + if (enable) + SetLook(B_TITLED_WINDOW_LOOK); + else + SetLook(B_MODAL_WINDOW_LOOK); + + fSettings->SetHasTitle(enable); + break; + } + + case kMsgToggleAutoRaise: + SetAutoRaise(!IsAutoRaising()); + SetFeel(B_NORMAL_WINDOW_FEEL); + break; + + case kMsgToggleAlwaysOnTop: + { + bool enable = false; + if (Feel() != B_FLOATING_ALL_WINDOW_FEEL) + enable = true; + + if (enable) + SetFeel(B_FLOATING_ALL_WINDOW_FEEL); + else + SetFeel(B_NORMAL_WINDOW_FEEL); + + fSettings->SetAlwaysOnTop(enable); + break; + } + + default: + BWindow::MessageReceived(message); + break; + } } @@ -371,9 +612,18 @@ WorkspacesWindow::QuitRequested() void -WorkspacesWindow::SetAutoRaise() +WorkspacesWindow::SetAutoRaise(bool enable) { - ChildAt(0)->SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY); + if (enable == fAutoRaising) + return; + + fAutoRaising = enable; + fSettings->SetAutoRaising(enable); + + if (enable) + ChildAt(0)->SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY); + else + ChildAt(0)->SetEventMask(0); } @@ -383,7 +633,7 @@ WorkspacesWindow::SetAutoRaise() WorkspacesApp::WorkspacesApp() : BApplication(kSignature) { - fWindow = new WorkspacesWindow(new WorkspacesPreferences()); + fWindow = new WorkspacesWindow(new WorkspacesSettings()); } @@ -395,21 +645,7 @@ WorkspacesApp::~WorkspacesApp() void WorkspacesApp::AboutRequested() { - BAlert *alert = new BAlert("about", "Workspaces\n" - "\twritten by François Revol, Axel Dörfler,\n" - "\t\tand Matt Madia.\n" - "\tCopyright 2002-2007, Haiku.\n", "Ok"); - BTextView *view = alert->TextView(); - BFont font; - - view->SetStylable(true); - - view->GetFont(&font); - font.SetSize(18); - font.SetFace(B_BOLD_FACE); - view->SetFontAndColor(0, 10, &font); - - alert->Go(); + fWindow->PostMessage(B_ABOUT_REQUESTED); } @@ -451,7 +687,7 @@ WorkspacesApp::ArgvReceived(int32 argc, char **argv) else if (!strcmp(argv[i], "--alwaysontop")) fWindow->SetFeel(B_FLOATING_ALL_WINDOW_FEEL); else if (!strcmp(argv[i], "--autoraise")) - fWindow->SetAutoRaise(); + fWindow->SetAutoRaise(true); else { const char *programName = strrchr(argv[0], '/'); programName = programName ? programName + 1 : argv[0];