f6d98b1
From ee49f01f73348c9e7c822212a7ed69ab2e916946 Mon Sep 17 00:00:00 2001
2ec3e50
From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= <caolanm@redhat.com>
2ec3e50
Date: Mon, 14 Dec 2015 14:05:53 +0000
2ec3e50
Subject: [PATCH] Resolves: rhbz#1289394 gtk3: implement tooltips natively
2ec3e50
2ec3e50
side step the whole pile of misery by using native gtk tooltips
2ec3e50
2ec3e50
also gets transparency and native themeing too by default
2ec3e50
2ec3e50
Related: rhbz#1289394 always provide the screen area the tip applies to
2ec3e50
2ec3e50
this will make it easier to implement native help tips
2ec3e50
2ec3e50
Change-Id: I984dfadaf02e9b7bf542ba82cf070911c89cb699
2ec3e50
(cherry picked from commit 01ef12d173fb2c54a49186c8eb4fa40288b82945)
2ec3e50
2ec3e50
Change-Id: I59552661cd9dc18a563341885bc40fcdadc5264f
2ec3e50
(cherry picked from commit c96eeb5bf2ef428e7d147258d69825ff97acb226)
2ec3e50
---
f6d98b1
 cui/source/customize/acccfg.cxx    |  2 +-
f6d98b1
 cui/source/customize/selector.cxx  | 10 +++--
f6d98b1
 include/vcl/help.hxx               |  3 --
f6d98b1
 sfx2/source/dialog/dinfdlg.cxx     |  2 +-
f6d98b1
 sw/source/core/draw/dpage.cxx      |  6 +--
f6d98b1
 sw/source/uibase/docvw/edtwin2.cxx | 17 +++++----
f6d98b1
 vcl/inc/helpwin.hxx                |  4 +-
f6d98b1
 vcl/inc/salframe.hxx               |  7 ++++
f6d98b1
 vcl/inc/unx/gtk/gtkframe.hxx       |  6 +++
f6d98b1
 vcl/source/app/help.cxx            | 75 +++++++++++++++++---------------------
f6d98b1
 vcl/source/window/menuwindow.cxx   |  2 +-
f6d98b1
 vcl/source/window/window.cxx       |  9 ++++-
f6d98b1
 vcl/unx/gtk3/gtk3gtkframe.cxx      | 28 ++++++++++++++
f6d98b1
 13 files changed, 106 insertions(+), 65 deletions(-)
2ec3e50
2ec3e50
diff --git a/cui/source/customize/acccfg.cxx b/cui/source/customize/acccfg.cxx
f6d98b1
index b3511e9..2125990 100644
2ec3e50
--- a/cui/source/customize/acccfg.cxx
2ec3e50
+++ b/cui/source/customize/acccfg.cxx
f6d98b1
@@ -1117,7 +1117,7 @@ IMPL_LINK_NOARG(SfxAcceleratorConfigPage, RemoveHdl)
f6d98b1
 IMPL_LINK( SfxAcceleratorConfigPage, SelectHdl, Control*, pListBox )
2ec3e50
 {
2ec3e50
     // disable help
2ec3e50
-    Help::ShowBalloon( this, Point(), OUString() );
2ec3e50
+    Help::ShowBalloon( this, Point(), Rectangle(), OUString() );
2ec3e50
     if (pListBox == m_pEntriesBox)
2ec3e50
     {
2ec3e50
         sal_uLong nPos = SvTreeList::GetRelPos( m_pEntriesBox->FirstSelected() );
2ec3e50
diff --git a/cui/source/customize/selector.cxx b/cui/source/customize/selector.cxx
f6d98b1
index 781ddbf..2da0b77 100644
2ec3e50
--- a/cui/source/customize/selector.cxx
2ec3e50
+++ b/cui/source/customize/selector.cxx
f6d98b1
@@ -130,7 +130,8 @@ void SvxConfigFunctionListBox::MouseMove( const MouseEvent& rMEvt )
2ec3e50
         aTimer.Start();
2ec3e50
     else
2ec3e50
     {
2ec3e50
-        Help::ShowBalloon( this, aMousePos, OUString() );
2ec3e50
+        Rectangle aRect(GetPosPixel(), GetSizePixel());
2ec3e50
+        Help::ShowBalloon( this, aMousePos, aRect, OUString() );
2ec3e50
         aTimer.Stop();
2ec3e50
     }
2ec3e50
 }
f6d98b1
@@ -142,7 +143,10 @@ IMPL_LINK_NOARG_TYPED(SvxConfigFunctionListBox, TimerHdl, Timer *, void)
2ec3e50
     Point aMousePos = GetPointerPosPixel();
2ec3e50
     SvTreeListEntry *pEntry = GetCurEntry();
2ec3e50
     if ( pEntry && GetEntry( aMousePos ) == pEntry && pCurEntry == pEntry )
2ec3e50
-        Help::ShowBalloon( this, OutputToScreenPixel( aMousePos ), GetHelpText( pEntry ) );
2ec3e50
+    {
2ec3e50
+        Rectangle aRect(GetPosPixel(), GetSizePixel());
2ec3e50
+        Help::ShowBalloon( this, OutputToScreenPixel(aMousePos), aRect, GetHelpText( pEntry ) );
2ec3e50
+    }
2ec3e50
 }
