wayland-cursor: load all cursors from a theme on wl_cursor_theme_load
authorAnder Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Thu, 24 May 2012 13:17:48 +0000 (16:17 +0300)
committerKristian Høgsberg <krh@bitplanet.net>
Sat, 26 May 2012 03:06:27 +0000 (23:06 -0400)
cursor/wayland-cursor.c
cursor/xcursor.c
cursor/xcursor.h

index bfacc71..05d79e8 100644 (file)
@@ -113,21 +113,6 @@ shm_pool_destroy(struct shm_pool *pool)
 }
 
 
-static const char *cursor_names[] = {
-       "bottom_left_corner",
-       "bottom_right_corner",
-       "bottom_side",
-       "grabbing",
-       "left_ptr",
-       "left_side",
-       "right_side",
-       "top_left_corner",
-       "top_right_corner",
-       "top_side",
-       "xterm",
-       "hand1",
-};
-
 struct wl_cursor_theme {
        unsigned int cursor_count;
        struct wl_cursor **cursors;
@@ -192,32 +177,25 @@ wl_cursor_destroy(struct wl_cursor *cursor)
 }
 
 static struct wl_cursor *
-load_cursor(struct wl_cursor_theme *theme, const char *name)
+wl_cursor_create_from_xcursor_images(XcursorImages *images,
+                                    struct wl_cursor_theme *theme)
 {
-       XcursorImages *images;
        struct wl_cursor *cursor;
        struct cursor_image *image;
        int i, size;
 
-       images = XcursorLibraryLoadImages(name, theme->name, theme->size);
-       if (!images)
-               return NULL;
-
        cursor = malloc(sizeof *cursor);
-       if (!cursor) {
-               XcursorImagesDestroy(images);
+       if (!cursor)
                return NULL;
-       }
 
        cursor->image_count = images->nimage;
        cursor->images = malloc(images->nimage * sizeof cursor->images[0]);
        if (!cursor->images) {
-               XcursorImagesDestroy(images);
                free(cursor);
                return NULL;
        }
 
-       cursor->name = strdup(name);
+       cursor->name = strdup(images->name);
 
        for (i = 0; i < images->nimage; i++) {
                image = malloc(sizeof *image);
@@ -239,11 +217,34 @@ load_cursor(struct wl_cursor_theme *theme, const char *name)
                       images->images[i]->pixels, size);
        }
 
-       XcursorImagesDestroy(images);
-
        return cursor;
 }
 
