Attacking round trips



I spent most of today finishing up some work I had done to cut
down on GTK+ roundtrips, especially on startup. The changes,
test case, and a detailed analysis of the remaining roundtrips
are attached.

The test case I was using was a copy of simple.c instrumented
to exit after processing the first expose.

I measured rountrips by taking a protoocol trace using xmon,
and doing hand analysis.

Highlights:

 - The total reduction was 52 roundtrips => 23 roundtrips.
   About 6 more of the remaining roundtrips could be eliminated
   inside GTK+, 2 of the remaining roundtrips stem from
   a bug in the XKB code in Xlib.

 - The biggest chunk of round trips were, as expecting, from
   interning atoms in hunks with XInternAtoms(), though there 
   were significant numbers of other points where I was
   able to prune roundtrips, some of them pretty easily.
   (There was an entirely unused call to  GetKeyboardControl()
   for example.)

 - Did these changes affect wall clock time for the local case? 
   Not to any measurable extent.

   One of the changes included here - gdk_display_sync() => 
   gdk_display_flush() in gdk_window_process_all_updates()
   *is* a big performance in many cases, though not in the  
   test case.

 - On the other hand, for a home=>work=>home DSL loop (cumulative
   latency about 80ms) it cuts wall time from about 5.9 seconds to 
   about 3.6 seconds.

I'll commit these changes to HEAD pretty soon, once I find an Xlib
expert to review gdkasync.c.

Regards,
					Owen

? changelog-stuff
? fresnel
? demos/gtk-demo/geninclude.pl
? gdk/gdkmarshalers.c
? gdk/gtk+-2.2.2-flush.patch
? gdk/x11/gdkasync-bak.c
? gdk/x11/gdkasync-bak.h
? gdk/x11/gdkasync-extras.c
? gdk/x11/gdkasync.c
? gdk/x11/gdkasync.h
? gtk/find-cross.pl
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gtk+/ChangeLog,v
retrieving revision 1.4269
diff -u -p -r1.4269 ChangeLog
--- ChangeLog	3 Jul 2003 01:02:01 -0000	1.4269
+++ ChangeLog	4 Jul 2003 23:02:48 -0000
@@ -1,3 +1,53 @@
+Fri Jul  4 15:57:52 2003  Owen Taylor  <otaylor redhat com>
+
+	* gdk/x11/gdkevents-x11.c (gdk_wm_protocols_filter):
+	Use asynchronously _gdk_x11_set_input_focus_safe
+	to avoid having to trap errors and XSync().
+
+	* gdk/x11/gdkwindow-x11.c (gdk_window_focus): Use
+	_gdk_x11_set_input_focus_safe() here as well.
+
+	* gdk/x11/gdkevents-x11.c (gdk_check_wm_state_changed):
+	Rework handling of property notifies on _NET_WM_STATE
+	so that we ignore _NET_WM_DESKTOP notifies unless we
+	really care.
+
+	* gdk/x11/gdkimage-x11.c (gdk_image_check_xshm): Use
+	XShmQueryExtension() rather than XQueryExtension() to
+	avoid extra rountrip.
+
+	* gdk/x11/gdkwindow-x11.c (_gdk_windowing_window_init):
+	Remove unused call to XGetWindowAttributes()
+	
+	* gdk/x11/gdkdisplay-x11.c (gdk_display_open): Remove
+	unused call to XGetKeyboardControl().
+
+	* gdk/x11/gdkdisplay-x11.c (gdk_display_flush): Add (#99571)
+
+	* gdk/gdkwindow.c (gdk_window_process_all_updates): Use
+	gdk_display_flush() rather than gdk_flush() to avoid
+	XSync().
+	
+	* gdk/x11/gdkwindow-x11.c (update_wm_hints)
+	gdk/x11/gdkwindow-x11.h: Centralize all handling of WM_HINTS here
+	so that we don't have to get the property back from the server.
+
+	* gdk/x11/gdkwindow-x11.c (show_window_internal): Store
+	the serial of when we map a toplevel to allow optimizing
+	out notifies on _NET_WM_STATE/_NET_WM_DESKTOP.
+
+Fri Jul  4 15:59:27 2003  Owen Taylor  <otaylor redhat com>
+
+	* gdk/x11/gdkwindow-x11.c (gdk_window_set_group): Remove comment
+	about setting window group after the window is mapped from docs
+	- nothing the ICCCM forbids that.
+
+	* gdk/x11/gdkcursor-x11.c (gdk_display_get_maximal_cursor_size):
+	Fix g_return_val_if_fail() in void return function.
+
+	* gdk/x11/gdkevents-x11.c (gdk_event_translate): 
+	remove call to _gdk_input_window_none_event().
+
 Thu Jul  3 03:13:20 2003  Soeren Sandmann  <sandmann daimi au dk>
 
 	* gtk/gtkpaned.c (gtk_paned_set_child_property): Insert cast to
Index: configure.in
===================================================================
RCS file: /cvs/gnome/gtk+/configure.in,v
retrieving revision 1.334
diff -u -p -r1.334 configure.in
--- configure.in	30 Jun 2003 22:30:52 -0000	1.334
+++ configure.in	4 Jul 2003 23:02:48 -0000
@@ -161,8 +161,8 @@ AC_ARG_ENABLE(debug,
               enable_debug=debug_default)
 AC_ARG_ENABLE(shm,
               [AC_HELP_STRING([--enable-shm],
-                              [support shared memory if available [default=yes]])],
-              [echo $enable_shm, enable_shm="yes"])
+                              [support shared memory if available [default=yes]])],,
+              [enable_shm="yes"])
 AC_ARG_ENABLE(ansi,
               [AC_HELP_STRING([--enable-ansi],
                               [turn on strict ansi [default=no]])],,
Index: gdk/gdkdisplay.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkdisplay.h,v
retrieving revision 1.14
diff -u -p -r1.14 gdkdisplay.h
--- gdk/gdkdisplay.h	30 Jun 2003 22:30:53 -0000	1.14
+++ gdk/gdkdisplay.h	4 Jul 2003 23:02:51 -0000
@@ -113,6 +113,8 @@ void        gdk_display_keyboard_ungrab 
 gboolean    gdk_display_pointer_is_grabbed (GdkDisplay  *display);
 void        gdk_display_beep               (GdkDisplay  *display);
 void        gdk_display_sync               (GdkDisplay  *display);
+void        gdk_display_flush              (GdkDisplay  *display);
+
 void	    gdk_display_close		   (GdkDisplay  *display);
 
 GList *     gdk_display_list_devices       (GdkDisplay  *display);
Index: gdk/gdkwindow.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkwindow.c,v
retrieving revision 1.148
diff -u -p -r1.148 gdkwindow.c
--- gdk/gdkwindow.c	9 Jun 2003 01:55:01 -0000	1.148
+++ gdk/gdkwindow.c	4 Jul 2003 23:02:52 -0000
@@ -2144,6 +2144,18 @@ gdk_window_process_updates_internal (Gdk
     }
 }
 
