[metacity/wip/muktupavels/issue-31] display: remove extra unmap events with same window and serial




commit 3db07fafa1c7ff9749b6a82ccb36d8b62f2304d9
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Wed Oct 5 01:57:04 2022 +0300

    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

 src/core/display.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
---
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,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]