[haiku-commits] r39608 - haiku/trunk/src/servers/app

  • From: ingo_weinhold@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Wed, 24 Nov 2010 17:17:32 +0100 (CET)

Author: bonefish
Date: 2010-11-24 17:17:32 +0100 (Wed, 24 Nov 2010)
New Revision: 39608
Changeset: http://dev.haiku-os.org/changeset/39608

Modified:
   haiku/trunk/src/servers/app/DefaultWindowBehaviour.cpp
   haiku/trunk/src/servers/app/DefaultWindowBehaviour.h
Log:
* Refactored the MouseMoved(), MouseUp(), and part of the MouseDown() code
  into newly introduced state classes.
* Fixed the right-click-while dragging behavior, I broke in r39602.


Modified: haiku/trunk/src/servers/app/DefaultWindowBehaviour.cpp
===================================================================
--- haiku/trunk/src/servers/app/DefaultWindowBehaviour.cpp      2010-11-24 
14:50:07 UTC (rev 39607)
+++ haiku/trunk/src/servers/app/DefaultWindowBehaviour.cpp      2010-11-24 
16:17:32 UTC (rev 39608)
@@ -34,51 +34,484 @@
 static const bigtime_t kWindowActivationTimeout = 500000LL;
 
 
+// #pragma mark - State
+
+
+struct DefaultWindowBehaviour::State {
+       State(DefaultWindowBehaviour& behavior)
+               :
+               fBehavior(behavior),
+               fWindow(behavior.fWindow),
+               fDesktop(behavior.fDesktop)
+       {
+       }
+
+       virtual ~State()
+       {
+       }
+
+       virtual void EnterState(State* previousState)
+       {
+       }
+
+       virtual bool MouseDown(BMessage* message, BPoint where)
+       {
+               return false;
+       }
+
+       virtual void MouseUp(BMessage* message, BPoint where)
+       {
+       }
+
+       virtual void MouseMoved(BMessage* message, BPoint where, bool isFake)
+       {
+       }
+
+       void UpateFFMFocus(bool isFake)
+       {
+               // 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);
+               }
+       }
+
+protected:
+       DefaultWindowBehaviour& fBehavior;
+       Window*                                 fWindow;
+       Desktop*                                fDesktop;
+};
+
+
+// #pragma mark - MouseTrackingState
+
+
+struct DefaultWindowBehaviour::MouseTrackingState : State {
+       MouseTrackingState(DefaultWindowBehaviour& behavior, BPoint where,
+               bool activateOnMouseUp, bool minimizeCheckOnMouseUp)
+               :
+               State(behavior),
+               fActivateOnMouseUp(activateOnMouseUp),
+               fMinimizeCheckOnMouseUp(minimizeCheckOnMouseUp),
+               fLastMousePosition(where),
+               fMouseMoveDistance(0),
+               fLastMoveTime(system_time())
+       {
+       }
+
+       virtual void MouseUp(BMessage* message, BPoint where)
+       {
+               // ignore, if it's not the primary mouse button
+               int32 buttons = message->FindInt32("buttons");
+               if ((buttons & B_PRIMARY_MOUSE_BUTTON) != 0)
+                       return;
+
+               if (fMinimizeCheckOnMouseUp) {
+                       // If the modifiers haven't changed in the meantime and 
not too
+                       // much time has elapsed, we're supposed to minimize 
the window.
+                       fMinimizeCheckOnMouseUp = false;
+                       if (message->FindInt32("modifiers") == 
fBehavior.fLastModifiers
+                               && (fWindow->Flags() & B_NOT_MINIMIZABLE) == 0
+                               && system_time() - fLastMoveTime
+                                       < kWindowActivationTimeout) {
+                               fWindow->ServerWindow()->NotifyMinimize(true);
+                       }
+               }
+
+               // 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);
+               }
+
+               fBehavior._NextState(NULL);
+       }
+
+       virtual void MouseMoved(BMessage* message, BPoint where, bool isFake)
+       {
+               // Limit the rate at which "mouse moved" events are handled 
that move
+               // or resize the window. At the moment this affects also tab 
sliding,
+               // but 1/75 s is a pretty fine granularity anyway, so don't 
bother.
+               bigtime_t now = system_time();
+               if (now - fLastMoveTime < 13333) {
+                       // TODO: add a "timed event" to query for
+                       // the then current mouse position
+                       return;
+               }
+               if (fActivateOnMouseUp || fMinimizeCheckOnMouseUp) {
+                       if (now - fLastMoveTime >= kWindowActivationTimeout) {
+                               // This click is too long already for window 
activation/
+                               // minimizing.
+                               fActivateOnMouseUp = false;
+                               fMinimizeCheckOnMouseUp = false;
+                               fLastMoveTime = now;
+                       }
+               } else
+                       fLastMoveTime = now;
+
+               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 || fMinimizeCheckOnMouseUp) {
+                       fMouseMoveDistance += delta.x * delta.x + delta.y * 
delta.y;
+                       if (fMouseMoveDistance > 16.0f) {
+                               fActivateOnMouseUp = false;
+                               fMinimizeCheckOnMouseUp = false;
+                       } else
+                               delta = B_ORIGIN;
+               }
+
+               // perform the action (this also updates the delta)
+               MouseMovedAction(delta, now);
+
+               // set the new mouse position
+               fLastMousePosition += delta;
+
+               // update the FFM focus
+               UpateFFMFocus(isFake);
+       }
+
+       virtual void MouseMovedAction(BPoint& delta, bigtime_t now) = 0;
+
+protected:
+       bool                            fActivateOnMouseUp : 1;
+       bool                            fMinimizeCheckOnMouseUp : 1;
+
+       BPoint                          fLastMousePosition;
+       float                           fMouseMoveDistance;
+       bigtime_t                       fLastMoveTime;
+};
+
+
+// #pragma mark - DragState
+
+
+struct DefaultWindowBehaviour::DragState : MouseTrackingState {
+       DragState(DefaultWindowBehaviour& behavior, BPoint where,
+               bool activateOnMouseUp, bool minimizeCheckOnMouseUp)
+               :
+               MouseTrackingState(behavior, where, activateOnMouseUp,
+                       minimizeCheckOnMouseUp)
+       {
+       }
+
+       virtual bool MouseDown(BMessage* message, BPoint where)
+       {
+               // right-click while dragging shall bring the window to front
+               int32 buttons = message->FindInt32("buttons");
+               if ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0) {
+                       if (fWindow == fDesktop->BackWindow())
+                               fDesktop->ActivateWindow(fWindow);
+                       else
+                               fDesktop->SendWindowBehind(fWindow);
+                       return false;
+               }
+
+               return MouseTrackingState::MouseDown(message, where);
+       }
+
+       virtual void MouseMovedAction(BPoint& delta, bigtime_t now)
+       {
+               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);
+       }
+
+private:
+       void _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();
+
+               Decorator* decorator = fWindow->Decorator();
+               if (decorator) {
+                       frame = decorator->GetFootprint().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;
+       }
+
+private:
+       bigtime_t                       fLastSnapTime;
+};
+
+
+// #pragma mark - ResizeState
+
+
+struct DefaultWindowBehaviour::ResizeState : MouseTrackingState {
+       ResizeState(DefaultWindowBehaviour& behavior, BPoint where,
+               bool activateOnMouseUp)
+               :
+               MouseTrackingState(behavior, where, activateOnMouseUp, false)
+       {
+       }
+
+       virtual void MouseMovedAction(BPoint& delta, bigtime_t now)
+       {
+               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);
+       }
+};
+
+
+// #pragma mark - SlideTabState
+
+
+struct DefaultWindowBehaviour::SlideTabState : MouseTrackingState {
+       SlideTabState(DefaultWindowBehaviour& behavior, BPoint where)
+               :
+               MouseTrackingState(behavior, where, false, false)
+       {
+       }
+
+       virtual void MouseMovedAction(BPoint& delta, bigtime_t now)
+       {
+               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);
+       }
+};
+
+
+// #pragma mark - DecoratorButtonState
+
+
+struct DefaultWindowBehaviour::DecoratorButtonState : State {
+       DecoratorButtonState(DefaultWindowBehaviour& behavior, Region button)
+               :
+               State(behavior),
+               fButton(button)
+       {
+       }
+
+       virtual void EnterState(State* previousState)
+       {
+               _RedrawDecorator(NULL);
+       }
+
+       virtual void MouseUp(BMessage* message, BPoint where)
+       {
+               // ignore, if it's not the primary mouse button
+               int32 buttons = message->FindInt32("buttons");
+               if ((buttons & B_PRIMARY_MOUSE_BUTTON) != 0)
+                       return;
+
+               // redraw the decorator
+               if (Decorator* decorator = fWindow->Decorator()) {
+                       BRegion* visibleBorder = 
fWindow->RegionPool()->GetRegion();
+                       fWindow->GetBorderRegion(visibleBorder);
+                       visibleBorder->IntersectWith(&fWindow->VisibleRegion());
+
+                       DrawingEngine* engine = decorator->GetDrawingEngine();
+                       engine->LockParallelAccess();
+                       engine->ConstrainClippingRegion(visibleBorder);
+
+                       switch (fButton) {
+                               case REGION_CLOSE_BUTTON:
+                                       decorator->SetClose(false);
+                                       if (fBehavior._RegionFor(message) == 
REGION_CLOSE_BUTTON)
+                                               
fWindow->ServerWindow()->NotifyQuitRequested();
+                                       break;
+
+                               case REGION_ZOOM_BUTTON:
+                                       decorator->SetZoom(false);
+                                       if (fBehavior._RegionFor(message) == 
REGION_ZOOM_BUTTON)
+                                               
fWindow->ServerWindow()->NotifyZoom();
+                                       break;
+
+                               case REGION_MINIMIZE_BUTTON:
+                                       decorator->SetMinimize(false);
+                                       if (fBehavior._RegionFor(message) == 
REGION_MINIMIZE_BUTTON)
+                                               
fWindow->ServerWindow()->NotifyMinimize(true);
+                                       break;
+
+                               default:
+                                       break;
+                       }
+
+                       engine->UnlockParallelAccess();
+
+                       fWindow->RegionPool()->Recycle(visibleBorder);
+               }
+
+               fBehavior._NextState(NULL);
+       }
+
+       virtual void MouseMoved(BMessage* message, BPoint where, bool isFake)
+       {
+               _RedrawDecorator(message);
+
+               // update the FFM focus
+               UpateFFMFocus(isFake);
+       }
+
+private:
+       void _RedrawDecorator(const BMessage* message)
+       {
+               if (Decorator* decorator = fWindow->Decorator()) {
+                       BRegion* visibleBorder = 
fWindow->RegionPool()->GetRegion();
+                       fWindow->GetBorderRegion(visibleBorder);
+                       visibleBorder->IntersectWith(&fWindow->VisibleRegion());
+
+                       DrawingEngine* engine = decorator->GetDrawingEngine();
+                       engine->LockParallelAccess();
+                       engine->ConstrainClippingRegion(visibleBorder);
+
+                       Region hitRegion = message != NULL
+                               ? fBehavior._RegionFor(message) : fButton;
+
+                       switch (fButton) {
+                               case REGION_CLOSE_BUTTON:
+                                       decorator->SetClose(hitRegion == 
REGION_CLOSE_BUTTON);
+                                       break;
+
+                               case REGION_ZOOM_BUTTON:
+                                       decorator->SetZoom(hitRegion == 
REGION_ZOOM_BUTTON);
+                                       break;
+
+                               case REGION_MINIMIZE_BUTTON:
+                                       decorator->SetMinimize(hitRegion == 
REGION_MINIMIZE_BUTTON);
+                                       break;
+
+                               default:
+                                       break;
+                       }
+
+                       engine->UnlockParallelAccess();
+                       fWindow->RegionPool()->Recycle(visibleBorder);
+               }
+       }
+
+protected:
+       Region  fButton;
+};
+
+
+// #pragma mark - DefaultWindowBehaviour
+
+
 DefaultWindowBehaviour::DefaultWindowBehaviour(Window* window)
        :
        fWindow(window),
