From 083e160f89ae6054d2e93a284b0a3853acd2f97a Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 2 Feb 2015 19:18:32 +0100 Subject: [PATCH] Partially fix excessive event spam when resizing windows --- direct/src/showbase/ShowBase.py | 13 ++- panda/src/x11display/x11GraphicsWindow.cxx | 93 +++++++++++++--------- 2 files changed, 66 insertions(+), 40 deletions(-) diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index b35fd6a78a..bb6ad5a2ce 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -372,6 +372,7 @@ class ShowBase(DirectObject.DirectObject): # Now hang a hook on the window-event from Panda. This allows # us to detect when the user resizes, minimizes, or closes the # main window. + self.__prevWindowProperties = None self.accept('window-event', self.windowEvent) # Transition effects (fade, iris, etc) @@ -2614,9 +2615,15 @@ class ShowBase(DirectObject.DirectObject): return Task.cont def windowEvent(self, win): - if win == self.win: - properties = win.getProperties() - self.notify.info("Got window event: %s" % (repr(properties))) + if win != self.win: + # This event isn't about our window. + return + + properties = win.getProperties() + if properties != self.__prevWindowProperties: + self.__prevWindowProperties = properties + + self.notify.debug("Got window event: %s" % (repr(properties))) if not properties.getOpen(): # If the user closes the main window, we should exit. self.notify.info("User closed main window.") diff --git a/panda/src/x11display/x11GraphicsWindow.cxx b/panda/src/x11display/x11GraphicsWindow.cxx index 80c1c884c7..592b404218 100644 --- a/panda/src/x11display/x11GraphicsWindow.cxx +++ b/panda/src/x11display/x11GraphicsWindow.cxx @@ -263,6 +263,12 @@ process_events() { XKeyEvent keyrelease_event; bool got_keyrelease_event = false; + XConfigureEvent configure_event; + bool got_configure_event = false; + + WindowProperties properties; + bool changed_properties = false; + while (XCheckIfEvent(_display, &event, check_event, (char *)this)) { if (XFilterEvent(&event, None)) { continue; @@ -295,7 +301,6 @@ process_events() { } } - WindowProperties properties; ButtonHandle button; switch (event.type) { @@ -303,38 +308,11 @@ process_events() { break; case ConfigureNotify: - _awaiting_configure = false; - - // Is this the inner corner or the outer corner? The Xlib docs - // say it should be the outer corner, but it appears to be the - // inner corner on my own implementation, which is inconsistent - // with XConfigureWindow. (Panda really wants to work with the - // inner corner, anyway, but that means we need to fix - // XConfigureWindow too.) - properties.set_origin(event.xconfigure.x, event.xconfigure.y); - - if (_properties.get_fixed_size()) { - // If the window properties indicate a fixed size only, undo - // any attempt by the user to change them. In X, there - // doesn't appear to be a way to universally disallow this - // directly (although we do set the min_size and max_size to - // the same value, which seems to work for most window - // managers.) - WindowProperties current_props = get_properties(); - if (event.xconfigure.width != current_props.get_x_size() || - event.xconfigure.height != current_props.get_y_size()) { - XWindowChanges changes; - changes.width = current_props.get_x_size(); - changes.height = current_props.get_y_size(); - int value_mask = (CWWidth | CWHeight); - XConfigureWindow(_display, _xwindow, value_mask, &changes); - } - - } else { - // A normal window may be resized by the user at will. - properties.set_size(event.xconfigure.width, event.xconfigure.height); - } - system_changed_properties(properties); + // When resizing or moving the window, multiple ConfigureNotify + // events may be sent in rapid succession. We only respond to + // the last one. + configure_event = event.xconfigure; + got_configure_event = true; break; case ButtonPress: @@ -391,23 +369,23 @@ process_events() { case FocusIn: properties.set_foreground(true); - system_changed_properties(properties); + changed_properties = true; break; case FocusOut: _input_devices[0].focus_lost(); properties.set_foreground(false); - system_changed_properties(properties); + changed_properties = true; break; case UnmapNotify: properties.set_minimized(true); - system_changed_properties(properties); + changed_properties = true; break; case MapNotify: properties.set_minimized(false); - system_changed_properties(properties); + changed_properties = true; // Auto-focus the window when it is mapped. XSetInputFocus(_display, _xwindow, RevertToPointerRoot, CurrentTime); @@ -449,6 +427,47 @@ process_events() { } } + if (got_configure_event) { + // Now handle the last configure event we found. + _awaiting_configure = false; + + // Is this the inner corner or the outer corner? The Xlib docs + // say it should be the outer corner, but it appears to be the + // inner corner on my own implementation, which is inconsistent + // with XConfigureWindow. (Panda really wants to work with the + // inner corner, anyway, but that means we need to fix + // XConfigureWindow too.) + properties.set_origin(configure_event.x, configure_event.y); + + if (_properties.get_fixed_size()) { + // If the window properties indicate a fixed size only, undo + // any attempt by the user to change them. In X, there + // doesn't appear to be a way to universally disallow this + // directly (although we do set the min_size and max_size to + // the same value, which seems to work for most window + // managers.) Incidentally, this also works to force my + // tiling window manager into 'floating' mode. + WindowProperties current_props = get_properties(); + if (configure_event.width != current_props.get_x_size() || + configure_event.height != current_props.get_y_size()) { + XWindowChanges changes; + changes.width = current_props.get_x_size(); + changes.height = current_props.get_y_size(); + int value_mask = (CWWidth | CWHeight); + XConfigureWindow(_display, _xwindow, value_mask, &changes); + } + + } else { + // A normal window may be resized by the user at will. + properties.set_size(configure_event.width, configure_event.height); + } + changed_properties = true; + } + + if (changed_properties) { + system_changed_properties(properties); + } + if (got_keyrelease_event) { // This keyrelease event is not immediately followed by a // matching keypress event, so it's a genuine release.