+static void
+load_callback(XcursorImages *images, void *data)
+{
+       struct wl_cursor_theme *theme = data;
+       struct wl_cursor *cursor;
+
+       if (wl_cursor_theme_get_cursor(theme, images->name)) {
+               XcursorImagesDestroy(images);
+               return;
+       }
+
+       cursor = wl_cursor_create_from_xcursor_images(images, theme);
+
+       if (cursor) {
+               theme->cursor_count++;
+               theme->cursors =
+                       realloc(theme->cursors,
+                               theme->cursor_count * sizeof theme->cursors[0]);
+
+               theme->cursors[theme->cursor_count - 1] = cursor;
+       }
+
+       XcursorImagesDestroy(images);
+}
+
 /** Load a cursor theme to memory shared with the compositor
  *
  * \param name The name of the cursor theme to load. If %NULL, the default
@@ -258,7 +259,6 @@ WL_EXPORT struct wl_cursor_theme *
 wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm)
 {
        struct wl_cursor_theme *theme;
-       unsigned int i;
 
        theme = malloc(sizeof *theme);
        if (!theme)
@@ -269,20 +269,13 @@ wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm)
 
        theme->name = strdup(name);
        theme->size = size;
-       theme->cursor_count = ARRAY_LENGTH(cursor_names);
-
-       theme->cursors =
-               malloc(theme->cursor_count * sizeof theme->cursors[0]);
-       if (!theme->cursors) {
-               free(theme);
-               return NULL;
-       }
+       theme->cursor_count = 0;
+       theme->cursors = NULL;
 
        theme->pool =
-               shm_pool_create(shm, theme->cursor_count * size * size * 4);
+               shm_pool_create(shm, size * size * 4);
 
-       for (i = 0; i < theme->cursor_count; i++)
-               theme->cursors[i] = load_cursor(theme, cursor_names[i]);
+       xcursor_load_theme(name, size, load_callback, theme);
 
        return theme;
 }
@@ -317,23 +310,11 @@ wl_cursor_theme_get_cursor(struct wl_cursor_theme *theme,
                           const char *name)
 {
        unsigned int i;
-       struct wl_cursor *cursor;
 
        for (i = 0; i < theme->cursor_count; i++) {
                if (strcmp(name, theme->cursors[i]->name) == 0)
                        return theme->cursors[i];
        }
 
-       cursor = load_cursor(theme, name);
-       if (!cursor)
-               return NULL;
-
-       theme->cursor_count++;
-       theme->cursors =
-               realloc(theme->cursors,
-                       theme->cursor_count * sizeof theme->cursors[0]);
-
-       theme->cursors[theme->cursor_count - 1] = cursor;
-
-       return cursor;
+       return NULL;
 }
index 8b1199f..b3fa271 100644 (file)
@@ -24,6 +24,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <dirent.h>
 
 /*
  * From libXcursor/include/X11/extensions/Xcursor.h
@@ -854,3 +855,109 @@ XcursorLibraryLoadImages (const char *file, const char *theme, int size)
     }
     return images;
 }
+
+static void
+load_all_cursors_from_dir(const char *path, int size,
+                         void (*load_callback)(XcursorImages *, void *),
+                         void *user_data)
+{
+       FILE *f;
+       DIR *dir = opendir(path);
+       struct dirent *ent;
+       char *full;
+       XcursorImages *images;
+
+       if (!dir)
+               return;
+
+       ent = readdir(dir);
+       for(ent = readdir(dir); ent; ent = readdir(dir)) {
+#ifdef _DIRENT_HAVE_D_TYPE
+               if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
+                       continue;
+#endif
+
+               full = _XcursorBuildFullname(path, "", ent->d_name);
+               if (!full)
+                       continue;
+
+               f = fopen(full, "r");
+               if (!f)
+                       continue;
+
+               images = XcursorFileLoadImages(f, size);
+
+               if (images) {
+                       XcursorImagesSetName(images, ent->d_name);
+                       load_callback(images, user_data);
+               }
+
+               fclose (f);
+       }
+
+       closedir(dir);
+}
+
+/** Load all the cursor of a theme
+ *
+ * This function loads all the cursor images of a given theme and its
+ * inherited themes. Each cursor is loaded into an XcursorImages object
+ * which is passed to the caller's load callback. If a cursor appears
+ * more than once across all the inherited themes, the load callback
+ * will be called multiple times, with possibly different XcursorImages
+ * object which have the same name. The user is expected to destroy the
+ * XcursorImages objects passed to the callback with
+ * XcursorImagesDestroy().
+ *
+ * \param theme The name of theme that should be loaded
+ * \param size The desired size of the cursor images
+ * \param load_callback A callback function that will be called
+ * for each cursor loaded. The first parameter is the XcursorImages
+ * object representing the loaded cursor and the second is a pointer
+ * to data provided by the user.
+ * \param user_data The data that should be passed to the load callback
+ */
+void
+xcursor_load_theme(const char *theme, int size,
+                   void (*load_callback)(XcursorImages *, void *),
+                   void *user_data)
+{
+       char *full, *dir;
+       char *inherits = NULL;
+       const char *path, *i;
+
+       if (!theme)
+               theme = "default";
+
+       for (path = XcursorLibraryPath();
+            path;
+            path = _XcursorNextPath(path)) {
+               dir = _XcursorBuildThemeDir(path, theme);
+               if (!dir)
+                       continue;
+
+               full = _XcursorBuildFullname(dir, "cursors", "");
+
+               if (full) {
+                       load_all_cursors_from_dir(full, size, load_callback,
+                                                 user_data);
+                       free(full);
+               }
+
+               if (!inherits) {
+                       full = _XcursorBuildFullname(dir, "", "index.theme");
+                       if (full) {
+                               inherits = _XcursorThemeInherits(full);
+                               free(full);
+                       }
+               }
+
+               free(dir);
+       }
+
+       for (i = inherits; i; i = _XcursorNextPath(i))
+               xcursor_load_theme(i, size, load_callback, user_data);
+
+       if (inherits)
+               free(inherits);
+}
index a39c58e..91747d9 100644 (file)
@@ -55,4 +55,8 @@ XcursorLibraryLoadImages (const char *file, const char *theme, int size);
 void
 XcursorImagesDestroy (XcursorImages *images);
 
+void
+xcursor_load_theme(const char *theme, int size,
+                   void (*load_callback)(XcursorImages *, void *),
+                   void *user_data);
 #endif