-
-       fIsClosing(false),
-       fIsMinimizing(false),
-       fIsZooming(false),
-       fIsSlidingTab(false),
-       fActivateOnMouseUp(false),
-       fMinimizeCheckOnMouseUp(false),
-
-       fLastMousePosition(0.0f, 0.0f),
-       fMouseMoveDistance(0.0f),
-       fLastMoveTime(0),
-       fLastSnapTime(0),
+       fDesktop(window->Desktop()),
+       fState(NULL),
        fLastModifiers(0),
        fResetClickCount(0)
 {
-       fDesktop = fWindow->Desktop();
 }
 
 
 DefaultWindowBehaviour::~DefaultWindowBehaviour()
 {
+       delete fState;
 }
 
 
 bool
 DefaultWindowBehaviour::MouseDown(BMessage* message, BPoint where)
 {
-       Decorator* decorator = fWindow->Decorator();
-
-       bool inBorderRegion = false;
-       if (decorator != NULL)
-               inBorderRegion = decorator->GetFootprint().Contains(where);
-
-       int32 modifiers = message->FindInt32("modifiers");
-       bool windowModifier = _IsWindowModifier(modifiers);
-
        // Get the click count and reset it, if the modifiers changed in the
        // meantime.
        // TODO: This should be done in a better place (e.g. the input server). 
It
        // should also reset clicks after mouse movement (which we don't do here
        // either -- though that's probably acceptable).
        int32 clickCount = message->FindInt32("clicks");
+       int32 modifiers = message->FindInt32("modifiers");
        if (clickCount <= 1) {
                fResetClickCount = 0;
        } else if (modifiers != fLastModifiers
@@ -89,9 +522,23 @@
                clickCount -= fResetClickCount;
        fLastModifiers = modifiers;
 
+       // if a state is active, let it do the job
+       if (fState != NULL)
+               return fState->MouseDown(message, where);
+
+       // No state active yet -- determine the click region and decide what to 
do.
+
+       Decorator* decorator = fWindow->Decorator();
+
        Region hitRegion = REGION_NONE;
        click_type action = CLICK_NONE;
 
+       bool inBorderRegion = false;
+       if (decorator != NULL)
+               inBorderRegion = decorator->GetFootprint().Contains(where);
+
+       bool windowModifier = _IsWindowModifier(modifiers);
+
        if (windowModifier || inBorderRegion) {
                // click on the window decorator or we have the window modifier 
keys
                // held
@@ -184,94 +631,57 @@
                        action = CLICK_DRAG;
        }
 
-       // set decorator internals
+       bool activateOnMouseUp = false;
+       if (action != CLICK_MOVE_TO_BACK) {
+               // 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);
+                       activateOnMouseUp = true;
+               }
+       }
+
+       // switch to the new state
        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"));
-                       }
+                       _NextState(
+                               new (std::nothrow) DecoratorButtonState(*this, 
hitRegion));
+                       STRACE_CLICK(("===> CLICK_CLOSE/ZOOM/MINIMIZE\n"));
                        break;
 
                case CLICK_DRAG:
-                       fIsDragging = true;
-                       fLastMousePosition = where;
+                       _NextState(new (std::nothrow) DragState(*this, where,
+                               activateOnMouseUp, clickCount == 2));
                        STRACE_CLICK(("===> CLICK_DRAG\n"));
                        break;
 
                case CLICK_RESIZE:
-                       fIsResizing = true;
-                       fLastMousePosition = where;
+                       _NextState(new (std::nothrow) ResizeState(*this, where,
+                               activateOnMouseUp));
                        STRACE_CLICK(("===> CLICK_RESIZE\n"));
                        break;
 
                case CLICK_SLIDE_TAB:
-                       fIsSlidingTab = true;
-                       fLastMousePosition = where;
+                       _NextState(new (std::nothrow) SlideTabState(*this, 
where));
                        STRACE_CLICK(("===> CLICK_SLIDE_TAB\n"));
                        break;
 
+               case CLICK_MOVE_TO_BACK:
+                       fDesktop->SendWindowBehind(fWindow);
+                       STRACE_CLICK(("===> CLICK_MOVE_TO_BACK\n"));
+                       break;
+
                default:
                        break;
        }
 
-       if (decorator != NULL) {
-               // redraw decorator
-               BRegion* visibleBorder = fWindow->RegionPool()->GetRegion();
-               fWindow->GetBorderRegion(visibleBorder);
-               visibleBorder->IntersectWith(&fWindow->VisibleRegion());
-
-               DrawingEngine* engine = decorator->GetDrawingEngine();
-               engine->LockParallelAccess();
-               engine->ConstrainClippingRegion(visibleBorder);
-
-               if (fIsZooming)
-                       decorator->SetZoom(true);
-               else if (fIsClosing)
-                       decorator->SetClose(true);
-               else if (fIsMinimizing)
-                       decorator->SetMinimize(true);
-
-               engine->UnlockParallelAccess();
-
-               fWindow->RegionPool()->Recycle(visibleBorder);
-       }
-
-       if (action == CLICK_MOVE_TO_BACK) {
-               if (!fIsDragging || fWindow != fDesktop->BackWindow())
-                       fDesktop->SendWindowBehind(fWindow);
-               else
-                       fDesktop->ActivateWindow(fWindow);
-       } else {
+       // If we have a state now, it surely wants all further mouse events.
+       if (fState != NULL)
                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 (action == CLICK_DRAG || action == CLICK_RESIZE)
-                               fActivateOnMouseUp = true;
-               }
-
-               if (fIsDragging && clickCount == 2)
-                       fMinimizeCheckOnMouseUp = true;
-
-               fMouseMoveDistance = 0.0f;
-               fLastMoveTime = system_time();
-       }
-
        return true;
 }
 
