* Decorator: Replaced the MouseAction() method with a new RegionAt().

RegionAt() just gets a point and returns which region was hit. This is in
  order to move behavioral code to [Default]WindowBehaviour. I'm not happy
  with this solution either, but to do it properly one would have to break the
  Decorator interface into separate look and feel interfaces and reorganize the
  interaction with WindowBehaviour. A task for the so-inclined reader. :-)
* Adjusted the Decorators implementations, but really tested only the default
  one.
* DefaultWindowBehaviour:
  - Replaced _ActionFor() method by a _RegionFor() which interprets the region
    returned by Decorator::RegionAt() and converts it to a "functional" region,
    i.e. combines cases we handle the same way.
  - MouseDown():
    - Handle the click region cases more in detail, disentangling the mouse
      button cases. With the following effects:
      - The middle mouse button has no effect anymore.
      - Left and right mouse buttons no longer share common behavior. A right
        click on a decorator button will send the window to the back.
    - The window key window management modifier combo does now have precedence,
      i.e. Cmd-Ctrl-click on the decorator buttons will have the same effect as
      clicking anywhere in the window.
    - When modifiers change between the clicks, reset the click count. Prevents
      a standard click in the window followed by a Cmd-Ctrl-click from being
      recognized as a double-click.
  - Mouse*(): Introduced a fMinimizeCheckOnMouseUp which works similar to
    fActivateOnMouseUp, just for double-clicks. The decision whether a
    double-click minimizes the window is postponed until releasing the mouse
    button. After moving the mouse sufficiently far or waiting half a second
    without moving the mouse the window will no longer be minimized. Fixes
    #6868.
  - MouseUp(): Moved the primary mouse button check without the
    "decorator != NULL" block. I suppose this fixes issues with the Cmd-Ctrl
    actions and decoratorless windows (if those actually exist).

