gtk+ r22145 - in trunk: . gdk gdk/x11



Author: matthiasc
Date: Tue Jan 20 02:15:59 2009
New Revision: 22145
URL: http://svn.gnome.org/viewvc/gtk+?rev=22145&view=rev

Log:
        Cache cursors to avoid libXcursor theme lookup overhead.
        Patch by David Alan Gilbert.

        * gdk/gdkcursor.h: Add a GDK_BLANK_CURSOR cursor type.

        * gdk/x11/gdkcursor-x11.c: Cache font cursors and named cursors.

        * gdk/x11/gdkprivate-x11.h:
        * gdk/x11/gdkcdisplay-x11.c: Remove cached cursors when a
        display if finalized.



Modified:
   trunk/ChangeLog
   trunk/gdk/gdkcursor.h
   trunk/gdk/x11/gdkcursor-x11.c
   trunk/gdk/x11/gdkdisplay-x11.c
   trunk/gdk/x11/gdkprivate-x11.h

Modified: trunk/gdk/gdkcursor.h
==============================================================================
--- trunk/gdk/gdkcursor.h	(original)
+++ trunk/gdk/gdkcursor.h	Tue Jan 20 02:15:59 2009
@@ -120,7 +120,8 @@
   GDK_WATCH 		  = 150,
   GDK_XTERM 		  = 152,
   GDK_LAST_CURSOR,
-  GDK_CURSOR_IS_PIXMAP 	= -1
+  GDK_BLANK_CURSOR        = -2,
+  GDK_CURSOR_IS_PIXMAP 	  = -1
 } GdkCursorType;
 
 struct _GdkCursor

Modified: trunk/gdk/x11/gdkcursor-x11.c
==============================================================================
--- trunk/gdk/x11/gdkcursor-x11.c	(original)
+++ trunk/gdk/x11/gdkcursor-x11.c	Tue Jan 20 02:15:59 2009
@@ -49,6 +49,140 @@
 
 static guint theme_serial = 0;
 
+/* cursor_cache holds a cache of non-pixmap cursors to avoid expensive 
+ * libXcursor searches, cursors are added to it but never removed. We make 
+ * the assumption that since there are a small number of GdkDisplay's and 
+ * a small number of cursor's that this list will stay small enough
+ * not to be a problem.
+ */
+static GSList* cursor_cache = NULL;
+
+struct cursor_cache_key
+{
+  GdkDisplay* display;
+  GdkCursorType type;
+  const char* name;
+};
+
+/* Caller should check if there is already a match first.
+ * Cursor MUST be either a typed cursor or a pixmap with 
+ * a non-NULL name.
+ */
+static void
+add_to_cache (GdkCursorPrivate* cursor)
+{
+  cursor_cache = g_slist_prepend (cursor_cache, cursor);
+
+  /* Take a ref so that if the caller frees it we still have it */
+  gdk_cursor_ref ((GdkCursor*) cursor);
+}
+
+/* Returns 0 on a match
+ */
+static gint
+cache_compare_func (gconstpointer listelem, 
+                    gconstpointer target)
+{
+  GdkCursorPrivate* cursor = (GdkCursorPrivate*)listelem;
+  struct cursor_cache_key* key = (struct cursor_cache_key*)target;
+
+  if ((cursor->cursor.type != key->type) ||
+      (cursor->display != key->display))
+    return 1; /* No match */
+  
+  /* Elements marked as pixmap must be named cursors 
+   * (since we don't store normal pixmap cursors 
+   */
+  if (key->type == GDK_CURSOR_IS_PIXMAP)
+    return strcmp (key->name, cursor->name);
+
+  return 0; /* Match */
+}
+
+/* Returns the cursor if there is a match, NULL if not
+ * For named cursors type shall be GDK_CURSOR_IS_PIXMAP
+ * For unnamed, typed cursors, name shall be NULL
+ */
+static GdkCursorPrivate*
+find_in_cache (GdkDisplay    *display, 
+               GdkCursorType  type,
+               const char    *name)
+{
+  GSList* res;
+  struct cursor_cache_key key;
+
+  key.display = display;
+  key.type = type;
+  key.name = name;
+
+  res = g_slist_find_custom (cursor_cache, &key, cache_compare_func);
+
+  if (res)
+    return (GdkCursorPrivate *) res->data;
+
+  return NULL;
+}
+
+/* Called by gdk_display_x11_finalize to flush any cached cursors
+ * for a dead display.
+ */
+void 
+_gdk_x11_cursor_display_finalize (GdkDisplay *display)
+{
+  GSList* item;
+  GSList** itemp; /* Pointer to the thing to fix when we delete an item */
+  item = cursor_cache;
+  itemp = &cursor_cache;
+  while (item)
+    {
+      GdkCursorPrivate* cursor = (GdkCursorPrivate*)(item->data);
+      if (cursor->display == display)
+        {
+	  GSList* olditem;
+          gdk_cursor_unref ((GdkCursor*) cursor);
+	  /* Remove this item from the list */
+	  *(itemp) = item->next;
+	  olditem = item;
+	  item = g_slist_next (item);
+	  g_slist_free_1 (olditem);
+        } 
+      else 
+        {
+	  itemp = &(item->next);
+	  item = g_slist_next (item);
+	}
+    }
+}
+
+static Cursor
+get_blank_cursor (GdkDisplay *display)
+{
+  GdkScreen *screen;
+  GdkPixmap *pixmap;
+  Pixmap source_pixmap;
+  XColor color;
+  Cursor cursor;
+
+  screen = gdk_display_get_default_screen (display);
+  pixmap = gdk_bitmap_create_from_data (gdk_screen_get_root_window (screen), 
+					"\0\0\0\0\0\0\0\0", 1, 1);
+ 
+  source_pixmap = GDK_PIXMAP_XID (pixmap);
+
+  color.pixel = 0; 
+  color.red = color.blue = color.green = 0;
+  
+  if (display->closed)
+    cursor = None;
+  else
+    cursor = XCreatePixmapCursor (GDK_DISPLAY_XDISPLAY (display),
+                                  source_pixmap, source_pixmap,
+                                  &color, &color, 1, 1);
+  g_object_unref (pixmap);
+
+  return cursor;
+}
+
 /**
  * gdk_cursor_new_for_display:
  * @display: the #GdkDisplay for which the cursor will be created
@@ -108,11 +242,11 @@
  * <listitem><para>
  * <inlinegraphic format="PNG" fileref="sb_v_double_arrow.png"></inlinegraphic> #GDK_SB_V_DOUBLE_ARROW (move horizontal splitter)
  * </para></listitem>
+ * <listitem><para>
+ * #GDK_BLANK_CURSOR (Blank cursor). Since 2.16
+ * </para></listitem>
  * </itemizedlist>
  *
- * To make the cursor invisible, use gdk_cursor_new_from_pixmap() to create
- * a cursor with no pixels in it.
- * 
  * Return value: a new #GdkCursor
  *
  * Since: 2.2
@@ -128,9 +262,29 @@
   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
 
   if (display->closed)
-    xcursor = None;
-  else
-    xcursor = XCreateFontCursor (GDK_DISPLAY_XDISPLAY (display), cursor_type);
+    {
+      xcursor = None;
+    } 
+  else 
+    {
+      private = find_in_cache (display, cursor_type, NULL);
+
+      if (private)
+        {
+          /* Cache had it, add a ref for this user */
+          gdk_cursor_ref ((GdkCursor*) private);
+       
+          return (GdkCursor*) private;
+        } 
+      else 
+        {
+	  if (cursor_type != GDK_BLANK_CURSOR)
+            xcursor = XCreateFontCursor (GDK_DISPLAY_XDISPLAY (display),
+                                         cursor_type);
+	  else
+	    xcursor = get_blank_cursor (display);
+       }
+    }
   
   private = g_new (GdkCursorPrivate, 1);
   private->display = display;