2ec3e50
 
2ec3e50
 void SvxConfigFunctionListBox::ClearAll()
f6d98b1
@@ -177,7 +181,7 @@ OUString SvxConfigFunctionListBox::GetHelpText( SvTreeListEntry *pEntry )
2ec3e50
 
2ec3e50
 void SvxConfigFunctionListBox::FunctionSelected()
2ec3e50
 {
2ec3e50
-    Help::ShowBalloon( this, Point(), OUString() );
2ec3e50
+    Help::ShowBalloon( this, Point(), Rectangle(), OUString() );
2ec3e50
 }
2ec3e50
 
2ec3e50
 // drag and drop support
2ec3e50
diff --git a/include/vcl/help.hxx b/include/vcl/help.hxx
2ec3e50
index 40dfcf2..4d226a8 100644
2ec3e50
--- a/include/vcl/help.hxx
2ec3e50
+++ b/include/vcl/help.hxx
2ec3e50
@@ -86,9 +86,6 @@ public:
2ec3e50
     static bool         IsBalloonHelpEnabled();
2ec3e50
     static bool         ShowBalloon( vcl::Window* pParent,
2ec3e50
                                      const Point& rScreenPos,
2ec3e50
-                                     const OUString& rHelpText );
2ec3e50
-    static bool         ShowBalloon( vcl::Window* pParent,
2ec3e50
-                                     const Point& rScreenPos,
2ec3e50
                                      const Rectangle&,
2ec3e50
                                      const OUString& rHelpText );
2ec3e50
 
2ec3e50
diff --git a/sfx2/source/dialog/dinfdlg.cxx b/sfx2/source/dialog/dinfdlg.cxx
f6d98b1
index 0e47101..56d4d98 100644
2ec3e50
--- a/sfx2/source/dialog/dinfdlg.cxx
2ec3e50
+++ b/sfx2/source/dialog/dinfdlg.cxx
f6d98b1
@@ -1336,7 +1336,7 @@ void CustomPropertiesDurationField::RequestHelp( const HelpEvent& rHEvt )
2ec3e50
         Size aSize( GetSizePixel() );
2ec3e50
         Rectangle aItemRect( rHEvt.GetMousePosPixel(), aSize );
2ec3e50
         if (Help::IsBalloonHelpEnabled())
2ec3e50
-            Help::ShowBalloon( this, rHEvt.GetMousePosPixel(), GetText() );
2ec3e50
+            Help::ShowBalloon( this, rHEvt.GetMousePosPixel(), aItemRect, GetText() );
2ec3e50
         else
2ec3e50
             Help::ShowQuickHelp( this, aItemRect, GetText(),
2ec3e50
                 QuickHelpFlags::Left|QuickHelpFlags::VCenter );
2ec3e50
diff --git a/sw/source/core/draw/dpage.cxx b/sw/source/core/draw/dpage.cxx
f6d98b1
index db5707c..e401512 100644
2ec3e50
--- a/sw/source/core/draw/dpage.cxx
2ec3e50
+++ b/sw/source/core/draw/dpage.cxx
2ec3e50
@@ -237,14 +237,14 @@ bool SwDPage::RequestHelp( vcl::Window* pWindow, SdrView* pView,
2ec3e50
                         sText = SwViewShell::GetShellRes()->aLinkClick + ": " + sText;
2ec3e50
                 }