I can't wait to hear what things I've broken. :-)


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39602 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2010-11-24 02:09:50 +00:00
parent 1e6e9d99cf
commit 89d652d5e0
12 changed files with 419 additions and 340 deletions
@@ -214,47 +214,35 @@ BeDecorator::GetSizeLimits(int32* minWidth, int32* minHeight,
}
click_type
BeDecorator::MouseAction(const BMessage* message, BPoint point, int32 buttons,
int32 modifiers)
Decorator::Region
BeDecorator::RegionAt(BPoint where) const
{
#ifdef DEBUG_DECORATOR
printf("BeDecorator: Clicked\n");
printf("\tPoint: (%.1f,%.1f)\n", point.x, point.y);
printf("\tButtons: %ld, Modifiers: 0x%lx\n", buttons, modifiers);
#endif // DEBUG_DECORATOR
// Let the base class version identify hits of the buttons and the tab.
Region region = Decorator::RegionAt(where);
if (region != REGION_NONE)
return region;
if (buttons != 0)
fWasDoubleClick = message->FindInt32("clicks") == 2;
// check the resize corner
if (fLook == B_DOCUMENT_WINDOW_LOOK && fResizeRect.Contains(where))
return REGION_RIGHT_BOTTOM_CORNER;
// In checking for hit test stuff, we start with the smallest rectangles
// the user might be clicking on and gradually work our way out into larger
// rectangles.
if (!(fFlags & B_NOT_CLOSABLE) && fCloseRect.Contains(point))
return CLICK_CLOSE;
// hit-test the borders
if (fLeftBorder.Contains(where))
return REGION_LEFT_BORDER;
if (fTopBorder.Contains(where))
return REGION_TOP_BORDER;
if (!(fFlags & B_NOT_ZOOMABLE) && fZoomRect.Contains(point))
return CLICK_ZOOM;
if (fLook == B_DOCUMENT_WINDOW_LOOK && fResizeRect.Contains(point))
return CLICK_RESIZE;
bool clicked = false;
// Clicking in the tab?
if (fTabRect.Contains(point)) {
// tab sliding in any case if either shift key is held down
// except sliding up-down by moving mouse left-right would look strange
if ((modifiers & B_SHIFT_KEY) && (fLook != kLeftTitledWindowLook))
return CLICK_SLIDE_TAB;
clicked = true;
} else if (fLeftBorder.Contains(point) || fRightBorder.Contains(point)
|| fTopBorder.Contains(point) || fBottomBorder.Contains(point)) {
// Clicked on border
// Part of the bottom and right borders may be a resize-region, so we have
// to check explicitly, if it has been it.
if (fRightBorder.Contains(where))
region = REGION_RIGHT_BORDER;
else if (fBottomBorder.Contains(where))
region = REGION_BOTTOM_BORDER;
else
return REGION_NONE;
// check resize area
if (!(fFlags & B_NOT_RESIZABLE)
if ((fFlags & B_NOT_RESIZABLE) == 0
&& (fLook == B_TITLED_WINDOW_LOOK
|| fLook == B_FLOATING_WINDOW_LOOK
|| fLook == B_MODAL_WINDOW_LOOK
@@ -262,28 +250,11 @@ BeDecorator::MouseAction(const BMessage* message, BPoint point, int32 buttons,
BRect resizeRect(BPoint(fBottomBorder.right - kBorderResizeLength,
fBottomBorder.bottom - kBorderResizeLength),
fBottomBorder.RightBottom());
if (resizeRect.Contains(point))
return CLICK_RESIZE;
if (resizeRect.Contains(where))
return REGION_RIGHT_BOTTOM_CORNER;
}
clicked = true;
}
if (clicked) {
// NOTE: On R5, windows are not moved to back if clicked inside the
// resize area with the second mouse button. So we check this after
// the check above
if ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0)
return CLICK_MOVE_TO_BACK;
if (fWasDoubleClick && !(fFlags & B_NOT_MINIMIZABLE))
return CLICK_MINIMIZE;
return CLICK_DRAG;
}
// Guess user didn't click anything
return CLICK_NONE;
return region;
}
@@ -117,43 +117,29 @@ MacDecorator::Draw()
// TODO : add GetSizeLimits
click_type
MacDecorator::MouseAction(const BMessage* message, BPoint point, int32 buttons,
int32 modifiers)
Decorator::Region
MacDecorator::RegionAt(BPoint where) const
{
if (!(fFlags & B_NOT_CLOSABLE) && fCloseRect.Contains(point)) {
STRACE(("MacDecorator():Clicked() - Close\n"));
return CLICK_CLOSE;
}
// Let the base class version identify hits of the buttons and the tab.
Region region = Decorator::RegionAt(where);
if (region != REGION_NONE)
return region;
if (!(fFlags & B_NOT_ZOOMABLE) && fZoomRect.Contains(point)) {
STRACE(("MacDecorator():Clicked() - Zoom\n"));
return CLICK_ZOOM;
}
// check the resize corner
if (fLook == B_DOCUMENT_WINDOW_LOOK && fResizeRect.Contains(where))
return REGION_RIGHT_BOTTOM_CORNER;
// Clicking in the tab?
if (fTabRect.Contains(point)) {
// Here's part of our window management stuff
/* TODO: This is missing CLICK_MOVETOFRONT
if(buttons == B_PRIMARY_MOUSE_BUTTON && !IsFocus())
return CLICK_MOVETOFRONT;
*/
return CLICK_DRAG;
}
// We got this far, so user is clicking on the border?
// hit-test the borders
if (!(fFlags & B_NOT_RESIZABLE)
&& (fLook == B_TITLED_WINDOW_LOOK
|| fLook == B_FLOATING_WINDOW_LOOK
|| fLook == B_MODAL_WINDOW_LOOK)
&& fBorderRect.Contains(point) && !fFrame.Contains(point)) {
STRACE(("MacDecorator():Clicked() - Resize\n"));
return CLICK_RESIZE;
&& fBorderRect.Contains(where) && !fFrame.Contains(where)) {
return REGION_BOTTOM_BORDER;
// TODO: Determine the actual border!
}
// Guess user didn't click anything
STRACE(("MacDecorator():Clicked()\n"));
return CLICK_NONE;
return REGION_NONE;
}
@@ -32,9 +32,7 @@ public:
void Draw(BRect updateRect);
void Draw();
click_type MouseAction(const BMessage* message,
BPoint point, int32 buttons,
int32 modifiers);
virtual Region RegionAt(BPoint where) const;
protected:
void _DoLayout();
@@ -140,12 +140,22 @@ StackAndTile::MouseDown(Window* window, BMessage* message, const BPoint& where)
// we are only interested in single clicks
if (message->FindInt32("clicks") == 2)
return;
int32 modifiers = message->FindInt32("modifiers");
int32 buttons = message->FindInt32("buttons");
click_type clickArea = satWindow->GetDecorator()->MouseAction(message,
where, buttons, modifiers);
if (clickArea != CLICK_DRAG && clickArea < CLICK_RESIZE)
switch (satWindow->GetDecorator()->RegionAt(where)) {
case Decorator::REGION_TAB:
case Decorator::REGION_LEFT_BORDER:
case Decorator::REGION_RIGHT_BORDER:
case Decorator::REGION_TOP_BORDER:
case Decorator::REGION_BOTTOM_BORDER:
case Decorator::REGION_LEFT_TOP_CORNER:
case Decorator::REGION_LEFT_BOTTOM_CORNER:
case Decorator::REGION_RIGHT_TOP_CORNER:
case Decorator::REGION_RIGHT_BOTTOM_CORNER:
break;
default:
return;
}
ASSERT(fCurrentSATWindow == NULL);
fCurrentSATWindow = satWindow;
@@ -119,40 +119,29 @@ WinDecorator::Draw()
// TODO : add GetSizeLimits
click_type
WinDecorator::MouseAction(const BMessage* message, BPoint where, int32 buttons,
int32 modifiers)
Decorator::Region
WinDecorator::RegionAt(BPoint where) const
{
if (!(fFlags & B_NOT_CLOSABLE) && fCloseRect.Contains(where))
return CLICK_CLOSE;
// Let the base class version identify hits of the buttons and the tab.
Region region = Decorator::RegionAt(where);
if (region != REGION_NONE)
return region;
if (!(fFlags & B_NOT_ZOOMABLE) && fZoomRect.Contains(where))
return CLICK_ZOOM;
// check the resize corner
if (fLook == B_DOCUMENT_WINDOW_LOOK && fResizeRect.Contains(where))
return REGION_RIGHT_BOTTOM_CORNER;
// Clicking in the tab?
if (fTabRect.Contains(where)) {
// Here's part of our window management stuff
/* TODO: This is missing CLICK_MOVETOFRONT
if(buttons == B_PRIMARY_MOUSE_BUTTON && !IsFocus())
return CLICK_MOVETOFRONT;
*/
return CLICK_DRAG;
}
// We got this far, so user is clicking on the border?
if (fBorderRect.Contains(where) && !fFrame.Contains(where)) {
STRACE(("WinDecorator():Clicked() - Resize\n"));
// hit-test the borders
if (!(fFlags & B_NOT_RESIZABLE)
&& (fLook == B_TITLED_WINDOW_LOOK
|| fLook == B_FLOATING_WINDOW_LOOK
|| fLook == B_MODAL_WINDOW_LOOK)) {
return CLICK_RESIZE;
}
|| fLook == B_MODAL_WINDOW_LOOK)
&& fBorderRect.Contains(where) && !fFrame.Contains(where)) {
return REGION_BOTTOM_BORDER;
// TODO: Determine the actual border!
}
// Guess user didn't click anything
STRACE(("WinDecorator():Clicked()\n"));
return CLICK_NONE;
return REGION_NONE;
}
@@ -32,9 +32,7 @@ public:
void Draw(BRect r);
void Draw();
click_type MouseAction(const BMessage* message,
BPoint point, int32 buttons,
int32 modifiers);
virtual Region RegionAt(BPoint where) const;
protected:
void _DoLayout();
+30 -34
View File
@@ -6,6 +6,7 @@
* DarkWyrm <bpmagic@columbus.rr.com>
* Stephan Aßmus <superstippi@gmx.de>
* Clemens Zeidler <haiku@clemens-zeidler.de>
* Ingo Weinhold <ingo_weinhold@gmx.de>
*/
@@ -314,44 +315,39 @@ Decorator::GetFootprint()
}
/*! \brief Performs hit-testing for the decorator
/*! \brief Performs hit-testing for the decorator.
Clicked is called whenever it has been determined that the window has
received a mouse click. The default version returns CLICK_NONE. A subclass
may use any or all of them.
The base class provides a basic implementation, recognizing only button and
tab hits. Derived classes must override/enhance it to handle borders and
corners correctly.
Click type : Action taken by the server
- \c CLICK_NONE: Do nothing
- \c CLICK_ZOOM: Handles the zoom button (setting states, etc)
- \c CLICK_CLOSE: Handles the close button (setting states, etc)
- \c CLICK_MINIMIZE: Handles the minimize button (setting states, etc)
- \c CLICK_TAB: Currently unused
- \c CLICK_DRAG: Moves the window to the front and prepares to move the
window
- \c CLICK_MOVE_TO_BACK: Moves the window to the back of the stack
- \c CLICK_MOVE_TO_FRONT: Moves the window to the front of the stack
- \c CLICK_SLIDE_TAB: Initiates tab-sliding
- \c CLICK_RESIZE: Handle window resizing as appropriate
- \c CLICK_RESIZE_L
- \c CLICK_RESIZE_T
- \c CLICK_RESIZE_R
- \c CLICK_RESIZE_B
- \c CLICK_RESIZE_LT
- \c CLICK_RESIZE_RT
- \c CLICK_RESIZE_LB
- \c CLICK_RESIZE_RB
This function is required by all subclasses.
\return The type of area clicked
\param where The point to be tested.
\return Either of the following, depending on what was hit:
- \c REGION_NONE: None of the decorator regions.
- \c REGION_TAB: The window tab (but none of the buttons embedded).
- \c REGION_CLOSE_BUTTON: The close button.
- \c REGION_ZOOM_BUTTON: The zoom button.
- \c REGION_MINIMIZE_BUTTON: The minimize button.
- \c REGION_LEFT_BORDER: The left border.
- \c REGION_RIGHT_BORDER: The right border.
- \c REGION_TOP_BORDER: The top border.
- \c REGION_BOTTOM_BORDER: The bottom border.
- \c REGION_LEFT_TOP_CORNER: The left-top corner.
- \c REGION_LEFT_BOTTOM_CORNER: The left-bottom corner.
- \c REGION_RIGHT_TOP_CORNER: The right-top corner.
- \c REGION_RIGHT_BOTTOM_CORNER The right-bottom corner.
*/
click_type
Decorator::MouseAction(const BMessage* message, BPoint point, int32 buttons,
int32 modifiers)
Decorator::Region
Decorator::RegionAt(BPoint where) const
{
return CLICK_NONE;
if (fCloseRect.Contains(where))
return REGION_CLOSE_BUTTON;
if (fZoomRect.Contains(where))
return REGION_ZOOM_BUTTON;
if (fTabRect.Contains(where))
return REGION_TAB;
return REGION_NONE;
}
+23 -2
View File
@@ -6,6 +6,7 @@
* DarkWyrm <bpmagic@columbus.rr.com>
* Stephan Aßmus <superstippi@gmx.de>
* Clemens Zeidler <haiku@clemens-zeidler.de>
* Ingo Weinhold <ingo_weinhold@gmx.de>
*/
#ifndef DECORATOR_H
#define DECORATOR_H
@@ -47,6 +48,27 @@ enum click_type {
class Decorator {
public:
enum Region {
REGION_NONE,
REGION_TAB,
REGION_CLOSE_BUTTON,
REGION_ZOOM_BUTTON,
REGION_MINIMIZE_BUTTON,
REGION_LEFT_BORDER,
REGION_RIGHT_BORDER,
REGION_TOP_BORDER,
REGION_BOTTOM_BORDER,
REGION_LEFT_TOP_CORNER,
REGION_LEFT_BOTTOM_CORNER,
REGION_RIGHT_TOP_CORNER,
REGION_RIGHT_BOTTOM_CORNER
};
public:
Decorator(DesktopSettings& settings, BRect rect,
window_look look, uint32 flags);
@@ -91,8 +113,7 @@ public:
const BRegion& GetFootprint();
virtual click_type MouseAction(const BMessage* message, BPoint where,
int32 buttons, int32 modifiers);
virtual Region RegionAt(BPoint where) const;
void MoveBy(float x, float y);
void MoveBy(BPoint offset);
+27 -50
View File
@@ -8,6 +8,7 @@
* Philippe Saint-Pierre, stpere@gmail.com
* Ryan Leavengood <leavengood@gmail.com>
* Clemens Zeidler <haiku@clemens-zeidler.de>
* Ingo Weinhold <ingo_weinhold@gmx.de>
*/
@@ -70,8 +71,7 @@ DefaultDecorator::DefaultDecorator(DesktopSettings& settings, BRect rect,
window_look look, uint32 flags)
: Decorator(settings, rect, look, flags),
fTabOffset(0),
fTabLocation(0.0),
fWasDoubleClick(false)
fTabLocation(0.0)
{
_UpdateFont(settings);
@@ -180,43 +180,35 @@ DefaultDecorator::GetSizeLimits(int32* minWidth, int32* minHeight,
}
click_type
DefaultDecorator::MouseAction(const BMessage* message, BPoint point,
int32 buttons, int32 modifiers)
Decorator::Region
DefaultDecorator::RegionAt(BPoint where) const
{
#ifdef DEBUG_DECORATOR
printf("DefaultDecorator: Clicked\n");
printf("\tPoint: (%.1f,%.1f)\n", point.x, point.y);
printf("\tButtons: %ld, Modifiers: 0x%lx\n", buttons, modifiers);
#endif // DEBUG_DECORATOR
// Let the base class version identify hits of the buttons and the tab.
Region region = Decorator::RegionAt(where);
if (region != REGION_NONE)
return region;
click_type action = CLICK_NONE;
// check the resize corner
if (fLook == B_DOCUMENT_WINDOW_LOOK && fResizeRect.Contains(where))
return REGION_RIGHT_BOTTOM_CORNER;
// We start with the smallest rectangles the user might be clicking
// on and gradually work our way out into larger rectangles.
if (!(fFlags & B_NOT_CLOSABLE) && fCloseRect.Contains(point))
action = CLICK_CLOSE;
else if (!(fFlags & B_NOT_ZOOMABLE) && fZoomRect.Contains(point))
action = CLICK_ZOOM;
else if ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0)
action = CLICK_MOVE_TO_BACK;
else if (fLook == B_DOCUMENT_WINDOW_LOOK && fResizeRect.Contains(point))
action = CLICK_RESIZE;
else if (fTabRect.Contains(point)) {
// Clicked in the tab
// hit-test the borders
if (fLeftBorder.Contains(where))
return REGION_LEFT_BORDER;
if (fTopBorder.Contains(where))
return REGION_TOP_BORDER;
// tab sliding in any case if either shift key is held down
// except sliding up-down by moving mouse left-right would look strange
if ((modifiers & B_SHIFT_KEY) != 0 && fLook != kLeftTitledWindowLook)
action = CLICK_SLIDE_TAB;
// Part of the bottom and right borders may be a resize-region, so we have
// to check explicitly, if it has been it.
if (fRightBorder.Contains(where))
region = REGION_RIGHT_BORDER;
else if (fBottomBorder.Contains(where))
region = REGION_BOTTOM_BORDER;
else
action = CLICK_DRAG;
} else if (fLeftBorder.Contains(point) || fRightBorder.Contains(point)
|| fTopBorder.Contains(point) || fBottomBorder.Contains(point)) {
// Clicked on border
return REGION_NONE;
// check resize area
if (!(fFlags & B_NOT_RESIZABLE)
if ((fFlags & B_NOT_RESIZABLE) == 0
&& (fLook == B_TITLED_WINDOW_LOOK
|| fLook == B_FLOATING_WINDOW_LOOK
|| fLook == B_MODAL_WINDOW_LOOK
@@ -224,26 +216,11 @@ DefaultDecorator::MouseAction(const BMessage* message, BPoint point,
BRect resizeRect(BPoint(fBottomBorder.right - kBorderResizeLength,
fBottomBorder.bottom - kBorderResizeLength),
fBottomBorder.RightBottom());
if (resizeRect.Contains(point))
action = CLICK_RESIZE;
} else
action = CLICK_DRAG;
if (resizeRect.Contains(where))
return REGION_RIGHT_BOTTOM_CORNER;
}
if (buttons != 0) {
fWasDoubleClick = message->FindInt32("clicks") == 2
&& fLastAction == action;
}
// Transform double clicks on the border to minimize, if allowed
if (action == CLICK_DRAG && fWasDoubleClick
&& (fFlags & B_NOT_MINIMIZABLE) == 0)
action = CLICK_MINIMIZE;
if (message->what == B_MOUSE_DOWN)
fLastAction = action;
return action;
return region;
}
+1 -7
View File
@@ -37,9 +37,7 @@ public:
virtual void GetSizeLimits(int32* minWidth, int32* minHeight,
int32* maxWidth, int32* maxHeight) const;
virtual click_type MouseAction(const BMessage* message,
BPoint point, int32 buttons,
int32 modifiers);
virtual Region RegionAt(BPoint where) const;
float BorderWidth();
float TabHeight();
@@ -134,10 +132,6 @@ protected:
float fMaxTabSize;
BString fTruncatedTitle;
int32 fTruncatedTitleLength;
private:
click_type fLastAction;
bool fWasDoubleClick;
};
+176 -54
View File
@@ -9,11 +9,14 @@
* Axel Dörfler <axeld@pinc-software.de>
* Brecht Machiels <brecht@mos6581.org>
* Clemens Zeidler <haiku@clemens-zeidler.de>
* Ingo Weinhold <ingo_weinhold@gmx.de>
*/
#include "DefaultWindowBehaviour.h"
#include <WindowPrivate.h>
#include "Desktop.h"
#include "DrawingEngine.h"
#include "Window.h"
@@ -27,6 +30,7 @@
#endif
// The span between mouse down
static const bigtime_t kWindowActivationTimeout = 500000LL;
@@ -39,11 +43,14 @@ DefaultWindowBehaviour::DefaultWindowBehaviour(Window* window)
fIsZooming(false),
fIsSlidingTab(false),
fActivateOnMouseUp(false),
fMinimizeCheckOnMouseUp(false),
fLastMousePosition(0.0f, 0.0f),
fMouseMoveDistance(0.0f),
fLastMoveTime(0),
fLastSnapTime(0)
fLastSnapTime(0),
fLastModifiers(0),
fResetClickCount(0)
{
fDesktop = fWindow->Desktop();
}
@@ -65,33 +72,106 @@ DefaultWindowBehaviour::MouseDown(BMessage* message, BPoint 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");
if (clickCount <= 1) {
fResetClickCount = 0;
} else if (modifiers != fLastModifiers
|| clickCount - fResetClickCount < 1) {
fResetClickCount = clickCount - 1;
clickCount = 1;
} else
clickCount -= fResetClickCount;
fLastModifiers = modifiers;
Region hitRegion = REGION_NONE;
click_type action = CLICK_NONE;
if (windowModifier || inBorderRegion) {
// Click on the window border or we have the window modifier keys held
// click on the window decorator or we have the window modifier keys
// held
// get the functional hit region
if (windowModifier) {
// click with window modifier keys -- let the whole window behave
// like the border
hitRegion = REGION_BORDER;
} else {
// click on the decorator -- get the exact region
hitRegion = _RegionFor(message);
}
// translate the region into an action
int32 buttons = message->FindInt32("buttons");
bool leftButton = (buttons & B_PRIMARY_MOUSE_BUTTON) != 0;
bool rightButton = (buttons & B_SECONDARY_MOUSE_BUTTON) != 0;
uint32 flags = fWindow->Flags();
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_MINIMIZABLE) == 0
&& message->FindInt32("clicks") == 2)
action = CLICK_MINIMIZE;
else if ((fWindow->Flags() & B_NOT_MOVABLE) == 0
&& decorator != NULL)
switch (hitRegion) {
case REGION_NONE:
break;
case REGION_TAB:
// tab sliding in any case if either shift key is held down
// except sliding up-down by moving mouse left-right would look
// strange
if (leftButton && (modifiers & B_SHIFT_KEY) != 0
&& fWindow->Look() != kLeftTitledWindowLook) {
action = CLICK_SLIDE_TAB;
break;
}
// otherwise fall through -- same handling as for the border...
case REGION_BORDER:
if (leftButton)
action = CLICK_DRAG;
else {
// pass click on to the application
windowModifier = false;
}
else if (rightButton)
action = CLICK_MOVE_TO_BACK;
break;
case REGION_CLOSE_BUTTON:
if (leftButton) {
action = (flags & B_NOT_CLOSABLE) == 0
? CLICK_CLOSE : CLICK_DRAG;
} else if (rightButton)
action = CLICK_MOVE_TO_BACK;
break;
case REGION_ZOOM_BUTTON:
if (leftButton) {
action = (flags & B_NOT_ZOOMABLE) == 0
? CLICK_ZOOM : CLICK_DRAG;
} else if (rightButton)
action = CLICK_MOVE_TO_BACK;
break;
case REGION_MINIMIZE_BUTTON:
if (leftButton) {
action = (flags & B_NOT_MINIMIZABLE) == 0
? CLICK_MINIMIZE : CLICK_DRAG;
} else if (rightButton)
action = CLICK_MOVE_TO_BACK;
break;
case REGION_RESIZE_CORNER:
if (leftButton) {
action = (flags & B_NOT_RESIZABLE) == 0
? CLICK_RESIZE : CLICK_DRAG;
} else if (rightButton)
action = CLICK_MOVE_TO_BACK;
break;
}
}
if (!windowModifier && !inBorderRegion) {
// This is a click inside the window's contents
return false;
if (action == CLICK_NONE) {
// No action -- if this is a click inside the window's contents,
// let it be forwarded to the window.
return inBorderRegion;
}
DesktopSettings desktopSettings(fDesktop);
@@ -165,9 +245,6 @@ DefaultWindowBehaviour::MouseDown(BMessage* message, BPoint where)
engine->UnlockParallelAccess();
fWindow->RegionPool()->Recycle(visibleBorder);
} else if (fIsMinimizing) {
fWindow->ServerWindow()->NotifyQuitRequested();
return true;
}
if (action == CLICK_MOVE_TO_BACK) {
@@ -184,13 +261,16 @@ DefaultWindowBehaviour::MouseDown(BMessage* message, BPoint where)
else {
fDesktop->SetFocusWindow(fWindow);
if (action == CLICK_DRAG || action == CLICK_RESIZE) {
if (action == CLICK_DRAG || action == CLICK_RESIZE)
fActivateOnMouseUp = true;
}
if (fIsDragging && clickCount == 2)
fMinimizeCheckOnMouseUp = true;
fMouseMoveDistance = 0.0f;
fLastMoveTime = system_time();
}
}
}
return true;
}
@@ -201,11 +281,9 @@ DefaultWindowBehaviour::MouseUp(BMessage* message, BPoint where)
{
Decorator* decorator = fWindow->Decorator();
if (decorator != NULL) {
int32 modifiers = message->FindInt32("modifiers");
int32 buttons = message->FindInt32("buttons");
click_type action = _ActionFor(message, buttons, modifiers);
if (decorator != NULL) {
// redraw decorator
BRegion* visibleBorder = fWindow->RegionPool()->GetRegion();
fWindow->GetBorderRegion(visibleBorder);
@@ -218,38 +296,43 @@ DefaultWindowBehaviour::MouseUp(BMessage* message, BPoint where)
if (fIsZooming) {
fIsZooming = false;
decorator->SetZoom(false);
if (action == CLICK_ZOOM)
if (_RegionFor(message) == REGION_ZOOM_BUTTON)
fWindow->ServerWindow()->NotifyZoom();
}
if (fIsClosing) {
fIsClosing = false;
decorator->SetClose(false);
if (action == CLICK_CLOSE)
if (_RegionFor(message) == REGION_CLOSE_BUTTON)
fWindow->ServerWindow()->NotifyQuitRequested();
}
if (fIsMinimizing) {
fIsMinimizing = false;
decorator->SetMinimize(false);
if (action == CLICK_MINIMIZE || _IsWindowModifier(modifiers))
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) {
fIsDragging = false;
fIsResizing = false;
fIsSlidingTab = false;
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
// 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
@@ -257,6 +340,11 @@ DefaultWindowBehaviour::MouseUp(BMessage* message, BPoint where)
if (system_time() - fLastMoveTime < kWindowActivationTimeout)
fDesktop->ActivateWindow(fWindow);
}
fIsDragging = false;
fIsResizing = false;
fIsSlidingTab = false;
}
}
@@ -285,10 +373,12 @@ DefaultWindowBehaviour::MouseMoved(BMessage *message, BPoint where, bool isFake)
// the then current mouse position
return;
}
if (fActivateOnMouseUp) {
if (fActivateOnMouseUp || fMinimizeCheckOnMouseUp) {
if (now - fLastMoveTime >= kWindowActivationTimeout) {
// This click is too long already for window activation.
// This click is too long already for window activation/
// minimizing.
fActivateOnMouseUp = false;
fMinimizeCheckOnMouseUp = false;
}
} else
fLastMoveTime = now;
@@ -303,16 +393,14 @@ DefaultWindowBehaviour::MouseMoved(BMessage *message, BPoint where, bool isFake)
engine->LockParallelAccess();
engine->ConstrainClippingRegion(visibleBorder);
int32 buttons = message->FindInt32("buttons");
int32 modifiers = message->FindInt32("modifiers");
click_type type = _ActionFor(message, buttons, modifiers);
Region hitRegion = _RegionFor(message);
if (fIsZooming)
decorator->SetZoom(type == CLICK_ZOOM);
decorator->SetZoom(hitRegion == REGION_ZOOM_BUTTON);
else if (fIsClosing)
decorator->SetClose(type == CLICK_CLOSE);
decorator->SetClose(hitRegion == REGION_CLOSE_BUTTON);
else if (fIsMinimizing)
decorator->SetMinimize(type == CLICK_MINIMIZE);
decorator->SetMinimize(hitRegion == REGION_MINIMIZE_BUTTON);
engine->UnlockParallelAccess();
fWindow->RegionPool()->Recycle(visibleBorder);
@@ -329,11 +417,12 @@ DefaultWindowBehaviour::MouseMoved(BMessage *message, BPoint where, bool isFake)
// If the window was moved enough, it doesn't come to
// the front in FFM mode when the mouse is released.
if (fActivateOnMouseUp) {
if (fActivateOnMouseUp || fMinimizeCheckOnMouseUp) {
fMouseMoveDistance += delta.x * delta.x + delta.y * delta.y;
if (fMouseMoveDistance > 16.0f)
if (fMouseMoveDistance > 16.0f) {
fActivateOnMouseUp = false;
else
fMinimizeCheckOnMouseUp = false;
} else
delta = B_ORIGIN;
}
@@ -403,19 +492,52 @@ DefaultWindowBehaviour::_IsWindowModifier(int32 modifiers) const
}
click_type
DefaultWindowBehaviour::_ActionFor(const BMessage* message, int32 buttons,
int32 modifiers) const
DefaultWindowBehaviour::Region
DefaultWindowBehaviour::_RegionFor(const BMessage* message) const
{
Decorator* decorator = fWindow->Decorator();
if (decorator == NULL)
return CLICK_NONE;
return REGION_NONE;
BPoint where;
if (message->FindPoint("where", &where) != B_OK)
return CLICK_NONE;
return REGION_NONE;
return decorator->MouseAction(message, where, buttons, modifiers);
// translate the tab region into a functional region
switch (decorator->RegionAt(where)) {
case Decorator::REGION_NONE:
return REGION_NONE;
case Decorator::REGION_TAB:
return REGION_TAB;
case Decorator::REGION_CLOSE_BUTTON:
return REGION_CLOSE_BUTTON;
case Decorator::REGION_ZOOM_BUTTON:
return REGION_ZOOM_BUTTON;
case Decorator::REGION_MINIMIZE_BUTTON:
return REGION_MINIMIZE_BUTTON;
case Decorator::REGION_LEFT_BORDER:
case Decorator::REGION_RIGHT_BORDER:
case Decorator::REGION_TOP_BORDER:
case Decorator::REGION_BOTTOM_BORDER:
return REGION_BORDER;
case Decorator::REGION_LEFT_TOP_CORNER:
case Decorator::REGION_LEFT_BOTTOM_CORNER:
case Decorator::REGION_RIGHT_TOP_CORNER:
// not supported yet
return REGION_BORDER;
case Decorator::REGION_RIGHT_BOTTOM_CORNER:
return REGION_RESIZE_CORNER;
default:
return REGION_NONE;
}
}
+19 -2
View File
@@ -9,6 +9,7 @@
* Axel Dörfler <axeld@pinc-software.de>
* Brecht Machiels <brecht@mos6581.org>
* Clemens Zeidler <haiku@clemens-zeidler.de>
* Ingo Weinhold <ingo_weinhold@gmx.de>
*/
#ifndef DEFAULT_WINDOW_BEHAVIOUR_H
#define DEFAULT_WINDOW_BEHAVIOUR_H
@@ -33,10 +34,23 @@ public:
virtual void MouseMoved(BMessage *message, BPoint where,
bool isFake);
private:
enum Region {
REGION_NONE,
REGION_TAB,
REGION_BORDER,
REGION_CLOSE_BUTTON,
REGION_ZOOM_BUTTON,
REGION_MINIMIZE_BUTTON,
REGION_RESIZE_CORNER
};
private:
bool _IsWindowModifier(int32 modifiers) const;
click_type _ActionFor(const BMessage* message,
int32 buttons, int32 modifiers) const;
Region _RegionFor(const BMessage* message) const;
void _AlterDeltaForSnap(BPoint& delta,
bigtime_t now);
@@ -49,11 +63,14 @@ protected:
bool fIsZooming : 1;
bool fIsSlidingTab : 1;
bool fActivateOnMouseUp : 1;
bool fMinimizeCheckOnMouseUp : 1;
BPoint fLastMousePosition;
float fMouseMoveDistance;
bigtime_t fLastMoveTime;
bigtime_t fLastSnapTime;
int32 fLastModifiers;
int32 fResetClickCount;
};