summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxim Monastirsky <momonasmon@gmail.com>2018-06-12 02:26:28 +0300
committerMaxim Monastirsky <momonasmon@gmail.com>2018-06-14 00:46:36 +0200
commitc3e552ac25be001a623469c549ee8d0719b98133 (patch)
tree624f73b7e15e93af22066a72917621ed9eefd69d
parent2bfc4cefc21ab18e9ff7cc5fdc743bcc856d103c (diff)
wayland: Make popup menus not show off-screen
Depends on gtk 3.22 for gtk_menu_popup_at_rect. Had to rework the toolbar context menu to not execute async, as otherwise it just closes immediately. (Basically it's same as rhbz#1342823, except that I couldn't find a way to feed gtk_menu_popup_at_rect with the correct timestamp). Change-Id: I779d8803c80314d93a342f1294c7280f1adf4c98 Reviewed-on: https://gerrit.libreoffice.org/55772 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Maxim Monastirsky <momonasmon@gmail.com>
-rw-r--r--include/vcl/toolbox.hxx1
-rw-r--r--vcl/inc/toolbox.h2
-rw-r--r--vcl/source/window/toolbox.cxx4
-rw-r--r--vcl/source/window/toolbox2.cxx27
-rw-r--r--vcl/unx/gtk/gtksalmenu.cxx87
5 files changed, 65 insertions, 56 deletions
diff --git a/include/vcl/toolbox.hxx b/include/vcl/toolbox.hxx
index 7944fd950a82..58bf32bb0e26 100644
--- a/include/vcl/toolbox.hxx
+++ b/include/vcl/toolbox.hxx
@@ -210,7 +210,6 @@ private:
SAL_DLLPRIVATE bool ImplHasExternalMenubutton();
SAL_DLLPRIVATE void ImplDrawFloatwinBorder(vcl::RenderContext& rRenderContext, ImplToolItem const * pItem );
- DECL_DLLPRIVATE_LINK( ImplCallExecuteCustomMenu, void*, void );
DECL_DLLPRIVATE_LINK( ImplUpdateHdl, Timer*, void );
DECL_DLLPRIVATE_LINK( ImplCustomMenuListener, VclMenuEvent&, void );
DECL_DLLPRIVATE_LINK( ImplDropdownLongClickHdl, Timer*, void );
diff --git a/vcl/inc/toolbox.h b/vcl/inc/toolbox.h
index 9d928ce6a1ba..17c5585ef490 100644
--- a/vcl/inc/toolbox.h
+++ b/vcl/inc/toolbox.h
@@ -129,9 +129,7 @@ struct ImplToolBoxPrivateData
// the optional custom menu
VclPtr<PopupMenu> mpMenu;
- tools::Rectangle maMenuRect;
ToolBoxMenuType maMenuType;
- ImplSVEvent * mnEventId;
// called when menu button is clicked and before the popup menu is executed
Link<ToolBox *, void> maMenuButtonHdl;
diff --git a/vcl/source/window/toolbox.cxx b/vcl/source/window/toolbox.cxx
index 2df527a8cbd4..d1007d4badcd 100644
--- a/vcl/source/window/toolbox.cxx
+++ b/vcl/source/window/toolbox.cxx
@@ -1341,10 +1341,6 @@ ToolBox::~ToolBox()
void ToolBox::dispose()
{
- // custom menu event still running?
- if( mpData && mpData->mnEventId )
- Application::RemoveUserEvent( mpData->mnEventId );
-
// #103005# make sure our activate/deactivate balance is right
while( mnActivateCount > 0 )
Deactivate();
diff --git a/vcl/source/window/toolbox2.cxx b/vcl/source/window/toolbox2.cxx
index cc86b0d9a0f9..ab4c90ece48f 100644
--- a/vcl/source/window/toolbox2.cxx
+++ b/vcl/source/window/toolbox2.cxx
@@ -48,7 +48,6 @@ ImplToolBoxPrivateData::ImplToolBoxPrivateData() :
{
meButtonSize = ToolBoxButtonSize::DontCare;
mpMenu = VclPtr<PopupMenu>::Create();
- mnEventId = nullptr;
maMenuType = ToolBoxMenuType::NONE;
maMenubuttonItem.maItemSize = Size( TB_MENUBUTTON_SIZE+TB_MENUBUTTON_OFFSET, TB_MENUBUTTON_SIZE+TB_MENUBUTTON_OFFSET );
@@ -1621,9 +1620,6 @@ namespace
void ToolBox::UpdateCustomMenu()
{
// fill clipped items into menu
- if( !IsMenuEnabled() )
- return;
-
PopupMenu *pMenu = GetMenu();
pMenu->Clear();
@@ -1680,12 +1676,13 @@ IMPL_LINK( ToolBox, ImplCustomMenuListener, VclMenuEvent&, rEvent, void )
}
}
-IMPL_LINK_NOARG(ToolBox, ImplCallExecuteCustomMenu, void*, void)
+void ToolBox::ExecuteCustomMenu( const tools::Rectangle& rRect )
{
- mpData->mnEventId = nullptr;
- if( !IsMenuEnabled() )
+ if ( !IsMenuEnabled() || ImplIsInPopupMode() )
return;
+ UpdateCustomMenu();
+
if( GetMenuType() & ToolBoxMenuType::Customize )
// call button handler to allow for menu customization
mpData->maMenuButtonHdl.Call( this );
@@ -1700,8 +1697,7 @@ IMPL_LINK_NOARG(ToolBox, ImplCallExecuteCustomMenu, void*, void)
bool bBorderDel = false;
VclPtr<vcl::Window> pWin = this;
- tools::Rectangle aMenuRect = mpData->maMenuRect;
- mpData->maMenuRect.SetEmpty();
+ tools::Rectangle aMenuRect = rRect;
VclPtr<ImplBorderWindow> pBorderWin;
if( aMenuRect.IsEmpty() && IsFloatingMode() )
{
@@ -1733,19 +1729,6 @@ IMPL_LINK_NOARG(ToolBox, ImplCallExecuteCustomMenu, void*, void)
if( uId )
GrabFocusToDocument();
-
-}
-
-void ToolBox::ExecuteCustomMenu( const tools::Rectangle& rRect )
-{
- if ( IsMenuEnabled() && !ImplIsInPopupMode() )
- {
- UpdateCustomMenu();
- // handle custom menu asynchronously
- // to avoid problems if the toolbox is closed during menu execute
- mpData->maMenuRect = rRect;
- mpData->mnEventId = Application::PostUserEvent( LINK( this, ToolBox, ImplCallExecuteCustomMenu ), nullptr, true );
- }
}
// checks override first, useful during calculation of sizes
diff --git a/vcl/unx/gtk/gtksalmenu.cxx b/vcl/unx/gtk/gtksalmenu.cxx
index 8fd2ea29636a..84add236d0be 100644
--- a/vcl/unx/gtk/gtksalmenu.cxx
+++ b/vcl/unx/gtk/gtksalmenu.cxx
@@ -410,33 +410,9 @@ bool GtkSalMenu::ShowNativePopupMenu(FloatingWindow* pWin, const tools::Rectangl
FloatWinPopupFlags nFlags)
{
#if GTK_CHECK_VERSION(3,0,0)
- guint nButton;
- guint32 nTime;
-
- //typically there is an event, and we can then distinguish if this was
- //launched from the keyboard (gets auto-mnemoniced) or the mouse (which
- //doesn't)
- GdkEvent *pEvent = gtk_get_current_event();
- if (pEvent)
- {
- gdk_event_get_button(pEvent, &nButton);
- nTime = gdk_event_get_time(pEvent);
- }
- else
- {
- nButton = 0;
- nTime = GtkSalFrame::GetLastInputEventTime();
- }
-
VclPtr<vcl::Window> xParent = pWin->ImplGetWindowImpl()->mpRealParent;
mpFrame = static_cast<GtkSalFrame*>(xParent->ImplGetFrame());
- // do the same strange semantics as vcl popup windows to arrive at a frame geometry
- // in mirrored UI case; best done by actually executing the same code
- sal_uInt16 nArrangeIndex;
- Point aPos = FloatingWindow::ImplCalcPos(pWin, rRect, nFlags, nArrangeIndex);
- aPos = FloatingWindow::ImplConvertToAbsPos(xParent, aPos);
-
GLOActionGroup* pActionGroup = g_lo_action_group_new();
mpActionGroup = G_ACTION_GROUP(pActionGroup);
mpMenuModel = G_MENU_MODEL(g_lo_menu_new());
@@ -445,7 +421,6 @@ bool GtkSalMenu::ShowNativePopupMenu(FloatingWindow* pWin, const tools::Rectangl
GtkWidget *pWidget = gtk_menu_new_from_model(mpMenuModel);
gtk_menu_attach_to_widget(GTK_MENU(pWidget), mpFrame->getMouseEventWidget(), nullptr);
-
gtk_widget_insert_action_group(mpFrame->getMouseEventWidget(), "win", mpActionGroup);
//run in a sub main loop because we need to keep vcl PopupMenu alive to use
@@ -454,8 +429,66 @@ bool GtkSalMenu::ShowNativePopupMenu(FloatingWindow* pWin, const tools::Rectangl
//until the gtk menu is destroyed
GMainLoop* pLoop = g_main_loop_new(nullptr, true);
g_signal_connect_swapped(G_OBJECT(pWidget), "deactivate", G_CALLBACK(g_main_loop_quit), pLoop);
- gtk_menu_popup(GTK_MENU(pWidget), nullptr, nullptr, MenuPositionFunc,
- &aPos, nButton, nTime);
+
+#if GTK_CHECK_VERSION(3,22,0)
+ if (gtk_check_version(3, 22, 0) == nullptr)
+ {
+ GdkGravity rect_anchor = GDK_GRAVITY_SOUTH_WEST, menu_anchor = GDK_GRAVITY_NORTH_WEST;
+
+ if (nFlags & FloatWinPopupFlags::Left)
+ {
+ rect_anchor = GDK_GRAVITY_NORTH_WEST;
+ menu_anchor = GDK_GRAVITY_NORTH_EAST;
+ }
+ else if (nFlags & FloatWinPopupFlags::Up)
+ {
+ rect_anchor = GDK_GRAVITY_NORTH_WEST;
+ menu_anchor = GDK_GRAVITY_SOUTH_WEST;
+ }
+ else if (nFlags & FloatWinPopupFlags::Right)
+ {
+ rect_anchor = GDK_GRAVITY_NORTH_EAST;
+ }
+
+ tools::Rectangle aFloatRect = FloatingWindow::ImplConvertToAbsPos(xParent, rRect);
+ aFloatRect.Move(-mpFrame->maGeometry.nX, -mpFrame->maGeometry.nY);
+ GdkRectangle rect {static_cast<int>(aFloatRect.Left()), static_cast<int>(aFloatRect.Top()),
+ static_cast<int>(aFloatRect.GetWidth()), static_cast<int>(aFloatRect.GetHeight())};
+
+ GdkWindow* gdkWindow = widget_get_window(mpFrame->getMouseEventWidget());
+ gtk_menu_popup_at_rect(GTK_MENU(pWidget), gdkWindow, &rect, rect_anchor, menu_anchor, nullptr);
+ }
+ else
+#endif
+ {
+ guint nButton;
+ guint32 nTime;
+
+ //typically there is an event, and we can then distinguish if this was
+ //launched from the keyboard (gets auto-mnemoniced) or the mouse (which
+ //doesn't)
+ GdkEvent *pEvent = gtk_get_current_event();
+ if (pEvent)
+ {
+ gdk_event_get_button(pEvent, &nButton);
+ nTime = gdk_event_get_time(pEvent);
+ }
+ else
+ {
+ nButton = 0;
+ nTime = GtkSalFrame::GetLastInputEventTime();
+ }
+
+ // do the same strange semantics as vcl popup windows to arrive at a frame geometry
+ // in mirrored UI case; best done by actually executing the same code
+ sal_uInt16 nArrangeIndex;
+ Point aPos = FloatingWindow::ImplCalcPos(pWin, rRect, nFlags, nArrangeIndex);
+ aPos = FloatingWindow::ImplConvertToAbsPos(xParent, aPos);
+
+ gtk_menu_popup(GTK_MENU(pWidget), nullptr, nullptr, MenuPositionFunc,
+ &aPos, nButton, nTime);
+ }
+
if (g_main_loop_is_running(pLoop))
{
gdk_threads_leave();