2ec3e50
 
2ec3e50
+                // then display the help:
2ec3e50
+                Rectangle aRect( rEvt.GetMousePosPixel(), Size(1,1) );
2ec3e50
                 if( rEvt.GetMode() & HelpEventMode::BALLOON )
2ec3e50
                 {
2ec3e50
-                    Help::ShowBalloon( pWindow, rEvt.GetMousePosPixel(), sText );
2ec3e50
+                    Help::ShowBalloon( pWindow, rEvt.GetMousePosPixel(), aRect, sText );
2ec3e50
                 }
2ec3e50
                 else
2ec3e50
                 {
2ec3e50
-                    // then display the help:
2ec3e50
-                    Rectangle aRect( rEvt.GetMousePosPixel(), Size(1,1) );
2ec3e50
                     Help::ShowQuickHelp( pWindow, aRect, sText );
2ec3e50
                 }
2ec3e50
                 bContinue = false;
2ec3e50
diff --git a/sw/source/uibase/docvw/edtwin2.cxx b/sw/source/uibase/docvw/edtwin2.cxx
f6d98b1
index dd78039..a7d55b3 100644
2ec3e50
--- a/sw/source/uibase/docvw/edtwin2.cxx
2ec3e50
+++ b/sw/source/uibase/docvw/edtwin2.cxx
f6d98b1
@@ -365,18 +365,19 @@ void SwEditWin::RequestHelp(const HelpEvent &rEvt)
2ec3e50
             }
2ec3e50
             if (!sText.isEmpty())
2ec3e50
             {
2ec3e50
+                Rectangle aRect( aFieldRect.SVRect() );
2ec3e50
+                Point aPt( OutputToScreenPixel( LogicToPixel( aRect.TopLeft() )));
2ec3e50
+                aRect.Left()   = aPt.X();
2ec3e50
+                aRect.Top()    = aPt.Y();
2ec3e50
+                aPt = OutputToScreenPixel( LogicToPixel( aRect.BottomRight() ));
2ec3e50
+                aRect.Right()  = aPt.X();
2ec3e50
+                aRect.Bottom() = aPt.Y();
2ec3e50
+
2ec3e50
                 if( bBalloon )
2ec3e50
-                    Help::ShowBalloon( this, rEvt.GetMousePosPixel(), sText );
2ec3e50
+                    Help::ShowBalloon( this, rEvt.GetMousePosPixel(), aRect, sText );
2ec3e50
                 else
2ec3e50
                 {
2ec3e50
                     // the show the help
2ec3e50
-                    Rectangle aRect( aFieldRect.SVRect() );
2ec3e50
-                    Point aPt( OutputToScreenPixel( LogicToPixel( aRect.TopLeft() )));
2ec3e50
-                    aRect.Left()   = aPt.X();
2ec3e50
-                    aRect.Top()    = aPt.Y();
2ec3e50
-                    aPt = OutputToScreenPixel( LogicToPixel( aRect.BottomRight() ));
2ec3e50
-                    aRect.Right()  = aPt.X();
2ec3e50
-                    aRect.Bottom() = aPt.Y();
2ec3e50
                     OUString sDisplayText(ClipLongToolTip(sText));
2ec3e50
                     Help::ShowQuickHelp(this, aRect, sDisplayText, nStyle);
2ec3e50
                 }
2ec3e50
diff --git a/vcl/inc/helpwin.hxx b/vcl/inc/helpwin.hxx
f6d98b1
index 5889a4f..7ff4072 100644
2ec3e50
--- a/vcl/inc/helpwin.hxx
2ec3e50
+++ b/vcl/inc/helpwin.hxx
f6d98b1
@@ -78,10 +78,10 @@ public:
2ec3e50
 
2ec3e50
 void ImplShowHelpWindow( vcl::Window* pParent, sal_uInt16 nHelpWinStyle, QuickHelpFlags nStyle,
2ec3e50
         const OUString& rHelpText, const OUString& rStatusText,
f6d98b1
-        const Point& rScreenPos, const Rectangle* pHelpArea = NULL );
5de1b6e
+        const Point& rScreenPos, const Rectangle& rHelpArea );
2ec3e50
 void ImplDestroyHelpWindow( bool bUpdateHideTime );
