Author: czeidler Date: 2010-06-08 00:14:16 +0200 (Tue, 08 Jun 2010) New Revision: 37053 Changeset: http://dev.haiku-os.org/changeset/37053/haiku Added: haiku/branches/features/stack-and-tile/src/servers/app/DefaultWindowBehaviour.cpp haiku/branches/features/stack-and-tile/src/servers/app/DefaultWindowBehaviour.h haiku/branches/features/stack-and-tile/src/servers/app/WindowBehaviour.cpp haiku/branches/features/stack-and-tile/src/servers/app/WindowBehaviour.h Modified: haiku/branches/features/stack-and-tile/src/servers/app/Jamfile haiku/branches/features/stack-and-tile/src/servers/app/Window.cpp haiku/branches/features/stack-and-tile/src/servers/app/Window.h Log: Introduce a new WindowBehaviour class as proposed by Ryan and Stippi. This class handle decorator events, e.g. mouse down/up/moved and translate them into the according actions. Added: haiku/branches/features/stack-and-tile/src/servers/app/DefaultWindowBehaviour.cpp =================================================================== --- haiku/branches/features/stack-and-tile/src/servers/app/DefaultWindowBehaviour.cpp (rev 0) +++ haiku/branches/features/stack-and-tile/src/servers/app/DefaultWindowBehaviour.cpp 2010-06-07 22:14:16 UTC (rev 37053) @@ -0,0 +1,505 @@ +#include "DefaultWindowBehaviour.h" + +#include "Desktop.h" +#include "DrawingEngine.h" +#include "Window.h" + + +//#define DEBUG_WINDOW_CLICK + +#ifdef DEBUG_WINDOW_CLICK +# define STRACE_CLICK(x) printf x +#else +# define STRACE_CLICK(x) ; +#endif + + +DefaultWindowBehaviour::DefaultWindowBehaviour(Window* window, + Decorator* decorator) + : + fWindow(window), + fDecorator(decorator), + + fIsClosing(false), + fIsMinimizing(false), + fIsZooming(false), + fIsSlidingTab(false), + fActivateOnMouseUp(false), + + fLastMousePosition(0.0f, 0.0f), + fMouseMoveDistance(0.0f), + fLastMoveTime(0), + fLastSnapTime(0) +{ + fDesktop = fWindow->Desktop(); +} + + +DefaultWindowBehaviour::~DefaultWindowBehaviour() +{ + +} + + +static const bigtime_t kWindowActivationTimeout = 500000LL; + + +bool +DefaultWindowBehaviour::MouseDown(BMessage* message, BPoint where) +{ + int32 modifiers = _ExtractModifiers(message); + bool inBorderRegion = fWindow->BorderRegion().Contains(where); + bool windowModifier = + (fWindow->Flags() & B_NO_SERVER_SIDE_WINDOW_MODIFIERS) == 0 + && (modifiers & (B_COMMAND_KEY | B_CONTROL_KEY | B_OPTION_KEY + | B_SHIFT_KEY)) == (B_COMMAND_KEY | B_CONTROL_KEY); + click_type action = CLICK_NONE; + + if (windowModifier || inBorderRegion) { + // clicking Window visible area + + int32 buttons = _ExtractButtons(message); + + if (inBorderRegion) + action = _ActionFor(message, buttons, modifiers); + else { + if ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0) + action = CLICK_MOVE_TO_BACK; + else if ((fWindow->Flags() & B_NOT_MOVABLE) == 0 + && fDecorator != NULL) + action = CLICK_DRAG; + else { + // pass click on to the application + windowModifier = false; + } + } + } + + DesktopSettings desktopSettings(fDesktop); + if (windowModifier || inBorderRegion) { + if (!desktopSettings.AcceptFirstClick()) { + // Ignore clicks on decorator buttons if the + // non-floating window doesn't have focus + if (!fWindow->IsFocus() && !fWindow->IsFloating() + && action != CLICK_MOVE_TO_BACK + && action != CLICK_RESIZE && action != CLICK_SLIDE_TAB) + action = CLICK_DRAG; + } + + // set decorator internals + switch (action) { + case CLICK_CLOSE: + fIsClosing = true; + STRACE_CLICK(("===> CLICK_CLOSE\n")); + break; + + case CLICK_ZOOM: + fIsZooming = true; + STRACE_CLICK(("===> CLICK_ZOOM\n")); + break; + + case CLICK_MINIMIZE: + if ((fWindow->Flags() & B_NOT_MINIMIZABLE) == 0) { + fIsMinimizing = true; + STRACE_CLICK(("===> CLICK_MINIMIZE\n")); + } + break; + + case CLICK_DRAG: + fIsDragging = true; + fLastMousePosition = where; + STRACE_CLICK(("===> CLICK_DRAG\n")); + break; + + case CLICK_RESIZE: + fIsResizing = true; + fLastMousePosition = where; + STRACE_CLICK(("===> CLICK_RESIZE\n")); + break; + + case CLICK_SLIDE_TAB: + fIsSlidingTab = true; + fLastMousePosition = where; + STRACE_CLICK(("===> CLICK_SLIDE_TAB\n")); + break; + + default: + break; + } + + if (fDecorator != NULL) { + // redraw decorator + BRegion* visibleBorder = fWindow->RegionPool()->GetRegion(); + fWindow->GetBorderRegion(visibleBorder); + visibleBorder->IntersectWith(&fWindow->VisibleRegion()); + + DrawingEngine* engine = fDecorator->GetDrawingEngine(); + engine->LockParallelAccess(); + engine->ConstrainClippingRegion(visibleBorder); + + if (fIsZooming) + fDecorator->SetZoom(true); + else if (fIsClosing) + fDecorator->SetClose(true); + else if (fIsMinimizing) + fDecorator->SetMinimize(true); + + engine->UnlockParallelAccess(); + + fWindow->RegionPool()->Recycle(visibleBorder); + } + + if (action == CLICK_MOVE_TO_BACK) { + if (desktopSettings.MouseMode() == B_CLICK_TO_FOCUS_MOUSE) { + bool covered = true; + BRegion fullRegion; + fWindow->GetFullRegion(&fullRegion); + if (fullRegion == fWindow->VisibleRegion()) { + // window is overlapped. + covered = false; + } + if (fWindow != fDesktop->FrontWindow() && covered) + fDesktop->ActivateWindow(fWindow); + else + fDesktop->SendWindowBehind(fWindow); + } else + fDesktop->SendWindowBehind(fWindow); + } else { + fDesktop->SetMouseEventWindow(fWindow); + + // activate window if in click to activate mode, else only focus it + if (desktopSettings.MouseMode() == B_NORMAL_MOUSE) + fDesktop->ActivateWindow(fWindow); + else { + fDesktop->SetFocusWindow(fWindow); + if (desktopSettings.MouseMode() == B_FOCUS_FOLLOWS_MOUSE + && (action == CLICK_DRAG || action == CLICK_RESIZE)) { + fActivateOnMouseUp = true; + fMouseMoveDistance = 0.0f; + fLastMoveTime = system_time(); + } + } + } + + return true; + } + return false; +} + + +void +DefaultWindowBehaviour::MouseUp(BMessage* message, BPoint where) +{ + bool invalidate = false; + if (fDecorator) { + click_type action = _ActionFor(message); + + // redraw decorator + BRegion* visibleBorder = fWindow->RegionPool()->GetRegion(); + fWindow->GetBorderRegion(visibleBorder); + visibleBorder->IntersectWith(&fWindow->VisibleRegion()); + + DrawingEngine* engine = fDecorator->GetDrawingEngine(); + engine->LockParallelAccess(); + engine->ConstrainClippingRegion(visibleBorder); + + if (fIsZooming) { + fIsZooming = false; + fDecorator->SetZoom(false); + if (action == CLICK_ZOOM) { + invalidate = true; + fWindow->ServerWindow()->NotifyZoom(); + } + } + if (fIsClosing) { + fIsClosing = false; + fDecorator->SetClose(false); + if (action == CLICK_CLOSE) { + invalidate = true; + fWindow->ServerWindow()->NotifyQuitRequested(); + } + } + if (fIsMinimizing) { + fIsMinimizing = false; + fDecorator->SetMinimize(false); + if (action == CLICK_MINIMIZE) { + invalidate = true; + fWindow->ServerWindow()->NotifyMinimize(true); + } + } + + engine->UnlockParallelAccess(); + + fWindow->RegionPool()->Recycle(visibleBorder); + + int32 buttons; + if (message->FindInt32("buttons", &buttons) != B_OK) + buttons = 0; + + // if the primary mouse button is released, stop + // dragging/resizing/sliding + if ((buttons & B_PRIMARY_MOUSE_BUTTON) == 0) { + fIsDragging = false; + fIsResizing = false; + fIsSlidingTab = false; + } + } + + // in FFM mode, activate the window and bring it + // to front in case this was a drag click but the + // mouse was not moved + if (fActivateOnMouseUp) { + fActivateOnMouseUp = false; + // on R5, there is a time window for this feature + // ie, click and press too long, nothing will happen + if (system_time() - fLastMoveTime < kWindowActivationTimeout) + fDesktop->ActivateWindow(fWindow); + } +} + + +void +DefaultWindowBehaviour::MouseMoved(BMessage *message, BPoint where, bool isFake) +{ + #if 0 + if (fDecorator != NULL && fTopView != NULL) { + DrawingEngine* engine = fDecorator->GetDrawingEngine(); + engine->LockParallelAccess(); + engine->ConstrainClippingRegion(&VisibleRegion()); + + fTopView->MarkAt(engine, where); + engine->UnlockParallelAccess(); + } + #endif + // limit the rate at which "mouse moved" events + // are handled that move or resize the window + bigtime_t now = 0; + if (fIsDragging || fIsResizing) { + now = system_time(); + if (now - fLastMoveTime < 13333) { + // TODO: add a "timed event" to query for + // the then current mouse position + return; + } + if (fActivateOnMouseUp) { + if (now - fLastMoveTime >= kWindowActivationTimeout) { + // This click is too long already for window activation. + fActivateOnMouseUp = false; + } + } else + fLastMoveTime = now; + } + + if (fDecorator) { + BRegion* visibleBorder = fWindow->RegionPool()->GetRegion(); + fWindow->GetBorderRegion(visibleBorder); + visibleBorder->IntersectWith(&fWindow->VisibleRegion()); + + DrawingEngine* engine = fDecorator->GetDrawingEngine(); + engine->LockParallelAccess(); + engine->ConstrainClippingRegion(visibleBorder); + + if (fIsZooming) { + fDecorator->SetZoom(_ActionFor(message) == CLICK_ZOOM); + } else if (fIsClosing) { + fDecorator->SetClose(_ActionFor(message) == CLICK_CLOSE); + } else if (fIsMinimizing) { + fDecorator->SetMinimize(_ActionFor(message) == CLICK_MINIMIZE); + } + + engine->UnlockParallelAccess(); + fWindow->RegionPool()->Recycle(visibleBorder); + } + + BPoint delta = where - fLastMousePosition; + // NOTE: "delta" is later used to change fLastMousePosition. + // If for some reason no change should take effect, delta + // is to be set to (0, 0) so that fLastMousePosition is not + // adjusted. This way the relative mouse position to the + // item being changed (border during resizing, tab during + // sliding...) stays fixed when the mouse is moved so that + // changes are taking effect again. + + // If the window was moved enough, it doesn't come to + // the front in FFM mode when the mouse is released. + if (fActivateOnMouseUp) { + fMouseMoveDistance += delta.x * delta.x + delta.y * delta.y; + if (fMouseMoveDistance > 16.0f) + fActivateOnMouseUp = false; + else + delta = B_ORIGIN; + } + + // moving + if (fIsDragging) { + if (!(fWindow->Flags() & B_NOT_MOVABLE)) { + BPoint oldLeftTop = fWindow->Frame().LeftTop(); + + _AlterDeltaForSnap(delta, now); + fDesktop->MoveWindowBy(fWindow, delta.x, delta.y); + + // constrain delta to true change in position + delta = fWindow->Frame().LeftTop() - oldLeftTop; + } else + delta = BPoint(0, 0); + } + // resizing + if (fIsResizing) { + if (!(fWindow->Flags() & B_NOT_RESIZABLE)) { + if (fWindow->Flags() & B_NOT_V_RESIZABLE) + delta.y = 0; + if (fWindow->Flags() & B_NOT_H_RESIZABLE) + delta.x = 0; + + BPoint oldRightBottom = fWindow->Frame().RightBottom(); + + fDesktop->ResizeWindowBy(fWindow, delta.x, delta.y); + + // constrain delta to true change in size + delta = fWindow->Frame().RightBottom() - oldRightBottom; + } else + delta = BPoint(0, 0); + } + // sliding tab + if (fIsSlidingTab) { + float loc = fWindow->TabLocation(); + // TODO: change to [0:1] + loc += delta.x; + if (fDesktop->SetWindowTabLocation(fWindow, loc)) + delta.y = 0; + else + delta = BPoint(0, 0); + } + + // NOTE: fLastMousePosition is currently only + // used for window moving/resizing/sliding the tab + fLastMousePosition += delta; + + // change focus in FFM mode + DesktopSettings desktopSettings(fDesktop); + if (desktopSettings.FocusFollowsMouse() + && !fWindow->IsFocus() && !(fWindow->Flags() & B_AVOID_FOCUS)) { + // If the mouse move is a fake one, we set the focus to NULL, which + // will cause the window that had focus last to retrieve it again - this + // makes FFM much nicer to use with the keyboard. + fDesktop->SetFocusWindow(isFake ? NULL : fWindow); + } +} + + +int32 +DefaultWindowBehaviour::_ExtractButtons(const BMessage* message) const +{ + int32 buttons; + if (message->FindInt32("buttons", &buttons) != B_OK) + buttons = 0; + return buttons; +} + + +int32 +DefaultWindowBehaviour::_ExtractModifiers(const BMessage* message) const +{ + int32 modifiers; + if (message->FindInt32("modifiers", &modifiers) != B_OK) + modifiers = 0; + return modifiers; +} + + +click_type +DefaultWindowBehaviour::_ActionFor(const BMessage* message) const +{ + if (fDecorator == NULL) + return CLICK_NONE; + + int32 buttons = _ExtractButtons(message); + int32 modifiers = _ExtractModifiers(message); + return _ActionFor(message, buttons, modifiers); +} + + +click_type +DefaultWindowBehaviour::_ActionFor(const BMessage* message, int32 buttons, + int32 modifiers) const +{ + if (fDecorator == NULL) + return CLICK_NONE; + + BPoint where; + if (message->FindPoint("where", &where) != B_OK) + return CLICK_NONE; + + return fDecorator->Clicked(where, buttons, modifiers); +} + + +void +DefaultWindowBehaviour::_AlterDeltaForSnap(BPoint& delta, bigtime_t now) +{ + // Alter the delta (which is a proposed offset used while dragging a + // window) so that the frame of the window 'snaps' to the edges of the + // screen. + + const bigtime_t kSnappingDuration = 1500000LL; + const bigtime_t kSnappingPause = 3000000LL; + const float kSnapDistance = 8.0f; + + if (now - fLastSnapTime > kSnappingDuration + && now - fLastSnapTime < kSnappingPause) { + // Maintain a pause between snapping. + return; + } + + BRect frame = fWindow->Frame(); + BPoint offsetWithinFrame; + // TODO: Perhaps obtain the usable area (not covered by the Deskbar)? + BRect screenFrame = fWindow->Screen()->Frame(); + + if (fDecorator) { + BRegion reg; + fDecorator->GetFootprint(®); + frame = reg.Frame(); + offsetWithinFrame.x = fWindow->Frame().left - frame.left; + offsetWithinFrame.y = fWindow->Frame().top - frame.top; + } + + frame.OffsetBy(delta); + + float leftDist = fabs(frame.left - screenFrame.left); + float topDist = fabs(frame.top - screenFrame.top); + float rightDist = fabs(frame.right - screenFrame.right); + float bottomDist = fabs(frame.bottom - screenFrame.bottom); + + bool snapped = false; + if (leftDist < kSnapDistance || rightDist < kSnapDistance) { + snapped = true; + if (leftDist < rightDist) { + frame.right -= frame.left; + frame.left = 0.0f; + } else { + frame.left -= frame.right - screenFrame.right; + frame.right = screenFrame.right; + } + } + + if (topDist < kSnapDistance || bottomDist < kSnapDistance) { + snapped = true; + if (topDist < bottomDist) { + frame.bottom -= frame.top; + frame.top = 0.0f; + } else { + frame.top -= frame.bottom - screenFrame.bottom; + frame.bottom = screenFrame.bottom; + } + } + if (snapped && now - fLastSnapTime > kSnappingPause) + fLastSnapTime = now; + + + frame.top += offsetWithinFrame.y; + frame.left += offsetWithinFrame.x; + + delta.y = frame.top - fWindow->Frame().top; + delta.x = frame.left - fWindow->Frame().left; +} Added: haiku/branches/features/stack-and-tile/src/servers/app/DefaultWindowBehaviour.h =================================================================== --- haiku/branches/features/stack-and-tile/src/servers/app/DefaultWindowBehaviour.h (rev 0) +++ haiku/branches/features/stack-and-tile/src/servers/app/DefaultWindowBehaviour.h 2010-06-07 22:14:16 UTC (rev 37053) @@ -0,0 +1,54 @@ +#ifndef DEFAULT_WINDOW_BEHAVIOUR_H +#define DEFAULT_WINDOW_BEHAVIOUR_H + + +#include "WindowBehaviour.h" + +#include "Decorator.h" + + +class Desktop; +class Window; + + +class DefaultWindowBehaviour : public WindowBehaviour +{ + public: + DefaultWindowBehaviour(Window* window, + Decorator* decorator); + virtual ~DefaultWindowBehaviour(); + + virtual bool MouseDown(BMessage* message, BPoint where); + virtual void MouseUp(BMessage* message, BPoint where); + virtual void MouseMoved(BMessage *message, BPoint where, + bool isFake); + + protected: + Window* fWindow; + Decorator* fDecorator; + Desktop* fDesktop; + + bool fIsClosing : 1; + bool fIsMinimizing : 1; + bool fIsZooming : 1; + bool fIsSlidingTab : 1; + bool fActivateOnMouseUp : 1; + + BPoint fLastMousePosition; + float fMouseMoveDistance; + bigtime_t fLastMoveTime; + bigtime_t fLastSnapTime; + + private: + int32 _ExtractButtons(const BMessage* message) const; + int32 _ExtractModifiers(const BMessage* message) const; + click_type _ActionFor(const BMessage* message) const; + click_type _ActionFor(const BMessage* message, int32 buttons, + int32 modifiers) const; + + void _AlterDeltaForSnap(BPoint& delta, + bigtime_t now); +}; + + +#endif Modified: haiku/branches/features/stack-and-tile/src/servers/app/Jamfile =================================================================== --- haiku/branches/features/stack-and-tile/src/servers/app/Jamfile 2010-06-07 21:17:49 UTC (rev 37052) +++ haiku/branches/features/stack-and-tile/src/servers/app/Jamfile 2010-06-07 22:14:16 UTC (rev 37053) @@ -22,6 +22,7 @@ DecorManager.cpp Decorator.cpp DefaultDecorator.cpp + DefaultWindowBehaviour.cpp Desktop.cpp DesktopSettings.cpp DirectWindowInfo.cpp @@ -61,6 +62,7 @@ View.cpp VirtualScreen.cpp Window.cpp + WindowBehaviour.cpp WindowList.cpp Workspace.cpp WorkspacesView.cpp Modified: haiku/branches/features/stack-and-tile/src/servers/app/Window.cpp =================================================================== --- haiku/branches/features/stack-and-tile/src/servers/app/Window.cpp 2010-06-07 21:17:49 UTC (rev 37052) +++ haiku/branches/features/stack-and-tile/src/servers/app/Window.cpp 2010-06-07 22:14:16 UTC (rev 37053) @@ -16,12 +16,14 @@ #include "Decorator.h" #include "DecorManager.h" #include "Desktop.h" +#include "DefaultWindowBehaviour.h" #include "DrawingEngine.h" #include "HWInterface.h" #include "MessagePrivate.h" #include "PortLink.h" #include "ServerApp.h" #include "ServerWindow.h" +#include "WindowBehaviour.h" #include "Workspace.h" #include "WorkspacesView.h" @@ -39,7 +41,6 @@ // Toggle debug output //#define DEBUG_WINDOW -//#define DEBUG_WINDOW_CLICK #ifdef DEBUG_WINDOW # define STRACE(x) printf x @@ -47,12 +48,6 @@ # define STRACE(x) ; #endif -#ifdef DEBUG_WINDOW_CLICK -# define STRACE_CLICK(x) printf x -#else -# define STRACE_CLICK(x) ; -#endif - // IMPORTANT: nested LockSingleWindow()s are not supported (by MultiLocker) using std::nothrow; @@ -96,25 +91,13 @@ fRegionPool(), - fIsClosing(false), - fIsMinimizing(false), - fIsZooming(false), - fIsResizing(false), - fIsSlidingTab(false), - fIsDragging(false), - fActivateOnMouseUp(false), - + fWindowBehaviour(NULL), fDecorator(NULL), fTopView(NULL), fWindow(window), fDrawingEngine(drawingEngine), fDesktop(window->Desktop()), - fLastMousePosition(0.0f, 0.0f), - fMouseMoveDistance(0.0f), - fLastMoveTime(0), - fLastSnapTime(0), - fCurrentUpdateSession(&fUpdateSessions[0]), fPendingUpdateSession(&fUpdateSessions[1]), fUpdateRequested(false), @@ -154,6 +137,7 @@ &fMaxWidth, &fMaxHeight); } } + fWindowBehaviour = new DefaultWindowBehaviour(this, fDecorator); // do we need to change our size to let the decorator fit? // _ResizeBy() will adapt the frame for validity before resizing @@ -196,7 +180,7 @@ status_t Window::InitCheck() const { - if (!fDrawingEngine) + if (!fDrawingEngine || !fWindowBehaviour) return B_NO_MEMORY; // TODO: anything else? return B_OK; @@ -775,9 +759,6 @@ // #pragma mark - -static const bigtime_t kWindowActivationTimeout = 500000LL; - - void Window::MouseDown(BMessage* message, BPoint where, int32* _viewToken) { @@ -787,136 +768,8 @@ if (!fBorderRegionValid) GetBorderRegion(&fBorderRegion); - int32 modifiers = _ExtractModifiers(message); - bool inBorderRegion = fBorderRegion.Contains(where); - bool windowModifier = (fFlags & B_NO_SERVER_SIDE_WINDOW_MODIFIERS) == 0 - && (modifiers & (B_COMMAND_KEY | B_CONTROL_KEY | B_OPTION_KEY - | B_SHIFT_KEY)) == (B_COMMAND_KEY | B_CONTROL_KEY); - click_type action = CLICK_NONE; - - if (windowModifier || inBorderRegion) { - // clicking Window visible area - - int32 buttons = _ExtractButtons(message); - - if (inBorderRegion) - action = _ActionFor(message, buttons, modifiers); - else { - if ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0) - action = CLICK_MOVE_TO_BACK; - else if ((fFlags & B_NOT_MOVABLE) == 0 && fDecorator != NULL) - action = CLICK_DRAG; - else { - // pass click on to the application - windowModifier = false; - } - } - } - - if (windowModifier || inBorderRegion) { - if (!desktopSettings.AcceptFirstClick()) { - // Ignore clicks on decorator buttons if the - // non-floating window doesn't have focus - if (!IsFocus() && !IsFloating() && action != CLICK_MOVE_TO_BACK - && action != CLICK_RESIZE && action != CLICK_SLIDE_TAB) - action = CLICK_DRAG; - } - - // set decorator internals - switch (action) { - case CLICK_CLOSE: - fIsClosing = true; - STRACE_CLICK(("===> CLICK_CLOSE\n")); - break; - - case CLICK_ZOOM: - fIsZooming = true; - STRACE_CLICK(("===> CLICK_ZOOM\n")); - break; - - case CLICK_MINIMIZE: - if ((Flags() & B_NOT_MINIMIZABLE) == 0) { - fIsMinimizing = true; - STRACE_CLICK(("===> CLICK_MINIMIZE\n")); - } - break; - - case CLICK_DRAG: - fIsDragging = true; - fLastMousePosition = where; - STRACE_CLICK(("===> CLICK_DRAG\n")); - break; - - case CLICK_RESIZE: - fIsResizing = true; - fLastMousePosition = where; - STRACE_CLICK(("===> CLICK_RESIZE\n")); - break; - - case CLICK_SLIDE_TAB: - fIsSlidingTab = true; - fLastMousePosition = where; - STRACE_CLICK(("===> CLICK_SLIDE_TAB\n")); - break; - - default: - break; - } - - if (fDecorator != NULL) { - // redraw decorator - BRegion* visibleBorder = fRegionPool.GetRegion(); - GetBorderRegion(visibleBorder); - visibleBorder->IntersectWith(&VisibleRegion()); - - DrawingEngine* engine = fDecorator->GetDrawingEngine(); - engine->LockParallelAccess(); - engine->ConstrainClippingRegion(visibleBorder); - - if (fIsZooming) - fDecorator->SetZoom(true); - else if (fIsClosing) - fDecorator->SetClose(true); - else if (fIsMinimizing) - fDecorator->SetMinimize(true); - - engine->UnlockParallelAccess(); - - fRegionPool.Recycle(visibleBorder); - } - - if (action == CLICK_MOVE_TO_BACK) { - if (desktopSettings.MouseMode() == B_CLICK_TO_FOCUS_MOUSE) { - bool covered = true; - BRegion fullRegion; - GetFullRegion(&fullRegion); - if (fullRegion == VisibleRegion()) { - // window is overlapped. - covered = false; - } - if (this != fDesktop->FrontWindow() && covered) - fDesktop->ActivateWindow(this); - else - fDesktop->SendWindowBehind(this); - } else - fDesktop->SendWindowBehind(this); - } else { - fDesktop->SetMouseEventWindow(this); - - // activate window if in click to activate mode, else only focus it - if (desktopSettings.MouseMode() == B_NORMAL_MOUSE) - fDesktop->ActivateWindow(this); - else { - fDesktop->SetFocusWindow(this); - if (desktopSettings.MouseMode() == B_FOCUS_FOLLOWS_MOUSE - && (action == CLICK_DRAG || action == CLICK_RESIZE)) { - fActivateOnMouseUp = true; - fMouseMoveDistance = 0.0f; - fLastMoveTime = system_time(); - } - } - } - } else { + bool eventEaten = fWindowBehaviour->MouseDown(message, where); + if (!eventEaten) { // click was inside the window contents if (View* view = ViewAt(where)) { if (HasModal()) @@ -957,72 +810,8 @@ void Window::MouseUp(BMessage* message, BPoint where, int32* _viewToken) { - bool invalidate = false; - if (fDecorator) { - click_type action = _ActionFor(message); + fWindowBehaviour->MouseUp(message, where); - // redraw decorator - BRegion* visibleBorder = fRegionPool.GetRegion(); - GetBorderRegion(visibleBorder); - visibleBorder->IntersectWith(&VisibleRegion()); - - DrawingEngine* engine = fDecorator->GetDrawingEngine(); - engine->LockParallelAccess(); - engine->ConstrainClippingRegion(visibleBorder); - - if (fIsZooming) { - fIsZooming = false; - fDecorator->SetZoom(false); - if (action == CLICK_ZOOM) { - invalidate = true; - fWindow->NotifyZoom(); - } - } - if (fIsClosing) { - fIsClosing = false; - fDecorator->SetClose(false); - if (action == CLICK_CLOSE) { - invalidate = true; - fWindow->NotifyQuitRequested(); - } - } - if (fIsMinimizing) { - fIsMinimizing = false; - fDecorator->SetMinimize(false); - if (action == CLICK_MINIMIZE) { - invalidate = true; - fWindow->NotifyMinimize(true); - } - } - - engine->UnlockParallelAccess(); - - fRegionPool.Recycle(visibleBorder); - - int32 buttons; - if (message->FindInt32("buttons", &buttons) != B_OK) - buttons = 0; - - // if the primary mouse button is released, stop - // dragging/resizing/sliding - if ((buttons & B_PRIMARY_MOUSE_BUTTON) == 0) { - fIsDragging = false; - fIsResizing = false; - fIsSlidingTab = false; - } - } - - // in FFM mode, activate the window and bring it - // to front in case this was a drag click but the - // mouse was not moved - if (fActivateOnMouseUp) { - fActivateOnMouseUp = false; - // on R5, there is a time window for this feature - // ie, click and press too long, nothing will happen - if (system_time() - fLastMoveTime < kWindowActivationTimeout) - fDesktop->ActivateWindow(this); - } - if (View* view = ViewAt(where)) { if (HasModal()) return; @@ -1037,17 +826,6 @@ Window::MouseMoved(BMessage *message, BPoint where, int32* _viewToken, bool isLatestMouseMoved, bool isFake) { -#if 0 - if (fDecorator != NULL && fTopView != NULL) { - DrawingEngine* engine = fDecorator->GetDrawingEngine(); - engine->LockParallelAccess(); - engine->ConstrainClippingRegion(&VisibleRegion()); - - fTopView->MarkAt(engine, where); - engine->UnlockParallelAccess(); - } -#endif - View* view = ViewAt(where); if (view != NULL) *_viewToken = view->Token(); @@ -1056,120 +834,8 @@ if (!isLatestMouseMoved) return; - // limit the rate at which "mouse moved" events - // are handled that move or resize the window - bigtime_t now = 0; - if (fIsDragging || fIsResizing) { - now = system_time(); - if (now - fLastMoveTime < 13333) { - // TODO: add a "timed event" to query for - // the then current mouse position - return; - } - if (fActivateOnMouseUp) { - if (now - fLastMoveTime >= kWindowActivationTimeout) { - // This click is too long already for window activation. - fActivateOnMouseUp = false; - } - } else - fLastMoveTime = now; - } + fWindowBehaviour->MouseMoved(message, where, isFake); - if (fDecorator) { - BRegion* visibleBorder = fRegionPool.GetRegion(); - GetBorderRegion(visibleBorder); - visibleBorder->IntersectWith(&VisibleRegion()); - - DrawingEngine* engine = fDecorator->GetDrawingEngine(); - engine->LockParallelAccess(); - engine->ConstrainClippingRegion(visibleBorder); - - if (fIsZooming) { - fDecorator->SetZoom(_ActionFor(message) == CLICK_ZOOM); - } else if (fIsClosing) { - fDecorator->SetClose(_ActionFor(message) == CLICK_CLOSE); - } else if (fIsMinimizing) { - fDecorator->SetMinimize(_ActionFor(message) == CLICK_MINIMIZE); - } - - engine->UnlockParallelAccess(); - fRegionPool.Recycle(visibleBorder); - } - - BPoint delta = where - fLastMousePosition; - // NOTE: "delta" is later used to change fLastMousePosition. - // If for some reason no change should take effect, delta - // is to be set to (0, 0) so that fLastMousePosition is not - // adjusted. This way the relative mouse position to the - // item being changed (border during resizing, tab during - // sliding...) stays fixed when the mouse is moved so that - // changes are taking effect again. - - // If the window was moved enough, it doesn't come to - // the front in FFM mode when the mouse is released. - if (fActivateOnMouseUp) { - fMouseMoveDistance += delta.x * delta.x + delta.y * delta.y; - if (fMouseMoveDistance > 16.0f) - fActivateOnMouseUp = false; - else - delta = B_ORIGIN; - } - - // moving - if (fIsDragging) { - if (!(Flags() & B_NOT_MOVABLE)) { - BPoint oldLeftTop = fFrame.LeftTop(); - - _AlterDeltaForSnap(delta, now); - fDesktop->MoveWindowBy(this, delta.x, delta.y); - - // constrain delta to true change in position - delta = fFrame.LeftTop() - oldLeftTop; - } else - delta = BPoint(0, 0); - } - // resizing - if (fIsResizing) { - if (!(Flags() & B_NOT_RESIZABLE)) { - if (Flags() & B_NOT_V_RESIZABLE) - delta.y = 0; - if (Flags() & B_NOT_H_RESIZABLE) [... truncated: 338 lines follow ...]