+static void
+flush_all_displays (void)
+{
+  GSList *displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
+  GSList *tmp_list;
+
+  for (tmp_list = displays; tmp_list; tmp_list = tmp_list->next)
+    gdk_display_flush (tmp_list->data);
+
+  g_slist_free (displays);
+}
+
 /**
  * gdk_window_process_all_updates:
  *
@@ -2174,7 +2186,7 @@ gdk_window_process_all_updates (void)
 
   g_slist_free (old_update_windows);
 
-  gdk_flush();
+  flush_all_displays ();
 }
 
 static gboolean
Index: gdk/x11/Makefile.am
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/Makefile.am,v
retrieving revision 1.30
diff -u -p -r1.30 Makefile.am
--- gdk/x11/Makefile.am	6 May 2003 21:54:25 -0000	1.30
+++ gdk/x11/Makefile.am	4 Jul 2003 23:02:52 -0000
@@ -20,6 +20,7 @@ noinst_LTLIBRARIES = libgdk-x11.la
 
 libgdk_x11_la_SOURCES =    	\
 	MwmUtil.h	   	\
+	gdkasync.c		\
 	gdkcolor-x11.c	   	\
 	gdkcursor-x11.c	   	\
 	gdkdisplay-x11.c	\
Index: gdk/x11/gdkcursor-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkcursor-x11.c,v
retrieving revision 1.28
diff -u -p -r1.28 gdkcursor-x11.c
--- gdk/x11/gdkcursor-x11.c	30 Jun 2003 22:30:54 -0000	1.28
+++ gdk/x11/gdkcursor-x11.c	4 Jul 2003 23:02:52 -0000
@@ -587,7 +587,7 @@ gdk_display_get_maximal_cursor_size (Gdk
   GdkScreen *screen;
   GdkWindow *window;
 
-  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+  g_return_if_fail (GDK_IS_DISPLAY (display));
   
   screen = gdk_display_get_default_screen (display);
   window = gdk_screen_get_root_window (screen);
Index: gdk/x11/gdkdisplay-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkdisplay-x11.c,v
retrieving revision 1.33
diff -u -p -r1.33 gdkdisplay-x11.c
--- gdk/x11/gdkdisplay-x11.c	27 May 2003 21:20:59 -0000	1.33
+++ gdk/x11/gdkdisplay-x11.c	4 Jul 2003 23:02:53 -0000
@@ -57,6 +57,32 @@ static void gdk_internal_connection_watc
 
 static gpointer parent_class = NULL;
 
+/* Note that we never *directly* use WM_LOCALE_NAME, WM_PROTOCOLS,
+ * but including them here has the side-effect of getting them
+ * into the internal Xlib cache
+ */
+static const char *const precache_atoms[] = {
+  "UTF8_STRING",
+  "WM_CLIENT_LEADER",
+  "WM_DELETE_WINDOW",
+  "WM_LOCALE_NAME",
+  "WM_PROTOCOLS",
+  "WM_TAKE_FOCUS",
+  "_NET_WM_DESKTOP",
+  "_NET_WM_ICON",
+  "_NET_WM_ICON_NAME",
+  "_NET_WM_NAME",
+  "_NET_WM_PID",
+  "_NET_WM_PING",
+  "_NET_WM_STATE",
+  "_NET_WM_STATE_STICKY",
+  "_NET_WM_STATE_MAXIMIZED_VERT",
+  "_NET_WM_STATE_MAXIMIZED_HORZ",
+  "_NET_WM_STATE_FULLSCREEN",
+  "_NET_WM_WINDOW_TYPE",
+  "_NET_WM_WINDOW_TYPE_NORMAL",
+};
+
 GType
 _gdk_display_x11_get_type (void)
 {
@@ -117,7 +143,6 @@ gdk_display_open (const gchar *display_n
   const char *sm_client_id;
   
   XClassHint *class_hint;
-  XKeyboardState keyboard_state;
   gulong pid;
   gint i;
 
@@ -162,6 +187,8 @@ gdk_display_open (const gchar *display_n
   if (_gdk_synchronize)
     XSynchronize (display_x11->xdisplay, True);
   
+  _gdk_x11_precache_atoms (display, precache_atoms, G_N_ELEMENTS (precache_atoms));
+
   class_hint = XAllocClassHint();
   class_hint->res_name = g_get_prgname ();
   
@@ -183,8 +210,6 @@ gdk_display_open (const gchar *display_n
 		   gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PID"),
 		   XA_CARDINAL, 32, PropModeReplace, (guchar *) & pid, 1);
   
-  XGetKeyboardControl (display_x11->xdisplay, &keyboard_state);
-
 #ifdef HAVE_XKB
   {
     gint xkb_major = XkbMajorVersion;
@@ -507,6 +532,31 @@ gdk_display_sync (GdkDisplay * display)
   g_return_if_fail (GDK_IS_DISPLAY (display));
   
   XSync (GDK_DISPLAY_XDISPLAY (display), False);
+}
+
+/**
+ * gdk_display_flush:
+ * @display: a #GdkDisplay
+ *
+ * Flushes any requests queued for the windowing system; this happens automatically
+ * when the main loop blocks waiting for new events, but if your application
+ * is drawing without returning control to the main loop, you may need
+ * to call this function explicitely. A common case where this function
+ * needs to be called is when an application is executing drawing commands
+ * from a thread other than the thread where the main loop is running.
+ *
+ * This is most useful for X11. On windowing systems where requests are
+ * handled synchronously, this function will do nothing.
+ *
+ * Since: 2.4
+ */
+void 
+gdk_display_flush (GdkDisplay *display)
+{
+  g_return_if_fail (GDK_IS_DISPLAY (display));
+
+  if (!display->closed)
+    XFlush (GDK_DISPLAY_XDISPLAY (display));
 }
 
 /**
Index: gdk/x11/gdkevents-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkevents-x11.c,v
retrieving revision 1.106.2.1
diff -u -p -r1.106.2.1 gdkevents-x11.c
--- gdk/x11/gdkevents-x11.c	22 Jan 2003 22:15:43 -0000	1.106.2.1
+++ gdk/x11/gdkevents-x11.c	4 Jul 2003 23:02:53 -0000
@@ -30,6 +30,7 @@
 #include "gdkx.h"
 #include "gdkscreen-x11.h"
 #include "gdkdisplay-x11.h"
+#include "gdkasync.h"
 
 #include "gdkkeysyms.h"
 
@@ -357,93 +358,31 @@ gdk_add_client_message_filter (GdkAtom  
 }
 
 static void
-gdk_check_wm_state_changed (GdkWindow *window)
+do_net_wm_state_changes (GdkWindow *window)
 {  
-  Atom type;
-  gint format;
-  gulong nitems;
-  gulong bytes_after;
-  Atom *atoms = NULL;
-  gulong i;
-  gboolean found_sticky, found_maxvert, found_maxhorz, found_fullscreen;
+  GdkWindowObject *window_private = (GdkWindowObject *)window;
+  GdkWindowImplX11 *window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
   GdkWindowState old_state;
-  GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
   
   if (GDK_WINDOW_DESTROYED (window) ||
       gdk_window_get_window_type (window) != GDK_WINDOW_TOPLEVEL)
     return;
   
-  found_sticky = FALSE;
-  found_maxvert = FALSE;
-  found_maxhorz = FALSE;
-  found_fullscreen = FALSE;
-  
-  XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
-		      gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
-		      0, G_MAXLONG, False, XA_ATOM, &type, &format, &nitems,
-		      &bytes_after, (guchar **)&atoms);
-
-  if (type != None)
-    {
-      Atom sticky_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_STICKY");
-      Atom maxvert_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_VERT");
-      Atom maxhorz_atom	= gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_HORZ");
-      Atom fullscreen_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_FULLSCREEN");
-      
-      i = 0;
-      while (i < nitems)
-        {
-          if (atoms[i] == sticky_atom)
-            found_sticky = TRUE;
-          else if (atoms[i] == maxvert_atom)
-            found_maxvert = TRUE;
-          else if (atoms[i] == maxhorz_atom)
-            found_maxhorz = TRUE;
-          else if (atoms[i] == fullscreen_atom)
-            found_fullscreen = TRUE;
-          
-          ++i;
-        }
-
-      XFree (atoms);
-    }
+  old_state = gdk_window_get_state (window);
 
   /* For found_sticky to remain TRUE, we have to also be on desktop
    * 0xFFFFFFFF
    */
-
-  if (found_sticky)
-    {
-      gulong *desktop;
-      
-      XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), 
-			  GDK_WINDOW_XID (window),
-                          gdk_x11_get_xatom_by_name_for_display 
-			  (display, "_NET_WM_DESKTOP"),
-			  0, G_MAXLONG, False, XA_CARDINAL, &type, 
-			  &format, &nitems,
-                          &bytes_after, (guchar **)&desktop);
-
-      if (type != None)
-        {
-          if (*desktop != 0xFFFFFFFF)
-            found_sticky = FALSE;
-          XFree (desktop);
-        }
-    }
-          
-  old_state = gdk_window_get_state (window);
-
   if (old_state & GDK_WINDOW_STATE_STICKY)
     {
-      if (!found_sticky)
+      if (!(window_impl->have_sticky && window_impl->on_all_desktops))
         gdk_synthesize_window_state (window,
                                      GDK_WINDOW_STATE_STICKY,
                                      0);
     }
   else
     {
-      if (found_sticky)
+      if (window_impl->have_sticky && window_impl->on_all_desktops)
         gdk_synthesize_window_state (window,
                                      0,
                                      GDK_WINDOW_STATE_STICKY);
@@ -451,14 +390,14 @@ gdk_check_wm_state_changed (GdkWindow *w
 
   if (old_state & GDK_WINDOW_STATE_FULLSCREEN)
     {
-      if (!found_fullscreen)
+      if (!window_impl->have_fullscreen)
         gdk_synthesize_window_state (window,
                                      GDK_WINDOW_STATE_FULLSCREEN,
                                      0);
     }
   else
     {
-      if (found_fullscreen)
+      if (window_impl->have_fullscreen)
         gdk_synthesize_window_state (window,
                                      0,
                                      GDK_WINDOW_STATE_FULLSCREEN);
@@ -469,20 +408,110 @@ gdk_check_wm_state_changed (GdkWindow *w
    */
   if (old_state & GDK_WINDOW_STATE_MAXIMIZED)
     {
-      if (!(found_maxvert && found_maxhorz))
+      if (!(window_impl->have_maxvert && window_impl->have_maxhorz))
         gdk_synthesize_window_state (window,
                                      GDK_WINDOW_STATE_MAXIMIZED,
                                      0);
     }
   else
     {
-      if (found_maxvert && found_maxhorz)
+      if (window_impl->have_maxvert && window_impl->have_maxhorz)
         gdk_synthesize_window_state (window,
                                      0,
                                      GDK_WINDOW_STATE_MAXIMIZED);
     }
 }
 
+static void
+gdk_check_wm_desktop_changed (GdkWindow *window)
+{
+  GdkWindowObject *window_private = (GdkWindowObject *)window;
+  GdkWindowImplX11 *window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
+
+  Atom type;
+  gint format;
+  gulong nitems;
+  gulong bytes_after;
+
+  if (window_impl->have_sticky)
+    {
+      gulong *desktop;
+      
+      XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), 
+			  GDK_WINDOW_XID (window),
+                          gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"),
+			  0, G_MAXLONG, False, XA_CARDINAL, &type, 
+			  &format, &nitems,
+                          &bytes_after, (guchar **)&desktop);
+
+      if (type != None)
+        {
+          window_impl->on_all_desktops = (*desktop == 0xFFFFFFFF);
+          XFree (desktop);
+        }
+      else
+	window_impl->on_all_desktops = FALSE;
+      
+      do_net_wm_state_changes (window);
+    }
+}
+
+static void
+gdk_check_wm_state_changed (GdkWindow *window)
+{
+  GdkWindowObject *window_private = (GdkWindowObject *)window;
+  GdkWindowImplX11 *window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
+  
+  Atom type;
+  gint format;
+  gulong nitems;
+  gulong bytes_after;
+  Atom *atoms = NULL;
+  gulong i;
+
+  gboolean had_sticky = window_impl->have_sticky;
+
+  XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
+		      gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
+		      0, G_MAXLONG, False, XA_ATOM, &type, &format, &nitems,
+		      &bytes_after, (guchar **)&atoms);
+
+  if (type != None)
+    {
+      Atom sticky_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_STICKY");
+      Atom maxvert_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_VERT");
+      Atom maxhorz_atom	= gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_HORZ");
+      Atom fullscreen_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_FULLSCREEN");
+      
+      i = 0;
+      while (i < nitems)
+        {
+          if (atoms[i] == sticky_atom)
+            window_impl->have_sticky = TRUE;
+          else if (atoms[i] == maxvert_atom)
+            window_impl->have_maxvert = TRUE;
+          else if (atoms[i] == maxhorz_atom)
+            window_impl->have_maxhorz = TRUE;
+          else if (atoms[i] == fullscreen_atom)
+            window_impl->have_fullscreen = TRUE;
+          
+          ++i;
+        }
+
+      XFree (atoms);
+    }
+
+  /* When have_sticky is turned on, we have to check the DESKTOP property
+   * as well.
+   */
+  if (window_impl->have_sticky && !had_sticky)
+    gdk_check_wm_desktop_changed (window);
+  else
+    do_net_wm_state_changes (window);
+}
+
 #define HAS_FOCUS(window_impl)                           \
   ((window_impl)->has_focus || (window_impl)->has_pointer_focus)
 
@@ -719,22 +748,6 @@ gdk_event_translate (GdkDisplay *display
         }
     }  
 