2ec3e50
 void ImplSetHelpWindowPos( vcl::Window* pHelpWindow, sal_uInt16 nHelpWinStyle, QuickHelpFlags nStyle,
2ec3e50
-                            const Point& rPos, const Rectangle* pHelpArea );
2ec3e50
+                            const Point& rPos, const Rectangle& rHelpArea );
2ec3e50
 
2ec3e50
 #endif // INCLUDED_VCL_INC_HELPWIN_HXX
2ec3e50
 
2ec3e50
diff --git a/vcl/inc/salframe.hxx b/vcl/inc/salframe.hxx
f6d98b1
index 484504c..cfd401d 100644
2ec3e50
--- a/vcl/inc/salframe.hxx
2ec3e50
+++ b/vcl/inc/salframe.hxx
f6d98b1
@@ -237,6 +237,13 @@ public:
2ec3e50
     {
2ec3e50
     }
2ec3e50
 
2ec3e50
+    // return true to indicate tooltips are shown natively, false otherwise
2ec3e50
+    virtual bool            ShowTooltip(const OUString& /*rHelpText*/, const Rectangle& /*rHelpArea*/ )
2ec3e50
+    {
2ec3e50
+        return false;
2ec3e50
+    }
2ec3e50
+
2ec3e50
+
2ec3e50
     // Callbacks (indepent part in vcl/source/window/winproc.cxx)
2ec3e50
     // for default message handling return 0
2ec3e50
     void                    SetCallback( vcl::Window* pWindow, SALFRAMEPROC pProc );
2ec3e50
diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx
f6d98b1
index ee19e6c..b779d39 100644
2ec3e50
--- a/vcl/inc/unx/gtk/gtkframe.hxx
2ec3e50
+++ b/vcl/inc/unx/gtk/gtkframe.hxx
f6d98b1
@@ -211,6 +211,8 @@ class GtkSalFrame : public SalFrame, public X11WindowProvider
2ec3e50
     Rectangle                       m_aRestorePosSize;
2ec3e50
 
2ec3e50
 #if GTK_CHECK_VERSION(3,0,0)
2ec3e50
+    OUString                        m_aTooltip;
2ec3e50
+    Rectangle                       m_aHelpArea;
2ec3e50
     guint32                         m_nLastScrollEventTime;
2ec3e50
     long                            m_nWidthRequest;
2ec3e50
     long                            m_nHeightRequest;
f6d98b1
@@ -243,6 +245,9 @@ class GtkSalFrame : public SalFrame, public X11WindowProvider
2ec3e50
 #if GTK_CHECK_VERSION(3,0,0)
2ec3e50
     static gboolean     signalDraw( GtkWidget*, cairo_t *cr, gpointer );
2ec3e50
     static void         sizeAllocated(GtkWidget*, GdkRectangle *pAllocation, gpointer frame);
2ec3e50
+    static gboolean     signalTooltipQuery(GtkWidget*, gint x, gint y,
2ec3e50
+                                     gboolean keyboard_mode, GtkTooltip *tooltip,
2ec3e50
+                                     gpointer frame);
2ec3e50
 #if GTK_CHECK_VERSION(3,14,0)
2ec3e50
     static void         gestureSwipe(GtkGestureSwipe* gesture, gdouble velocity_x, gdouble velocity_y, gpointer frame);
2ec3e50
     static void         gestureLongPress(GtkGestureLongPress* gesture, gpointer frame);
f6d98b1
@@ -467,6 +472,7 @@ public:
2ec3e50
 
2ec3e50
 #if GTK_CHECK_VERSION(3,0,0)
2ec3e50
     virtual void                SetModal(bool bModal) override;
2ec3e50
+    virtual bool                ShowTooltip(const OUString& rHelpText, const Rectangle& rHelpArea) override;
2ec3e50
 #endif
2ec3e50
 
2ec3e50
     static GtkSalFrame         *getFromWindow( GtkWindow *pWindow );
