From 14fe11cfaed1dc4450ffdd8c82cab879d9f97d39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 13 Mar 2006 22:05:49 +0000 Subject: [PATCH] * Implemented moving windows around via the Workspaces app. However, you can't move them to another workspace, and you currently don't see a window moving that is not in the current workspace. (this fixes bug #135) * Desktop::SetWindowBehind() didn't update the WorkspacesLayer. * Changed Desktop::MoveWindowBy() to be able to move window on any workspace. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16776 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/servers/app/Desktop.cpp | 24 ++- src/servers/app/Desktop.h | 3 +- src/servers/app/ViewLayer.cpp | 21 +++ src/servers/app/ViewLayer.h | 4 + src/servers/app/WindowLayer.cpp | 24 +-- src/servers/app/WorkspacesLayer.cpp | 230 ++++++++++++++++++++++++++-- src/servers/app/WorkspacesLayer.h | 16 +- 7 files changed, 286 insertions(+), 36 deletions(-) diff --git a/src/servers/app/Desktop.cpp b/src/servers/app/Desktop.cpp index a9b90a3321..2462b92383 100644 --- a/src/servers/app/Desktop.cpp +++ b/src/servers/app/Desktop.cpp @@ -1205,7 +1205,7 @@ Desktop::SendWindowBehind(WindowLayer* window, WindowLayer* behindOf) _UpdateFronts(); SetFocusWindow(FrontWindow()); - //_WindowsChanged(); + _WindowChanged(window); UnlockAllWindows(); } @@ -1282,6 +1282,9 @@ Desktop::HideWindow(WindowLayer* window) SetFocusWindow(FrontWindow()); } + if (fWorkspacesLayer != NULL) + fWorkspacesLayer->WindowRemoved(window); + if (dynamic_cast(window->TopLayer()) != NULL) fWorkspacesLayer = NULL; @@ -1340,13 +1343,26 @@ Desktop::_HideWindow(WindowLayer* window) void -Desktop::MoveWindowBy(WindowLayer* window, float x, float y) +Desktop::MoveWindowBy(WindowLayer* window, float x, float y, int32 workspace) { if (!LockAllWindows()) return; - if (!window->IsVisible()) { - window->MoveBy(x, y); + if (workspace == -1) + workspace = fCurrentWorkspace; + + if (!window->IsVisible() || workspace != fCurrentWorkspace) { + if (workspace != fCurrentWorkspace) { + // move the window on another workspace - this doesn't change it's + // current position + if (window->Anchor(workspace).position == kInvalidWindowPosition) + window->Anchor(workspace).position = window->Frame().LeftTop(); + + window->Anchor(workspace).position += BPoint(x, y); + _WindowChanged(window); + } else + window->MoveBy(x, y); + UnlockAllWindows(); return; } diff --git a/src/servers/app/Desktop.h b/src/servers/app/Desktop.h index 9a331f7647..7c6171034b 100644 --- a/src/servers/app/Desktop.h +++ b/src/servers/app/Desktop.h @@ -106,7 +106,8 @@ class Desktop : public MessageLooper, public ScreenOwner { void ShowWindow(WindowLayer* window); void HideWindow(WindowLayer* window); - void MoveWindowBy(WindowLayer* window, float x, float y); + void MoveWindowBy(WindowLayer* window, float x, float y, + int32 workspace = -1); void ResizeWindowBy(WindowLayer* window, float x, float y); void SetWindowWorkspaces(WindowLayer* window, diff --git a/src/servers/app/ViewLayer.cpp b/src/servers/app/ViewLayer.cpp index a9731d976f..3e22852ce6 100644 --- a/src/servers/app/ViewLayer.cpp +++ b/src/servers/app/ViewLayer.cpp @@ -980,6 +980,27 @@ ViewLayer::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, } +void +ViewLayer::MouseDown(BMessage* message, BPoint where) +{ + // empty hook methods +} + + +void +ViewLayer::MouseUp(BMessage* message, BPoint where) +{ + // empty hook methods +} + + +void +ViewLayer::MouseMoved(BMessage* message, BPoint where) +{ + // empty hook methods +} + + // #pragma mark - diff --git a/src/servers/app/ViewLayer.h b/src/servers/app/ViewLayer.h index 0452737d1f..29b06a2eb0 100644 --- a/src/servers/app/ViewLayer.h +++ b/src/servers/app/ViewLayer.h @@ -165,6 +165,10 @@ class ViewLayer { BRegion* windowContentClipping, bool deep = false); + virtual void MouseDown(BMessage* message, BPoint where); + virtual void MouseUp(BMessage* message, BPoint where); + virtual void MouseMoved(BMessage* message, BPoint where); + void SetHidden(bool hidden); bool IsHidden() const; diff --git a/src/servers/app/WindowLayer.cpp b/src/servers/app/WindowLayer.cpp index 851ed3d7ee..0be578c751 100644 --- a/src/servers/app/WindowLayer.cpp +++ b/src/servers/app/WindowLayer.cpp @@ -837,22 +837,18 @@ WindowLayer::MouseDown(BMessage* message, BPoint where, int32* _viewToken) // fill out view token for the view under the mouse *_viewToken = view->Token(); - - // TODO: that's not really a clean solution - maybe move that - // functionality back into the ViewLayer class - if (WorkspacesLayer* layer = dynamic_cast(view)) - layer->MouseDown(message, where); + view->MouseDown(message, where); } } } void -WindowLayer::MouseUp(BMessage* msg, BPoint where, int32* _viewToken) +WindowLayer::MouseUp(BMessage* message, BPoint where, int32* _viewToken) { bool invalidate = false; if (fDecorator) { - click_type action = _ActionFor(msg); + click_type action = _ActionFor(message); // redraw decorator BRegion visibleBorder; @@ -893,13 +889,15 @@ WindowLayer::MouseUp(BMessage* msg, BPoint where, int32* _viewToken) fIsResizing = false; fIsSlidingTab = false; - if (ViewLayer* view = ViewAt(where)) + if (ViewLayer* view = ViewAt(where)) { *_viewToken = view->Token(); + view->MouseUp(message, where); + } } void -WindowLayer::MouseMoved(BMessage *msg, BPoint where, int32* _viewToken, +WindowLayer::MouseMoved(BMessage *message, BPoint where, int32* _viewToken, bool isLatestMouseMoved) { ViewLayer* view = ViewAt(where); @@ -931,11 +929,11 @@ WindowLayer::MouseMoved(BMessage *msg, BPoint where, int32* _viewToken, fDrawingEngine->ConstrainClippingRegion(&visibleBorder); if (fIsZooming) { - fDecorator->SetZoom(_ActionFor(msg) == DEC_ZOOM); + fDecorator->SetZoom(_ActionFor(message) == DEC_ZOOM); } else if (fIsClosing) { - fDecorator->SetClose(_ActionFor(msg) == DEC_CLOSE); + fDecorator->SetClose(_ActionFor(message) == DEC_CLOSE); } else if (fIsMinimizing) { - fDecorator->SetMinimize(_ActionFor(msg) == DEC_MINIMIZE); + fDecorator->SetMinimize(_ActionFor(message) == DEC_MINIMIZE); } fDrawingEngine->Unlock(); @@ -990,6 +988,8 @@ WindowLayer::MouseMoved(BMessage *msg, BPoint where, int32* _viewToken, // mouse cursor if (view != NULL) { + view->MouseMoved(message, where); + // TODO: there is more for real cursor support, ie. if a window is closed, // new app cursor shouldn't override view cursor, ... ServerWindow()->App()->SetCurrentCursor(view->Cursor()); diff --git a/src/servers/app/WorkspacesLayer.cpp b/src/servers/app/WorkspacesLayer.cpp index d135181921..f724deb9b5 100644 --- a/src/servers/app/WorkspacesLayer.cpp +++ b/src/servers/app/WorkspacesLayer.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2005, Haiku Inc. + * Copyright 2005-2006, Haiku Inc. * Distributed under the terms of the MIT License. * * Authors: @@ -21,8 +21,11 @@ WorkspacesLayer::WorkspacesLayer(BRect frame, const char* name, - int32 token, uint32 resizeMode, uint32 flags) - : ViewLayer(frame, name, token, resizeMode, flags) + int32 token, uint32 resizeMode, uint32 flags) + : ViewLayer(frame, name, token, resizeMode, flags), + fSelectedWindow(NULL), + fSelectedWorkspace(-1), + fHasMoved(false) { fDrawState->SetLowColor(RGBColor(255, 255, 255)); fDrawState->SetHighColor(RGBColor(0, 0, 0)); @@ -50,6 +53,28 @@ WorkspacesLayer::_GetGrid(int32& columns, int32& rows) } +/*! + \brief Returns the frame of the screen for the specified workspace. +*/ +BRect +WorkspacesLayer::_ScreenFrame(int32 i) +{ + // TODO: we don't need the current screen frame, but the one + // from the workspace! + uint16 width, height; + uint32 colorSpace; + float frequency; + Window()->Desktop()->ScreenAt(0)->GetMode(width, height, + colorSpace, frequency); + + return BRect(0, 0, width - 1, height - 1); +} + + +/*! + \brief Returns the frame of the specified workspace within the + workspaces layer. +*/ BRect WorkspacesLayer::_WorkspaceAt(int32 i) { @@ -76,6 +101,30 @@ WorkspacesLayer::_WorkspaceAt(int32 i) } +/*! + \brief Returns the workspace frame and index of the workspace + under \a where. + + If, for some reason, there is no workspace located under \where, + an empty rectangle is returned, and \a index is set to -1. +*/ +BRect +WorkspacesLayer::_WorkspaceAt(BPoint where, int32& index) +{ + int32 columns, rows; + _GetGrid(columns, rows); + + for (index = columns * rows; index-- > 0;) { + BRect workspaceFrame = _WorkspaceAt(index); + + if (workspaceFrame.Contains(where)) + return workspaceFrame; + } + + return BRect(); +} + + BRect WorkspacesLayer::_WindowFrame(const BRect& workspaceFrame, const BRect& screenFrame, const BRect& windowFrame, @@ -115,6 +164,8 @@ WorkspacesLayer::_DrawWindow(DrawingEngine* drawingEngine, const BRect& workspac tabFrame = _WindowFrame(workspaceFrame, screenFrame, tabFrame, tabFrame.LeftTop() - offset); + if (!workspaceFrame.Intersects(frame) && !workspaceFrame.Intersects(tabFrame)) + return; // ToDo: let decorator do this! RGBColor yellow; @@ -202,12 +253,7 @@ WorkspacesLayer::_DrawWorkspace(DrawingEngine* drawingEngine, // ToDo: would be nice to get the real update region here - uint16 width, height; - uint32 colorSpace; - float frequency; - Window()->Desktop()->ScreenAt(0)->GetMode(width, height, - colorSpace, frequency); - BRect screenFrame(0, 0, width - 1, height - 1); + BRect screenFrame = _ScreenFrame(index); BRegion workspaceRegion(rect); backgroundRegion.IntersectWith(&workspaceRegion); @@ -295,19 +341,161 @@ WorkspacesLayer::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, void WorkspacesLayer::MouseDown(BMessage* message, BPoint where) { - int32 columns, rows; - _GetGrid(columns, rows); + // reset tracking variables + fSelectedWorkspace = -1; + fSelectedWindow = NULL; + fHasMoved = false; - for (int32 i = columns * rows; i-- > 0;) { - BRect rect = _WorkspaceAt(i); + // check if the correct mouse button is pressed + int32 buttons; + if (message->FindInt32("buttons", &buttons) != B_OK + || (buttons & B_PRIMARY_MOUSE_BUTTON) == 0) + return; - if (rect.Contains(where)) { - Window()->Desktop()->SetWorkspace(i); - break; + int32 index; + BRect workspaceFrame = _WorkspaceAt(where, index); + if (index < 0) + return; + + Workspace workspace(*Window()->Desktop(), index); + workspaceFrame.InsetBy(1, 1); + + BRect screenFrame = _ScreenFrame(index); + + WindowLayer* window; + BPoint leftTop; + while (workspace.GetNextWindow(window, leftTop) == B_OK) { + BRect frame = _WindowFrame(workspaceFrame, screenFrame, window->Frame(), + leftTop); + if (frame.Contains(where) && window->Feel() != kDesktopWindowFeel) + fSelectedWindow = window; + } + + // Some special functionality (clicked with modifiers) + + int32 modifiers; + if (fSelectedWindow != NULL + && message->FindInt32("modifiers", &modifiers) == B_OK) { + if ((modifiers & B_CONTROL_KEY) != 0) { + // Activate window if clicked with the control key pressed, + // minimize it if control+shift - this mirrors Deskbar + // shortcuts (when pressing a team menu item). + if ((modifiers & B_SHIFT_KEY) != 0) + fSelectedWindow->ServerWindow()->NotifyMinimize(true); + else + Window()->Desktop()->ActivateWindow(fSelectedWindow); + fSelectedWindow = NULL; + } else if ((modifiers & B_OPTION_KEY) != 0) { + // Also, send window to back if clicked with the option + // key pressed. + Window()->Desktop()->SendWindowBehind(fSelectedWindow); + fSelectedWindow = NULL; } } - //ViewLayer::MouseDown(message, where, _viewToken); + // If this window is movable, we keep it selected + + if (fSelectedWindow != NULL && (fSelectedWindow->Flags() & B_NOT_MOVABLE) != 0) + fSelectedWindow = NULL; + + fSelectedWorkspace = index; + fLastMousePosition = where; +} + + +void +WorkspacesLayer::MouseUp(BMessage* message, BPoint where) +{ + if (!fHasMoved && fSelectedWorkspace >= 0) + Window()->Desktop()->SetWorkspace(fSelectedWorkspace); + + fSelectedWindow = NULL; +} + + +void +WorkspacesLayer::MouseMoved(BMessage* message, BPoint where) +{ + if (fSelectedWindow == NULL) + return; + + // check if the correct mouse button is pressed + int32 buttons; + if (message->FindInt32("buttons", &buttons) != B_OK + || (buttons & B_PRIMARY_MOUSE_BUTTON) == 0) + return; + + BPoint delta = where - fLastMousePosition; + if (delta.x == 0 && delta.y == 0) + return; + + Window()->Desktop()->SetMouseEventWindow(Window()); + // don't let us off the mouse + + int32 index; + BRect workspaceFrame = _WorkspaceAt(where, index); + workspaceFrame.InsetBy(1, 1); + + if (index != fSelectedWorkspace) { + return; +// TODO: the code below doesn't work yet... +#if 0 + if (!fSelectedWindow->InWorkspace(index) && fSelectedWindow->IsNormal()) { + // move window to this new workspace + uint32 newWorkspaces = fSelectedWindow->Workspaces() + & ~(1UL << fSelectedWorkspace) | (1UL << index); + + Window()->Desktop()->SetWindowWorkspaces(fSelectedWindow, + newWorkspaces); + + // move window to the correct location on this new workspace + // (preserve offset to window relative to the mouse) + + BRect screenFrame = _ScreenFrame(index); + BPoint leftTop = fSelectedWindow->Anchor(fSelectedWorkspace).position; + BRect windowFrame = _WindowFrame(workspaceFrame, screenFrame, + fSelectedWindow->Frame(), leftTop); + + BPoint delta = fLastMousePosition - windowFrame.LeftTop(); + delta.x = rintf(delta.x * screenFrame.Width() / workspaceFrame.Width()); + delta.y = rintf(delta.y * screenFrame.Height() / workspaceFrame.Height()); +printf("delta: %g, %g\n", delta.x, delta.y); + + // normalize position + // TODO: take the actual grid position into account!!! + + float left = leftTop.x + delta.x; + if (delta.x < 0) + left += screenFrame.Width(); + else if (screenFrame.Width() + delta.x > 0) + left -= screenFrame.Width(); + + float top = leftTop.y + delta.y; + if (delta.y < 0) + top += screenFrame.Height(); + else if (delta.y > 0) + top -= screenFrame.Height(); + +printf("new absolute position: %g, %g\n", left, top); + leftTop = fSelectedWindow->Anchor(index).position; + if (leftTop == kInvalidWindowPosition) + leftTop = fSelectedWindow->Anchor(fSelectedWorkspace).position; + + Window()->Desktop()->MoveWindowBy(fSelectedWindow, left - leftTop.x, + top - leftTop.y, index); + } + fSelectedWorkspace = index; +#endif + } + + BRect screenFrame = _ScreenFrame(index); + float deltaX = rintf(delta.x * screenFrame.Width() / workspaceFrame.Width()); + float deltaY = rintf(delta.y * screenFrame.Height() / workspaceFrame.Height()); + + fHasMoved = true; + Window()->Desktop()->MoveWindowBy(fSelectedWindow, deltaX, deltaY); + + fLastMousePosition += delta; } @@ -319,3 +507,11 @@ WorkspacesLayer::WindowChanged(WindowLayer* window) Window()->MarkContentDirty(region); } + +void +WorkspacesLayer::WindowRemoved(WindowLayer* window) +{ + if (fSelectedWindow == window) + fSelectedWindow = NULL; +} + diff --git a/src/servers/app/WorkspacesLayer.h b/src/servers/app/WorkspacesLayer.h index 1b4d99684c..a6af322d3a 100644 --- a/src/servers/app/WorkspacesLayer.h +++ b/src/servers/app/WorkspacesLayer.h @@ -1,5 +1,5 @@ /* - * Copyright 2005, Haiku Inc. + * Copyright 2005-2006, Haiku Inc. * Distributed under the terms of the MIT License. * * Authors: @@ -24,13 +24,19 @@ class WorkspacesLayer : public ViewLayer { BRegion* effectiveClipping, BRegion* windowContentClipping, bool deep = false); + virtual void MouseDown(BMessage* message, BPoint where); + virtual void MouseUp(BMessage* message, BPoint where); + virtual void MouseMoved(BMessage* message, BPoint where); void WindowChanged(WindowLayer* window); + void WindowRemoved(WindowLayer* window); private: void _GetGrid(int32& columns, int32& rows); - BRect _WorkspaceAt(int32 i); + BRect _ScreenFrame(int32 index); + BRect _WorkspaceAt(int32 index); + BRect _WorkspaceAt(BPoint where, int32& index); BRect _WindowFrame(const BRect& workspaceFrame, const BRect& screenFrame, const BRect& windowFrame, BPoint windowPosition); @@ -43,6 +49,12 @@ class WorkspacesLayer : public ViewLayer { int32 index); void _DarkenColor(RGBColor& color) const; + + private: + WindowLayer* fSelectedWindow; + int32 fSelectedWorkspace; + bool fHasMoved; + BPoint fLastMousePosition; }; #endif // WORKSPACES_LAYER_H