diff options
author | Matthias Clasen <matthiasc@src.gnome.org> | 2009-01-20 02:15:59 +0000 |
---|---|---|
committer | Matthias Clasen <matthiasc@src.gnome.org> | 2009-01-20 02:15:59 +0000 |
commit | 1cba7387ce6bc59b4d9b22f7b9462358dbd9fec9 (patch) | |
tree | 8b4e8537705f8a1ba53200b9d70af69fc5145c06 | |
parent | 42371c1a03773cd2759a48de07e0caabff4658a6 (diff) | |
download | gtk+-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-- | ChangeLog | 13 | ||||
-rw-r--r-- | gdk/gdkcursor.h | 3 | ||||
-rw-r--r-- | gdk/x11/gdkcursor-x11.c | 203 | ||||
-rw-r--r-- | gdk/x11/gdkdisplay-x11.c | 2 | ||||
-rw-r--r-- | gdk/x11/gdkprivate-x11.h | 1 |
5 files changed, 201 insertions, 21 deletions
@@ -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, |