[gnome-terminal] Turn off demands-attention state after unrealizing/realizing



commit f4a3c7e8665b32f0e9aed04def3784bb5c7a8d57
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Thu Jun 18 17:51:57 2009 -0400

    Turn off demands-attention state after unrealizing/realizing
    
    Unrealizing and realizing the window is likely to cause the window
    to be focus-stealing-preventing and start blinking in the taskbar.
    There's no obvious way to prevent this, so just turn off the
    _NET_WM_STATE_DEMANDS_ATTENTION after the window is remapped.
    
    http://bugzilla.gnome.org/show_bug.cgi?id=564648

 src/terminal-util.c   |   34 ++++++++++++++++++++++++++++++++++
 src/terminal-util.h   |    2 ++
 src/terminal-window.c |   41 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 77 insertions(+), 0 deletions(-)
---
diff --git a/src/terminal-util.c b/src/terminal-util.c
index 587d1d7..fbaf372 100644
--- a/src/terminal-util.c
+++ b/src/terminal-util.c
@@ -984,4 +984,38 @@ terminal_util_x11_set_net_wm_desktop (GdkWindow *window,
   XFlush (xdisplay);
 }
 
+/* Asks the window manager to turn off the "demands attention" state on the window.
+ *
+ * This only works for windows that are currently window managed; if the window
+ * is unmapped (in the withdrawn state) it would be necessary to change _NET_WM_STATE
+ * directly.
+ */
+void
+terminal_util_x11_clear_demands_attention (GdkWindow *window)
+{
+  GdkScreen *screen = gdk_drawable_get_screen (window);
+  GdkDisplay *display = gdk_screen_get_display (screen);
+  XClientMessageEvent xclient;
+
+  memset (&xclient, 0, sizeof (xclient));
+  xclient.type = ClientMessage;
+  xclient.serial = 0;
+  xclient.send_event = True;
+  xclient.window = GDK_WINDOW_XWINDOW (window);
+  xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE");
+  xclient.format = 32;
+
+  xclient.data.l[0] = 0; /* _NET_WM_STATE_REMOVE */
+  xclient.data.l[1] = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_DEMANDS_ATTENTION");
+  xclient.data.l[2] = 0;
+  xclient.data.l[3] = 0;
+  xclient.data.l[4] = 0;
+
+  XSendEvent (GDK_DISPLAY_XDISPLAY (display),
+	      GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen)),
+	      False,
+	      SubstructureRedirectMask | SubstructureNotifyMask,
+	      (XEvent *)&xclient);
+}
+
 #endif /* GDK_WINDOWING_X11 */
diff --git a/src/terminal-util.h b/src/terminal-util.h
index acfd437..71743f9 100644
--- a/src/terminal-util.h
+++ b/src/terminal-util.h
@@ -105,4 +105,6 @@ gboolean terminal_util_x11_get_net_wm_desktop (GdkWindow *window,
 void     terminal_util_x11_set_net_wm_desktop (GdkWindow *window,
 					       guint32    desktop);
 
+void terminal_util_x11_clear_demands_attention (GdkWindow *window);
+
 #endif /* TERMINAL_UTIL_H */
diff --git a/src/terminal-window.c b/src/terminal-window.c
index 95db45a..5d0345f 100644
--- a/src/terminal-window.c
+++ b/src/terminal-window.c
@@ -77,6 +77,11 @@ struct _TerminalWindowPrivate
   /* Compositing manager integration */
   guint have_argb_visual : 1;
 
+  /* Used to clear stray "demands attention" flashing on our window when we
+   * unmap and map it to switch to an ARGB visual.
+   */
+  guint clear_demands_attention : 1;
+
   guint disposed : 1;
   guint present_on_insert : 1;
 
@@ -1425,6 +1430,32 @@ terminal_window_realize (GtkWidget *widget)
 
   GTK_WIDGET_CLASS (terminal_window_parent_class)->realize (widget);
 }
+
+static gboolean
+terminal_window_map_event (GtkWidget    *widget,
+			   GdkEventAny  *event)
+{
+  gboolean (* map_event) (GtkWidget *, GdkEventAny *) =
+      GTK_WIDGET_CLASS (terminal_window_parent_class)->map_event;
+
+  TerminalWindow *window = TERMINAL_WINDOW (widget);
+  TerminalWindowPrivate *priv = window->priv;
+
+  if (priv->clear_demands_attention)
+    {
+#ifdef GDK_WINDOWING_X11
+      terminal_util_x11_clear_demands_attention (widget->window);
+#endif
+
+      priv->clear_demands_attention = FALSE;
+    }
+
+  if (map_event)
+    return map_event (widget, event);
+
+  return FALSE;
+}
+
     
 static gboolean
 terminal_window_state_event (GtkWidget            *widget,
@@ -1513,6 +1544,15 @@ terminal_window_composited_changed_cb (GdkScreen *screen,
       gtk_widget_show (widget);
       if (have_desktop)
         terminal_util_x11_set_net_wm_desktop (widget->window, desktop);
+
+      /* Mapping the window is likely to have set the "demands-attention" state.
+       * In particular, Metacity will always set the state if a window is mapped,
+       * is not given the focus (because of an old user time), and is covered
+       * by some other window. We have no way of preventing this, so we just
+       * wait for our window to be mapped, and then tell the window manager
+       * to turn off the bit. If it wasn't set, no harm.
+       */
+      priv->clear_demands_attention = TRUE;
     }
 }
 
@@ -1921,6 +1961,7 @@ terminal_window_class_init (TerminalWindowClass *klass)
 
   widget_class->show = terminal_window_show;
   widget_class->realize = terminal_window_realize;
+  widget_class->map_event = terminal_window_map_event;
   widget_class->window_state_event = terminal_window_state_event;
   widget_class->screen_changed = terminal_window_screen_changed;
 



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