1 |
From ef70b6a3b0a2e1cc27c890d4c648bac4f276d6ff Mon Sep 17 00:00:00 2001 |
2 |
From: rpmbuild <rpmbuild@fedoraproject.org> |
3 |
Date: Thu, 7 Jul 2016 15:56:54 +0100 |
4 |
Subject: [PATCH] Resolves: rhbz#1351224 wayland grab related crashes |
5 |
|
6 |
only one popup active at a time. Try and find the right path through the |
7 |
uncanny valley which allows popups to appear, to get all mouse input that |
8 |
happens to them, forward keyboard input to their parents, dismiss when the |
9 |
mouse is clicked outside them and not crash if another popup wants to appear |
10 |
to replace it |
11 |
--- |
12 |
vcl/inc/unx/gtk/gtkframe.hxx | 9 ++- |
13 |
vcl/unx/gtk3/gtk3gtkframe.cxx | 171 +++++++++++++++++++----------------------- |
14 |
2 files changed, 84 insertions(+), 96 deletions(-) |
15 |
|
16 |
diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx |
17 |
index d5aa627..06f9162 100644 |
18 |
--- a/vcl/inc/unx/gtk/gtkframe.hxx |
19 |
+++ b/vcl/inc/unx/gtk/gtkframe.hxx |
20 |
@@ -268,6 +268,8 @@ class GtkSalFrame : public SalFrame |
21 |
#endif |
22 |
#else |
23 |
static gboolean signalExpose( GtkWidget*, GdkEventExpose*, gpointer ); |
24 |
+ void askForXEmbedFocus( sal_Int32 nTimecode ); |
25 |
+ void grabKeyboard(bool bGrab); |
26 |
#endif |
27 |
static gboolean signalFocus( GtkWidget*, GdkEventFocus*, gpointer ); |
28 |
static gboolean signalMap( GtkWidget*, GdkEvent*, gpointer ); |
29 |
@@ -298,7 +300,6 @@ class GtkSalFrame : public SalFrame |
30 |
static GdkNativeWindow findTopLevelSystemWindow( GdkNativeWindow aWindow ); |
31 |
|
32 |
static int m_nFloats; |
33 |
- static std::vector<GtkWidget*> m_aGrabWidgetsBeforeShowFloat; |
34 |
|
35 |
bool isFloatGrabWindow() const |
36 |
{ |
37 |
@@ -337,7 +338,6 @@ class GtkSalFrame : public SalFrame |
38 |
|
39 |
void setMinMaxSize(); |
40 |
void createNewWindow( ::Window aParent, bool bXEmbed, SalX11Screen nXScreen ); |
41 |
- void askForXEmbedFocus( sal_Int32 nTimecode ); |
42 |
|
43 |
void AllocateFrame(); |
44 |
void TriggerPaintEvent(); |
45 |
@@ -364,7 +364,6 @@ public: |
46 |
// be swallowed |
47 |
bool Dispatch( const XEvent* pEvent ); |
48 |
void grabPointer(bool bGrab, bool bOwnerEvents = false); |
49 |
- void grabKeyboard(bool bGrab); |
50 |
|
51 |
static GtkSalDisplay* getDisplay(); |
52 |
static GdkDisplay* getGdkDisplay(); |
53 |
@@ -420,6 +419,10 @@ public: |
54 |
void startDrag(gint nButton, gint nDragOriginX, gint nDragOriginY, |
55 |
GdkDragAction sourceActions, GtkTargetList* pTargetList); |
56 |
|
57 |
+ void WithDrawn(); |
58 |
+ |
59 |
+ static void closePopup(); |
60 |
+ |
61 |
#endif |
62 |
virtual ~GtkSalFrame(); |
63 |
|
64 |
diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx |
65 |
index db2c25d..41d4c2e 100644 |
66 |
--- a/vcl/unx/gtk3/gtk3gtkframe.cxx |
67 |
+++ b/vcl/unx/gtk3/gtk3gtkframe.cxx |
68 |
@@ -106,7 +106,6 @@ |
69 |
using namespace com::sun::star; |
70 |
|
71 |
int GtkSalFrame::m_nFloats = 0; |
72 |
-std::vector<GtkWidget*> GtkSalFrame::m_aGrabWidgetsBeforeShowFloat; |
73 |
|
74 |
#if defined ENABLE_GMENU_INTEGRATION |
75 |
static GDBusConnection* pSessionBus = nullptr; |
76 |
@@ -1297,13 +1296,6 @@ void GtkSalFrame::Init( SystemParentData* pSysData ) |
77 |
//FIXME: Handling embedded windows, is going to be fun ... |
78 |
} |
79 |
|
80 |
-void GtkSalFrame::askForXEmbedFocus( sal_Int32 i_nTimeCode ) |
81 |
-{ |
82 |
- (void) this; // loplugin:staticmethods |
83 |
- (void)i_nTimeCode; |
84 |
- //FIXME: no askForXEmbedFocus for gtk3 yet |
85 |
-} |
86 |
- |
87 |
void GtkSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle ) |
88 |
{ |
89 |
if( nStyle != m_nExtStyle && ! isChild() ) |
90 |
@@ -1443,30 +1435,26 @@ void GtkSalFrame::Show( bool bVisible, bool bNoActivate ) |
91 |
if( ! bNoActivate && (m_nStyle & SalFrameStyleFlags::TOOLWINDOW) ) |
92 |
m_bSetFocusOnMap = true; |
93 |
|
94 |
- gtk_widget_show( m_pWindow ); |
95 |
+ if (isFloatGrabWindow() && !getDisplay()->GetCaptureFrame() && m_nFloats == 0) |
96 |
+ { |
97 |
+ m_pParent->grabPointer(true, true); |
98 |
+ gtk_grab_add(m_pParent->getMouseEventWidget()); |
99 |
+ } |
100 |
+ |
101 |
+ gtk_widget_show(m_pWindow); |
102 |
|
103 |
if( isFloatGrabWindow() ) |
104 |
{ |
105 |
m_nFloats++; |
106 |
if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 1 ) |
107 |
{ |
108 |
- GtkWindowGroup *pWindowGroup = gtk_window_get_group(GTK_WINDOW(m_pWindow)); |
109 |
- GtkWidget* pGrabWidgetBeforeShowFloat; |
110 |
- while ((pGrabWidgetBeforeShowFloat = gtk_window_group_get_current_grab(pWindowGroup))) |
111 |
- { |
112 |
- m_aGrabWidgetsBeforeShowFloat.push_back(pGrabWidgetBeforeShowFloat); |
113 |
- gtk_grab_remove(pGrabWidgetBeforeShowFloat); |
114 |
- } |
115 |
grabPointer(true, true); |
116 |
- GtkSalFrame *pKeyboardFrame = m_pParent ? m_pParent : this; |
117 |
- pKeyboardFrame->grabKeyboard(true); |
118 |
+ gtk_grab_add(getMouseEventWidget()); |
119 |
} |
120 |
// #i44068# reset parent's IM context |
121 |
if( m_pParent ) |
122 |
m_pParent->EndExtTextInput(EndExtTextInputFlags::NONE); |
123 |
} |
124 |
- if( m_bWindowIsGtkPlug ) |
125 |
- askForXEmbedFocus( 0 ); |
126 |
} |
127 |
else |
128 |
{ |
129 |
@@ -1475,12 +1463,10 @@ void GtkSalFrame::Show( bool bVisible, bool bNoActivate ) |
130 |
m_nFloats--; |
131 |
if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 0) |
132 |
{ |
133 |
- GtkSalFrame *pKeyboardFrame = m_pParent ? m_pParent : this; |
134 |
- pKeyboardFrame->grabKeyboard(false); |
135 |
+ gtk_grab_remove(getMouseEventWidget()); |
136 |
grabPointer(false); |
137 |
- for (auto i = m_aGrabWidgetsBeforeShowFloat.rbegin(); i != m_aGrabWidgetsBeforeShowFloat.rend(); ++i) |
138 |
- gtk_grab_add(*i); |
139 |
- m_aGrabWidgetsBeforeShowFloat.clear(); |
140 |
+ gtk_grab_remove(m_pParent->getMouseEventWidget()); |
141 |
+ m_pParent->grabPointer(false); |
142 |
} |
143 |
} |
144 |
gtk_widget_hide( m_pWindow ); |
145 |
@@ -2085,37 +2071,32 @@ void GtkSalFrame::grabPointer( bool bGrab, bool bOwnerEvents ) |
146 |
if (!m_pWindow) |
147 |
return; |
148 |
|
149 |
- const int nMask = (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); |
150 |
- |
151 |
- GdkDeviceManager* pDeviceManager = gdk_display_get_device_manager(getGdkDisplay()); |
152 |
- GdkDevice* pPointer = gdk_device_manager_get_client_pointer(pDeviceManager); |
153 |
+#if GTK_CHECK_VERSION(3, 19, 2) |
154 |
+ GdkSeat* pSeat = gdk_display_get_default_seat(getGdkDisplay()); |
155 |
if (bGrab) |
156 |
- gdk_device_grab(pPointer, widget_get_window(getMouseEventWidget()), GDK_OWNERSHIP_NONE, bOwnerEvents, (GdkEventMask) nMask, m_pCurrentCursor, gtk_get_current_event_time()); |
157 |
+ { |
158 |
+ gdk_seat_grab(pSeat, widget_get_window(getMouseEventWidget()), GDK_SEAT_CAPABILITY_ALL_POINTING, |
159 |
+ bOwnerEvents, NULL, NULL, NULL, NULL); |
160 |
+ } |
161 |
else |
162 |
- gdk_device_ungrab(pPointer, gtk_get_current_event_time()); |
163 |
-} |
164 |
- |
165 |
-void GtkSalFrame::grabKeyboard( bool bGrab ) |
166 |
-{ |
167 |
- static const char* pEnv = getenv("SAL_NO_MOUSEGRABS"); // let's not introduce a special var for this |
168 |
- if (pEnv && *pEnv) |
169 |
- return; |
170 |
- |
171 |
- if (!m_pWindow) |
172 |
- return; |
173 |
+ { |
174 |
+ gdk_seat_ungrab(pSeat); |
175 |
+ } |
176 |
+#else |
177 |
+ const int nMask = (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); |
178 |
|
179 |
GdkDeviceManager* pDeviceManager = gdk_display_get_device_manager(getGdkDisplay()); |
180 |
GdkDevice* pPointer = gdk_device_manager_get_client_pointer(pDeviceManager); |
181 |
- GdkDevice* pKeyboard = gdk_device_get_associated_device(pPointer); |
182 |
if (bGrab) |
183 |
{ |
184 |
- gdk_device_grab(pKeyboard, widget_get_window(m_pWindow), GDK_OWNERSHIP_NONE, |
185 |
- true, (GdkEventMask)(GDK_KEY_PRESS | GDK_KEY_RELEASE), nullptr, gtk_get_current_event_time()); |
186 |
+ gdk_device_grab(pPointer, widget_get_window(getMouseEventWidget()), GDK_OWNERSHIP_NONE, |
187 |
+ bOwnerEvents, (GdkEventMask) nMask, m_pCurrentCursor, gtk_get_current_event_time()); |
188 |
} |
189 |
else |
190 |
{ |
191 |
- gdk_device_ungrab(pKeyboard, gtk_get_current_event_time()); |
192 |
+ gdk_device_ungrab(pPointer, gtk_get_current_event_time()); |
193 |
} |
194 |
+#endif |
195 |
} |
196 |
|
197 |
void GtkSalFrame::CaptureMouse( bool bCapture ) |
198 |
@@ -2557,6 +2538,22 @@ bool GtkSalFrame::HidePopover(sal_uIntPtr nId) |
199 |
#endif |
200 |
} |
201 |
|
202 |
+void GtkSalFrame::WithDrawn() |
203 |
+{ |
204 |
+ if (isFloatGrabWindow()) |
205 |
+ closePopup(); |
206 |
+} |
207 |
+ |
208 |
+void GtkSalFrame::closePopup() |
209 |
+{ |
210 |
+ if (!m_nFloats) |
211 |
+ return; |
212 |
+ ImplSVData* pSVData = ImplGetSVData(); |
213 |
+ if (!pSVData->maWinData.mpFirstFloat) |
214 |
+ return; |
215 |
+ pSVData->maWinData.mpFirstFloat->EndPopupMode(FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::CloseAll); |
216 |
+} |
217 |
+ |
218 |
gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer frame ) |
219 |
{ |
220 |
UpdateLastInputEventTime(pEvent->time); |
221 |
@@ -2588,62 +2585,33 @@ gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer |
222 |
aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY; |
223 |
aEvent.mnCode = GetMouseModCode( pEvent->state ); |
224 |
|
225 |
- bool bClosePopups = false; |
226 |
- if( pEvent->type == GDK_BUTTON_PRESS && |
227 |
- !(pThis->m_nStyle & SalFrameStyleFlags::OWNERDRAWDECORATION) |
228 |
- ) |
229 |
- { |
230 |
- if( m_nFloats > 0 ) |
231 |
- { |
232 |
- // close popups if user clicks outside our application |
233 |
- gint x, y; |
234 |
- bClosePopups = (gdk_display_get_window_at_pointer( GtkSalFrame::getGdkDisplay(), &x, &y ) == nullptr); |
235 |
- } |
236 |
- /* #i30306# release implicit pointer grab if no popups are open; else |
237 |
- * Drag cannot grab the pointer and will fail. |
238 |
- */ |
239 |
- if( m_nFloats < 1 || bClosePopups ) |
240 |
- gdk_display_pointer_ungrab( GtkSalFrame::getGdkDisplay(), GDK_CURRENT_TIME ); |
241 |
- } |
242 |
+ vcl::DeletionListener aDel( pThis ); |
243 |
|
244 |
- if( pThis->m_bWindowIsGtkPlug && |
245 |
- pEvent->type == GDK_BUTTON_PRESS && |
246 |
- pEvent->button == 1 ) |
247 |
+ if (pEvent->type == GDK_BUTTON_PRESS && pThis->isFloatGrabWindow()) |
248 |
{ |
249 |
- pThis->askForXEmbedFocus( pEvent->time ); |
250 |
+ bool bClosePopups = (pEvent->window != widget_get_window(pThis->getMouseEventWidget())); |
251 |
+ if (bClosePopups) |
252 |
+ closePopup(); |
253 |
} |
254 |
|
255 |
// --- RTL --- (mirror mouse pos) |
256 |
if( AllSettings::GetLayoutRTL() ) |
257 |
aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX; |
258 |
|
259 |
- vcl::DeletionListener aDel( pThis ); |
260 |
- |
261 |
- pThis->CallCallback( nEventType, &aEvent ); |
262 |
- |
263 |
- if( ! aDel.isDeleted() ) |
264 |
+ if (!aDel.isDeleted()) |
265 |
{ |
266 |
- if( bClosePopups ) |
267 |
- { |
268 |
- ImplSVData* pSVData = ImplGetSVData(); |
269 |
- if ( pSVData->maWinData.mpFirstFloat ) |
270 |
- { |
271 |
- static const char* pEnv = getenv( "SAL_FLOATWIN_NOAPPFOCUSCLOSE" ); |
272 |
- if ( !(pSVData->maWinData.mpFirstFloat->GetPopupModeFlags() & FloatWinPopupFlags::NoAppFocusClose) && !(pEnv && *pEnv) ) |
273 |
- pSVData->maWinData.mpFirstFloat->EndPopupMode( FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::CloseAll ); |
274 |
- } |
275 |
- } |
276 |
+ pThis->CallCallback( nEventType, &aEvent ); |
277 |
+ } |
278 |
|
279 |
- if( ! aDel.isDeleted() ) |
280 |
+ if (!aDel.isDeleted()) |
281 |
+ { |
282 |
+ int frame_x = (int)(pEvent->x_root - pEvent->x); |
283 |
+ int frame_y = (int)(pEvent->y_root - pEvent->y); |
284 |
+ if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY ) |
285 |
{ |
286 |
- int frame_x = (int)(pEvent->x_root - pEvent->x); |
287 |
- int frame_y = (int)(pEvent->y_root - pEvent->y); |
288 |
- if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY ) |
289 |
- { |
290 |
- pThis->maGeometry.nX = frame_x; |
291 |
- pThis->maGeometry.nY = frame_y; |
292 |
- pThis->CallCallback( SALEVENT_MOVE, nullptr ); |
293 |
- } |
294 |
+ pThis->maGeometry.nX = frame_x; |
295 |
+ pThis->maGeometry.nY = frame_y; |
296 |
+ pThis->CallCallback( SALEVENT_MOVE, nullptr ); |
297 |
} |
298 |
} |
299 |
|
300 |
@@ -2787,6 +2755,13 @@ gboolean GtkSalFrame::signalMotion( GtkWidget*, GdkEventMotion* pEvent, gpointer |
301 |
|
302 |
GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame); |
303 |
|
304 |
+ //If a menu, e.g. font name dropdown, is open, then under wayland moving the |
305 |
+ //mouse in the top left corner of the toplevel window in a |
306 |
+ //0,0,float-width,float-height area generates motion events which are |
307 |
+ //delivered to the dropdown |
308 |
+ if (pThis->isFloatGrabWindow() && pEvent->window != widget_get_window(pThis->getMouseEventWidget())) |
309 |
+ return true; |
310 |
+ |
311 |
SalMouseEvent aEvent; |
312 |
aEvent.mnTime = pEvent->time; |
313 |
aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX; |
314 |
@@ -3027,12 +3002,15 @@ gboolean GtkSalFrame::signalUnmap( GtkWidget*, GdkEvent*, gpointer frame ) |
315 |
return false; |
316 |
} |
317 |
|
318 |
-gboolean GtkSalFrame::signalKey( GtkWidget*, GdkEventKey* pEvent, gpointer frame ) |
319 |
+gboolean GtkSalFrame::signalKey(GtkWidget* pWidget, GdkEventKey* pEvent, gpointer frame) |
320 |
{ |
321 |
UpdateLastInputEventTime(pEvent->time); |
322 |
|
323 |
GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame); |
324 |
|
325 |
+ if (pThis->isFloatGrabWindow()) |
326 |
+ return signalKey(pWidget, pEvent, pThis->m_pParent); |
327 |
+ |
328 |
vcl::DeletionListener aDel( pThis ); |
329 |
|
330 |
if( pThis->m_pIMHandler ) |
331 |
@@ -3187,11 +3165,18 @@ gboolean GtkSalFrame::signalWindowState( GtkWidget*, GdkEvent* pEvent, gpointer |
332 |
pThis->TriggerPaintEvent(); |
333 |
} |
334 |
|
335 |
- if( (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_MAXIMIZED) && |
336 |
- ! (pThis->m_nState & GDK_WINDOW_STATE_MAXIMIZED) ) |
337 |
+ if ((pEvent->window_state.new_window_state & GDK_WINDOW_STATE_MAXIMIZED) && |
338 |
+ !(pThis->m_nState & GDK_WINDOW_STATE_MAXIMIZED)) |
339 |
{ |
340 |
pThis->m_aRestorePosSize = GetPosAndSize(GTK_WINDOW(pThis->m_pWindow)); |
341 |
} |
342 |
+ |
343 |
+ if ((pEvent->window_state.new_window_state & GDK_WINDOW_STATE_WITHDRAWN) && |
344 |
+ !(pThis->m_nState & GDK_WINDOW_STATE_WITHDRAWN)) |
345 |
+ { |
346 |
+ pThis->WithDrawn(); |
347 |
+ } |
348 |
+ |
349 |
pThis->m_nState = pEvent->window_state.new_window_state; |
350 |
|
351 |
#if OSL_DEBUG_LEVEL > 1 |
352 |
-- |
353 |
2.7.4 |
354 |
|