@@ -279,207 +689,16 @@
 void
 DefaultWindowBehaviour::MouseUp(BMessage* message, BPoint where)
 {
-       Decorator* decorator = fWindow->Decorator();
-
-       int32 buttons = message->FindInt32("buttons");
-
-       if (decorator != NULL) {
-               // redraw decorator
-               BRegion* visibleBorder = fWindow->RegionPool()->GetRegion();
-               fWindow->GetBorderRegion(visibleBorder);
-               visibleBorder->IntersectWith(&fWindow->VisibleRegion());
-
-               DrawingEngine* engine = decorator->GetDrawingEngine();
-               engine->LockParallelAccess();
-               engine->ConstrainClippingRegion(visibleBorder);
-
-               if (fIsZooming) {
-                       fIsZooming = false;
-                       decorator->SetZoom(false);
-                       if (_RegionFor(message) == REGION_ZOOM_BUTTON)
-                               fWindow->ServerWindow()->NotifyZoom();
-               }
-               if (fIsClosing) {
-                       fIsClosing = false;
-                       decorator->SetClose(false);
-                       if (_RegionFor(message) == REGION_CLOSE_BUTTON)
-                               fWindow->ServerWindow()->NotifyQuitRequested();
-               }
-               if (fIsMinimizing) {
-                       fIsMinimizing = false;
-                       decorator->SetMinimize(false);
-                       if (_RegionFor(message) == REGION_MINIMIZE_BUTTON)
-                               fWindow->ServerWindow()->NotifyMinimize(true);
-               }
-
-               engine->UnlockParallelAccess();
-
-               fWindow->RegionPool()->Recycle(visibleBorder);
-       }
-
-       // if the primary mouse button is released, stop
-       // dragging/resizing/sliding
-       if ((buttons & B_PRIMARY_MOUSE_BUTTON) == 0) {
-               if (fMinimizeCheckOnMouseUp) {
-                       // If the modifiers haven't changed in the meantime and 
not too
-                       // much time has elapsed, we're supposed to minimize 
the window.
-                       fMinimizeCheckOnMouseUp = false;
-                       if (message->FindInt32("modifiers") == fLastModifiers
-                               && (fWindow->Flags() & B_NOT_MINIMIZABLE) == 0
-                               && system_time() - fLastMoveTime < 
kWindowActivationTimeout) {
-                               fWindow->ServerWindow()->NotifyMinimize(true);
-                       }
-               }
-
-               // 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);
-               }
-
-               fIsDragging = false;
-               fIsResizing = false;
-               fIsSlidingTab = false;
-       }
+       if (fState != NULL)
+               fState->MouseUp(message, where);
 }
 
 
 void
 DefaultWindowBehaviour::MouseMoved(BMessage *message, BPoint where, bool 
isFake)
 {
-       Decorator* decorator = fWindow->Decorator();
-
-       #if 0
-       if (decorator != NULL && fWindow->TopView() != NULL) {
-               DrawingEngine* engine = decorator->GetDrawingEngine();
-               engine->LockParallelAccess();
-               engine->ConstrainClippingRegion(&fWindow->VisibleRegion());
-
-               fWindow->TopView()->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 || fMinimizeCheckOnMouseUp) {
-                       if (now - fLastMoveTime >= kWindowActivationTimeout) {
-                               // This click is too long already for window 
activation/
-                               // minimizing.
-                               fActivateOnMouseUp = false;
-                               fMinimizeCheckOnMouseUp = false;
-                       }
-               } else
-                       fLastMoveTime = now;
-       }
-
-       if (decorator != NULL) {
-               BRegion* visibleBorder = fWindow->RegionPool()->GetRegion();
-               fWindow->GetBorderRegion(visibleBorder);
-               visibleBorder->IntersectWith(&fWindow->VisibleRegion());
-
-               DrawingEngine* engine = decorator->GetDrawingEngine();
-               engine->LockParallelAccess();
-               engine->ConstrainClippingRegion(visibleBorder);
-
-               Region hitRegion = _RegionFor(message);
-
-               if (fIsZooming)
-                       decorator->SetZoom(hitRegion == REGION_ZOOM_BUTTON);
-               else if (fIsClosing)
-                       decorator->SetClose(hitRegion == REGION_CLOSE_BUTTON);
-               else if (fIsMinimizing)
-                       decorator->SetMinimize(hitRegion == 
REGION_MINIMIZE_BUTTON);
-
-               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 || fMinimizeCheckOnMouseUp) {
-               fMouseMoveDistance += delta.x * delta.x + delta.y * delta.y;
-               if (fMouseMoveDistance > 16.0f) {
-                       fActivateOnMouseUp = false;
-                       fMinimizeCheckOnMouseUp = 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);
-       }
+       if (fState != NULL)
+               fState->MouseMoved(message, where, isFake);
 }
 
 
