summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2016-07-07 10:39:00 +0100
committerCaolán McNamara <caolanm@redhat.com>2016-07-07 15:57:01 +0000
commit6b9f42ea1dc0926bc445982ad57bf93561f1bd03 (patch)
tree1ba078e3eeacabd4f0560b4ca48b10701b149898
parentfb045517532aababc06fb4b1112def53b03d9144 (diff)
Resolves: rhbz#1351224 wayland grab related crashes
only one popup active at a time. Try and find the right path through the uncanny valley which allows popups to appear, to get all mouse input that happens to them, forward keyboard input to their parents, dismiss when the mouse is clicked outside them and not crash if another popup wants to appear to replace it Change-Id: If4b39df41ca3dccde1e506d5328b06731a8c80eb Reviewed-on: https://gerrit.libreoffice.org/27005 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Caolán McNamara <caolanm@redhat.com> Tested-by: Caolán McNamara <caolanm@redhat.com>
-rw-r--r--vcl/inc/unx/gtk/gtkframe.hxx5
-rw-r--r--vcl/unx/gtk3/gtk3gtkframe.cxx136
2 files changed, 60 insertions, 81 deletions
diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx
index 4e13318215df..374884713334 100644
--- a/vcl/inc/unx/gtk/gtkframe.hxx
+++ b/vcl/inc/unx/gtk/gtkframe.hxx
@@ -269,6 +269,7 @@ class GtkSalFrame : public SalFrame
#else
static gboolean signalExpose( GtkWidget*, GdkEventExpose*, gpointer );
void askForXEmbedFocus( sal_Int32 nTimecode );
+ void grabKeyboard(bool bGrab);
#endif
static gboolean signalFocus( GtkWidget*, GdkEventFocus*, gpointer );
static gboolean signalMap( GtkWidget*, GdkEvent*, gpointer );
@@ -299,7 +300,6 @@ class GtkSalFrame : public SalFrame
static GdkNativeWindow findTopLevelSystemWindow( GdkNativeWindow aWindow );
static int m_nFloats;
- static std::vector<GtkWidget*> m_aGrabWidgetsBeforeShowFloat;
bool isFloatGrabWindow() const
{
@@ -365,7 +365,6 @@ public:
// be swallowed
bool Dispatch( const XEvent* pEvent );
void grabPointer(bool bGrab, bool bOwnerEvents = false);
- void grabKeyboard(bool bGrab);
static GtkSalDisplay* getDisplay();
static GdkDisplay* getGdkDisplay();
@@ -424,7 +423,7 @@ public:
void WithDrawn();
- static void closePopup(bool bWithDrawn);
+ static void closePopup();
#endif
virtual ~GtkSalFrame();
diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx
index 79b0e11d6a76..0046a13dc96d 100644
--- a/vcl/unx/gtk3/gtk3gtkframe.cxx
+++ b/vcl/unx/gtk3/gtk3gtkframe.cxx
@@ -107,7 +107,6 @@
using namespace com::sun::star;
int GtkSalFrame::m_nFloats = 0;
-std::vector<GtkWidget*> GtkSalFrame::m_aGrabWidgetsBeforeShowFloat;
#if defined ENABLE_GMENU_INTEGRATION
static GDBusConnection* pSessionBus = nullptr;
@@ -1421,23 +1420,21 @@ void GtkSalFrame::Show( bool bVisible, bool /*bNoActivate*/ )
SetDefaultSize();
setMinMaxSize();
- gtk_widget_show( m_pWindow );
+ if (isFloatGrabWindow() && !getDisplay()->GetCaptureFrame() && m_nFloats == 0)
+ {
+ m_pParent->grabPointer(true, true);
+ gtk_grab_add(m_pParent->getMouseEventWidget());
+ }
+
+ gtk_widget_show(m_pWindow);
if( isFloatGrabWindow() )
{
m_nFloats++;
if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 1 )
{
- GtkWindowGroup *pWindowGroup = gtk_window_get_group(GTK_WINDOW(m_pWindow));
- GtkWidget* pGrabWidgetBeforeShowFloat;
- while ((pGrabWidgetBeforeShowFloat = gtk_window_group_get_current_grab(pWindowGroup)))
- {
- m_aGrabWidgetsBeforeShowFloat.push_back(pGrabWidgetBeforeShowFloat);
- gtk_grab_remove(pGrabWidgetBeforeShowFloat);
- }
grabPointer(true, true);
- GtkSalFrame *pKeyboardFrame = m_pParent ? m_pParent : this;
- pKeyboardFrame->grabKeyboard(true);
+ gtk_grab_add(getMouseEventWidget());
}
// #i44068# reset parent's IM context
if( m_pParent )
@@ -1451,12 +1448,10 @@ void GtkSalFrame::Show( bool bVisible, bool /*bNoActivate*/ )
m_nFloats--;
if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 0)
{
- GtkSalFrame *pKeyboardFrame = m_pParent ? m_pParent : this;
- pKeyboardFrame->grabKeyboard(false);
+ gtk_grab_remove(getMouseEventWidget());
grabPointer(false);
- for (auto i = m_aGrabWidgetsBeforeShowFloat.rbegin(); i != m_aGrabWidgetsBeforeShowFloat.rend(); ++i)
- gtk_grab_add(*i);
- m_aGrabWidgetsBeforeShowFloat.clear();
+ gtk_grab_remove(m_pParent->getMouseEventWidget());
+ m_pParent->grabPointer(false);
}
}
gtk_widget_hide( m_pWindow );
@@ -2058,37 +2053,32 @@ void GtkSalFrame::grabPointer( bool bGrab, bool bOwnerEvents )
if (!m_pWindow)
return;
- const int nMask = (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
-
- GdkDeviceManager* pDeviceManager = gdk_display_get_device_manager(getGdkDisplay());
- GdkDevice* pPointer = gdk_device_manager_get_client_pointer(pDeviceManager);
+#if GTK_CHECK_VERSION(3, 19, 2)
+ GdkSeat* pSeat = gdk_display_get_default_seat(getGdkDisplay());
if (bGrab)
- gdk_device_grab(pPointer, widget_get_window(getMouseEventWidget()), GDK_OWNERSHIP_NONE, bOwnerEvents, (GdkEventMask) nMask, m_pCurrentCursor, gtk_get_current_event_time());
+ {
+ gdk_seat_grab(pSeat, widget_get_window(getMouseEventWidget()), GDK_SEAT_CAPABILITY_ALL_POINTING,
+ bOwnerEvents, NULL, NULL, NULL, NULL);
+ }
else
- gdk_device_ungrab(pPointer, gtk_get_current_event_time());
-}
-
-void GtkSalFrame::grabKeyboard( bool bGrab )
-{
- static const char* pEnv = getenv("SAL_NO_MOUSEGRABS"); // let's not introduce a special var for this
- if (pEnv && *pEnv)
- return;
-
- if (!m_pWindow)
- return;
+ {
+ gdk_seat_ungrab(pSeat);
+ }
+#else
+ const int nMask = (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
GdkDeviceManager* pDeviceManager = gdk_display_get_device_manager(getGdkDisplay());
GdkDevice* pPointer = gdk_device_manager_get_client_pointer(pDeviceManager);
- GdkDevice* pKeyboard = gdk_device_get_associated_device(pPointer);
if (bGrab)
{
- gdk_device_grab(pKeyboard, widget_get_window(m_pWindow), GDK_OWNERSHIP_NONE,
- true, (GdkEventMask)(GDK_KEY_PRESS | GDK_KEY_RELEASE), nullptr, gtk_get_current_event_time());
+ gdk_device_grab(pPointer, widget_get_window(getMouseEventWidget()), GDK_OWNERSHIP_NONE,
+ bOwnerEvents, (GdkEventMask) nMask, m_pCurrentCursor, gtk_get_current_event_time());
}
else
{
- gdk_device_ungrab(pKeyboard, gtk_get_current_event_time());
+ gdk_device_ungrab(pPointer, gtk_get_current_event_time());
}
+#endif
}
void GtkSalFrame::CaptureMouse( bool bCapture )
@@ -2553,21 +2543,17 @@ void GtkSalFrame::StartToolKitMoveBy()
void GtkSalFrame::WithDrawn()
{
if (isFloatGrabWindow())
- closePopup(true);
+ closePopup();
}
-void GtkSalFrame::closePopup(bool bWithDrawn)
+void GtkSalFrame::closePopup()
{
if (!m_nFloats)
return;
ImplSVData* pSVData = ImplGetSVData();
if (!pSVData->maWinData.mpFirstFloat)
return;
- bool bClosePopup = bWithDrawn;
- if (!bClosePopup)
- bClosePopup = !(pSVData->maWinData.mpFirstFloat->GetPopupModeFlags() & FloatWinPopupFlags::NoAppFocusClose);
- if (bClosePopup)
- pSVData->maWinData.mpFirstFloat->EndPopupMode(FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::CloseAll);
+ pSVData->maWinData.mpFirstFloat->EndPopupMode(FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::CloseAll);
}
gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer frame )
@@ -2601,56 +2587,40 @@ gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer
aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
aEvent.mnCode = GetMouseModCode( pEvent->state );
- bool bClosePopups = false;
- if( pEvent->type == GDK_BUTTON_PRESS &&
- !(pThis->m_nStyle & SalFrameStyleFlags::OWNERDRAWDECORATION)
- )
+ vcl::DeletionListener aDel( pThis );
+
+ if (pEvent->type == GDK_BUTTON_PRESS && pThis->isFloatGrabWindow())
{
- if( m_nFloats > 0 )
- {
- // close popups if user clicks outside our application
- gint x, y;
- bClosePopups = (gdk_display_get_window_at_pointer( GtkSalFrame::getGdkDisplay(), &x, &y ) == nullptr);
- }
- /* #i30306# release implicit pointer grab if no popups are open; else
- * Drag cannot grab the pointer and will fail.
- */
- if( m_nFloats < 1 || bClosePopups )
- gdk_display_pointer_ungrab( GtkSalFrame::getGdkDisplay(), GDK_CURRENT_TIME );
+ bool bClosePopups = (pEvent->window != widget_get_window(pThis->getMouseEventWidget()));
+ if (bClosePopups)
+ closePopup();
}
// --- RTL --- (mirror mouse pos)
if( AllSettings::GetLayoutRTL() )
aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
- vcl::DeletionListener aDel( pThis );
-
- pThis->CallCallback( nEventType, &aEvent );
-
- if( ! aDel.isDeleted() )
+ if (!aDel.isDeleted())
{
- if( bClosePopups )
- {
- closePopup(false);
- }
+ pThis->CallCallback( nEventType, &aEvent );
+ }
- if( ! aDel.isDeleted() )
+ if (!aDel.isDeleted())
+ {
+ int frame_x = (int)(pEvent->x_root - pEvent->x);
+ int frame_y = (int)(pEvent->y_root - pEvent->y);
+ if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY )
{
- int frame_x = (int)(pEvent->x_root - pEvent->x);
- int frame_y = (int)(pEvent->y_root - pEvent->y);
- if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY )
- {
- pThis->maGeometry.nX = frame_x;
- pThis->maGeometry.nY = frame_y;
- pThis->CallCallback( SalEvent::Move, nullptr );
- }
+ pThis->maGeometry.nX = frame_x;
+ pThis->maGeometry.nY = frame_y;
+ pThis->CallCallback( SalEvent::Move, nullptr );
}
}
return true;
}
-gboolean GtkSalFrame::signalScroll( GtkWidget*, GdkEventScroll* pEvent, gpointer frame )
+gboolean GtkSalFrame::signalScroll(GtkWidget*, GdkEventScroll* pEvent, gpointer frame)
{
UpdateLastInputEventTime(pEvent->time);
@@ -2787,6 +2757,13 @@ gboolean GtkSalFrame::signalMotion( GtkWidget*, GdkEventMotion* pEvent, gpointer
GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+ //If a menu, e.g. font name dropdown, is open, then under wayland moving the
+ //mouse in the top left corner of the toplevel window in a
+ //0,0,float-width,float-height area generates motion events which are
+ //delivered to the dropdown
+ if (pThis->isFloatGrabWindow() && pEvent->window != widget_get_window(pThis->getMouseEventWidget()))
+ return true;
+
SalMouseEvent aEvent;
aEvent.mnTime = pEvent->time;
aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
@@ -2996,12 +2973,15 @@ gboolean GtkSalFrame::signalUnmap( GtkWidget*, GdkEvent*, gpointer frame )
return false;
}
-gboolean GtkSalFrame::signalKey( GtkWidget*, GdkEventKey* pEvent, gpointer frame )
+gboolean GtkSalFrame::signalKey(GtkWidget* pWidget, GdkEventKey* pEvent, gpointer frame)
{
UpdateLastInputEventTime(pEvent->time);
GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+ if (pThis->isFloatGrabWindow())
+ return signalKey(pWidget, pEvent, pThis->m_pParent);
+
vcl::DeletionListener aDel( pThis );
if( pThis->m_pIMHandler )