include/svtools/scrolladaptor.hxx               |    2 -
 include/vcl/customweld.hxx                      |    6 ++--
 include/vcl/weld.hxx                            |    6 ++--
 sd/source/ui/animations/CustomAnimationPane.cxx |    2 -
 vcl/inc/qt5/QtInstanceWidget.hxx                |    6 ++--
 vcl/inc/salvtables.hxx                          |    6 ++--
 vcl/qt5/QtInstanceWidget.cxx                    |   25 ++++++++++++++----
 vcl/source/app/salvtables.cxx                   |    6 ++--
 vcl/unx/gtk3/gtkinst.cxx                        |   33 +++++++++++++-----------
 9 files changed, 55 insertions(+), 37 deletions(-)

New commits:
commit 176bc1783f4fd162114a47a692d9eee6c4cf96c5
Author:     Michael Weghorn <[email protected]>
AuthorDate: Tue May 13 12:37:09 2025 +0200
Commit:     Michael Weghorn <[email protected]>
CommitDate: Wed May 14 08:38:37 2025 +0200

    tdf#130857 qt weld: Implement mouse grab API
    
    Change-Id: I224b29b71852064fd40f455cbf52f06e89521cb7
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185255
    Tested-by: Jenkins
    Reviewed-by: Michael Weghorn <[email protected]>

