Kaydet (Commit) c3e552ac authored tarafından Maxim Monastirsky's avatar Maxim Monastirsky

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/55772Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarMaxim Monastirsky <momonasmon@gmail.com>
üst 2bfc4cef
......@@ -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 );
......
......@@ -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;
......
......@@ -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();
......
......@@ -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
......
......@@ -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();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment