diff --git a/src/servers/app/Layer.cpp b/src/servers/app/Layer.cpp index 42aa2a8f59..0e87322f39 100644 --- a/src/servers/app/Layer.cpp +++ b/src/servers/app/Layer.cpp @@ -1100,7 +1100,7 @@ Layer::ScrollBy(float x, float y) void Layer::MouseDown(const PointerEvent& evt) { - if (Window()) { + if (Window() && !IsTopLayer()) { BMessage msg; msg.what = B_MOUSE_DOWN; msg.AddInt64("when", evt.when); @@ -1116,7 +1116,7 @@ Layer::MouseDown(const PointerEvent& evt) void Layer::MouseUp(const PointerEvent& evt) { - if (Window()) { + if (Window() && !IsTopLayer()) { BMessage upmsg(B_MOUSE_UP); upmsg.AddInt64("when",evt.when); upmsg.AddPoint("where",evt.where); @@ -1129,7 +1129,7 @@ Layer::MouseUp(const PointerEvent& evt) void Layer::MouseMoved(const PointerEvent& evt, uint32 transit) { - if (Window()) { + if (Window() && !IsTopLayer()) { BMessage movemsg(B_MOUSE_MOVED); movemsg.AddInt64("when", evt.when); movemsg.AddPoint("where", evt.where); diff --git a/src/servers/app/Layer.h b/src/servers/app/Layer.h index d91d3b2214..131cb0379d 100644 --- a/src/servers/app/Layer.h +++ b/src/servers/app/Layer.h @@ -199,9 +199,11 @@ class Layer { ServerApp* App() const { return fServerWin? fServerWin->App(): NULL; } + inline WinBorder* Owner() const + { return fOwner; } + virtual bool HasClient() { return true; } -// bool IsServerLayer() const; uint32 EventMask() const { return fEventMask; } @@ -250,6 +252,9 @@ class Layer { void CopyBits(BRect& src, BRect& dst, int32 xOffset, int32 yOffset); + inline const BRegion& VisibleRegion() const { return fVisible; } + inline const BRegion& FullVisible() const { return fFullVisible; } + #ifdef NEW_CLIPPING inline const BRegion& VisibleRegion() const { return fVisible2; } inline const BRegion& FullVisible() const { return fFullVisible2; } diff --git a/src/servers/app/RootLayer.cpp b/src/servers/app/RootLayer.cpp index b57bd96cdd..9f92731983 100644 --- a/src/servers/app/RootLayer.cpp +++ b/src/servers/app/RootLayer.cpp @@ -1033,9 +1033,6 @@ RootLayer::WinBorderAt(const BPoint& pt) const void RootLayer::_ProcessMouseMovedEvent(PointerEvent &evt) { - // move cursor on screen - GetHWInterface()->MoveCursorTo(evt.where.x, evt.where.y); - Layer* target = LayerAt(evt.where); if (target == NULL) { CRITICAL("RootLayer::_ProcessMouseMovedEvent() 'target' can't be null.\n"); @@ -1120,6 +1117,9 @@ RootLayer::MouseEventHandler(int32 code, BPrivate::PortLink& msg) if (fLastMousePosition != evt.where) { #ifdef NEW_INPUT_HANDLING + // move cursor on screen + GetHWInterface()->MoveCursorTo(evt.where.x, evt.where.y); + _ProcessMouseMovedEvent(evt); #else @@ -1146,6 +1146,65 @@ 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); #else // we are clicking a WinBorder @@ -1235,16 +1294,13 @@ RootLayer::MouseEventHandler(int32 code, BPrivate::PortLink& msg) evt.where.ConstrainTo(fFrame); -#ifdef NEW_INPUT_HANDLING - ClearNotifyLayer(); -#endif - - if (fLastLayerUnderMouse == NULL) { - CRITICAL("RootLayer::MouseEventHandler(B_MOUSE_UP) fLastLayerUnderMouse is null!\n"); - break; - } - if (fLastMousePosition != evt.where) { +#ifdef NEW_INPUT_HANDLING + // move cursor on screen + GetHWInterface()->MoveCursorTo(evt.where.x, evt.where.y); + + _ProcessMouseMovedEvent(evt); +#else // TODO: a B_MOUSE_MOVED message might have to be generated in order to // correctly trigger entered/exited view transits. fprintf(stderr, "mouse position changed in B_MOUSE_UP (%.1f, %.1f) from last B_MOUSE_MOVED (%.1f, %.1f)!\n", @@ -1252,6 +1308,20 @@ fprintf(stderr, "mouse position changed in B_MOUSE_UP (%.1f, %.1f) from last B_M // update on screen mouse pos GetHWInterface()->MoveCursorTo(evt.where.x, evt.where.y); fLastMousePosition = evt.where; +#endif + } + +#ifdef NEW_INPUT_HANDLING + ClearNotifyLayer(); + if (fLastLayerUnderMouse == NULL) { + CRITICAL("RootLayer::MouseEventHandler(B_MOUSE_UP) fLastLayerUnderMouse is null!\n"); + break; + } + fLastLayerUnderMouse->MouseUp(evt); +#else + if (fLastLayerUnderMouse == NULL) { + CRITICAL("RootLayer::MouseEventHandler(B_MOUSE_UP) fLastLayerUnderMouse is null!\n"); + break; } // TODO: what if 'fNotifyLayer' is deleted in the mean time. @@ -1296,7 +1366,7 @@ fprintf(stderr, "mouse position changed in B_MOUSE_UP (%.1f, %.1f) from last B_M } STRACE(("MOUSE UP: at (%f, %f)\n", evt.where.x, evt.where.y)); - +#endif // TODO: This is a quick fix to avoid the endless loop with windows created // with the B_ASYNCHRONOUS_CONTROLS flag, but please someone have a look into this. fButtons = 0; @@ -1320,6 +1390,9 @@ fprintf(stderr, "mouse position changed in B_MOUSE_UP (%.1f, %.1f) from last B_M evt.where.ConstrainTo(fFrame); #ifdef NEW_INPUT_HANDLING + // move cursor on screen + GetHWInterface()->MoveCursorTo(evt.where.x, evt.where.y); + _ProcessMouseMovedEvent(evt); #else GetHWInterface()->MoveCursorTo(evt.where.x, evt.where.y); @@ -1871,10 +1944,10 @@ RootLayer::SetNotifyLayer(Layer *lay, uint32 mask, uint32 options) Lock(); -#if 0 // to be removed when the new "event" stuff is ready +#if NEW_INPUT_HANDLING // to be removed when the new "event" stuff is ready fNotifyLayer = lay; fSavedEventMask = lay->EventMask(); - fSavedOptions = lay->EventOptions(); + fSavedEventOptions = lay->EventOptions(); AddToInputNotificationLists(lay, mask, options); diff --git a/src/servers/app/RootLayer.h b/src/servers/app/RootLayer.h index 6dd0aa364f..b614277b2c 100644 --- a/src/servers/app/RootLayer.h +++ b/src/servers/app/RootLayer.h @@ -142,7 +142,9 @@ public: private: friend class Desktop; - +#ifdef NEW_INPUT_HANDLING +friend class WinBorder; // temporarily, I need invalidate_layer() +#endif // these are meant for Desktop class only! void AddWinBorder(WinBorder* winBorder); void RemoveWinBorder(WinBorder* winBorder); diff --git a/src/servers/app/WinBorder.cpp b/src/servers/app/WinBorder.cpp index a8913bba9f..d8e5360902 100644 --- a/src/servers/app/WinBorder.cpp +++ b/src/servers/app/WinBorder.cpp @@ -450,16 +450,134 @@ WinBorder::GetSizeLimits(float* minWidth, float* maxWidth, void WinBorder::MouseDown(const PointerEvent& event) { + 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; + + case DEC_DRAG: + fIsDragging = true; +#ifdef NEW_INPUT_HANDLING +GetRootLayer()->SetNotifyLayer(this, B_POINTER_EVENTS, 0UL); +#endif + fLastMousePosition = event.where; + STRACE_CLICK(("===> DEC_DRAG\n")); + break; + + case DEC_RESIZE: + fIsResizing = true; + fLastMousePosition = event.where; + STRACE_CLICK(("===> DEC_RESIZE\n")); + break; + + case DEC_SLIDETAB: + fIsSlidingTab = true; + fLastMousePosition = event.where; + STRACE_CLICK(("===> DEC_SLIDETAB\n")); + break; + + default: + break; + } + } + + // TODO: set dirty regions! +#ifndef NEW_CLIPPING + GetRootLayer()->invalidate_layer(this, VisibleRegion()); +#else + do_Invalidate(VisibleRegion()); +#endif } void WinBorder::MouseUp(const PointerEvent& event) { + if (fDecorator) { + click_type action = _ActionFor(event); + + if (fIsZooming) { + fIsZooming = false; + fDecorator->SetZoom(false); + if (action == DEC_ZOOM) + Window()->NotifyZoom(); + return; + } + if (fIsClosing) { + fIsClosing = false; + fDecorator->SetClose(false); + if (action == DEC_CLOSE) + Window()->NotifyQuitRequested(); + return; + } + if (fIsMinimizing) { + fIsMinimizing = false; + fDecorator->SetMinimize(false); + if (action == DEC_MINIMIZE) + Window()->NotifyMinimize(true); + return; + } + } + fIsDragging = false; + fIsResizing = false; + fIsSlidingTab = false; + + // TODO: set dirty regions! +#ifndef NEW_CLIPPING + GetRootLayer()->invalidate_layer(this, VisibleRegion()); +#else + do_Invalidate(VisibleRegion()); +#endif } void WinBorder::MouseMoved(const PointerEvent& event, uint32 transit) { + if (fDecorator) { + if (fIsZooming) { + fDecorator->SetZoom(_ActionFor(event) == DEC_ZOOM); + } else if (fIsClosing) { + fDecorator->SetClose(_ActionFor(event) == DEC_CLOSE); + } else if (fIsMinimizing) { + fDecorator->SetMinimize(_ActionFor(event) == DEC_MINIMIZE); + } + } + if (fIsDragging) { + BPoint delta = event.where - fLastMousePosition; +#ifndef NEW_CLIPPING + MoveBy(delta.x, delta.y); +#else + do_MoveBy(delta.x, delta.y); +#endif + } + if (fIsResizing) { + BPoint delta = event.where - fLastMousePosition; +#ifndef NEW_CLIPPING + ResizeBy(delta.x, delta.y); +#else + do_ResizeBy(delta.x, delta.y); +#endif + } + if (fIsSlidingTab) { + // TODO: implement + } + fLastMousePosition = event.where; } #else @@ -745,6 +863,7 @@ WinBorder::QuietlySetFeel(int32 feel) click_type WinBorder::_ActionFor(const PointerEvent& event) const { +#ifndef NEW_INPUT_HANDING #ifndef NEW_CLIPPING if (fTopLayer->fFullVisible.Contains(event.where)) return DEC_NONE; @@ -753,6 +872,7 @@ WinBorder::_ActionFor(const PointerEvent& event) const if (fTopLayer->fFullVisible2.Contains(event.where)) return DEC_NONE; else +#endif #endif if (fDecorator) return fDecorator->Clicked(event.where, event.buttons, event.modifiers); diff --git a/src/servers/app/WinBorder.h b/src/servers/app/WinBorder.h index be6123af14..93926a5997 100644 --- a/src/servers/app/WinBorder.h +++ b/src/servers/app/WinBorder.h @@ -85,6 +85,8 @@ class WinBorder : public Layer { virtual void MouseDown(const PointerEvent& evt); virtual void MouseUp(const PointerEvent& evt); virtual void MouseMoved(const PointerEvent& evt, uint32 transit); + click_type ActionFor(const PointerEvent& evt) + { return _ActionFor(evt); } #else click_type MouseDown(const PointerEvent& evt); void MouseMoved(const PointerEvent& evt); diff --git a/src/servers/app/Workspace.cpp b/src/servers/app/Workspace.cpp index b547d8a443..1681e7361d 100644 --- a/src/servers/app/Workspace.cpp +++ b/src/servers/app/Workspace.cpp @@ -219,7 +219,36 @@ Workspace::Active() const //return fActiveItem ? fActiveItem->layerPtr: NULL; } +void +Workspace::GetState(Workspace::State *state) const +{ + state->Front = Front(); + state->Focus = Focus(); + ListData *cursor = fBottomItem; + while (cursor) { + if (!cursor->layerPtr->IsHidden()) + state->WindowList.AddItem(cursor->layerPtr); + cursor = cursor->upperItem; + } +} +bool +Workspace::AttemptToSetFront(WinBorder *newFront) +{ + return MoveToFront(newFront); +} + +bool +Workspace::AttemptToSetFocus(WinBorder *newFocus) +{ + return SetFocus(newFocus); +} + +bool +Workspace::AttemptToMoveToBack(WinBorder *newBack) +{ + return MoveToBack(newBack); +} /* \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 941d67c8fc..96fd151aab 100644 --- a/src/servers/app/Workspace.h +++ b/src/servers/app/Workspace.h @@ -49,6 +49,13 @@ struct ListData class Workspace { public: + class State { + public: + State() : Front(NULL), Focus(NULL), WindowList(40) { } + WinBorder* Front; + WinBorder* Focus; + BList WindowList; + }; Workspace( const int32 ID, const uint32 colorspace, const RGBColor& BGColor); @@ -63,6 +70,10 @@ class Workspace { WinBorder* Focus() const; WinBorder* Front() const; WinBorder* Active() const; + void GetState(Workspace::State *state) const; + bool AttemptToSetFront(WinBorder *newFront); + bool AttemptToSetFocus(WinBorder *newFocus); + bool AttemptToMoveToBack(WinBorder *newBack); bool GetWinBorderList(void **list, int32 *itemCount ) const;