diff --git a/vcl/qt5/QtInstanceWidget.cxx b/vcl/qt5/QtInstanceWidget.cxx
index 34c7cbbcdcfb..3e303c58ecb8 100644
--- a/vcl/qt5/QtInstanceWidget.cxx
+++ b/vcl/qt5/QtInstanceWidget.cxx
@@ -560,15 +560,30 @@ OUString QtInstanceWidget::get_tooltip_text() const
 
 void QtInstanceWidget::set_cursor_data(void*) { assert(false && "Not 
implemented yet"); }
 
-void QtInstanceWidget::grab_mouse() { assert(false && "Not implemented yet"); }
+void QtInstanceWidget::grab_mouse()
+{
+    SolarMutexGuard g;
+
+    GetQtInstance().RunInMainThread([&] { getQWidget()->grabMouse(); });
+}
 
 bool QtInstanceWidget::has_mouse_grab() const
 {
-    assert(false && "Not implemented yet");
-    return false;
+    SolarMutexGuard g;
+
+    bool bHasMouseGrab = false;
+    GetQtInstance().RunInMainThread(
+        [&] { bHasMouseGrab = QWidget::mouseGrabber() == getQWidget(); });
+
+    return bHasMouseGrab;
 }
 
-void QtInstanceWidget::release_mouse() { assert(false && "Not implemented 
yet"); }
+void QtInstanceWidget::release_mouse()
+{
+    SolarMutexGuard g;
+
+    GetQtInstance().RunInMainThread([&] { getQWidget()->releaseMouse(); });
+}
 
 bool QtInstanceWidget::get_extents_relative_to(const Widget& rRelative, int& 
rX, int& rY,
                                                int& rWidth, int& rHeight) const
commit 61fa9c603b5757f36e471d381195c15d96fc6548
Author:     Michael Weghorn <[email protected]>
AuthorDate: Tue May 13 12:07:04 2025 +0200
Commit:     Michael Weghorn <[email protected]>
CommitDate: Wed May 14 08:38:30 2025 +0200

    tdf#130857 weld: Simplify/Clarify grab API
    
    The weld::Widget API for grabbing is inspired by
    `gtk_grab_add` from GTK 3 [1] which grabs both,
    mouse and keyboard, blocking interaction with
    other widgets in the application.
    
    For LibreOffice, only grabbing the mouse is of
    interest. CustomWidgetController::CaptureMouse
    is the only caller of weld::Widget::add_grab,
    and the VCL implementation in SalInstanceWidget::add_grab
    also only calls `Window::CaptureMouse` on its
    vcl::Window.
    
    In addition, there is a concept of a "grab count",
    i.e. calling `weld::Widget::grab_add` multiple
    times without `weld::Widget::grab_remove` means
    that `weld::Widget::grab_remove` needs to be
    called the same amount of times later on.
    However, the concept of having "multiple grabs" at
    the same time is also not used anywhere in LO
    in practice, and the VCL implementation also
    doesn't implement that concept.
    
    Therefore:
    
    1) Drop the logical concept of multiple grabs from the
    weld::API. Adjust the gtk3 implementation
    to make sure to have at most one grab at a time
    that is owned by LO application code.
    (Internal GTK toolkit code may use additional grabs.)
    
    2) Rename the methods to make clear that only
    the mouse grab is of relevance.
    (The gtk3 implementation still uses
    `gtk_grab_add`, i.e. grabs the keyboard
    as well.)
    
    In GTK 4, there is no more API for grabbing the
    mouse and only a counter was used to keep track
    of how often weld::Widget::add_grab had been called.
    Switch that to a bool instead.
    
    Qt provides separate methods for grabbing the mouse
    (QWidget::grabMouse [2]) and the keyboard
    (QWidget::grabKeyboard [3]).
    This commit is also to clarify that only the former will
    be needed when implementing this weld API for the Qt-based
    VCL plugins in an upcoming commit and grabbing the keyboard
    isn't needed.
    
    [1] https://docs.gtk.org/gtk3/method.Widget.grab_add.html
    [2] https://doc.qt.io/qt-6/qwidget.html#grabMouse
    [3] https://doc.qt.io/qt-6/qwidget.html#grabKeyboard
    
    Change-Id: If6f34a5eed8efe3dfb8d453c1ee97796cd4418c7
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185254
    Tested-by: Jenkins
    Reviewed-by: Michael Weghorn <[email protected]>

diff --git a/include/svtools/scrolladaptor.hxx 
b/include/svtools/scrolladaptor.hxx
index 1eba1dfdf844..4b6c18dfca3f 100644
--- a/include/svtools/scrolladaptor.hxx
+++ b/include/svtools/scrolladaptor.hxx
@@ -67,7 +67,7 @@ public:
 
     virtual bool Inactive() const override { return 
!m_xScrollBar->get_sensitive(); }
 
-    bool HasGrab() const { return m_xScrollBar->has_grab(); }
+    bool HasGrab() const { return m_xScrollBar->has_mouse_grab(); }
 
     void SetThickness(int nThickness);
 
diff --git a/include/vcl/customweld.hxx b/include/vcl/customweld.hxx
index ca50afbd23e0..b875e4963423 100644
--- a/include/vcl/customweld.hxx
+++ b/include/vcl/customweld.hxx
@@ -90,12 +90,12 @@ public:
             return m_pDrawingArea->get_accessible_id();
         return OUString();
     }
-    void CaptureMouse() { m_pDrawingArea->grab_add(); }
-    bool IsMouseCaptured() const { return m_pDrawingArea->has_grab(); }
+    void CaptureMouse() { m_pDrawingArea->grab_mouse(); }
+    bool IsMouseCaptured() const { return m_pDrawingArea->has_mouse_grab(); }
     Point GetPointerPosPixel() const { return 
m_pDrawingArea->get_pointer_position(); }
     void EnableRTL(bool bEnable) { m_pDrawingArea->set_direction(bEnable); }
     bool IsRTLEnabled() const { return m_pDrawingArea->get_direction(); }
-    void ReleaseMouse() { m_pDrawingArea->grab_remove(); }
+    void ReleaseMouse() { m_pDrawingArea->release_mouse(); }
     void SetPointer(PointerStyle ePointerStyle) { 
m_pDrawingArea->set_cursor(ePointerStyle); }
     void SetHelpId(const OUString& rHelpId) { 
m_pDrawingArea->set_help_id(rHelpId); }
     void SetAccessibleName(const OUString& rName) { 
m_pDrawingArea->set_accessible_name(rName); }
diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx
index ec8f3f5ac4b9..02e8a97a387a 100644
--- a/include/vcl/weld.hxx
+++ b/include/vcl/weld.hxx
@@ -301,9 +301,9 @@ public:
         m_aStyleUpdatedHdl = rLink;
     }
 
