diff --git a/0001-Resolves-rhbz-1351224-wayland-grab-related-crashes.patch b/0001-Resolves-rhbz-1351224-wayland-grab-related-crashes.patch new file mode 100644 index 0000000..91450a8 --- /dev/null +++ b/0001-Resolves-rhbz-1351224-wayland-grab-related-crashes.patch @@ -0,0 +1,378 @@ +From 5c9d1063505335ea9734936c5549bc68acf7f5f9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= +Date: Fri, 1 Jul 2016 15:42:34 +0100 +Subject: [PATCH] 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 + +gtk3: XEmbed isn't going to happen + +Change-Id: I7a7589a159a7fccdc224262bf5f91f8d98f5f619 +(cherry picked from commit fe7b8bc9fdb57087ba9daa22cdec77d735eb71cd) + +gtk3: if a popup is withdrawn close the popup + +we don't always get the click that causes the popup +to be withdrawn when the mouse is clicked outside +the application during a grab + +Change-Id: I2dbef23813972ebd75c8899711a2d1309110f968 +(cherry picked from commit 1190e7385291fb0e6cd3505e88e589c80b02db00) + +Change-Id: If4b39df41ca3dccde1e506d5328b06731a8c80eb +--- + vcl/inc/unx/gtk/gtkframe.hxx | 9 ++- + vcl/unx/gtk3/gtk3gtkframe.cxx | 173 +++++++++++++++++++----------------------- + 2 files changed, 85 insertions(+), 97 deletions(-) + +diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx +index 4677923..a660567 100644 +--- a/vcl/inc/unx/gtk/gtkframe.hxx ++++ b/vcl/inc/unx/gtk/gtkframe.hxx +@@ -269,6 +269,8 @@ class GtkSalFrame : public SalFrame + #endif + #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 +301,6 @@ class GtkSalFrame : public SalFrame + static GdkNativeWindow findTopLevelSystemWindow( GdkNativeWindow aWindow ); + + static int m_nFloats; +- static std::vector m_aGrabWidgetsBeforeShowFloat; + + bool isFloatGrabWindow() const + { +@@ -335,7 +336,6 @@ class GtkSalFrame : public SalFrame + + void setMinMaxSize(); + void createNewWindow( ::Window aParent, bool bXEmbed, SalX11Screen nXScreen ); +- void askForXEmbedFocus( sal_Int32 nTimecode ); + + void AllocateFrame(); + void TriggerPaintEvent(); +@@ -366,7 +366,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,6 +423,10 @@ public: + void startDrag(gint nButton, gint nDragOriginX, gint nDragOriginY, + GdkDragAction sourceActions, GtkTargetList* pTargetList); + ++ void WithDrawn(); ++ ++ static void closePopup(); ++ + #endif + virtual ~GtkSalFrame(); + +diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx +index 2320356..04af596 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 GtkSalFrame::m_aGrabWidgetsBeforeShowFloat; + + #if defined ENABLE_GMENU_INTEGRATION + static GDBusConnection* pSessionBus = nullptr; +@@ -1292,13 +1291,6 @@ void GtkSalFrame::Init( SystemParentData* pSysData ) + //FIXME: Handling embedded windows, is going to be fun ... + } + +-void GtkSalFrame::askForXEmbedFocus( sal_Int32 i_nTimeCode ) +-{ +- (void) this; // loplugin:staticmethods +- (void)i_nTimeCode; +- //FIXME: no askForXEmbedFocus for gtk3 yet +-} +- + void GtkSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle ) + { + if( nStyle != m_nExtStyle && ! isChild() ) +@@ -1433,30 +1425,26 @@ void GtkSalFrame::Show( bool bVisible, bool bNoActivate ) + if( ! bNoActivate && (m_nStyle & SalFrameStyleFlags::TOOLWINDOW) ) + m_bSetFocusOnMap = true; + +- 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 ) + m_pParent->EndExtTextInput(EndExtTextInputFlags::NONE); + } +- if( m_bWindowIsGtkPlug ) +- askForXEmbedFocus( 0 ); + } + else + { +@@ -1465,12 +1453,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 ); +@@ -2070,37 +2056,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 ) +@@ -2562,6 +2543,22 @@ void GtkSalFrame::StartToolKitMoveBy() + pEvent->button.time); + } + ++void GtkSalFrame::WithDrawn() ++{ ++ if (isFloatGrabWindow()) ++ closePopup(); ++} ++ ++void GtkSalFrame::closePopup() ++{ ++ if (!m_nFloats) ++ return; ++ ImplSVData* pSVData = ImplGetSVData(); ++ if (!pSVData->maWinData.mpFirstFloat) ++ return; ++ pSVData->maWinData.mpFirstFloat->EndPopupMode(FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::CloseAll); ++} ++ + gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer frame ) + { + UpdateLastInputEventTime(pEvent->time); +@@ -2593,69 +2590,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) +- ) +- { +- 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 ); +- } ++ vcl::DeletionListener aDel( pThis ); + +- if( pThis->m_bWindowIsGtkPlug && +- pEvent->type == GDK_BUTTON_PRESS && +- pEvent->button == 1 ) ++ if (pEvent->type == GDK_BUTTON_PRESS && pThis->isFloatGrabWindow()) + { +- pThis->askForXEmbedFocus( pEvent->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 ) +- { +- ImplSVData* pSVData = ImplGetSVData(); +- if ( pSVData->maWinData.mpFirstFloat ) +- { +- static const char* pEnv = getenv( "SAL_FLOATWIN_NOAPPFOCUSCLOSE" ); +- if ( !(pSVData->maWinData.mpFirstFloat->GetPopupModeFlags() & FloatWinPopupFlags::NoAppFocusClose) && !(pEnv && *pEnv) ) +- pSVData->maWinData.mpFirstFloat->EndPopupMode( FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::CloseAll ); +- } +- } ++ 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); + +@@ -2757,6 +2725,13 @@ gboolean GtkSalFrame::signalMotion( GtkWidget*, GdkEventMotion* pEvent, gpointer + + GtkSalFrame* pThis = static_cast(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; +@@ -2972,12 +2947,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(frame); + ++ if (pThis->isFloatGrabWindow()) ++ return signalKey(pWidget, pEvent, pThis->m_pParent); ++ + vcl::DeletionListener aDel( pThis ); + + if( pThis->m_pIMHandler ) +@@ -3132,11 +3110,18 @@ gboolean GtkSalFrame::signalWindowState( GtkWidget*, GdkEvent* pEvent, gpointer + pThis->TriggerPaintEvent(); + } + +- if( (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_MAXIMIZED) && +- ! (pThis->m_nState & GDK_WINDOW_STATE_MAXIMIZED) ) ++ if ((pEvent->window_state.new_window_state & GDK_WINDOW_STATE_MAXIMIZED) && ++ !(pThis->m_nState & GDK_WINDOW_STATE_MAXIMIZED)) + { + pThis->m_aRestorePosSize = GetPosAndSize(GTK_WINDOW(pThis->m_pWindow)); + } ++ ++ if ((pEvent->window_state.new_window_state & GDK_WINDOW_STATE_WITHDRAWN) && ++ !(pThis->m_nState & GDK_WINDOW_STATE_WITHDRAWN)) ++ { ++ pThis->WithDrawn(); ++ } ++ + pThis->m_nState = pEvent->window_state.new_window_state; + + #if OSL_DEBUG_LEVEL > 1 +-- +2.7.4 + diff --git a/libreoffice.spec b/libreoffice.spec index a64e9ae..0363bae 100644 --- a/libreoffice.spec +++ b/libreoffice.spec @@ -239,6 +239,7 @@ Patch9: 0002-update-other-places-that-read-data-from-cairo-image-.patch Patch10: 0001-don-t-autocapitalize-words-that-follow-a-field-mark.patch Patch11: 0001-a11y-crash-on-deleting-certain-frame-in-certain-docu.patch Patch12: 0001-Resolves-rhbz-1353069-don-t-clear-XATTR_FILL-from-st.patch +Patch13: 0001-Resolves-rhbz-1351224-wayland-grab-related-crashes.patch %if 0%{?rhel} # not upstreamed