@@ -142,6 +296,9 @@
   cursor->type = cursor_type;
   cursor->ref_count = 1;
   
+  if (xcursor != None)
+    add_to_cache (private);
+
   return cursor;
 }
 
@@ -427,25 +584,20 @@
 	new_cursor = XcursorShapeLoadCursor (xdisplay, cursor->type);
       
       if (new_cursor != None)
-	XFixesChangeCursor (xdisplay, new_cursor, private->xcursor);
+	{
+	  XFixesChangeCursor (xdisplay, new_cursor, private->xcursor);
+ 	  private->xcursor = new_cursor;
+	}
     }
 }
 
 static void
-update_cursor (gpointer key,
-	       gpointer value,
-	       gpointer data)
+update_cursor (gpointer data,
+	       gpointer user_data)
 {
-  XID *xid = key;
   GdkCursor *cursor;
 
-  if (*xid & XID_FONT_BIT)
-    return;
-
-  if (!GDK_IS_WINDOW (value))
-    return;
-
-  cursor = _gdk_x11_window_get_cursor (GDK_WINDOW (value));
+  cursor = (GdkCursor*)(data);
 
   if (!cursor)
     return;
@@ -503,7 +655,7 @@
   if (size > 0)
     XcursorSetDefaultSize (xdisplay, size);
     
-  g_hash_table_foreach (display_x11->xid_ht, update_cursor, NULL);
+  g_slist_foreach (cursor_cache, update_cursor, NULL);
 }
 
 #else
@@ -679,6 +831,16 @@
     xcursor = None;
   else 
     {
+      private = find_in_cache (display, GDK_CURSOR_IS_PIXMAP, name);
+
+      if (private)
+        {
+          /* Cache had it, add a ref for this user */
+          gdk_cursor_ref ((GdkCursor*) private);
+
+          return (GdkCursor*) private;
+        }
+
       xdisplay = GDK_DISPLAY_XDISPLAY (display);
       xcursor = XcursorLibraryLoadCursor (xdisplay, name);
       if (xcursor == None)
@@ -694,7 +856,8 @@
   cursor = (GdkCursor *) private;
   cursor->type = GDK_CURSOR_IS_PIXMAP;
   cursor->ref_count = 1;
-  
+  add_to_cache (private);
+
   return cursor;
 }
 

Modified: trunk/gdk/x11/gdkdisplay-x11.c
==============================================================================
--- trunk/gdk/x11/gdkdisplay-x11.c	(original)
+++ trunk/gdk/x11/gdkdisplay-x11.c	Tue Jan 20 02:15:59 2009
@@ -838,6 +838,8 @@
       g_free (display_x11->motif_target_lists);
     }
 
+  _gdk_x11_cursor_display_finalize (GDK_DISPLAY_OBJECT(display_x11));
+
   /* Atom Hashtable */
   g_hash_table_destroy (display_x11->atom_from_virtual);
   g_hash_table_destroy (display_x11->atom_to_virtual);

Modified: trunk/gdk/x11/gdkprivate-x11.h
==============================================================================
--- trunk/gdk/x11/gdkprivate-x11.h	(original)
+++ trunk/gdk/x11/gdkprivate-x11.h	Tue Jan 20 02:15:59 2009
@@ -191,6 +191,7 @@
 				      GdkGC       *gc);
 
 void _gdk_x11_cursor_update_theme (GdkCursor *cursor);
+void _gdk_x11_cursor_display_finalize (GdkDisplay *display);
 
 gboolean _gdk_x11_get_xft_setting (GdkScreen   *screen,
 				   const gchar *name,



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