2ec3e50
diff --git a/vcl/source/app/help.cxx b/vcl/source/app/help.cxx
f6d98b1
index 7014a79..9a6e845 100644
2ec3e50
--- a/vcl/source/app/help.cxx
2ec3e50
+++ b/vcl/source/app/help.cxx
2ec3e50
@@ -31,6 +31,7 @@
2ec3e50
 #include "vcl/settings.hxx"
2ec3e50
 
2ec3e50
 #include "helpwin.hxx"
2ec3e50
+#include "salframe.hxx"
2ec3e50
 #include "svdata.hxx"
2ec3e50
 
2ec3e50
 #define HELPWINSTYLE_QUICK      0
2ec3e50
@@ -147,21 +148,11 @@ bool Help::IsBalloonHelpEnabled()
2ec3e50
 }
2ec3e50
 
2ec3e50
 bool Help::ShowBalloon( vcl::Window* pParent,
2ec3e50
-                        const Point& rScreenPos,
2ec3e50
-                        const OUString& rHelpText )
2ec3e50
-{
2ec3e50
-    ImplShowHelpWindow( pParent, HELPWINSTYLE_BALLOON, QuickHelpFlags::NONE,
2ec3e50
-                        rHelpText, OUString(), rScreenPos );
2ec3e50
-
2ec3e50
-    return true;
2ec3e50
-}
2ec3e50
-
2ec3e50
-bool Help::ShowBalloon( vcl::Window* pParent,
2ec3e50
                         const Point& rScreenPos, const Rectangle& rRect,
2ec3e50
                         const OUString& rHelpText )
2ec3e50
 {
2ec3e50
     ImplShowHelpWindow( pParent, HELPWINSTYLE_BALLOON, QuickHelpFlags::NONE,
2ec3e50
-                        rHelpText, OUString(), rScreenPos, &rRect );
2ec3e50
+                        rHelpText, OUString(), rScreenPos, rRect );
2ec3e50
 
2ec3e50
     return true;
2ec3e50
 }
2ec3e50
@@ -189,7 +180,7 @@ bool Help::ShowQuickHelp( vcl::Window* pParent,
2ec3e50
 {
2ec3e50
     ImplShowHelpWindow( pParent, HELPWINSTYLE_QUICK, nStyle,
2ec3e50
                         rHelpText, rLongHelpText,
2ec3e50
-                        pParent->OutputToScreenPixel( pParent->GetPointerPosPixel() ), &rScreenRect );
2ec3e50
+                        pParent->OutputToScreenPixel( pParent->GetPointerPosPixel() ), rScreenRect );
2ec3e50
     return true;
2ec3e50
 }
2ec3e50
 
2ec3e50
@@ -221,7 +212,7 @@ void Help::UpdateTip( sal_uIntPtr nId, vcl::Window* pParent, const Rectangle& rS
2ec3e50
     Size aSz = pHelpWin->CalcOutSize();
2ec3e50
     pHelpWin->SetOutputSizePixel( aSz );
2ec3e50
     ImplSetHelpWindowPos( pHelpWin, pHelpWin->GetWinStyle(), pHelpWin->GetStyle(),
2ec3e50
-        pParent->OutputToScreenPixel( pParent->GetPointerPosPixel() ), &rScreenRect );
2ec3e50
+        pParent->OutputToScreenPixel( pParent->GetPointerPosPixel() ), rScreenRect );
2ec3e50
 
2ec3e50
     pHelpWin->SetHelpText( rText );
2ec3e50
     pHelpWin->Invalidate();
f6d98b1
@@ -475,8 +466,14 @@ OUString HelpTextWindow::GetText() const
2ec3e50
 