-   /* We handle events with window=None
-    *  specially - they are generated by XFree86's XInput under
-    *  some circumstances. This handling for obvious reasons
-    * goes before we bother to lookup the event window.
-    */
-  
-  if (xevent->xany.window == None)
-    {
-      return_val = _gdk_input_window_none_event (event, xevent);
-      
-      if (return_val >= 0)	/* was handled */
-	return return_val;
-      else
-	return_val = FALSE;
-    }
-
   /* Find the GdkWindow that this event relates to.
    * Basically this means substructure events
    * are reported same as structure events
@@ -1621,14 +1634,10 @@ gdk_event_translate (GdkDisplay *display
 					 &tx, &ty,
 					 &child_window))
 		{
-		  if (!gdk_error_trap_pop ())
-		    {
-		      event->configure.x = tx;
-		      event->configure.y = ty;
-		    }
+		  event->configure.x = tx;
+		  event->configure.y = ty;
 		}
-	      else
-		gdk_error_trap_pop ();
+	      gdk_error_trap_pop ();
 	    }
 	  else
 	    {
@@ -1663,13 +1672,18 @@ gdk_event_translate (GdkDisplay *display
 	  return_val = FALSE;
           break;
         }
-      
-      if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE") ||
-	  xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"))
-        {
-          /* If window state changed, then synthesize those events. */
-          gdk_check_wm_state_changed (window);
-        }
+
+      /* We compare with the serial of the last time we mapped the
+       * window to avoid refetching properties that we set ourselves
+       */
+      if (xevent->xproperty.serial >= GDK_WINDOW_IMPL_X11 (window_private->impl)->map_serial)
+	{
+	  if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"))
+	    gdk_check_wm_state_changed (window);
+	  
+	  if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"))
+	    gdk_check_wm_desktop_changed (window);
+	}
       
       if (window_private->event_mask & GDK_PROPERTY_CHANGE_MASK) 
 	{
@@ -1891,18 +1905,14 @@ gdk_wm_protocols_filter (GdkXEvent *xev,
   else if ((Atom) xevent->xclient.data.l[0] == gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS"))
     {
       GdkWindow *win = event->any.window;
-      Window focus_win = GDK_WINDOW_IMPL_X11(((GdkWindowObject *)win)->impl)->focus_window;
+      GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (((GdkWindowObject *)win)->impl);
 
-      /* There is no way of knowing reliably whether we are viewable so we need
-       * to trap errors so we don't cause a BadMatch.
+      /* There is no way of knowing reliably whether we are viewable;
+       * _gdk_x11_set_input_focus_safe() traps errors asynchronously.
        */
-      gdk_error_trap_push ();
-      XSetInputFocus (GDK_WINDOW_XDISPLAY (win),
-		      focus_win,
-		      RevertToParent,
-		      xevent->xclient.data.l[1]);
-      XSync (GDK_WINDOW_XDISPLAY (win), False);
-      gdk_error_trap_pop ();
+      _gdk_x11_set_input_focus_safe (display, impl->focus_window,
+				     RevertToParent,
+				     xevent->xclient.data.l[1]);
     }
   else if ((Atom) xevent->xclient.data.l[0] == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PING"))
     {
@@ -2203,8 +2213,8 @@ timestamp_predicate (Display *display,
 
   if (xevent->type == PropertyNotify &&
       xevent->xproperty.window == xwindow &&
-      xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display 
-      (gdk_display, "GDK_TIMESTAMP_PROP"))
+      xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (gdk_display,
+								       "GDK_TIMESTAMP_PROP"))
     return True;
 
   return False;
Index: gdk/x11/gdkimage-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkimage-x11.c,v
retrieving revision 1.51
diff -u -p -r1.51 gdkimage-x11.c
--- gdk/x11/gdkimage-x11.c	7 Apr 2003 23:47:59 -0000	1.51
+++ gdk/x11/gdkimage-x11.c	4 Jul 2003 23:02:53 -0000
@@ -205,16 +205,12 @@ static int
 gdk_image_check_xshm(Display *display)
 {
 #ifdef USE_SHM
-  int major, minor, ignore;
+  int major, minor;
   Bool pixmaps;
   
-  if (XQueryExtension(display, "MIT-SHM", &ignore, &ignore, &ignore)) 
-    {
-      if (XShmQueryVersion(display, &major, &minor, &pixmaps )==True) 
-	{
-	  return (pixmaps==True) ? 2 : 1;
-	}
-    }
+  if (XShmQueryExtension (display) &&
+      XShmQueryVersion (display, &major, &minor, &pixmaps))
+    return pixmaps ? 2 : 1;
 #endif /* USE_SHM */
   return 0;
 }
Index: gdk/x11/gdkprivate-x11.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkprivate-x11.h,v
retrieving revision 1.28
diff -u -p -r1.28 gdkprivate-x11.h
--- gdk/x11/gdkprivate-x11.h	4 Jun 2003 23:26:52 -0000	1.28
+++ gdk/x11/gdkprivate-x11.h	4 Jul 2003 23:02:54 -0000
@@ -167,6 +167,10 @@ void _gdk_xgrab_check_destroy (GdkWindow
 gboolean _gdk_x11_display_is_root_window (GdkDisplay *display,
 					  Window      xroot_window);
 
+void _gdk_x11_precache_atoms (GdkDisplay          *display,
+			      const gchar * const *atom_names,
+			      gint                 n_atoms);
+
 void _gdk_x11_events_init_screen   (GdkScreen *screen);
 void _gdk_x11_events_uninit_screen (GdkScreen *screen);
 
Index: gdk/x11/gdkproperty-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkproperty-x11.c,v
retrieving revision 1.34
diff -u -p -r1.34 gdkproperty-x11.c
--- gdk/x11/gdkproperty-x11.c	28 Nov 2002 00:33:06 -0000	1.34
+++ gdk/x11/gdkproperty-x11.c	4 Jul 2003 23:02:54 -0000
@@ -142,6 +142,23 @@ insert_atom_pair (GdkDisplay *display,
 		       GUINT_TO_POINTER (xatom), 
 		       GDK_ATOM_TO_POINTER (virtual_atom));
 }
+
+static Atom
+lookup_cached_xatom (GdkDisplay *display,
+		     GdkAtom     atom)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+  if (ATOM_TO_INDEX (atom) < G_N_ELEMENTS (XAtomsStrings) - N_CUSTOM_PREDEFINED)
+    return ATOM_TO_INDEX (atom);
+  
+  if (display_x11->atom_from_virtual)
+    return GPOINTER_TO_UINT (g_hash_table_lookup (display_x11->atom_from_virtual,
+						  GDK_ATOM_TO_POINTER (atom)));
+
+  return None;
+}
+
 /**
  * gdk_x11_atom_to_xatom_for_display:
  * @display: A #GdkDisplay
@@ -158,7 +175,6 @@ Atom
 gdk_x11_atom_to_xatom_for_display (GdkDisplay *display, 
 				   GdkAtom atom)
 {
-  GdkDisplayX11 *display_x11;
   Atom xatom = None;
   
   g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
@@ -166,14 +182,8 @@ gdk_x11_atom_to_xatom_for_display (GdkDi
   if (display->closed)
     return None;
   
-  display_x11 = GDK_DISPLAY_X11 (display); 
-  
-  if (ATOM_TO_INDEX (atom) < G_N_ELEMENTS (XAtomsStrings) - N_CUSTOM_PREDEFINED)
-    return ATOM_TO_INDEX (atom);
+  xatom = lookup_cached_xatom (display, atom);
   
-  if (display_x11->atom_from_virtual)
-    xatom = GPOINTER_TO_UINT (g_hash_table_lookup (display_x11->atom_from_virtual,
-						   GDK_ATOM_TO_POINTER (atom)));
   if (!xatom)
     {
       char *name;
@@ -187,6 +197,45 @@ gdk_x11_atom_to_xatom_for_display (GdkDi
     }
 
   return xatom;
+}
+
+void
+_gdk_x11_precache_atoms (GdkDisplay          *display,
+			 const gchar * const *atom_names,
+			 gint                 n_atoms)
+{
+  Atom *xatoms;
+  GdkAtom *atoms;
+  const gchar **xatom_names;
+  gint n_xatoms;
+  gint i;
+
+  xatoms = g_new (Atom, n_atoms);
+  xatom_names = g_new (const gchar *, n_atoms);
+  atoms = g_new (GdkAtom, n_atoms);
+
+  n_xatoms = 0;
+  for (i = 0; i < n_atoms; i++)
+    {
+      GdkAtom atom = gdk_atom_intern (atom_names[i], FALSE);
+      if (lookup_cached_xatom (display, atom) == None)
+	{
+	  atoms[n_xatoms] = atom;
+	  xatom_names[n_xatoms] = atom_names[i];
+	  n_xatoms++;
+	}
+    }
+
+  if (n_xatoms)
+    XInternAtoms (GDK_DISPLAY_XDISPLAY (display),
+		  (char **)xatom_names, n_xatoms, False, xatoms);
+
+  for (i = 0; i < n_xatoms; i++)
+    insert_atom_pair (display, atoms[i], xatoms[i]);
+
+  g_free (xatoms);
+  g_free (atoms);
+  g_free (atom_names);
 }
 
 /**
Index: gdk/x11/gdkwindow-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkwindow-x11.c,v
retrieving revision 1.187
diff -u -p -r1.187 gdkwindow-x11.c
--- gdk/x11/gdkwindow-x11.c	20 May 2003 21:01:08 -0000	1.187
+++ gdk/x11/gdkwindow-x11.c	4 Jul 2003 23:02:55 -0000
@@ -33,6 +33,7 @@
 #include "config.h"
 
 #include "gdkwindow.h"
+#include "gdkasync.h"
 #include "gdkinputprivate.h"
 #include "gdkdisplay-x11.h"
 #include "gdkprivate-x11.h"
@@ -283,12 +284,6 @@ _gdk_windowing_window_init (GdkScreen * 
   GdkWindowImplX11 *impl;
   GdkDrawableImplX11 *draw_impl;
   GdkScreenX11 *screen_x11;
-  XWindowAttributes xattributes;
-  unsigned int width;
-  unsigned int height;
-  unsigned int border_width;
-  unsigned int depth;
-  int x, y;
 
   screen_x11 = GDK_SCREEN_X11 (screen);
 
@@ -297,10 +292,6 @@ _gdk_windowing_window_init (GdkScreen * 
   gdk_screen_set_default_colormap (screen,
 				   gdk_screen_get_system_colormap (screen));
 
-  XGetGeometry (screen_x11->xdisplay, screen_x11->xroot_window,
-		&screen_x11->xroot_window, &x, &y, &width, &height, &border_width, &depth);
-  XGetWindowAttributes (screen_x11->xdisplay, screen_x11->xroot_window, &xattributes);
-
   screen_x11->root_window = g_object_new (GDK_TYPE_WINDOW, NULL);
   private = (GdkWindowObject *)screen_x11->root_window;
   impl = GDK_WINDOW_IMPL_X11 (private->impl);
@@ -313,10 +304,10 @@ _gdk_windowing_window_init (GdkScreen * 
   g_object_ref (draw_impl->colormap);
   
   private->window_type = GDK_WINDOW_ROOT;
-  private->depth = depth;
+  private->depth = DefaultDepthOfScreen (screen_x11->xscreen);
   
-  impl->width = width;
-  impl->height = height;
+  impl->width = WidthOfScreen (screen_x11->xscreen);
+  impl->height = HeightOfScreen (screen_x11->xscreen);
   
   _gdk_window_init_position (GDK_WINDOW (private));
 
@@ -400,7 +391,6 @@ gdk_window_new (GdkWindow     *parent,
   XSetWindowAttributes xattributes;
   long xattributes_mask;
   XSizeHints size_hints;
-  XWMHints wm_hints;
   XClassHint *class_hint;
   int x, y, depth;
   
@@ -659,19 +649,12 @@ gdk_window_new (GdkWindow     *parent,
 
   check_leader_window_title (screen_x11->display);
   
-  wm_hints.flags = StateHint | WindowGroupHint;
-  wm_hints.window_group = GDK_DISPLAY_X11 (screen_x11->display)->leader_window;
-  wm_hints.input = True;
-  wm_hints.initial_state = NormalState;
-  
   /* FIXME: Is there any point in doing this? Do any WM's pay
    * attention to PSize, and even if they do, is this the
    * correct value???
    */
   XSetWMNormalHints (xdisplay, xid, &size_hints);
   
-  XSetWMHints (xdisplay, xid, &wm_hints);
-  
   /* This will set WM_CLIENT_MACHINE and WM_LOCALE_NAME */
   XSetWMProperties (xdisplay, xid, NULL, NULL, NULL, 0, NULL, NULL, NULL);
 
@@ -855,14 +838,38 @@ _gdk_windowing_window_destroy (GdkWindow
 			       gboolean   foreign_destroy)
 {
   GdkWindowObject *private = (GdkWindowObject *)window;
-
+  GdkWindowImplX11 *window_impl;
+  
   g_return_if_fail (GDK_IS_WINDOW (window));
 
+  window_impl = GDK_WINDOW_IMPL_X11 (private->impl);
+
   _gdk_selection_window_destroyed (window);
   
   if (private->extension_events != 0)
     _gdk_input_window_destroy (window);
 
+  if (window_impl->icon_window)
+    {
+      g_object_unref (window_impl->icon_window);
+      window_impl->icon_window = NULL;
+    }
+  if (window_impl->icon_pixmap)
+    {
+      g_object_unref (window_impl->icon_pixmap);
+      window_impl->icon_pixmap = NULL;
+    }
+  if (window_impl->icon_mask)
+    {
+      g_object_unref (window_impl->icon_mask);
+      window_impl->icon_mask = NULL;
+    }
+  if (window_impl->group_leader)
+    {
+      g_object_unref (window_impl->group_leader);
+      window_impl->group_leader = NULL;
+    }
+
 #ifdef HAVE_XFT  
   {
     GdkDrawableImplX11 *draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl);
@@ -945,6 +952,61 @@ gdk_window_destroy_notify (GdkWindow *wi
 }
 
 static void
+update_wm_hints (GdkWindow *window,
+		 gboolean   force)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (private->impl);
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
+  XWMHints wm_hints;
+
+  if (!force &&
+      private->state & GDK_WINDOW_STATE_WITHDRAWN)
+    return;
+
+  wm_hints.flags = StateHint;
+  wm_hints.input = True;
+  wm_hints.initial_state = NormalState;
+  
+  if (private->state & GDK_WINDOW_STATE_ICONIFIED)
+    {
+      wm_hints.flags |= StateHint;
+      wm_hints.initial_state = IconicState;
+    }
+
+  if (impl->icon_window && !GDK_WINDOW_DESTROYED (impl->icon_window))
+    {
+      wm_hints.flags |= IconWindowHint;
+      wm_hints.icon_window = GDK_WINDOW_XID (impl->icon_window);
+    }
+
+  if (impl->icon_pixmap)
+    {
+      wm_hints.flags |= IconPixmapHint;
+      wm_hints.icon_pixmap = GDK_PIXMAP_XID (impl->icon_pixmap);
+    }
+
+  if (impl->icon_mask)
+    {
+      wm_hints.flags |= IconMaskHint;
+      wm_hints.icon_mask = GDK_PIXMAP_XID (impl->icon_mask);
+    }
+  
+  wm_hints.flags |= WindowGroupHint;
+  if (impl->group_leader && !GDK_WINDOW_DESTROYED (impl->group_leader))
+    {
+      wm_hints.flags |= WindowGroupHint;
+      wm_hints.window_group = GDK_WINDOW_XID (impl->group_leader);
+    }
+  else
+    wm_hints.window_group = GDK_DISPLAY_X11 (display)->leader_window;
+  
+  XSetWMHints (GDK_WINDOW_XDISPLAY (window),
+	       GDK_WINDOW_XID (window),
+	       &wm_hints);
+}
+
+static void
 set_initial_hints (GdkWindow *window)
 {
   GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
@@ -957,22 +1019,9 @@ set_initial_hints (GdkWindow *window)
 
   private = (GdkWindowObject*) window;
   impl = GDK_WINDOW_IMPL_X11 (private->impl);
-  
-  if (private->state & GDK_WINDOW_STATE_ICONIFIED)
-    {
-      XWMHints *wm_hints;
-      
-      wm_hints = XGetWMHints (xdisplay, xwindow);
-      if (!wm_hints)
-        wm_hints = XAllocWMHints ();
-
-      wm_hints->flags |= StateHint;
-      wm_hints->initial_state = IconicState;
-      
-      XSetWMHints (xdisplay, xwindow, wm_hints);
-      XFree (wm_hints);
-    }
 
+  update_wm_hints (window, TRUE);
+  
   /* We set the spec hints regardless of whether the spec is supported,
    * since it can't hurt and it's kind of expensive to check whether
    * it's supported.
@@ -1068,9 +1117,12 @@ show_window_internal (GdkWindow *window,
   private = (GdkWindowObject*) window;
   if (!private->destroyed)
     {
+      GdkWindowImplX11 *impl =GDK_WINDOW_IMPL_X11 (private->impl);
+      Display *xdisplay = GDK_WINDOW_XDISPLAY (window);
+      Window xwindow = GDK_WINDOW_XID (window);
+      
       if (raise)
-        XRaiseWindow (GDK_WINDOW_XDISPLAY (window),
-                      GDK_WINDOW_XID (window));
+        XRaiseWindow (xdisplay, xwindow);
 
       if (!GDK_WINDOW_IS_MAPPED (window))
         {
@@ -1079,13 +1131,14 @@ show_window_internal (GdkWindow *window,
           gdk_synthesize_window_state (window,
                                        GDK_WINDOW_STATE_WITHDRAWN,
                                        0);
+
+	  impl->map_serial = NextRequest (xdisplay);
         }
       
       g_assert (GDK_WINDOW_IS_MAPPED (window));
-      
-      if (GDK_WINDOW_IMPL_X11 (private->impl)->position_info.mapped)
-        XMapWindow (GDK_WINDOW_XDISPLAY (window),
-                    GDK_WINDOW_XID (window));
+
+      if (impl->position_info.mapped)
+        XMapWindow (xdisplay, xwindow);
     }
 }
 
@@ -1550,11 +1603,15 @@ void
 gdk_window_focus (GdkWindow *window,
                   guint32    timestamp)
 {
+  GdkDisplay *display;
+  
   g_return_if_fail (GDK_IS_WINDOW (window));
 
   if (GDK_WINDOW_DESTROYED (window))
     return;
 
+  display = GDK_WINDOW_DISPLAY (window);
+
   if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
 					   gdk_atom_intern ("_NET_ACTIVE_WINDOW", FALSE)))
     {
@@ -1564,7 +1621,7 @@ gdk_window_focus (GdkWindow *window,
       xev.xclient.serial = 0;
       xev.xclient.send_event = True;
       xev.xclient.window = GDK_WINDOW_XWINDOW (window);
-      xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window),
+      xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display,
 									"_NET_ACTIVE_WINDOW");
       xev.xclient.format = 32;
       xev.xclient.data.l[0] = 0;
@@ -1573,24 +1630,20 @@ gdk_window_focus (GdkWindow *window,
       xev.xclient.data.l[3] = 0;
       xev.xclient.data.l[4] = 0;
       
-      XSendEvent (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XROOTWIN (window), False,
+      XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False,
                   SubstructureRedirectMask | SubstructureNotifyMask,
                   &xev);
     }
   else
     {
-      XRaiseWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
+      XRaiseWindow (GDK_DISPLAY_XDISPLAY (window), GDK_WINDOW_XID (window));
 
-      /* There is no way of knowing reliably whether we are viewable so we need
-       * to trap errors so we don't cause a BadMatch.
+      /* There is no way of knowing reliably whether we are viewable;
+       * _gdk_x11_set_input_focus_safe() traps errors asynchronously.
        */
-      gdk_error_trap_push ();
-      XSetInputFocus (GDK_WINDOW_XDISPLAY (window),
-                      GDK_WINDOW_XWINDOW (window),
-                      RevertToParent,
-                      timestamp);
-      XSync (GDK_WINDOW_XDISPLAY (window), False);
-      gdk_error_trap_pop ();
+      _gdk_x11_set_input_focus_safe (display, GDK_WINDOW_XID (window),
+				     RevertToParent,
+				     timestamp);
     }
 }
 
@@ -3277,40 +3330,40 @@ gdk_window_set_icon (GdkWindow *window, 
 		     GdkPixmap *pixmap,
 		     GdkBitmap *mask)
 {
-  XWMHints *wm_hints;
-  
+  GdkWindowObject *private;
+  GdkWindowImplX11 *impl;
+
   g_return_if_fail (window != NULL);
   g_return_if_fail (GDK_IS_WINDOW (window));
 
   if (GDK_WINDOW_DESTROYED (window))
     return;
 
-  wm_hints = XGetWMHints (GDK_WINDOW_XDISPLAY (window),
-			  GDK_WINDOW_XID (window));
-  if (!wm_hints)
-    wm_hints = XAllocWMHints ();
+  private = (GdkWindowObject *)window;
+  impl = GDK_WINDOW_IMPL_X11 (private->impl);
 
-  if (icon_window != NULL)
+  if (impl->icon_window != icon_window)
     {
-      wm_hints->flags |= IconWindowHint;
-      wm_hints->icon_window = GDK_WINDOW_XID (icon_window);
+      if (impl->icon_window)
+	g_object_unref (impl->icon_window);
+      impl->icon_window = g_object_ref (icon_window);
     }
   
-  if (pixmap != NULL)
+  if (impl->icon_pixmap != pixmap)
     {
-      wm_hints->flags |= IconPixmapHint;
-      wm_hints->icon_pixmap = GDK_PIXMAP_XID (pixmap);
+      if (impl->icon_pixmap)
+	g_object_unref (impl->icon_pixmap);
+      impl->icon_pixmap = g_object_ref (pixmap);
     }
   
-  if (mask != NULL)
+  if (impl->icon_mask != mask)
     {
-      wm_hints->flags |= IconMaskHint;
-      wm_hints->icon_mask = GDK_PIXMAP_XID (mask);
+      if (impl->icon_mask)
+	g_object_unref (impl->icon_mask);
+      impl->icon_mask = g_object_ref (mask);
     }
-
-  XSetWMHints (GDK_WINDOW_XDISPLAY (window),
-	       GDK_WINDOW_XID (window), wm_hints);
-  XFree (wm_hints);
+  
+  update_wm_hints (window, FALSE);
 }
 
 static gboolean
@@ -3733,15 +3786,13 @@ gdk_window_unfullscreen (GdkWindow *wind
  * allow users to minimize/unminimize all windows belonging to an
  * application at once. You should only set a non-default group window
  * if your application pretends to be multiple applications.
- * The group leader window may not be changed after a window has been
- * mapped (with gdk_window_show() for example).
- * 
  **/
 void          
 gdk_window_set_group (GdkWindow *window, 
 		      GdkWindow *leader)
 {
-  XWMHints *wm_hints;
+  GdkWindowObject *private;
+  GdkWindowImplX11 *impl;
   
   g_return_if_fail (window != NULL);
   g_return_if_fail (GDK_IS_WINDOW (window));
@@ -3751,17 +3802,17 @@ gdk_window_set_group (GdkWindow *window,
   if (GDK_WINDOW_DESTROYED (window) || GDK_WINDOW_DESTROYED (leader))
     return;
   
-  wm_hints = XGetWMHints (GDK_WINDOW_XDISPLAY (window),
-			  GDK_WINDOW_XID (window));
-  if (!wm_hints)
-    wm_hints = XAllocWMHints ();
+  private = (GdkWindowObject *)window;
+  impl = GDK_WINDOW_IMPL_X11 (private->impl);
 
-  wm_hints->flags |= WindowGroupHint;
-  wm_hints->window_group = GDK_WINDOW_XID (leader);
+  if (impl->group_leader != leader)
+    {
+      if (impl->group_leader)
+	g_object_unref (impl->group_leader);
+      impl->group_leader = g_object_ref (impl->group_leader);
+    }
 
-  XSetWMHints (GDK_WINDOW_XDISPLAY (window),
-	       GDK_WINDOW_XID (window), wm_hints);
-  XFree (wm_hints);
+  update_wm_hints (window, FALSE);
 }
 
 static MotifWmHints *
Index: gdk/x11/gdkwindow-x11.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkwindow-x11.h,v
retrieving revision 1.7
diff -u -p -r1.7 gdkwindow-x11.h
--- gdk/x11/gdkwindow-x11.h	10 Dec 2002 20:06:02 -0000	1.7
+++ gdk/x11/gdkwindow-x11.h	4 Jul 2003 23:02:55 -0000
@@ -90,7 +90,21 @@ struct _GdkWindowImplX11
   /* Set if we are requesting these hints */
   guint skip_taskbar_hint : 1;
   guint skip_pager_hint : 1;
+
+  guint on_all_desktops : 1;   /* _NET_WM_STICKY == 0xFFFFFFFF */
+
+  guint have_sticky : 1;	/* _NET_WM_STATE_STICKY */
+  guint have_maxvert : 1;       /* _NET_WM_STATE_MAXIMIZED_VERT */
+  guint have_maxhorz : 1;       /* _NET_WM_STATE_MAXIMIZED_HORZ */
+  guint have_fullscreen : 1;    /* _NET_WM_STATE_FULLSCREEN */
+
+  gulong map_serial;	/* Serial of last transition from unmapped */
   
+  GdkPixmap *icon_pixmap;
+  GdkPixmap *icon_mask;
+  GdkPixmap *icon_window;
+  GdkWindow *group_leader;
+
   /* We use an extra X window for toplevel windows that we XSetInputFocus()
    * to in order to avoid getting keyboard events redirected to subwindows
    * that might not even be part of this app
Index: gdk/x11/xsettings-client.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/xsettings-client.c,v
retrieving revision 1.5
diff -u -p -r1.5 xsettings-client.c
--- gdk/x11/xsettings-client.c	5 Aug 2002 19:28:55 -0000	1.5
+++ gdk/x11/xsettings-client.c	4 Jul 2003 23:02:55 -0000
@@ -439,7 +439,9 @@ xsettings_client_new (Display           
 {
   XSettingsClient *client;
   char buffer[256];
-
+  char *atom_names[3];
+  Atom atoms[3];
+  
   client = malloc (sizeof *client);
   if (!client)
     return NULL;
@@ -454,9 +456,15 @@ xsettings_client_new (Display           
   client->settings = NULL;
 
   sprintf(buffer, "_XSETTINGS_S%d", screen);
-  client->selection_atom = XInternAtom (display, buffer, False);
-  client->xsettings_atom = XInternAtom (display, "_XSETTINGS_SETTINGS", False);
-  client->manager_atom = XInternAtom (display, "MANAGER", False);
+  atom_names[0] = buffer;
+  atom_names[1] = "_XSETTINGS_SETTINGS";
+  atom_names[2] = "MANAGER";
+
+  XInternAtoms (display, atom_names, 3, False, atoms);
+  
+  client->selection_atom = atoms[0];
+  client->xsettings_atom = atoms[1];
+  client->manager_atom = atoms[2];
 
   /* Select on StructureNotify so we get MANAGER events
    */
Summary: 23 roundtrips
2 are from an Xlib bug
6 could be eliminated using suffiicently clever programming in GTK+
 (of which, 1 could otherwise be fixed in metacity)
1 could be eliminated with an appropriate WM protocol

XOpenDisplay =>BigRequest/XA_RESOURCE_MANAGER;
	 ............REQUEST: QueryExtension
	 ............REQUEST: GetProperty
				 ..............REPLY: QueryExtension
				 ..............REPLY: GetProperty
XOpenDisplay
	 ............REQUEST: BigReqEnable
				 ..............REPLY: BigReqEnable
XkbUseExtension()
	 ............REQUEST: QueryExtension
				 ..............REPLY: QueryExtension
XkbUseExtension()
	 ............REQUEST: kbUseExtension
				 ..............REPLY: kbUseExtension
init_xinerama_support()
	 ............REQUEST: QueryExtension
				 ..............REPLY: QueryExtension
xsettings_client_new() => XInternAtoms [1]
	 ............REQUEST: InternAtom
	 ............REQUEST: InternAtom
	 ............REQUEST: InternAtom
				 ..............REPLY: InternAtom
				 ..............REPLY: InternAtom
				 ..............REPLY: InternAtom
xsettings-client.c:add_events() => XGetWindowAttributes()
	 ............REQUEST: GetWindowAttributes
	 ............REQUEST: GetGeometry
				 ..............REPLY: GetWindowAttributes
				 ..............REPLY: GetGeometry
xsettings-client.c:check_manager_window()
	 ............REQUEST: GetSelectionOwner
				 ..............REPLY: GetSelectionOwner
xsettings-client.c:check_manager_window() => gdk_window_foreign_new() [2]
	 ............REQUEST: GetWindowAttributes
	 ............REQUEST: GetGeometry
				 ..............REPLY: GetWindowAttributes
				 ..............REPLY: GetGeometry
xsettings-client.c:check_manager_window() => gdk_window_foreign_new() [2']
	 ............REQUEST: QueryTree
				 ..............REPLY: QueryTree
xsettings-client.c:read_settings() [3]
	 ............REQUEST: GetProperty
				 ..............REPLY: GetProperty
_gdk_x11_precache_atoms()
	 ............REQUEST: InternAtom
	 ............REQUEST: InternAtom
	 ............REQUEST: InternAtom
	 ............REQUEST: InternAtom
	 ............REQUEST: InternAtom
	 ............REQUEST: InternAtom
	 ............REQUEST: InternAtom
	 ............REQUEST: InternAtom
	 ............REQUEST: InternAtom
	 ............REQUEST: InternAtom
	 ............REQUEST: InternAtom
	 ............REQUEST: InternAtom
	 ............REQUEST: InternAtom
	 ............REQUEST: InternAtom
	 ............REQUEST: InternAtom
	 ............REQUEST: InternAtom
	 ............REQUEST: InternAtom
	 ............REQUEST: InternAtom
	 ............REQUEST: InternAtom
				 ..............REPLY: InternAtom
				 ..............REPLY: InternAtom
				 ..............REPLY: InternAtom
				 ..............REPLY: InternAtom
				 ..............REPLY: InternAtom
				 ..............REPLY: InternAtom
				 ..............REPLY: InternAtom
				 ..............REPLY: InternAtom
				 ..............REPLY: InternAtom
				 ..............REPLY: InternAtom
				 ..............REPLY: InternAtom
				 ..............REPLY: InternAtom
				 ..............REPLY: InternAtom
				 ..............REPLY: InternAtom
				 ..............REPLY: InternAtom
				 ..............REPLY: InternAtom
				 ..............REPLY: InternAtom
				 ..............REPLY: InternAtom
				 ..............REPLY: InternAtom
XkbUseExtension()  [http://bugs.xfree86.org/cgi-bin/bugzilla/show_bug.cgi?id=473]
	 ............REQUEST: QueryExtension
				 ..............REPLY: QueryExtension
XkbUseExtension()
	 ............REQUEST: kbUseExtension
				 ..............REPLY: kbUseExtension
XkbSetDetectableAutoRepeat()
	 ............REQUEST: kbPerClientFlags
				 ..............REPLY: kbPerClientFlags
gdk_image_check_xshm => XShmQueryExtension()
	 ............REQUEST: QueryExtension
				 ..............REPLY: QueryExtension
XShmQueryVersion()
	 ............REQUEST: ShmQueryVersion
				 ..............REPLY: ShmQueryVersion
XRenderQueryExtension()
	 ............REQUEST: QueryExtension
				 ..............REPLY: QueryExtension
XRenderQueryFormats()
	 ............REQUEST: RenderQueryVersion
	 ............REQUEST: RenderQueryPictFormats
				 ..............REPLY: RenderQueryVersion
				 ..............REPLY: RenderQueryPictFormats
gdk_check_wm_state_changed()  [3']
 	 ............REQUEST: GetProperty
				 ..............REPLY: GetProperty
ConfigureNotify [4]
	 ............REQUEST: TranslateCoordinates
				 ..............REPLY: TranslateCoordinates
[*1] WM_TAKE_FOCUS => _gdk_x11_set_input_focus_safe()
	 ............REQUEST: GetInputFocus
gdk_check_wm_state_changed() [3'']
	 ............REQUEST: GetProperty
				 ..............REPLY: GetInputFocus [*1]
				 ..............REPLY: GetProperty
gtk_main_quit() => XSync()
				 ..............REPLY: GetInputFocus
	 ............REQUEST: GetInputFocus
				 ..............REPLY: GetInputFocus

[1] Could be eliminated by looking up these atoms in _gdk_x11_precache_atoms()
[2][2'] Could be possibly eliminated by special version of 
     gdk_window_foreign_new() that didn't look up info on window
[3][3'][3''] Could be eliminated using an async get_property interface
[3'] Also
[4] Could be eliminated with an appropriate WM protocol
[*N] Done using X async API, no extra roundtrip
/* GTK - The GIMP Toolkit
 * gdkasync.h: Utility functions using the Xlib asynchronous interfaces
 * Copyright (C) 2003, Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#ifndef __GDK_ASYNC_H__
#define __GDK_ASYNC_H__

#include <X11/Xlib.h>
#include "gdk.h"

G_BEGIN_DECLS

void _gdk_x11_set_input_focus_safe (GdkDisplay             *display,
				    Window                  window,
				    int                     revert_to,
				    Time                    time);

G_END_DECLS

#endif /* __GDK_ASYNC_H__ */
/* GTK - The GIMP Toolkit
 * gdkasync.c: Utility functions using the Xlib asynchronous interfaces
 * Copyright (C) 2003, Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
/* Portions of code in this file are based on code from Xlib
 */
/*
Copyright 1986, 1998  The Open Group

Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.

*/
#include <X11/Xlibint.h>
#include "gdkasync.h"
#include "gdkx.h"

typedef struct _SetInputFocusState SetInputFocusState;

struct _SetInputFocusState
{
  Display *dpy;
  Window window;
  _XAsyncHandler async;
  gulong set_input_focus_req;
  gulong get_input_focus_req;
  gboolean have_error;
  GdkSendXEventCallback callback;
  gpointer data;
};

static Bool
set_input_focus_handler (Display *dpy,
			 xReply  *rep,
			 char    *buf,
			 int      len,
			 XPointer data)
{
  SetInputFocusState *state = (SetInputFocusState *)data;  

  if (dpy->last_request_read == state->set_input_focus_req)
    {
      if (rep->generic.type == X_Error &&
	  rep->error.errorCode == BadMatch)
	{
	  /* Consume BadMatch errors, since we have no control
	   * over them.
	   */
	  return True;
	}
    }
  
  if (dpy->last_request_read == state->get_input_focus_req)
    {
      xGetInputFocusReply replbuf;
      xGetInputFocusReply *repl;
      
      if (rep->generic.type != X_Error)
	{
	  /* Actually does nothing, since there are no additional bytes
	   * to read, but maintain good form.
	   */
	  repl = (xGetInputFocusReply *)
	    _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
			    (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
			    True);
	}

      DeqAsyncHandler(state->dpy, &state->async);

      g_free (state);
      
      return (rep->generic.type != X_Error);
    }

  return False;
}

void
_gdk_x11_set_input_focus_safe (GdkDisplay             *display,
			       Window                  window,
			       int                     revert_to,
			       Time                    time)
{
  Display *dpy;
  SetInputFocusState *state;
  
  dpy = GDK_DISPLAY_XDISPLAY (display);

  state = g_new (SetInputFocusState, 1);

  state->dpy = dpy;
  state->window = window;
  
  LockDisplay(dpy);

  state->async.next = dpy->async_handlers;
  state->async.handler = set_input_focus_handler;
  state->async.data = (XPointer) state;
  dpy->async_handlers = &state->async;

  {
    xSetInputFocusReq *req;
    
    GetReq(SetInputFocus, req);
    req->focus = window;
    req->revertTo = revert_to;
    req->time = time;
    state->set_input_focus_req = dpy->request;
  }

  /*
   * XSync (dpy, 0)
   */
  {
    xReq *req;
    
    GetEmptyReq(GetInputFocus, req);
    state->get_input_focus_req = dpy->request;
  }
  
  UnlockDisplay(dpy);
  SyncHandle();
}
#include <gtk/gtk.h>


void
hello (void)
{
  g_print ("hello world\n");
}

int
main (int argc, char *argv[])
{
  GtkWidget *window;
  GtkWidget *button;

  /* FIXME: This is not allowable - what is this supposed to be? */
  /*  gdk_progclass = g_strdup ("XTerm"); */
  gtk_init (&argc, &argv);
  
  window = g_object_connect (gtk_widget_new (gtk_window_get_type (),
					     "user_data", NULL,
					     "type", GTK_WINDOW_TOPLEVEL,
					     "title", "hello world",
					     "allow_grow", FALSE,
					     "allow_shrink", FALSE,
					     "border_width", 10,
					     NULL),
			     "signal::destroy", gtk_main_quit, NULL,
			     NULL);
  button = g_object_connect (gtk_widget_new (gtk_button_get_type (),
					     "GtkButton::label", "hello world",
					     "GtkWidget::parent", window,
					     "GtkWidget::visible", TRUE,
					     NULL),
			     "signal::clicked", hello, NULL,
			     NULL);
  g_signal_connect_after (window, "expose_event",
			  G_CALLBACK (gtk_main_quit), NULL);
  gtk_widget_show (window);

  gtk_main ();

  return 0;
}


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