summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlberts Muktupāvels <alberts.muktupavels@gmail.com>2022-10-05 01:57:04 +0300
committerAlberts Muktupāvels <alberts.muktupavels@gmail.com>2022-10-05 01:57:04 +0300
commit3db07fafa1c7ff9749b6a82ccb36d8b62f2304d9 (patch)
tree0213172714648df1866cb7c629627c6638f7e6e5
parent77f1d55479bfef479f76011a1ee5636f9bf6b08b (diff)
downloadmetacity-3db07fafa1c7ff9749b6a82ccb36d8b62f2304d9.tar.gz
display: remove extra unmap events with same window and serial
Single XUnmapWindow call can result in multiple UnmapNotify events. Linked issue has attached python code intended to reproduce original bug and can be used to reproduce multiple UnmapNotify events for the same window. Steps to reproduce problem: 1. Run python3 Untitled.py; 2. Undock one of the application's child windows; 3. Minimize main window; 4. Unminimize main window. On drag start metacity gets map event - new MetaWindow is created. This window has override_redirect set to true, metacity selects StructureNotifyMask events. When child window is dropped outside main window we get 3 unmap events! One event was sent because we asked X server to do that by selecting StructureNotifyMask events. Second event was sent because child window parent was root window. We have asked for such events on root window by selecting SubstructureNotifyMask events. Third event seems to come from XSendEvent. At this point these multiple events are not problem. MetaWindow is destroyed when we get first event and rest are ignored. After that application sends map request and we create new MetaWindow. This time override_redirect is not set and we choose to not select StructureNotifyMask events. Unfortunately this mask is already in your_event_mask as we are not unselecting events when window is unmanaged. Now when we minimize main window (step 3) also dock window is minimized. We are just hiding window so we are adding pending unmap event so we can ignore it when it will arrive. On first event we correctly detect that it should be ignored but once second event arrives we are unmanaging this window. And here is our problem - trying to unminimize main window only main window gets restored! Main window does not find child window because it is destroyed. Use XCheckIfEvent to remove extra UnmapNotify events that has same window and serial preventing unnecessary window destruction. https://gitlab.gnome.org/GNOME/metacity/-/issues/31
-rw-r--r--src/core/display.c23
1 files changed, 23 insertions, 0 deletions
diff --git a/src/core/display.c b/src/core/display.c
index 17a4eaf7..9e0d8d60 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -1717,6 +1717,20 @@ handle_window_focus_event (MetaDisplay *display,
}
}
+static Bool
+unmap_predicate (Display *display,
+ XEvent *event,
+ XPointer arg)
+{
+ XUnmapEvent *unmap;
+
+ unmap = (XUnmapEvent *) arg;
+
+ return event->type == UnmapNotify &&
+ event->xunmap.window == unmap->window &&
+ event->xunmap.serial == unmap->serial;
+}
+
/**
* This is the most important function in the whole program. It is the heart,
* it is the nexus, it is the Grand Central Station of Metacity's world.
@@ -2304,6 +2318,15 @@ event_callback (XEvent *event,
if (!frame_was_receiver)
{
+ XEvent unmap_event;
+
+ while (XCheckIfEvent (display->xdisplay,
+ &unmap_event,
+ unmap_predicate,
+ (XPointer) &event->xunmap))
+ {
+ }
+
if (!meta_window_remove_pending_unmap (window, event->xany.serial))
{
meta_topic (META_DEBUG_WINDOW_STATE,