@@ -542,70 +761,13 @@
 
 
 void
-DefaultWindowBehaviour::_AlterDeltaForSnap(BPoint& delta, bigtime_t now)
+DefaultWindowBehaviour::_NextState(State* state)
 {
-       // 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.
+       State* oldState = fState;
+       fState = state;
 
-       const bigtime_t kSnappingDuration = 1500000LL;
-       const bigtime_t kSnappingPause = 3000000LL;
-       const float kSnapDistance = 8.0f;
+       if (fState != NULL)
+               fState->EnterState(oldState);
 
-       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();
-
-       Decorator* decorator = fWindow->Decorator();
-       if (decorator) {
-               frame = decorator->GetFootprint().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;
+       delete oldState;
 }

Modified: haiku/trunk/src/servers/app/DefaultWindowBehaviour.h
===================================================================
--- haiku/trunk/src/servers/app/DefaultWindowBehaviour.h        2010-11-24 
14:50:07 UTC (rev 39607)
+++ haiku/trunk/src/servers/app/DefaultWindowBehaviour.h        2010-11-24 
16:17:32 UTC (rev 39608)
@@ -48,27 +48,31 @@
                                REGION_RESIZE_CORNER
                        };
 
+                       struct State;
+                       struct MouseTrackingState;
+                       struct DragState;
+                       struct ResizeState;
+                       struct SlideTabState;
+                       struct DecoratorButtonState;
+
+                       // to keep gcc 2 happy
+                       friend struct State;
+                       friend struct MouseTrackingState;
+                       friend struct DragState;
+                       friend struct ResizeState;
+                       friend struct SlideTabState;
+                       friend struct DecoratorButtonState;
+
 private:
                        bool                            _IsWindowModifier(int32 
modifiers) const;
                        Region                          _RegionFor(const 
BMessage* message) const;
-                       void                            
_AlterDeltaForSnap(BPoint& delta,
-                                                                       
bigtime_t now);
 
+                       void                            _NextState(State* 
state);
+
 protected:
                        Window*                         fWindow;
                        Desktop*                        fDesktop;
-
-                       bool                            fIsClosing : 1;
-                       bool                            fIsMinimizing : 1;
-                       bool                            fIsZooming : 1;
-                       bool                            fIsSlidingTab : 1;
-                       bool                            fActivateOnMouseUp : 1;
-                       bool                            fMinimizeCheckOnMouseUp 
: 1;
-
-                       BPoint                          fLastMousePosition;
-                       float                           fMouseMoveDistance;
-                       bigtime_t                       fLastMoveTime;
-                       bigtime_t                       fLastSnapTime;
+                       State*                          fState;
                        int32                           fLastModifiers;
                        int32                           fResetClickCount;
 };


Other related posts: