Refactoring of the Window class. Move window behaviour into separate WindowBehaviour class.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37524 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Clemens Zeidler
2010-07-15 04:49:38 +00:00
parent 0009e148b8
commit 177ecc46b6
7 changed files with 644 additions and 490 deletions
+505
View File
@@ -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 && fWindow->TopView() != NULL) {
DrawingEngine* engine = fDecorator->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) {
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(&reg);
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;
}
+54
View File
@@ -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
+2
View File
@@ -21,6 +21,7 @@ Server app_server :
DecorManager.cpp
Decorator.cpp
DefaultDecorator.cpp
DefaultWindowBehaviour.cpp
Desktop.cpp
DesktopSettings.cpp
DirectWindowInfo.cpp
@@ -57,6 +58,7 @@ Server app_server :
View.cpp
VirtualScreen.cpp
Window.cpp
WindowBehaviour.cpp
WindowList.cpp
Workspace.cpp
WorkspacesView.cpp
+28 -463
View File
@@ -16,6 +16,7 @@
#include "Decorator.h"
#include "DecorManager.h"
#include "Desktop.h"
#include "DefaultWindowBehaviour.h"
#include "DrawingEngine.h"
#include "HWInterface.h"
#include "MessagePrivate.h"
@@ -39,7 +40,6 @@
// Toggle debug output
//#define DEBUG_WINDOW
//#define DEBUG_WINDOW_CLICK
#ifdef DEBUG_WINDOW
# define STRACE(x) printf x
@@ -47,12 +47,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 +90,13 @@ Window::Window(const BRect& frame, const char *name,
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 +136,8 @@ Window::Window(const BRect& frame, const char *name,
&fMaxWidth, &fMaxHeight);
}
}
fWindowBehaviour = new (std::nothrow)DefaultWindowBehaviour(this,
fDecorator);
// do we need to change our size to let the decorator fit?
// _ResizeBy() will adapt the frame for validity before resizing
@@ -187,6 +171,7 @@ Window::~Window()
delete fTopView;
}
delete fWindowBehaviour;
delete fDecorator;
delete fDrawingEngine;
@@ -196,7 +181,7 @@ Window::~Window()
status_t
Window::InitCheck() const
{
if (!fDrawingEngine)
if (!fDrawingEngine || !fWindowBehaviour)
return B_NO_MEMORY;
// TODO: anything else?
return B_OK;
@@ -775,9 +760,6 @@ Window::EnableUpdateRequests()
// #pragma mark -
static const bigtime_t kWindowActivationTimeout = 500000LL;
void
Window::MouseDown(BMessage* message, BPoint where, int32* _viewToken)
{
@@ -787,136 +769,8 @@ Window::MouseDown(BMessage* message, BPoint where, int32* _viewToken)
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,71 +811,7 @@ Window::MouseDown(BMessage* message, BPoint where, int32* _viewToken)
void
Window::MouseUp(BMessage* message, BPoint where, int32* _viewToken)
{
bool invalidate = false;
if (fDecorator) {
click_type action = _ActionFor(message);
// 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);
}
fWindowBehaviour->MouseUp(message, where);
if (View* view = ViewAt(where)) {
if (HasModal())
@@ -1037,17 +827,6 @@ void
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,119 +835,7 @@ Window::MouseMoved(BMessage *message, BPoint where, int32* _viewToken,
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;
}
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)
delta.x = 0;
BPoint oldRightBottom = fFrame.RightBottom();
fDesktop->ResizeWindowBy(this, delta.x, delta.y);
// constrain delta to true change in size
delta = fFrame.RightBottom() - oldRightBottom;
} else
delta = BPoint(0, 0);
}
// sliding tab
if (fIsSlidingTab) {
float loc = TabLocation();
// TODO: change to [0:1]
loc += delta.x;
if (fDesktop->SetWindowTabLocation(this, 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()
&& !IsFocus() && !(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 : this);
}
fWindowBehaviour->MouseMoved(message, where, isFake);
// mouse cursor
@@ -1182,77 +849,6 @@ Window::MouseMoved(BMessage *message, BPoint where, int32* _viewToken,
}
void
Window::_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 = fFrame;
BPoint offsetWithinFrame;
// TODO: Perhaps obtain the usable area (not covered by the Deskbar)?
BRect screenFrame = Screen()->Frame();
if (fDecorator) {
BRegion reg;
fDecorator->GetFootprint(&reg);
frame = reg.Frame();
offsetWithinFrame.x = fFrame.left - frame.left;
offsetWithinFrame.y = fFrame.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 - fFrame.top;
delta.x = frame.left - fFrame.left;
}
// #pragma mark -
@@ -1375,6 +971,24 @@ Window::IsVisible() const
}
bool
Window::IsDragging() const
{
if (!fWindowBehaviour)
return false;
return fWindowBehaviour->IsDragging();
}
bool
Window::IsResizing() const
{
if (!fWindowBehaviour)
return false;
return fWindowBehaviour->IsResizing();
}
void
Window::SetSizeLimits(int32 minWidth, int32 maxWidth, int32 minHeight,
int32 maxHeight)
@@ -2226,53 +1840,6 @@ Window::_UpdateContentRegion()
}
int32
Window::_ExtractButtons(const BMessage* message) const
{
int32 buttons;
if (message->FindInt32("buttons", &buttons) != B_OK)
buttons = 0;
return buttons;
}
int32
Window::_ExtractModifiers(const BMessage* message) const
{
int32 modifiers;
if (message->FindInt32("modifiers", &modifiers) != B_OK)
modifiers = 0;
return modifiers;
}
click_type
Window::_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
Window::_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
Window::_ObeySizeLimits()
{
@@ -2370,5 +1937,3 @@ Window::UpdateSession::AddCause(uint8 cause)
{
fCause |= cause;
}
+7 -27
View File
@@ -33,6 +33,7 @@ class Desktop;
class DrawingEngine;
class EventDispatcher;
class Screen;
class WindowBehaviour;
class WorkspacesView;
// TODO: move this into a proper place
@@ -169,10 +170,12 @@ public:
void SetCurrentWorkspace(int32 index)
{ fCurrentWorkspace = index; }
int32 CurrentWorkspace() const
{ return fCurrentWorkspace; }
bool IsVisible() const;
bool IsDragging() const { return fIsDragging; }
bool IsResizing() const { return fIsResizing; }
bool IsDragging() const;
bool IsResizing() const;
void SetSizeLimits(int32 minWidth, int32 maxWidth,
int32 minHeight, int32 maxHeight);
@@ -244,6 +247,7 @@ public:
static uint32 ValidWindowFlags();
static uint32 ValidWindowFlags(window_feel feel);
BRegion& BorderRegion() { return fBorderRegion; }
protected:
void _ShiftPartOfRegion(BRegion* region,
BRegion* regionToShift, int32 xOffset,
@@ -260,20 +264,9 @@ protected:
void _UpdateContentRegion();
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 _ObeySizeLimits();
void _PropagatePosition();
void _AlterDeltaForSnap(BPoint& delta,
bigtime_t now);
BString fTitle;
// TODO: no fp rects anywhere
BRect fFrame;
@@ -309,26 +302,13 @@ protected:
BObjectList<Window> fSubsets;
// TODO: remove those some day (let the decorator handle that stuff)
bool fIsClosing : 1;
bool fIsMinimizing : 1;
bool fIsZooming : 1;
bool fIsResizing : 1;
bool fIsSlidingTab : 1;
bool fIsDragging : 1;
bool fActivateOnMouseUp : 1;
WindowBehaviour* fWindowBehaviour;
::Decorator* fDecorator;
View* fTopView;
::ServerWindow* fWindow;
DrawingEngine* fDrawingEngine;
::Desktop* fDesktop;
BPoint fLastMousePosition;
float fMouseMoveDistance;
bigtime_t fLastMoveTime;
bigtime_t fLastSnapTime;
// The synchronization, which client drawing commands
// belong to the redraw of which dirty region is handled
// through an UpdateSession. When the client has
+16
View File
@@ -0,0 +1,16 @@
#include "WindowBehaviour.h"
WindowBehaviour::WindowBehaviour()
:
fIsResizing(false),
fIsDragging(false)
{
}
WindowBehaviour::~WindowBehaviour()
{
}
+32
View File
@@ -0,0 +1,32 @@
#ifndef WINDOW_BEHAVIOUR_H
#define WINDOW_BEHAVIOUR_H
#include <Region.h>
class BMessage;
class WindowBehaviour
{
public:
WindowBehaviour();
virtual ~WindowBehaviour();
//! \return true if event was a WindowBehaviour event and should be discard
virtual bool MouseDown(BMessage* message, BPoint where) = 0;
virtual void MouseUp(BMessage* message, BPoint where) = 0;
virtual void MouseMoved(BMessage *message, BPoint where,
bool isFake) = 0;
bool IsDragging() const { return fIsDragging; }
bool IsResizing() const { return fIsResizing; }
protected:
bool fIsResizing : 1;
bool fIsDragging : 1;
};
#endif