diff --git a/src/add-ons/decorators/BeDecorator/BeDecorator.cpp b/src/add-ons/decorators/BeDecorator/BeDecorator.cpp index c8e7a32f5a..d39d8e0049 100644 --- a/src/add-ons/decorators/BeDecorator/BeDecorator.cpp +++ b/src/add-ons/decorators/BeDecorator/BeDecorator.cpp @@ -89,7 +89,7 @@ BeDecorAddOn::BeDecorAddOn(image_id id, const char* name) : DecorAddOn(id, name) { - + } @@ -214,76 +214,47 @@ 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; + // 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; - 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 - - // check resize area - if (!(fFlags & B_NOT_RESIZABLE) - && (fLook == B_TITLED_WINDOW_LOOK - || fLook == B_FLOATING_WINDOW_LOOK - || fLook == B_MODAL_WINDOW_LOOK - || fLook == kLeftTitledWindowLook)) { - BRect resizeRect(BPoint(fBottomBorder.right - kBorderResizeLength, - fBottomBorder.bottom - kBorderResizeLength), - fBottomBorder.RightBottom()); - if (resizeRect.Contains(point)) - return CLICK_RESIZE; - } - - clicked = true; + // check resize area + if ((fFlags & B_NOT_RESIZABLE) == 0 + && (fLook == B_TITLED_WINDOW_LOOK + || fLook == B_FLOATING_WINDOW_LOOK + || fLook == B_MODAL_WINDOW_LOOK + || fLook == kLeftTitledWindowLook)) { + BRect resizeRect(BPoint(fBottomBorder.right - kBorderResizeLength, + fBottomBorder.bottom - kBorderResizeLength), + fBottomBorder.RightBottom()); + if (resizeRect.Contains(where)) + return REGION_RIGHT_BOTTOM_CORNER; } - 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; } diff --git a/src/add-ons/decorators/MacDecorator/MacDecorator.cpp b/src/add-ons/decorators/MacDecorator/MacDecorator.cpp index e805c18d3c..320c8b5a62 100644 --- a/src/add-ons/decorators/MacDecorator/MacDecorator.cpp +++ b/src/add-ons/decorators/MacDecorator/MacDecorator.cpp @@ -34,7 +34,7 @@ MacDecorAddOn::MacDecorAddOn(image_id id, const char* name) : DecorAddOn(id, name) { - + } @@ -64,7 +64,7 @@ MacDecorator::MacDecorator(DesktopSettings& settings, BRect rect, frame_midcol = (rgb_color){ 216, 216, 216, 255 }; frame_lowcol = (rgb_color){ 110, 110, 110, 255 }; frame_lowercol = (rgb_color){ 0, 0, 0, 255 }; - + fButtonHighColor = (rgb_color){ 232, 232, 232, 255 }; fButtonLowColor = (rgb_color){ 128, 128, 128, 255 }; @@ -72,7 +72,7 @@ MacDecorator::MacDecorator(DesktopSettings& settings, BRect rect, fNonFocusTextColor = settings.UIColor(B_WINDOW_INACTIVE_TEXT_COLOR); _DoLayout(); - + textoffset=5; STRACE(("MacDecorator()\n")); @@ -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; - } - - // 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; - } + // check the resize corner + if (fLook == B_DOCUMENT_WINDOW_LOOK && fResizeRect.Contains(where)) + return REGION_RIGHT_BOTTOM_CORNER; - // 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; } @@ -215,7 +201,7 @@ MacDecorator::_DoLayout() fMinimizeRect=fZoomRect; fCloseRect.OffsetTo(fTabRect.left+4,fTabRect.top+4); - + fZoomRect.OffsetBy(0-(fZoomRect.Width()+4),0); if (Title() && fDrawingEngine) { titlepixelwidth=fDrawingEngine->StringWidth(Title(),strlen(Title())); @@ -468,7 +454,7 @@ MacDecorator::_DrawTab(BRect invalid) } } - // Draw the buttons if we're supposed to + // Draw the buttons if we're supposed to if (!(fFlags & B_NOT_CLOSABLE)) _DrawClose(fCloseRect); if (!(fFlags & B_NOT_ZOOMABLE)) @@ -776,7 +762,7 @@ MacDecorator::_GetFootprint(BRegion* region) if (fLook == B_NO_BORDER_WINDOW_LOOK) return; - + region->Set(fBorderRect); region->Exclude(fFrame); diff --git a/src/add-ons/decorators/MacDecorator/MacDecorator.h b/src/add-ons/decorators/MacDecorator/MacDecorator.h index d2b0f2eea4..2eebfa0e9e 100644 --- a/src/add-ons/decorators/MacDecorator/MacDecorator.h +++ b/src/add-ons/decorators/MacDecorator/MacDecorator.h @@ -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(); @@ -57,7 +55,7 @@ protected: BRegion* updateRegion = NULL); void _SetFlags(uint32 flags, BRegion* updateRegion = NULL); - + void _SetColors(); void _MoveBy(BPoint offset); diff --git a/src/add-ons/decorators/SATDecorator/StackAndTile.cpp b/src/add-ons/decorators/SATDecorator/StackAndTile.cpp index 6137dc7a60..3c0f360804 100644 --- a/src/add-ons/decorators/SATDecorator/StackAndTile.cpp +++ b/src/add-ons/decorators/SATDecorator/StackAndTile.cpp @@ -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) - return; + + 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; @@ -330,7 +340,7 @@ StackAndTile::WindowLookChanged(Window* window, window_look look) SATGroup* group = satWindow->GetGroup(); if (!group) return; - group->RemoveWindow(satWindow); + group->RemoveWindow(satWindow); } @@ -617,5 +627,5 @@ WindowIterator::_ReverseRewind() SATSnappingBehaviour::~SATSnappingBehaviour() { - + } diff --git a/src/add-ons/decorators/WinDecorator/WinDecorator.cpp b/src/add-ons/decorators/WinDecorator/WinDecorator.cpp index d04b71fe2e..c4ffa19c3f 100644 --- a/src/add-ons/decorators/WinDecorator/WinDecorator.cpp +++ b/src/add-ons/decorators/WinDecorator/WinDecorator.cpp @@ -77,7 +77,7 @@ WinDecorator::WinDecorator(DesktopSettings& settings, BRect rect, // Do initial decorator setup _DoLayout(); - + textoffset=5; STRACE(("WinDecorator()\n")); @@ -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; - - // 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; + // check the resize corner + if (fLook == B_DOCUMENT_WINDOW_LOOK && fResizeRect.Contains(where)) + return REGION_RIGHT_BOTTOM_CORNER; + + // 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(where) && !fFrame.Contains(where)) { + return REGION_BOTTOM_BORDER; + // TODO: Determine the actual border! } - // We got this far, so user is clicking on the border? - if (fBorderRect.Contains(where) && !fFrame.Contains(where)) { - STRACE(("WinDecorator():Clicked() - Resize\n")); - if (!(fFlags & B_NOT_RESIZABLE) - && (fLook == B_TITLED_WINDOW_LOOK - || fLook == B_FLOATING_WINDOW_LOOK - || fLook == B_MODAL_WINDOW_LOOK)) { - return CLICK_RESIZE; - } - } - - // Guess user didn't click anything - STRACE(("WinDecorator():Clicked()\n")); - return CLICK_NONE; + return REGION_NONE; } @@ -162,7 +151,7 @@ WinDecorator::_DoLayout() STRACE(("WinDecorator()::_DoLayout()\n")); bool hasTab = false; - + fBorderRect=fFrame; fTabRect=fFrame; @@ -224,13 +213,13 @@ WinDecorator::_DrawFrame(BRect rect) return; BRect r = fBorderRect; - + fDrawingEngine->SetHighColor(frame_lowercol); fDrawingEngine->StrokeRect(r); if (fLook == B_BORDERED_WINDOW_LOOK) return; - + BPoint pt; pt=r.RightTop(); @@ -242,7 +231,7 @@ WinDecorator::_DrawFrame(BRect rect) fDrawingEngine->StrokeLine(r.RightTop(),r.RightBottom(),frame_lowercol); fDrawingEngine->StrokeLine(r.LeftBottom(),r.RightBottom(),frame_lowercol); - + r.InsetBy(1,1); pt=r.RightTop(); pt.x--; @@ -253,7 +242,7 @@ WinDecorator::_DrawFrame(BRect rect) fDrawingEngine->StrokeLine(r.RightTop(),r.RightBottom(),frame_lowcol); fDrawingEngine->StrokeLine(r.LeftBottom(),r.RightBottom(),frame_lowcol); - + r.InsetBy(1,1); fDrawingEngine->StrokeRect(r,frame_midcol); r.InsetBy(1,1); @@ -273,7 +262,7 @@ WinDecorator::_DrawTab(BRect invalid) _DrawTitle(fTabRect); - // Draw the buttons if we're supposed to + // Draw the buttons if we're supposed to // TODO : we should still draw the buttons if they are disabled, but grey them out if (!(fFlags & B_NOT_CLOSABLE) && invalid.Intersects(fCloseRect)) _DrawClose(fCloseRect); @@ -287,14 +276,14 @@ WinDecorator::_DrawClose(BRect r) { // Just like DrawZoom, but for a close button _DrawBeveledRect(r,GetClose()); - + // Draw the X BRect rect(r); rect.InsetBy(4,4); rect.right--; rect.top--; - + if (GetClose()) rect.OffsetBy(1,1); @@ -333,7 +322,7 @@ void WinDecorator::_DrawZoom(BRect r) { _DrawBeveledRect(r,GetZoom()); - + // Draw the Zoom box BRect rect(r); @@ -341,7 +330,7 @@ WinDecorator::_DrawZoom(BRect r) rect.InsetBy(1,0); rect.bottom--; rect.right--; - + if (GetZoom()) rect.OffsetBy(1,1); @@ -363,7 +352,7 @@ WinDecorator::_DrawMinimize(BRect r) BRect rect(r.left+5,r.bottom-4,r.right-5,r.bottom-3); if(GetMinimize()) rect.OffsetBy(1,1); - + fDrawingEngine->SetHighColor(RGBColor(0,0,0)); fDrawingEngine->StrokeRect(rect); } @@ -523,7 +512,7 @@ WinDecorator::_GetFootprint(BRegion* region) if (fLook == B_NO_BORDER_WINDOW_LOOK) return; - + region->Set(fBorderRect); region->Include(fTabRect); region->Exclude(fFrame); @@ -553,7 +542,7 @@ WinDecorator::_DrawBeveledRect(BRect r, bool down) RGBColor mid; RGBColor low; RGBColor lower; - + if (down) { lower.SetColor(255,255,255); low.SetColor(216,216,216); @@ -582,7 +571,7 @@ WinDecorator::_DrawBeveledRect(BRect r, bool down) pt=rect.RightTop(); pt.y++; fDrawingEngine->StrokeLine(pt,rect.RightBottom(),lower); - + // Bottom shading pt=rect.LeftBottom(); pt.x++; @@ -600,12 +589,12 @@ WinDecorator::_DrawBeveledRect(BRect r, bool down) pt=rect.RightTop(); pt.y++; fDrawingEngine->StrokeLine(pt,rect.RightBottom(),lower); - + // Bottom inside shading pt=rect.LeftBottom(); pt.x++; fDrawingEngine->StrokeLine(pt,rect.RightBottom(),lower); - + rect.InsetBy(1,1); fDrawingEngine->FillRect(rect,mid); diff --git a/src/add-ons/decorators/WinDecorator/WinDecorator.h b/src/add-ons/decorators/WinDecorator/WinDecorator.h index 9dc9722998..60ea74cd08 100644 --- a/src/add-ons/decorators/WinDecorator/WinDecorator.h +++ b/src/add-ons/decorators/WinDecorator/WinDecorator.h @@ -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(); @@ -57,7 +55,7 @@ protected: BRegion* updateRegion = NULL); void _SetFlags(uint32 flags, BRegion* updateRegion = NULL); - + void _SetColors(); void _MoveBy(BPoint pt); @@ -72,7 +70,7 @@ private: private: uint32 taboffset; - + rgb_color tab_highcol; rgb_color tab_lowcol; rgb_color frame_highcol; @@ -85,10 +83,10 @@ private: rgb_color fFocusTextColor; rgb_color fNonFocusTextColor; uint64 solidhigh, solidlow; - + BString fTruncatedTitle; int32 fTruncatedTitleLength; - + bool slidetab; int textoffset; }; diff --git a/src/servers/app/Decorator.cpp b/src/servers/app/Decorator.cpp index a74d3c548a..fdc2c2c202 100644 --- a/src/servers/app/Decorator.cpp +++ b/src/servers/app/Decorator.cpp @@ -6,6 +6,7 @@ * DarkWyrm * Stephan Aßmus * Clemens Zeidler + * Ingo Weinhold */ @@ -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; } diff --git a/src/servers/app/Decorator.h b/src/servers/app/Decorator.h index 3815fcda42..65937cecf7 100644 --- a/src/servers/app/Decorator.h +++ b/src/servers/app/Decorator.h @@ -6,6 +6,7 @@ * DarkWyrm * Stephan Aßmus * Clemens Zeidler + * Ingo Weinhold */ #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); diff --git a/src/servers/app/DefaultDecorator.cpp b/src/servers/app/DefaultDecorator.cpp index 3360077398..86b7100e92 100644 --- a/src/servers/app/DefaultDecorator.cpp +++ b/src/servers/app/DefaultDecorator.cpp @@ -8,6 +8,7 @@ * Philippe Saint-Pierre, stpere@gmail.com * Ryan Leavengood * Clemens Zeidler + * Ingo Weinhold */ @@ -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,70 +180,47 @@ 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; - else - action = CLICK_DRAG; - } 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) - && (fLook == B_TITLED_WINDOW_LOOK - || fLook == B_FLOATING_WINDOW_LOOK - || fLook == B_MODAL_WINDOW_LOOK - || fLook == kLeftTitledWindowLook)) { - BRect resizeRect(BPoint(fBottomBorder.right - kBorderResizeLength, - fBottomBorder.bottom - kBorderResizeLength), - fBottomBorder.RightBottom()); - if (resizeRect.Contains(point)) - action = CLICK_RESIZE; - } else - action = CLICK_DRAG; + // check resize area + if ((fFlags & B_NOT_RESIZABLE) == 0 + && (fLook == B_TITLED_WINDOW_LOOK + || fLook == B_FLOATING_WINDOW_LOOK + || fLook == B_MODAL_WINDOW_LOOK + || fLook == kLeftTitledWindowLook)) { + BRect resizeRect(BPoint(fBottomBorder.right - kBorderResizeLength, + fBottomBorder.bottom - kBorderResizeLength), + fBottomBorder.RightBottom()); + 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; } diff --git a/src/servers/app/DefaultDecorator.h b/src/servers/app/DefaultDecorator.h index 313ccd445e..02dcdb8020 100644 --- a/src/servers/app/DefaultDecorator.h +++ b/src/servers/app/DefaultDecorator.h @@ -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; }; diff --git a/src/servers/app/DefaultWindowBehaviour.cpp b/src/servers/app/DefaultWindowBehaviour.cpp index 46bb087cc0..6a6880a532 100644 --- a/src/servers/app/DefaultWindowBehaviour.cpp +++ b/src/servers/app/DefaultWindowBehaviour.cpp @@ -9,11 +9,14 @@ * Axel Dörfler * Brecht Machiels * Clemens Zeidler + * Ingo Weinhold */ #include "DefaultWindowBehaviour.h" +#include + #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 - int32 buttons = message->FindInt32("buttons"); + // click on the window decorator or we have the window modifier keys + // held - 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) - action = CLICK_DRAG; - else { - // pass click on to the application - windowModifier = false; - } + // 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(); + + 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 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,12 +261,15 @@ 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; - fMouseMoveDistance = 0.0f; - fLastMoveTime = system_time(); - } } + + 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); + int32 buttons = message->FindInt32("buttons"); + if (decorator != NULL) { // redraw decorator BRegion* visibleBorder = fWindow->RegionPool()->GetRegion(); fWindow->GetBorderRegion(visibleBorder); @@ -218,44 +296,54 @@ 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; - } } - // 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); + // 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; } } @@ -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; + } } diff --git a/src/servers/app/DefaultWindowBehaviour.h b/src/servers/app/DefaultWindowBehaviour.h index c9760771a3..845ef5480c 100644 --- a/src/servers/app/DefaultWindowBehaviour.h +++ b/src/servers/app/DefaultWindowBehaviour.h @@ -9,6 +9,7 @@ * Axel Dörfler * Brecht Machiels * Clemens Zeidler + * Ingo Weinhold */ #ifndef DEFAULT_WINDOW_BEHAVIOUR_H #define DEFAULT_WINDOW_BEHAVIOUR_H @@ -32,28 +33,44 @@ public: virtual void MouseUp(BMessage* message, BPoint where); 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); 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; + int32 fLastModifiers; + int32 fResetClickCount; };