Blame SOURCES/0001-Resolves-rhbz-1289394-gtk3-implement-tooltips-native.patch

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