2ec3e50
 void ImplShowHelpWindow( vcl::Window* pParent, sal_uInt16 nHelpWinStyle, QuickHelpFlags nStyle,
2ec3e50
                          const OUString& rHelpText, const OUString& rStatusText,
2ec3e50
-                         const Point& rScreenPos, const Rectangle* pHelpArea )
2ec3e50
+                         const Point& rScreenPos, const Rectangle& rHelpArea )
2ec3e50
 {
2ec3e50
+    if (pParent->ImplGetFrame()->ShowTooltip(rHelpText, rHelpArea))
2ec3e50
+    {
2ec3e50
+        //tooltips are handled natively, return early
2ec3e50
+        return;
2ec3e50
+    }
2ec3e50
+
2ec3e50
     ImplSVData* pSVData = ImplGetSVData();
2ec3e50
 
2ec3e50
     if (rHelpText.isEmpty() && !pSVData->maHelpData.mbRequestingHelp)
f6d98b1
@@ -490,9 +487,7 @@ void ImplShowHelpWindow( vcl::Window* pParent, sal_uInt16 nHelpWinStyle, QuickHe
2ec3e50
 
2ec3e50
         if  (   (   ( pHelpWin->GetHelpText() != rHelpText )
2ec3e50
                 ||  ( pHelpWin->GetWinStyle() != nHelpWinStyle )
2ec3e50
-                ||  (   pHelpArea
2ec3e50
-                    &&  ( pHelpWin->GetHelpArea() != *pHelpArea )
2ec3e50
-                    )
2ec3e50
+                ||  ( pHelpWin->GetHelpArea() != rHelpArea )
2ec3e50
                 )
2ec3e50
             &&  pSVData->maHelpData.mbRequestingHelp
2ec3e50
             )
f6d98b1
@@ -517,7 +512,7 @@ void ImplShowHelpWindow( vcl::Window* pParent, sal_uInt16 nHelpWinStyle, QuickHe
2ec3e50
 
2ec3e50
                 pHelpWin->SetHelpText( rHelpText );
2ec3e50
                 // approach mouse position
2ec3e50
-                ImplSetHelpWindowPos( pHelpWin, nHelpWinStyle, nStyle, rScreenPos, pHelpArea );
2ec3e50
+                ImplSetHelpWindowPos( pHelpWin, nHelpWinStyle, nStyle, rScreenPos, rHelpArea );
2ec3e50
                 if( pHelpWin->IsVisible() )
2ec3e50
                     pHelpWin->Invalidate();
2ec3e50
             }
f6d98b1
@@ -536,13 +531,12 @@ void ImplShowHelpWindow( vcl::Window* pParent, sal_uInt16 nHelpWinStyle, QuickHe
2ec3e50
         pHelpWin = VclPtr<HelpTextWindow>::Create( pParent, rHelpText, nHelpWinStyle, nStyle );
2ec3e50
         pSVData->maHelpData.mpHelpWin = pHelpWin;
2ec3e50
         pHelpWin->SetStatusText( rStatusText );
2ec3e50
-        if ( pHelpArea )
2ec3e50
-            pHelpWin->SetHelpArea( *pHelpArea );
2ec3e50
+        pHelpWin->SetHelpArea( rHelpArea );
2ec3e50
 
2ec3e50
         //  positioning
2ec3e50
         Size aSz = pHelpWin->CalcOutSize();
2ec3e50
         pHelpWin->SetOutputSizePixel( aSz );
2ec3e50
-        ImplSetHelpWindowPos( pHelpWin, nHelpWinStyle, nStyle, rScreenPos, pHelpArea );
2ec3e50
+        ImplSetHelpWindowPos( pHelpWin, nHelpWinStyle, nStyle, rScreenPos, rHelpArea );
2ec3e50
         // if not called from Window::RequestHelp, then without delay...
2ec3e50
         if ( !pSVData->maHelpData.mbRequestingHelp )
2ec3e50
             nDelayMode = HELPDELAY_NONE;
f6d98b1
@@ -571,7 +565,7 @@ void ImplDestroyHelpWindow( bool bUpdateHideTime )
2ec3e50
 }
2ec3e50
 
2ec3e50
 void ImplSetHelpWindowPos( vcl::Window* pHelpWin, sal_uInt16 nHelpWinStyle, QuickHelpFlags nStyle,
2ec3e50
-                           const Point& rPos, const Rectangle* pHelpArea )
2ec3e50
+                           const Point& rPos, const Rectangle& rHelpArea )
2ec3e50
 {
2ec3e50
     Point       aPos = rPos;
2ec3e50
     Size        aSz = pHelpWin->GetSizePixel();
f6d98b1
@@ -606,26 +600,23 @@ void ImplSetHelpWindowPos( vcl::Window* pHelpWin, sal_uInt16 nHelpWinStyle, Quic
2ec3e50
 
2ec3e50
     if ( nStyle & QuickHelpFlags::NoAutoPos )
2ec3e50
     {
2ec3e50
-        if ( pHelpArea )
2ec3e50
-        {
2ec3e50
-            // convert help area to screen coords
2ec3e50
-            Rectangle devHelpArea(
2ec3e50
-                pHelpWin->GetParent()->ImplGetFrameWindow()->OutputToAbsoluteScreenPixel( pHelpArea->TopLeft() ),
2ec3e50
-                pHelpWin->GetParent()->ImplGetFrameWindow()->OutputToAbsoluteScreenPixel( pHelpArea->BottomRight() ) );
2ec3e50
-
2ec3e50
-            // Welche Position vom Rechteck?
2ec3e50
-            aPos = devHelpArea.Center();
2ec3e50
-
2ec3e50
-            if ( nStyle & QuickHelpFlags::Left )
2ec3e50
-                aPos.X() = devHelpArea.Left();
2ec3e50
-            else if ( nStyle & QuickHelpFlags::Right )
2ec3e50
-                aPos.X() = devHelpArea.Right();
2ec3e50
-
2ec3e50
-            if ( nStyle & QuickHelpFlags::Top )
2ec3e50
-                aPos.Y() = devHelpArea.Top();
2ec3e50
-            else if ( nStyle & QuickHelpFlags::Bottom )
2ec3e50
-                aPos.Y() = devHelpArea.Bottom();
2ec3e50
-        }
2ec3e50
+        // convert help area to screen coords
2ec3e50
+        Rectangle devHelpArea(
2ec3e50
+            pHelpWin->GetParent()->ImplGetFrameWindow()->OutputToAbsoluteScreenPixel( rHelpArea.TopLeft() ),
2ec3e50
+            pHelpWin->GetParent()->ImplGetFrameWindow()->OutputToAbsoluteScreenPixel( rHelpArea.BottomRight() ) );
2ec3e50
+
2ec3e50
+        // Welche Position vom Rechteck?
2ec3e50
+        aPos = devHelpArea.Center();
2ec3e50
+
2ec3e50
+        if ( nStyle & QuickHelpFlags::Left )
2ec3e50
+            aPos.X() = devHelpArea.Left();
2ec3e50
+        else if ( nStyle & QuickHelpFlags::Right )
2ec3e50
+            aPos.X() = devHelpArea.Right();
2ec3e50
+
2ec3e50
+        if ( nStyle & QuickHelpFlags::Top )
2ec3e50
+            aPos.Y() = devHelpArea.Top();
2ec3e50
+        else if ( nStyle & QuickHelpFlags::Bottom )
2ec3e50
+            aPos.Y() = devHelpArea.Bottom();
2ec3e50
 
2ec3e50
         // which direction?
2ec3e50
         if ( nStyle & QuickHelpFlags::Left )
2ec3e50
diff --git a/vcl/source/window/menuwindow.cxx b/vcl/source/window/menuwindow.cxx
f6d98b1
index e915c33..4e89f44 100644
2ec3e50
--- a/vcl/source/window/menuwindow.cxx
2ec3e50
+++ b/vcl/source/window/menuwindow.cxx
2ec3e50
@@ -63,7 +63,7 @@ bool MenuWindow::ImplHandleHelpEvent(vcl::Window* pMenuWindow, Menu* pMenu, sal_
2ec3e50
 
2ec3e50
         Rectangle aRect( aPos, Size() );
2ec3e50
         if (!pMenu->GetHelpText(nId).isEmpty())
2ec3e50
-            Help::ShowBalloon( pMenuWindow, aPos, pMenu->GetHelpText( nId ) );
2ec3e50
+            Help::ShowBalloon( pMenuWindow, aPos, aRect, pMenu->GetHelpText( nId ) );
2ec3e50
         else
2ec3e50
         {
2ec3e50
             // give user a chance to read the full filename
2ec3e50
diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx
f6d98b1
index e8d2b96..20377ac 100644
2ec3e50
--- a/vcl/source/window/window.cxx
2ec3e50
+++ b/vcl/source/window/window.cxx
f6d98b1
@@ -1976,7 +1976,14 @@ void Window::RequestHelp( const HelpEvent& rHEvt )
2ec3e50
         if ( rStr.isEmpty() && ImplGetParent() && !ImplIsOverlapWindow() )
2ec3e50
             ImplGetParent()->RequestHelp( rHEvt );
2ec3e50
         else
2ec3e50
-            Help::ShowBalloon( this, rHEvt.GetMousePosPixel(), rStr );
2ec3e50
+        {
2ec3e50
+            Point aPos = GetPosPixel();
2ec3e50
+            if ( ImplGetParent() && !ImplIsOverlapWindow() )
2ec3e50
+                aPos = ImplGetParent()->OutputToScreenPixel( aPos );
2ec3e50
+            Rectangle   aRect( aPos, GetSizePixel() );
2ec3e50
+
2ec3e50
+            Help::ShowBalloon( this, rHEvt.GetMousePosPixel(), aRect, rStr );
2ec3e50
+        }
2ec3e50
     }
2ec3e50
     else if ( rHEvt.GetMode() & HelpEventMode::QUICK )
2ec3e50
     {
2ec3e50
diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx
f6d98b1
index ca9d371..592c872 100644
2ec3e50
--- a/vcl/unx/gtk3/gtk3gtkframe.cxx
2ec3e50
+++ b/vcl/unx/gtk3/gtk3gtkframe.cxx
f6d98b1
@@ -978,6 +978,8 @@ void GtkSalFrame::InitCommon()
2ec3e50
 
2ec3e50
     // connect signals
2ec3e50
     g_signal_connect( G_OBJECT(m_pWindow), "style-set", G_CALLBACK(signalStyleSet), this );
2ec3e50
+    gtk_widget_set_has_tooltip(pEventWidget, true);
2ec3e50
+    m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "query-tooltip", G_CALLBACK(signalTooltipQuery), this ));
2ec3e50
     m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "button-press-event", G_CALLBACK(signalButton), this ));
2ec3e50
     m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "motion-notify-event", G_CALLBACK(signalMotion), this ));
