/* * Copyright © 2002 Keith Packard * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS * 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. */ #define _GNU_SOURCE #include "xcursor.h" #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <dirent.h> /* * Cursor files start with a header. The header * contains a magic number, a version number and a * table of contents which has type and offset information * for the remaining tables in the file. * * File minor versions increment for compatible changes * File major versions increment for incompatible changes (never, we hope) * * Chunks of the same type are always upward compatible. Incompatible * changes are made with new chunk types; the old data can remain under * the old type. Upward compatible changes can add header data as the * header lengths are specified in the file. * * File: * FileHeader * LISTofChunk * * FileHeader: * CARD32 magic magic number * CARD32 header bytes in file header * CARD32 version file version * CARD32 ntoc number of toc entries * LISTofFileToc toc table of contents * * FileToc: * CARD32 type entry type * CARD32 subtype entry subtype (size for images) * CARD32 position absolute file position */ #define XCURSOR_MAGIC … /* * This version number is stored in cursor files; changes to the * file format require updating this version number */ #define XCURSOR_FILE_MAJOR … #define XCURSOR_FILE_MINOR … #define XCURSOR_FILE_VERSION … #define XCURSOR_FILE_HEADER_LEN … #define XCURSOR_FILE_TOC_LEN … struct xcursor_file_toc { … }; struct xcursor_file_header { … }; /* * The rest of the file is a list of chunks, each tagged by type * and version. * * Chunk: * ChunkHeader * <extra type-specific header fields> * <type-specific data> * * ChunkHeader: * CARD32 header bytes in chunk header + type header * CARD32 type chunk type * CARD32 subtype chunk subtype * CARD32 version chunk type version */ #define XCURSOR_CHUNK_HEADER_LEN … struct xcursor_chunk_header { … }; /* * Each cursor image occupies a separate image chunk. * The length of the image header follows the chunk header * so that future versions can extend the header without * breaking older applications * * Image: * ChunkHeader header chunk header * CARD32 width actual width * CARD32 height actual height * CARD32 xhot hot spot x * CARD32 yhot hot spot y * CARD32 delay animation delay * LISTofCARD32 pixels ARGB pixels */ #define XCURSOR_IMAGE_TYPE … #define XCURSOR_IMAGE_VERSION … #define XCURSOR_IMAGE_HEADER_LEN … #define XCURSOR_IMAGE_MAX_SIZE … /* * From libXcursor/src/file.c */ static struct xcursor_image * xcursor_image_create(int width, int height) { … } static void xcursor_image_destroy(struct xcursor_image *image) { … } static struct xcursor_images * xcursor_images_create(int size) { … } void xcursor_images_destroy(struct xcursor_images *images) { … } static bool xcursor_read_uint(FILE *file, uint32_t *u) { … } static void xcursor_file_header_destroy(struct xcursor_file_header *file_header) { … } static struct xcursor_file_header * xcursor_file_header_create(uint32_t ntoc) { … } static struct xcursor_file_header * xcursor_read_file_header(FILE *file) { … } static bool xcursor_seek_to_toc(FILE *file, struct xcursor_file_header *file_header, int toc) { … } static bool xcursor_file_read_chunk_header(FILE *file, struct xcursor_file_header *file_header, int toc, struct xcursor_chunk_header *chunk_header) { … } static uint32_t dist(uint32_t a, uint32_t b) { … } static uint32_t xcursor_file_best_size(struct xcursor_file_header *file_header, uint32_t size, int *nsizesp) { … } static int xcursor_find_image_toc(struct xcursor_file_header *file_header, uint32_t size, int count) { … } static struct xcursor_image * xcursor_read_image(FILE *file, struct xcursor_file_header *file_header, int toc) { … } static struct xcursor_images * xcursor_xc_file_load_images(FILE *file, int size) { … } /* * From libXcursor/src/library.c */ #ifndef ICONDIR #define ICONDIR … #endif #ifndef XCURSORPATH #define XCURSORPATH … #endif #define XDG_DATA_HOME_FALLBACK … #define CURSORDIR … /** Get search path for cursor themes * * This function builds the list of directories to look for cursor * themes in. The format is PATH-like: directories are separated by * colons. * * The memory block returned by this function is allocated on the heap * and must be freed by the caller. */ static char * xcursor_library_path(void) { … } static char * xcursor_build_theme_dir(const char *dir, const char *theme) { … } static char * xcursor_build_fullname(const char *dir, const char *subdir, const char *file) { … } static const char * xcursor_next_path(const char *path) { … } static bool xcursor_white(char c) { … } static bool xcursor_sep(char c) { … } static char * xcursor_theme_inherits(const char *full) { … } static void load_all_cursors_from_dir(const char *path, int size, void (*load_callback)(struct xcursor_images *, void *), void *user_data) { … } struct xcursor_nodelist { … }; static bool nodelist_contains(struct xcursor_nodelist *nodelist, const char *s, size_t ss) { … } static void xcursor_load_theme_protected(const char *theme, int size, void (*load_callback)(struct xcursor_images *, void *), void *user_data, struct xcursor_nodelist *visited_nodes) { … } /** 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 struct xcursor_images 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 struct xcursor_images * object which have the same name. The user is expected to destroy the * struct xcursor_images objects passed to the callback with * xcursor_images_destroy(). * * \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 struct xcursor_images * 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)(struct xcursor_images *, void *), void *user_data) { … }