-    virtual void grab_add() = 0;
-    virtual bool has_grab() const = 0;
-    virtual void grab_remove() = 0;
+    virtual void grab_mouse() = 0;
+    virtual bool has_mouse_grab() const = 0;
+    virtual void release_mouse() = 0;
 
     // font size is in points, not pixels, e.g. see Window::[G]etPointFont
     virtual vcl::Font get_font() = 0;
diff --git a/sd/source/ui/animations/CustomAnimationPane.cxx 
b/sd/source/ui/animations/CustomAnimationPane.cxx
index f38390e4aee4..364d1cbddadc 100644
--- a/sd/source/ui/animations/CustomAnimationPane.cxx
+++ b/sd/source/ui/animations/CustomAnimationPane.cxx
@@ -2098,7 +2098,7 @@ IMPL_LINK_NOARG(CustomAnimationPane, AnimationSelectHdl, 
weld::TreeView&, void)
 
 IMPL_LINK_NOARG(CustomAnimationPane, SelectionHandler, Timer*, void)
 {
-    if (mxLBAnimation->has_grab()) // tdf#136474 try again later
+    if (mxLBAnimation->has_mouse_grab()) // tdf#136474 try again later
     {
         maIdle.Start();
         return;
diff --git a/vcl/inc/qt5/QtInstanceWidget.hxx b/vcl/inc/qt5/QtInstanceWidget.hxx
index 53ace384176e..fb2bfb512e43 100644
--- a/vcl/inc/qt5/QtInstanceWidget.hxx
+++ b/vcl/inc/qt5/QtInstanceWidget.hxx
@@ -120,11 +120,11 @@ public:
 
     virtual void set_cursor_data(void*) override;
 
-    virtual void grab_add() override;
+    virtual void grab_mouse() override;
 
-    virtual bool has_grab() const override;
+    virtual bool has_mouse_grab() const override;
 
-    virtual void grab_remove() override;
+    virtual void release_mouse() override;
 
     virtual bool get_extents_relative_to(const Widget& rRelative, int& rX, 
int& rY, int& rWidth,
                                          int& rHeight) const override;
diff --git a/vcl/inc/salvtables.hxx b/vcl/inc/salvtables.hxx
index a9c4b4c3f306..04439f471dce 100644
--- a/vcl/inc/salvtables.hxx
+++ b/vcl/inc/salvtables.hxx
@@ -340,11 +340,11 @@ public:
     virtual bool get_extents_relative_to(const Widget& rRelative, int& x, int& 
y, int& width,
                                          int& height) const override;
 
-    virtual void grab_add() override;
+    virtual void grab_mouse() override;
 
-    virtual bool has_grab() const override;
+    virtual bool has_mouse_grab() const override;
 
-    virtual void grab_remove() override;
+    virtual void release_mouse() override;
 
     virtual bool get_direction() const override;
 
diff --git a/vcl/qt5/QtInstanceWidget.cxx b/vcl/qt5/QtInstanceWidget.cxx
index e759abe019dd..34c7cbbcdcfb 100644
--- a/vcl/qt5/QtInstanceWidget.cxx
+++ b/vcl/qt5/QtInstanceWidget.cxx
@@ -560,15 +560,15 @@ OUString QtInstanceWidget::get_tooltip_text() const
 
 void QtInstanceWidget::set_cursor_data(void*) { assert(false && "Not 
implemented yet"); }
 
-void QtInstanceWidget::grab_add() { assert(false && "Not implemented yet"); }
+void QtInstanceWidget::grab_mouse() { assert(false && "Not implemented yet"); }
 
-bool QtInstanceWidget::has_grab() const
+bool QtInstanceWidget::has_mouse_grab() const
 {
     assert(false && "Not implemented yet");
     return false;
 }
 
-void QtInstanceWidget::grab_remove() { assert(false && "Not implemented yet"); 
}
+void QtInstanceWidget::release_mouse() { assert(false && "Not implemented 
yet"); }
 
 bool QtInstanceWidget::get_extents_relative_to(const Widget& rRelative, int& 
rX, int& rY,
                                                int& rWidth, int& rHeight) const
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index d4fe36fd8b0c..6ef981e16125 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -590,11 +590,11 @@ bool SalInstanceWidget::get_extents_relative_to(const 
Widget& rRelative, int& x,
     return true;
 }
 
-void SalInstanceWidget::grab_add() { m_xWidget->CaptureMouse(); }
+void SalInstanceWidget::grab_mouse() { m_xWidget->CaptureMouse(); }
 
-bool SalInstanceWidget::has_grab() const { return 
m_xWidget->IsMouseCaptured(); }
+bool SalInstanceWidget::has_mouse_grab() const { return 
m_xWidget->IsMouseCaptured(); }
 
-void SalInstanceWidget::grab_remove() { m_xWidget->ReleaseMouse(); }
+void SalInstanceWidget::release_mouse() { m_xWidget->ReleaseMouse(); }
 
 bool SalInstanceWidget::get_direction() const { return 
m_xWidget->IsRTLEnabled(); }
 
diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx
index c43224bf81aa..07cac1419e65 100644
--- a/vcl/unx/gtk3/gtkinst.cxx
+++ b/vcl/unx/gtk3/gtkinst.cxx
@@ -2872,8 +2872,10 @@ private:
     gulong m_nDragDataDeleteignalId;
     gulong m_nDragGetSignalId;
 
+    // whether mouse has explicitly been grabbed from LO application code
+    bool m_bMouseGrabbed;
+
 #if GTK_CHECK_VERSION(4, 0, 0)
-    int m_nGrabCount;
     GtkEventController* m_pFocusController;
     GtkEventController* m_pClickController;
     GtkEventController* m_pMotionController;
@@ -3448,8 +3450,8 @@ public:
         , m_nDragFailedSignalId(0)
         , m_nDragDataDeleteignalId(0)
         , m_nDragGetSignalId(0)
+        , m_bMouseGrabbed(false)
 #if GTK_CHECK_VERSION(4, 0, 0)
-        , m_nGrabCount(0)
         , m_pFocusController(nullptr)
         , m_pClickController(nullptr)
         , m_pMotionController(nullptr)
@@ -4080,31 +4082,32 @@ public:
     }
 #endif
 
-    virtual void grab_add() override
+    virtual void grab_mouse() override
     {
-#if GTK_CHECK_VERSION(4, 0, 0)
-        ++m_nGrabCount;
-#else
-        gtk_grab_add(m_pWidget);
+#if !GTK_CHECK_VERSION(4, 0, 0)
+        // have at most one grab owned by LO application code
+        if (!m_bMouseGrabbed)
+            gtk_grab_add(m_pWidget);
 #endif
+        m_bMouseGrabbed = true;
     }
 
-    virtual bool has_grab() const override
+    virtual bool has_mouse_grab() const override
     {
 #if GTK_CHECK_VERSION(4, 0, 0)
-        return m_nGrabCount != 0;
+        return m_bMouseGrabbed;
 #else
         return gtk_widget_has_grab(m_pWidget);
 #endif
     }
 
-    virtual void grab_remove() override
+    virtual void release_mouse() override
     {
-#if GTK_CHECK_VERSION(4, 0, 0)
-        --m_nGrabCount;
-#else
-        gtk_grab_remove(m_pWidget);
+#if !GTK_CHECK_VERSION(4, 0, 0)
+        if (m_bMouseGrabbed)
+            gtk_grab_remove(m_pWidget);
 #endif
+        m_bMouseGrabbed = false;
     }
 
     virtual bool get_direction() const override
@@ -8755,7 +8758,7 @@ public:
     virtual ScrollType get_scroll_type() const override
     {
         // tdf#153049 want a mousewheel spin to be treated as DontKnow
-        return has_grab() ? ScrollType::Drag : ScrollType::DontKnow;
+        return has_mouse_grab() ? ScrollType::Drag : ScrollType::DontKnow;
     }
 
     virtual int get_scroll_thickness() const override

Reply via email to