2ec3e50
     m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "button-release-event", G_CALLBACK(signalButton), this ));
f6d98b1
@@ -2623,6 +2625,32 @@ void GtkSalFrame::SetModal(bool bModal)
2ec3e50
     gtk_window_set_modal(GTK_WINDOW(m_pWindow), bModal);
2ec3e50
 }
2ec3e50
 
2ec3e50
+gboolean GtkSalFrame::signalTooltipQuery(GtkWidget*, gint /*x*/, gint /*y*/,
2ec3e50
+                                     gboolean /*keyboard_mode*/, GtkTooltip *tooltip,
2ec3e50
+                                     gpointer frame)
2ec3e50
+{
2ec3e50
+    GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
2ec3e50
+    if (pThis->m_aTooltip.isEmpty())
2ec3e50
+        return false;
2ec3e50
+    gtk_tooltip_set_text(tooltip,
2ec3e50
+        OUStringToOString(pThis->m_aTooltip, RTL_TEXTENCODING_UTF8).getStr());
2ec3e50
+    GdkRectangle aHelpArea;
2ec3e50
+    aHelpArea.x = pThis->m_aHelpArea.Left();
2ec3e50
+    aHelpArea.y = pThis->m_aHelpArea.Top();
2ec3e50
+    aHelpArea.width = pThis->m_aHelpArea.GetWidth();
2ec3e50
+    aHelpArea.height = pThis->m_aHelpArea.GetHeight();
2ec3e50
+    gtk_tooltip_set_tip_area(tooltip, &aHelpArea);
2ec3e50
+    return true;
2ec3e50
+}
2ec3e50
+
2ec3e50
+bool GtkSalFrame::ShowTooltip(const OUString& rHelpText, const Rectangle& rHelpArea)
2ec3e50
+{
2ec3e50
+    m_aTooltip = rHelpText;
2ec3e50
+    m_aHelpArea = rHelpArea;
2ec3e50
+    gtk_widget_trigger_tooltip_query(getMouseEventWidget());
2ec3e50
+    return true;
2ec3e50
+}
2ec3e50
+
2ec3e50
 gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer frame )
2ec3e50
 {
2ec3e50
     GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
f6d98b1
-- 
f6d98b1
2.5.0
f6d98b1