summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <matthiasc@src.gnome.org>2009-01-20 02:15:59 +0000
committerMatthias Clasen <matthiasc@src.gnome.org>2009-01-20 02:15:59 +0000
commit1cba7387ce6bc59b4d9b22f7b9462358dbd9fec9 (patch)
tree8b4e8537705f8a1ba53200b9d70af69fc5145c06
parent42371c1a03773cd2759a48de07e0caabff4658a6 (diff)
downloadgtk+-1cba7387ce6bc59b4d9b22f7b9462358dbd9fec9.tar.gz
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. svn path=/trunk/; revision=22145
-rw-r--r--ChangeLog13
-rw-r--r--gdk/gdkcursor.h3
-rw-r--r--gdk/x11/gdkcursor-x11.c203
-rw-r--r--gdk/x11/gdkdisplay-x11.c2
-rw-r--r--gdk/x11/gdkprivate-x11.h1
5 files changed, 201 insertions, 21 deletions
diff --git a/ChangeLog b/ChangeLog
index e56dd8911b..503535ebd5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2009-01-19 Matthias Clasen <mclasen@redhat.com>
+
+ 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.
+
2009-01-18 Matthias Clasen <mclasen@redhat.com>
Bug 568263 – gtk can't recognize the wrong X Selection TARGETS'
diff --git a/gdk/gdkcursor.h b/gdk/gdkcursor.h
index 488faa498f..f20400368d 100644
--- a/gdk/gdkcursor.h
+++ b/gdk/gdkcursor.h
@@ -120,7 +120,8 @@ typedef enum
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
diff --git a/gdk/x11/gdkcursor-x11.c b/gdk/x11/gdkcursor-x11.c
index ef18c519dc..d40f6ddc6c 100644
--- a/gdk/x11/gdkcursor-x11.c
+++ b/gdk/x11/gdkcursor-x11.c
@@ -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 @@ static guint theme_serial = 0;
* <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 @@ gdk_cursor_new_for_display (GdkDisplay *display,
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 @@ gdk_cursor_new_for_display (GdkDisplay *display,
cursor->type = cursor_type;
cursor->ref_count = 1;
+ if (xcursor != None)
+ add_to_cache (private);
+
return cursor;
}
@@ -427,25 +584,20 @@ _gdk_x11_cursor_update_theme (GdkCursor *cursor)
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 @@ gdk_x11_display_set_cursor_theme (GdkDisplay *display,
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 @@ gdk_cursor_new_from_name (GdkDisplay *display,
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 @@ gdk_cursor_new_from_name (GdkDisplay *display,
cursor = (GdkCursor *) private;
cursor->type = GDK_CURSOR_IS_PIXMAP;
cursor->ref_count = 1;
-
+ add_to_cache (private);
+
return cursor;
}
diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c
index 87a5200498..cdab444910 100644
--- a/gdk/x11/gdkdisplay-x11.c
+++ b/gdk/x11/gdkdisplay-x11.c
@@ -838,6 +838,8 @@ gdk_display_x11_finalize (GObject *object)
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);
diff --git a/gdk/x11/gdkprivate-x11.h b/gdk/x11/gdkprivate-x11.h
index 1ae97c1623..f24a0df4c1 100644
--- a/gdk/x11/gdkprivate-x11.h
+++ b/gdk/x11/gdkprivate-x11.h
@@ -191,6 +191,7 @@ PangoRenderer *_gdk_x11_renderer_get (GdkDrawable *drawable,
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,