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