From 1b65556d662b8ffbc251791433c58112eac398b4 Mon Sep 17 00:00:00 2001 From: Adi Oanca Date: Sun, 18 Sep 2005 22:43:31 +0000 Subject: [PATCH] more work on the input handling. I let Layer/WinBorder handle the MouseDown/Moved/Up instead of doing this in RootLayer::MouseEventHandler(). I did this because I felt it's more clean and in the near future RootLayer may have other children than WinBorders, for example simple Layers representing tooltips/bubbles/etc. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14198 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/servers/app/Layer.cpp | 13 ++- src/servers/app/Layer.h | 2 +- src/servers/app/RootLayer.cpp | 70 ++----------- src/servers/app/WinBorder.cpp | 181 +++++++++++++++++++++++++--------- src/servers/app/Workspace.cpp | 21 +++- src/servers/app/Workspace.h | 1 + 6 files changed, 171 insertions(+), 117 deletions(-) diff --git a/src/servers/app/Layer.cpp b/src/servers/app/Layer.cpp index 0e87322f39..688c2c8a64 100644 --- a/src/servers/app/Layer.cpp +++ b/src/servers/app/Layer.cpp @@ -404,9 +404,20 @@ Layer::FindLayer(const int32 token) \return The layer containing the point or NULL if no layer found */ Layer* -Layer::LayerAt(const BPoint &pt) +Layer::LayerAt(const BPoint &pt, bool recursive) { //printf("%p:%s:LayerAt(x = %g, y = %g)\n", this, Name(), pt.x, pt.y); + if (!recursive) { + if (VisibleRegion().Contains(pt)) + return this; + + for (Layer* child = LastChild(); child; child = PreviousChild()) + if (child->FullVisible().Contains(pt)) + return child; + + return NULL; + } + #ifndef NEW_CLIPPING if (fVisible.Contains(pt)) return this; diff --git a/src/servers/app/Layer.h b/src/servers/app/Layer.h index 131cb0379d..07b1677a72 100644 --- a/src/servers/app/Layer.h +++ b/src/servers/app/Layer.h @@ -108,7 +108,7 @@ class Layer { uint32 CountChildren() const; Layer* FindLayer(const int32 token); - Layer* LayerAt(const BPoint &pt); + Layer* LayerAt(const BPoint &pt, bool recursive = true); virtual Layer* FirstChild() const; virtual Layer* NextChild() const; diff --git a/src/servers/app/RootLayer.cpp b/src/servers/app/RootLayer.cpp index 9f92731983..dc3b2a9dfc 100644 --- a/src/servers/app/RootLayer.cpp +++ b/src/servers/app/RootLayer.cpp @@ -1145,67 +1145,11 @@ RootLayer::MouseEventHandler(int32 code, BPrivate::PortLink& msg) if (fLastLayerUnderMouse == this) break; + #ifdef NEW_INPUT_HANDLING - WinBorder* winBorderUnderMouse = fLastLayerUnderMouse->Owner() ? - fLastLayerUnderMouse->fOwner : - (WinBorder*)fLastLayerUnderMouse; - - DesktopSettings ds(gDesktop); - Workspace::State oldState, newState; - click_type action = winBorderUnderMouse->ActionFor(evt); - - ActiveWorkspace()->GetState(&oldState); - if (action == DEC_MOVETOBACK) { - ActiveWorkspace()->AttemptToMoveToBack(winBorderUnderMouse); - } - // in FFM, only bring in front if clicking on WinBorder's(decorator's) area - else if (dynamic_cast(fLastLayerUnderMouse) || ds.MouseMode() == B_NORMAL_MOUSE) { - ActiveWorkspace()->AttemptToSetFront(winBorderUnderMouse); - } - ActiveWorkspace()->AttemptToSetFocus(winBorderUnderMouse); - ActiveWorkspace()->GetState(&newState); - - // send window activation messages - - // NOTE !!! ATM we're sending B_WINDOW_ACTIVATED to front windows only! - // This means floating windows do not have their BWindow::WindowActivated() - // hook function called. - if (oldState.Front != newState.Front) { - if (oldState.Front && oldState.Front->Window()) { - BMessage msg(B_WINDOW_ACTIVATED); - msg.AddBool("active", false); - oldState.Front->Window()->SendMessageToClient(&msg, B_NULL_TOKEN, false); - } - if (newState.Front && newState.Front->Window()) { - BMessage msg(B_WINDOW_ACTIVATED); - msg.AddBool("active", true); - newState.Front->Window()->SendMessageToClient(&msg, B_NULL_TOKEN, false); - } - } - - // calculate the region that must be invalidated/redrawn - - // first, if the focus window changed, make sure the decorators reflect this state. - BRegion dirtyRegion; - if (oldState.Focus != newState.Focus) { - dirtyRegion.Include(&oldState.Focus->VisibleRegion()); - dirtyRegion.Include(&newState.Focus->VisibleRegion()); - } - -#ifndef NEW_CLIPPING - invalidate_layer(this, dirtyRegion); -#else - do_Invalidate(dirtyRegion); -#endif - -#ifndef NEW_CLIPPING - invalidate_layer(this, fFull); -#else - do_Invalidate(Bounds()); -#endif -// TODO: DO NOT ALWAYS SEND THE FIRST MOUSE DOWN!!! -// TODO: if B_WILL_ACCEPT_FIRST_CLICK, DO NOT ACTIVATE THE CLICKED WINDOW!!! - fLastLayerUnderMouse->MouseDown(evt); + // get the pointer for one of the first RootLayer's descendants + Layer *primaryTarget = LayerAt(evt.where, false); + primaryTarget->MouseDown(evt); #else // we are clicking a WinBorder @@ -2241,7 +2185,7 @@ RootLayer::draw_window_tab(WinBorder *exFocus) } #ifndef NEW_CLIPPING -inline void +void RootLayer::empty_visible_regions(Layer *layer) { // TODO: optimize by avoiding recursion? @@ -2257,7 +2201,7 @@ RootLayer::empty_visible_regions(Layer *layer) } #endif -inline void +void RootLayer::winborder_activation(WinBorder* exActive) { // ToDo: not sure if this is correct - do floating windows get WindowActivated() events? @@ -2274,7 +2218,7 @@ RootLayer::winborder_activation(WinBorder* exActive) } -inline void +void RootLayer::show_final_scene(WinBorder *exFocus, WinBorder *exActive) { if (fHaveWinBorderList || get_workspace_windows()) { diff --git a/src/servers/app/WinBorder.cpp b/src/servers/app/WinBorder.cpp index d8e5360902..5a939c3b18 100644 --- a/src/servers/app/WinBorder.cpp +++ b/src/servers/app/WinBorder.cpp @@ -218,7 +218,7 @@ fInUpdateRegion.OffsetBy(x, y); // ...and here we get really hacky... fTopLayer->fFrame.OffsetTo(0.0, 0.0); } else { - move_layer(x, y); + Layer::move_layer(x, y); } if (Window()) { @@ -448,62 +448,145 @@ WinBorder::GetSizeLimits(float* minWidth, float* maxWidth, #ifdef NEW_INPUT_HANDLING void -WinBorder::MouseDown(const PointerEvent& event) +WinBorder::MouseDown(const PointerEvent& evt) { - if (fDecorator) { - click_type action = _ActionFor(event); - // find out where user clicked in Decorator - switch(action) { - case DEC_CLOSE: - fIsClosing = true; - fDecorator->SetClose(true); - STRACE_CLICK(("===> DEC_CLOSE\n")); - break; - - case DEC_ZOOM: - fIsZooming = true; - fDecorator->SetZoom(true); - STRACE_CLICK(("===> DEC_ZOOM\n")); - break; - - case DEC_MINIMIZE: - fIsMinimizing = true; - fDecorator->SetMinimize(true); - STRACE_CLICK(("===> DEC_MINIMIZE\n")); - break; + DesktopSettings desktopSettings(gDesktop); + Workspace::State oldState, newState; - case DEC_DRAG: - fIsDragging = true; -#ifdef NEW_INPUT_HANDLING -GetRootLayer()->SetNotifyLayer(this, B_POINTER_EVENTS, 0UL); + GetRootLayer()->ActiveWorkspace()->GetState(&oldState); + + // not in FFM mode? + if (desktopSettings.MouseMode() == B_NORMAL_MOUSE) { + // default action is to drag the WinBorder + click_type action = DEC_DRAG; + Layer *target = LayerAt(evt.where); + // clicking a simple Layer. + if (target != this) { + if (GetRootLayer()->ActiveWorkspace()->Active() == this) { + target->MouseDown(evt); + } + else { + if (WindowFlags() & B_WILL_ACCEPT_FIRST_CLICK) + target->MouseDown(evt); + else + goto activateWindow; + } +// TODO: send mouse down to event registered BViews!!! + } + // clicking WinBorder visible area + else { + winBorderAreaHandle: + + if (fDecorator) + action = _ActionFor(evt); + + // set decorator internals + switch(action) { + case DEC_CLOSE: + fIsClosing = true; + fDecorator->SetClose(true); + STRACE_CLICK(("===> DEC_CLOSE\n")); + break; + + case DEC_ZOOM: + fIsZooming = true; + fDecorator->SetZoom(true); + STRACE_CLICK(("===> DEC_ZOOM\n")); + break; + + case DEC_MINIMIZE: + fIsMinimizing = true; + fDecorator->SetMinimize(true); + STRACE_CLICK(("===> DEC_MINIMIZE\n")); + break; + + case DEC_DRAG: + fIsDragging = true; + fLastMousePosition = evt.where; + STRACE_CLICK(("===> DEC_DRAG\n")); + break; + + case DEC_RESIZE: + fIsResizing = true; + fLastMousePosition = evt.where; + STRACE_CLICK(("===> DEC_RESIZE\n")); + break; + + case DEC_SLIDETAB: + fIsSlidingTab = true; + fLastMousePosition = evt.where; + STRACE_CLICK(("===> DEC_SLIDETAB\n")); + break; + + default: + break; + } + + // based on what the Decorator returned, properly place this window. + if (action == DEC_MOVETOBACK) { + GetRootLayer()->ActiveWorkspace()->MoveToBack(this); + } + else if (action == DEC_DRAG) { + GetRootLayer()->SetNotifyLayer(this, B_POINTER_EVENTS, 0UL); + activateWindow: + GetRootLayer()->ActiveWorkspace()->AttemptToActivate(this); + } + + GetRootLayer()->ActiveWorkspace()->GetState(&newState); +//-------------------------- +// BOOKMARK! + // send window activation messages + + // NOTE !!! ATM we're sending B_WINDOW_ACTIVATED to front windows only! + // This means floating windows do not have their BWindow::WindowActivated() + // hook function called. + if (oldState.Front != newState.Front) { + if (oldState.Front && oldState.Front->Window()) { + BMessage msg(B_WINDOW_ACTIVATED); + msg.AddBool("active", false); + oldState.Front->Window()->SendMessageToClient(&msg, B_NULL_TOKEN, false); + } + if (newState.Front && newState.Front->Window()) { + BMessage msg(B_WINDOW_ACTIVATED); + msg.AddBool("active", true); + newState.Front->Window()->SendMessageToClient(&msg, B_NULL_TOKEN, false); + } + } + + // calculate the region that must be invalidated/redrawn + + // first, if the focus window changed, make sure the decorators reflect this state. + BRegion dirtyRegion; + if (oldState.Focus != newState.Focus) { + dirtyRegion.Include(&oldState.Focus->VisibleRegion()); + dirtyRegion.Include(&newState.Focus->VisibleRegion()); +#ifndef NEW_CLIPPING + GetRootLayer()->fRedrawReg.Include(&dirtyRegion); +#else +// TODO: code for new clipping engine! #endif - fLastMousePosition = event.where; - STRACE_CLICK(("===> DEC_DRAG\n")); - break; + } - case DEC_RESIZE: - fIsResizing = true; - fLastMousePosition = event.where; - STRACE_CLICK(("===> DEC_RESIZE\n")); - break; +#ifndef NEW_CLIPPING + GetRootLayer()->invalidate_layer(this, fFull); +#else + GetRootLayer()->do_Invalidate(Bounds()); +#endif - case DEC_SLIDETAB: - fIsSlidingTab = true; - fLastMousePosition = event.where; - STRACE_CLICK(("===> DEC_SLIDETAB\n")); - break; - default: - break; +// TODO: FINISH ABOVE. } } - - // TODO: set dirty regions! -#ifndef NEW_CLIPPING - GetRootLayer()->invalidate_layer(this, VisibleRegion()); -#else - do_Invalidate(VisibleRegion()); -#endif + // in FFM mode + else { + Layer *target = LayerAt(evt.where); + // clicking a simple Layer; forward event. + if (target != this) + target->MouseDown(evt); + // clicking inside our visible area. + else + goto winBorderAreaHandle; + } } void diff --git a/src/servers/app/Workspace.cpp b/src/servers/app/Workspace.cpp index 1681e7361d..5f2b70eaea 100644 --- a/src/servers/app/Workspace.cpp +++ b/src/servers/app/Workspace.cpp @@ -214,9 +214,16 @@ Workspace::Front() const WinBorder * Workspace::Active() const { - // ToDo: for now! - return Focus(); - //return fActiveItem ? fActiveItem->layerPtr: NULL; + // in case of a normal or modal window + if (fFrontItem && fFrontItem == fFocusItem) + return fFrontItem->layerPtr; + + // a floating window is considered active if it has focus. + if (fFocusItem && (fFocusItem->layerPtr->Level() == B_FLOATING_APP || + fFocusItem->layerPtr->Level() == B_FLOATING_ALL)) + return fFocusItem->layerPtr; + + return NULL; } void @@ -249,6 +256,14 @@ Workspace::AttemptToMoveToBack(WinBorder *newBack) { return MoveToBack(newBack); } + +bool +Workspace::AttemptToActivate(WinBorder *toActivate) +{ + MoveToFront(toActivate); + SetFocus(toActivate); + return Active() == toActivate; +} /* \brief This method provides you the list of visible windows in this workspace. \param list The list of visible WinBorders found in this workspace. diff --git a/src/servers/app/Workspace.h b/src/servers/app/Workspace.h index 96fd151aab..b0e9b11a28 100644 --- a/src/servers/app/Workspace.h +++ b/src/servers/app/Workspace.h @@ -74,6 +74,7 @@ class Workspace { bool AttemptToSetFront(WinBorder *newFront); bool AttemptToSetFocus(WinBorder *newFocus); bool AttemptToMoveToBack(WinBorder *newBack); + bool AttemptToActivate(WinBorder *toActivate); bool GetWinBorderList(void **list, int32 *itemCount ) const;