aboutsummaryrefslogtreecommitdiff
path: root/cursor/xcursor.c
diff options
context:
space:
mode:
Diffstat (limited to 'cursor/xcursor.c')
-rw-r--r--cursor/xcursor.c1195
1 files changed, 500 insertions, 695 deletions
diff --git a/cursor/xcursor.c b/cursor/xcursor.c
index 1f1360f..43a5292 100644
--- a/cursor/xcursor.c
+++ b/cursor/xcursor.c
@@ -23,20 +23,15 @@
* SOFTWARE.
*/
+#define _GNU_SOURCE
#include "xcursor.h"
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
/*
- * From libXcursor/include/X11/extensions/Xcursor.h
- */
-
-#define XcursorTrue 1
-#define XcursorFalse 0
-
-/*
* 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
@@ -67,43 +62,31 @@
* CARD32 position absolute file position
*/
-#define XCURSOR_MAGIC 0x72756358 /* "Xcur" LSBFirst */
-
-/*
- * Current Xcursor version number. Will be substituted by configure
- * from the version in the libXcursor configure.ac file.
- */
-
-#define XCURSOR_LIB_MAJOR 1
-#define XCURSOR_LIB_MINOR 1
-#define XCURSOR_LIB_REVISION 13
-#define XCURSOR_LIB_VERSION ((XCURSOR_LIB_MAJOR * 10000) + \
- (XCURSOR_LIB_MINOR * 100) + \
- (XCURSOR_LIB_REVISION))
+#define XCURSOR_MAGIC 0x72756358 /* "Xcur" LSBFirst */
/*
* This version number is stored in cursor files; changes to the
* file format require updating this version number
*/
-#define XCURSOR_FILE_MAJOR 1
-#define XCURSOR_FILE_MINOR 0
-#define XCURSOR_FILE_VERSION ((XCURSOR_FILE_MAJOR << 16) | (XCURSOR_FILE_MINOR))
-#define XCURSOR_FILE_HEADER_LEN (4 * 4)
-#define XCURSOR_FILE_TOC_LEN (3 * 4)
-
-typedef struct _XcursorFileToc {
- XcursorUInt type; /* chunk type */
- XcursorUInt subtype; /* subtype (size for images) */
- XcursorUInt position; /* absolute position in file */
-} XcursorFileToc;
-
-typedef struct _XcursorFileHeader {
- XcursorUInt magic; /* magic number */
- XcursorUInt header; /* byte length of header */
- XcursorUInt version; /* file version number */
- XcursorUInt ntoc; /* number of toc entries */
- XcursorFileToc *tocs; /* table of contents */
-} XcursorFileHeader;
+#define XCURSOR_FILE_MAJOR 1
+#define XCURSOR_FILE_MINOR 0
+#define XCURSOR_FILE_VERSION ((XCURSOR_FILE_MAJOR << 16) | (XCURSOR_FILE_MINOR))
+#define XCURSOR_FILE_HEADER_LEN (4 * 4)
+#define XCURSOR_FILE_TOC_LEN (3 * 4)
+
+struct xcursor_file_toc {
+ uint32_t type; /* chunk type */
+ uint32_t subtype; /* subtype (size for images) */
+ uint32_t position; /* absolute position in file */
+};
+
+struct xcursor_file_header {
+ uint32_t magic; /* magic number */
+ uint32_t header; /* byte length of header */
+ uint32_t version; /* file version number */
+ uint32_t ntoc; /* number of toc entries */
+ struct xcursor_file_toc *tocs; /* table of contents */
+};
/*
* The rest of the file is a list of chunks, each tagged by type
@@ -121,42 +104,14 @@ typedef struct _XcursorFileHeader {
* CARD32 version chunk type version
*/
-#define XCURSOR_CHUNK_HEADER_LEN (4 * 4)
+#define XCURSOR_CHUNK_HEADER_LEN (4 * 4)
-typedef struct _XcursorChunkHeader {
- XcursorUInt header; /* bytes in chunk header */
- XcursorUInt type; /* chunk type */
- XcursorUInt subtype; /* chunk subtype (size for images) */
- XcursorUInt version; /* version of this type */
-} XcursorChunkHeader;
-
-/*
- * Here's a list of the known chunk types
- */
-
-/*
- * Comments consist of a 4-byte length field followed by
- * UTF-8 encoded text
- *
- * Comment:
- * ChunkHeader header chunk header
- * CARD32 length bytes in text
- * LISTofCARD8 text UTF-8 encoded text
- */
-
-#define XCURSOR_COMMENT_TYPE 0xfffe0001
-#define XCURSOR_COMMENT_VERSION 1
-#define XCURSOR_COMMENT_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (1 *4))
-#define XCURSOR_COMMENT_COPYRIGHT 1
-#define XCURSOR_COMMENT_LICENSE 2
-#define XCURSOR_COMMENT_OTHER 3
-#define XCURSOR_COMMENT_MAX_LEN 0x100000
-
-typedef struct _XcursorComment {
- XcursorUInt version;
- XcursorUInt comment_type;
- char *comment;
-} XcursorComment;
+struct xcursor_chunk_header {
+ uint32_t header; /* bytes in chunk header */
+ uint32_t type; /* chunk type */
+ uint32_t subtype; /* chunk subtype (size for images) */
+ uint32_t version; /* version of this type */
+};
/*
* Each cursor image occupies a separate image chunk.
@@ -174,439 +129,354 @@ typedef struct _XcursorComment {
* LISTofCARD32 pixels ARGB pixels
*/
-#define XCURSOR_IMAGE_TYPE 0xfffd0002
-#define XCURSOR_IMAGE_VERSION 1
-#define XCURSOR_IMAGE_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (5*4))
-#define XCURSOR_IMAGE_MAX_SIZE 0x7fff /* 32767x32767 max cursor size */
-
-typedef struct _XcursorFile XcursorFile;
-
-struct _XcursorFile {
- void *closure;
- int (*read) (XcursorFile *file, unsigned char *buf, int len);
- int (*write) (XcursorFile *file, unsigned char *buf, int len);
- int (*seek) (XcursorFile *file, long offset, int whence);
-};
-
-typedef struct _XcursorComments {
- int ncomment; /* number of comments */
- XcursorComment **comments; /* array of XcursorComment pointers */
-} XcursorComments;
+#define XCURSOR_IMAGE_TYPE 0xfffd0002
+#define XCURSOR_IMAGE_VERSION 1
+#define XCURSOR_IMAGE_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (5*4))
+#define XCURSOR_IMAGE_MAX_SIZE 0x7fff /* 32767x32767 max cursor size */
/*
* From libXcursor/src/file.c
*/
-static XcursorImage *
-XcursorImageCreate (int width, int height)
+static struct xcursor_image *
+xcursor_image_create(int width, int height)
{
- XcursorImage *image;
-
- if (width < 0 || height < 0)
- return NULL;
- if (width > XCURSOR_IMAGE_MAX_SIZE || height > XCURSOR_IMAGE_MAX_SIZE)
- return NULL;
-
- image = malloc (sizeof (XcursorImage) +
- width * height * sizeof (XcursorPixel));
- if (!image)
- return NULL;
- image->version = XCURSOR_IMAGE_VERSION;
- image->pixels = (XcursorPixel *) (image + 1);
- image->size = width > height ? width : height;
- image->width = width;
- image->height = height;
- image->delay = 0;
- return image;
+ struct xcursor_image *image;
+
+ if (width < 0 || height < 0)
+ return NULL;
+ if (width > XCURSOR_IMAGE_MAX_SIZE || height > XCURSOR_IMAGE_MAX_SIZE)
+ return NULL;
+
+ image = malloc(sizeof(struct xcursor_image) +
+ width * height * sizeof(uint32_t));
+ if (!image)
+ return NULL;
+ image->version = XCURSOR_IMAGE_VERSION;
+ image->pixels = (uint32_t *) (image + 1);
+ image->size = width > height ? width : height;
+ image->width = width;
+ image->height = height;
+ image->delay = 0;
+ return image;
}
static void
-XcursorImageDestroy (XcursorImage *image)
+xcursor_image_destroy(struct xcursor_image *image)
{
- free (image);
+ free(image);
}
-static XcursorImages *
-XcursorImagesCreate (int size)
+static struct xcursor_images *
+xcursor_images_create(int size)
{
- XcursorImages *images;
-
- images = malloc (sizeof (XcursorImages) +
- size * sizeof (XcursorImage *));
- if (!images)
- return NULL;
- images->nimage = 0;
- images->images = (XcursorImage **) (images + 1);
- images->name = NULL;
- return images;
+ struct xcursor_images *images;
+
+ images = malloc(sizeof(struct xcursor_images) +
+ size * sizeof(struct xcursor_image *));
+ if (!images)
+ return NULL;
+ images->nimage = 0;
+ images->images = (struct xcursor_image **) (images + 1);
+ images->name = NULL;
+ return images;
}
void
-XcursorImagesDestroy (XcursorImages *images)
-{
- int n;
-
- if (!images)
- return;
-
- for (n = 0; n < images->nimage; n++)
- XcursorImageDestroy (images->images[n]);
- if (images->name)
- free (images->name);
- free (images);
-}
-
-static void
-XcursorImagesSetName (XcursorImages *images, const char *name)
+xcursor_images_destroy(struct xcursor_images *images)
{
- char *new;
+ int n;
- if (!images || !name)
- return;
-
- new = malloc (strlen (name) + 1);
-
- if (!new)
- return;
+ if (!images)
+ return;
- strcpy (new, name);
- if (images->name)
- free (images->name);
- images->name = new;
+ for (n = 0; n < images->nimage; n++)
+ xcursor_image_destroy(images->images[n]);
+ free(images->name);
+ free(images);
}
-static XcursorBool
-_XcursorReadUInt (XcursorFile *file, XcursorUInt *u)
+static bool
+xcursor_read_uint(FILE *file, uint32_t *u)
{
- unsigned char bytes[4];
+ unsigned char bytes[4];
- if (!file || !u)
- return XcursorFalse;
+ if (!file || !u)
+ return false;
- if ((*file->read) (file, bytes, 4) != 4)
- return XcursorFalse;
+ if (fread(bytes, 1, 4, file) != 4)
+ return false;
- *u = ((XcursorUInt)(bytes[0]) << 0) |
- ((XcursorUInt)(bytes[1]) << 8) |
- ((XcursorUInt)(bytes[2]) << 16) |
- ((XcursorUInt)(bytes[3]) << 24);
- return XcursorTrue;
+ *u = ((uint32_t)(bytes[0]) << 0) |
+ ((uint32_t)(bytes[1]) << 8) |
+ ((uint32_t)(bytes[2]) << 16) |
+ ((uint32_t)(bytes[3]) << 24);
+ return true;
}
static void
-_XcursorFileHeaderDestroy (XcursorFileHeader *fileHeader)
+xcursor_file_header_destroy(struct xcursor_file_header *file_header)
{
- free (fileHeader);
+ free(file_header);
}
-static XcursorFileHeader *
-_XcursorFileHeaderCreate (int ntoc)
+static struct xcursor_file_header *
+xcursor_file_header_create(uint32_t ntoc)
{
- XcursorFileHeader *fileHeader;
-
- if (ntoc > 0x10000)
- return NULL;
- fileHeader = malloc (sizeof (XcursorFileHeader) +
- ntoc * sizeof (XcursorFileToc));
- if (!fileHeader)
- return NULL;
- fileHeader->magic = XCURSOR_MAGIC;
- fileHeader->header = XCURSOR_FILE_HEADER_LEN;
- fileHeader->version = XCURSOR_FILE_VERSION;
- fileHeader->ntoc = ntoc;
- fileHeader->tocs = (XcursorFileToc *) (fileHeader + 1);
- return fileHeader;
+ struct xcursor_file_header *file_header;
+
+ if (ntoc > 0x10000)
+ return NULL;
+ file_header = malloc(sizeof(struct xcursor_file_header) +
+ ntoc * sizeof(struct xcursor_file_toc));
+ if (!file_header)
+ return NULL;
+ file_header->magic = XCURSOR_MAGIC;
+ file_header->header = XCURSOR_FILE_HEADER_LEN;
+ file_header->version = XCURSOR_FILE_VERSION;
+ file_header->ntoc = ntoc;
+ file_header->tocs = (struct xcursor_file_toc *) (file_header + 1);
+ return file_header;
}
-static XcursorFileHeader *
-_XcursorReadFileHeader (XcursorFile *file)
+static struct xcursor_file_header *
+xcursor_read_file_header(FILE *file)
{
- XcursorFileHeader head, *fileHeader;
- XcursorUInt skip;
- unsigned int n;
-
- if (!file)
- return NULL;
-
- if (!_XcursorReadUInt (file, &head.magic))
- return NULL;
- if (head.magic != XCURSOR_MAGIC)
- return NULL;
- if (!_XcursorReadUInt (file, &head.header))
- return NULL;
- if (!_XcursorReadUInt (file, &head.version))
- return NULL;
- if (!_XcursorReadUInt (file, &head.ntoc))
- return NULL;
- skip = head.header - XCURSOR_FILE_HEADER_LEN;
- if (skip)
- if ((*file->seek) (file, skip, SEEK_CUR) == EOF)
- return NULL;
- fileHeader = _XcursorFileHeaderCreate (head.ntoc);
- if (!fileHeader)
- return NULL;
- fileHeader->magic = head.magic;
- fileHeader->header = head.header;
- fileHeader->version = head.version;
- fileHeader->ntoc = head.ntoc;
- for (n = 0; n < fileHeader->ntoc; n++)
- {
- if (!_XcursorReadUInt (file, &fileHeader->tocs[n].type))
- break;
- if (!_XcursorReadUInt (file, &fileHeader->tocs[n].subtype))
- break;
- if (!_XcursorReadUInt (file, &fileHeader->tocs[n].position))
- break;
- }
- if (n != fileHeader->ntoc)
- {
- _XcursorFileHeaderDestroy (fileHeader);
- return NULL;
- }
- return fileHeader;
+ struct xcursor_file_header head, *file_header;
+ uint32_t skip;
+ unsigned int n;
+
+ if (!file)
+ return NULL;
+
+ if (!xcursor_read_uint(file, &head.magic))
+ return NULL;
+ if (head.magic != XCURSOR_MAGIC)
+ return NULL;
+ if (!xcursor_read_uint(file, &head.header))
+ return NULL;
+ if (!xcursor_read_uint(file, &head.version))
+ return NULL;
+ if (!xcursor_read_uint(file, &head.ntoc))
+ return NULL;
+ skip = head.header - XCURSOR_FILE_HEADER_LEN;
+ if (skip)
+ if (fseek(file, skip, SEEK_CUR) == EOF)
+ return NULL;
+ file_header = xcursor_file_header_create(head.ntoc);
+ if (!file_header)
+ return NULL;
+ file_header->magic = head.magic;
+ file_header->header = head.header;
+ file_header->version = head.version;
+ file_header->ntoc = head.ntoc;
+ for (n = 0; n < file_header->ntoc; n++) {
+ if (!xcursor_read_uint(file, &file_header->tocs[n].type))
+ break;
+ if (!xcursor_read_uint(file, &file_header->tocs[n].subtype))
+ break;
+ if (!xcursor_read_uint(file, &file_header->tocs[n].position))
+ break;
+ }
+ if (n != file_header->ntoc) {
+ xcursor_file_header_destroy(file_header);
+ return NULL;
+ }
+ return file_header;
}
-static XcursorBool
-_XcursorSeekToToc (XcursorFile *file,
- XcursorFileHeader *fileHeader,
- int toc)
+static bool
+xcursor_seek_to_toc(FILE *file,
+ struct xcursor_file_header *file_header,
+ int toc)
{
- if (!file || !fileHeader || \
- (*file->seek) (file, fileHeader->tocs[toc].position, SEEK_SET) == EOF)
- return XcursorFalse;
- return XcursorTrue;
+ if (!file || !file_header ||
+ fseek(file, file_header->tocs[toc].position, SEEK_SET) == EOF)
+ return false;
+ return true;
}
-static XcursorBool
-_XcursorFileReadChunkHeader (XcursorFile *file,
- XcursorFileHeader *fileHeader,
- int toc,
- XcursorChunkHeader *chunkHeader)
+static bool
+xcursor_file_read_chunk_header(FILE *file,
+ struct xcursor_file_header *file_header,
+ int toc,
+ struct xcursor_chunk_header *chunk_header)
{
- if (!file || !fileHeader || !chunkHeader)
- return XcursorFalse;
- if (!_XcursorSeekToToc (file, fileHeader, toc))
- return XcursorFalse;
- if (!_XcursorReadUInt (file, &chunkHeader->header))
- return XcursorFalse;
- if (!_XcursorReadUInt (file, &chunkHeader->type))
- return XcursorFalse;
- if (!_XcursorReadUInt (file, &chunkHeader->subtype))
- return XcursorFalse;
- if (!_XcursorReadUInt (file, &chunkHeader->version))
- return XcursorFalse;
- /* sanity check */
- if (chunkHeader->type != fileHeader->tocs[toc].type ||
- chunkHeader->subtype != fileHeader->tocs[toc].subtype)
- return XcursorFalse;
- return XcursorTrue;
+ if (!file || !file_header || !chunk_header)
+ return false;
+ if (!xcursor_seek_to_toc(file, file_header, toc))
+ return false;
+ if (!xcursor_read_uint(file, &chunk_header->header))
+ return false;
+ if (!xcursor_read_uint(file, &chunk_header->type))
+ return false;
+ if (!xcursor_read_uint(file, &chunk_header->subtype))
+ return false;
+ if (!xcursor_read_uint(file, &chunk_header->version))
+ return false;
+ /* sanity check */
+ if (chunk_header->type != file_header->tocs[toc].type ||
+ chunk_header->subtype != file_header->tocs[toc].subtype)
+ return false;
+ return true;
}
-#define dist(a,b) ((a) > (b) ? (a) - (b) : (b) - (a))
-
-static XcursorDim
-_XcursorFindBestSize (XcursorFileHeader *fileHeader,
- XcursorDim size,
- int *nsizesp)
+static uint32_t
+dist(uint32_t a, uint32_t b)
{
- unsigned int n;
- int nsizes = 0;
- XcursorDim bestSize = 0;
- XcursorDim thisSize;
-
- if (!fileHeader || !nsizesp)
- return 0;
-
- for (n = 0; n < fileHeader->ntoc; n++)
- {
- if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE)
- continue;
- thisSize = fileHeader->tocs[n].subtype;
- if (!bestSize || dist (thisSize, size) < dist (bestSize, size))
- {
- bestSize = thisSize;
- nsizes = 1;
- }
- else if (thisSize == bestSize)
- nsizes++;
- }
- *nsizesp = nsizes;
- return bestSize;
+ return a > b ? a - b : b - a;
}
-static int
-_XcursorFindImageToc (XcursorFileHeader *fileHeader,
- XcursorDim size,
- int count)
+static uint32_t
+xcursor_file_best_size(struct xcursor_file_header *file_header,
+ uint32_t size, int *nsizesp)
{
- unsigned int toc;
- XcursorDim thisSize;
-
- if (!fileHeader)
- return 0;
-
- for (toc = 0; toc < fileHeader->ntoc; toc++)
- {
- if (fileHeader->tocs[toc].type != XCURSOR_IMAGE_TYPE)
- continue;
- thisSize = fileHeader->tocs[toc].subtype;
- if (thisSize != size)
- continue;
- if (!count)
- break;
- count--;
- }
- if (toc == fileHeader->ntoc)
- return -1;
- return toc;
-}
+ unsigned int n;
+ int nsizes = 0;
+ uint32_t best_size = 0;
+ uint32_t this_size;
-static XcursorImage *
-_XcursorReadImage (XcursorFile *file,
- XcursorFileHeader *fileHeader,
- int toc)
-{
- XcursorChunkHeader chunkHeader;
- XcursorImage head;
- XcursorImage *image;
- int n;
- XcursorPixel *p;
-
- if (!file || !fileHeader)
- return NULL;
-
- if (!_XcursorFileReadChunkHeader (file, fileHeader, toc, &chunkHeader))
- return NULL;
- if (!_XcursorReadUInt (file, &head.width))
- return NULL;
- if (!_XcursorReadUInt (file, &head.height))
- return NULL;
- if (!_XcursorReadUInt (file, &head.xhot))
- return NULL;
- if (!_XcursorReadUInt (file, &head.yhot))
- return NULL;
- if (!_XcursorReadUInt (file, &head.delay))
- return NULL;
- /* sanity check data */
- if (head.width > XCURSOR_IMAGE_MAX_SIZE ||
- head.height > XCURSOR_IMAGE_MAX_SIZE)
- return NULL;
- if (head.width == 0 || head.height == 0)
- return NULL;
- if (head.xhot > head.width || head.yhot > head.height)
- return NULL;
-
- /* Create the image and initialize it */
- image = XcursorImageCreate (head.width, head.height);
- if (image == NULL)
- return NULL;
- if (chunkHeader.version < image->version)
- image->version = chunkHeader.version;
- image->size = chunkHeader.subtype;
- image->xhot = head.xhot;
- image->yhot = head.yhot;
- image->delay = head.delay;
- n = image->width * image->height;
- p = image->pixels;
- while (n--)
- {
- if (!_XcursorReadUInt (file, p))
- {
- XcursorImageDestroy (image);
- return NULL;
- }
- p++;
- }
- return image;
-}
+ if (!file_header || !nsizesp)
+ return 0;
-static XcursorImages *
-XcursorXcFileLoadImages (XcursorFile *file, int size)
-{
- XcursorFileHeader *fileHeader;
- XcursorDim bestSize;
- int nsize;
- XcursorImages *images;
- int n;
- int toc;
-
- if (!file || size < 0)
- return NULL;
- fileHeader = _XcursorReadFileHeader (file);
- if (!fileHeader)
- return NULL;
- bestSize = _XcursorFindBestSize (fileHeader, (XcursorDim) size, &nsize);
- if (!bestSize)
- {
- _XcursorFileHeaderDestroy (fileHeader);
- return NULL;
- }
- images = XcursorImagesCreate (nsize);
- if (!images)
- {
- _XcursorFileHeaderDestroy (fileHeader);
- return NULL;
- }
- for (n = 0; n < nsize; n++)
- {
- toc = _XcursorFindImageToc (fileHeader, bestSize, n);
- if (toc < 0)
- break;
- images->images[images->nimage] = _XcursorReadImage (file, fileHeader,
- toc);
- if (!images->images[images->nimage])
- break;
- images->nimage++;
- }
- _XcursorFileHeaderDestroy (fileHeader);
- if (images->nimage != nsize)
- {
- XcursorImagesDestroy (images);
- images = NULL;
- }
- return images;
+ for (n = 0; n < file_header->ntoc; n++) {
+ if (file_header->tocs[n].type != XCURSOR_IMAGE_TYPE)
+ continue;
+ this_size = file_header->tocs[n].subtype;
+ if (!best_size || dist(this_size, size) < dist(best_size, size)) {
+ best_size = this_size;
+ nsizes = 1;
+ } else if (this_size == best_size) {
+ nsizes++;
+ }
+ }
+ *nsizesp = nsizes;
+ return best_size;
}
static int
-_XcursorStdioFileRead (XcursorFile *file, unsigned char *buf, int len)
+xcursor_find_image_toc(struct xcursor_file_header *file_header,
+ uint32_t size, int count)
{
- FILE *f = file->closure;
- return fread (buf, 1, len, f);
-}
+ unsigned int toc;
+ uint32_t this_size;
-static int
-_XcursorStdioFileWrite (XcursorFile *file, unsigned char *buf, int len)
-{
- FILE *f = file->closure;
- return fwrite (buf, 1, len, f);
-}
+ if (!file_header)
+ return 0;
-static int
-_XcursorStdioFileSeek (XcursorFile *file, long offset, int whence)
-{
- FILE *f = file->closure;
- return fseek (f, offset, whence);
+ for (toc = 0; toc < file_header->ntoc; toc++) {
+ if (file_header->tocs[toc].type != XCURSOR_IMAGE_TYPE)
+ continue;
+ this_size = file_header->tocs[toc].subtype;
+ if (this_size != size)
+ continue;
+ if (!count)
+ break;
+ count--;
+ }
+ if (toc == file_header->ntoc)
+ return -1;
+ return toc;
}
-static void
-_XcursorStdioFileInitialize (FILE *stdfile, XcursorFile *file)
+static struct xcursor_image *
+xcursor_read_image(FILE *file,
+ struct xcursor_file_header *file_header,
+ int toc)
{
- file->closure = stdfile;
- file->read = _XcursorStdioFileRead;
- file->write = _XcursorStdioFileWrite;
- file->seek = _XcursorStdioFileSeek;
+ struct xcursor_chunk_header chunk_header;
+ struct xcursor_image head;
+ struct xcursor_image *image;
+ int n;
+ uint32_t *p;
+
+ if (!file || !file_header)
+ return NULL;
+
+ if (!xcursor_file_read_chunk_header(file, file_header, toc, &chunk_header))
+ return NULL;
+ if (!xcursor_read_uint(file, &head.width))
+ return NULL;
+ if (!xcursor_read_uint(file, &head.height))
+ return NULL;
+ if (!xcursor_read_uint(file, &head.xhot))
+ return NULL;
+ if (!xcursor_read_uint(file, &head.yhot))
+ return NULL;
+ if (!xcursor_read_uint(file, &head.delay))
+ return NULL;
+ /* sanity check data */
+ if (head.width > XCURSOR_IMAGE_MAX_SIZE ||
+ head.height > XCURSOR_IMAGE_MAX_SIZE)
+ return NULL;
+ if (head.width == 0 || head.height == 0)
+ return NULL;
+ if (head.xhot > head.width || head.yhot > head.height)
+ return NULL;
+
+ /* Create the image and initialize it */
+ image = xcursor_image_create(head.width, head.height);
+ if (image == NULL)
+ return NULL;
+ if (chunk_header.version < image->version)
+ image->version = chunk_header.version;
+ image->size = chunk_header.subtype;
+ image->xhot = head.xhot;
+ image->yhot = head.yhot;
+ image->delay = head.delay;
+ n = image->width * image->height;
+ p = image->pixels;
+ while (n--) {
+ if (!xcursor_read_uint(file, p)) {
+ xcursor_image_destroy(image);
+ return NULL;
+ }
+ p++;
+ }
+ return image;
}
-static XcursorImages *
-XcursorFileLoadImages (FILE *file, int size)
+static struct xcursor_images *
+xcursor_xc_file_load_images(FILE *file, int size)
{
- XcursorFile f;
-
- if (!file)
- return NULL;
-
- _XcursorStdioFileInitialize (file, &f);
- return XcursorXcFileLoadImages (&f, size);
+ struct xcursor_file_header *file_header;
+ uint32_t best_size;
+ int nsize;
+ struct xcursor_images *images;
+ int n;
+ int toc;
+
+ if (!file || size < 0)
+ return NULL;
+ file_header = xcursor_read_file_header(file);
+ if (!file_header)
+ return NULL;
+ best_size = xcursor_file_best_size(file_header, (uint32_t) size, &nsize);
+ if (!best_size) {
+ xcursor_file_header_destroy(file_header);
+ return NULL;
+ }
+ images = xcursor_images_create(nsize);
+ if (!images) {
+ xcursor_file_header_destroy(file_header);
+ return NULL;
+ }
+ for (n = 0; n < nsize; n++) {
+ toc = xcursor_find_image_toc(file_header, best_size, n);
+ if (toc < 0)
+ break;
+ images->images[images->nimage] = xcursor_read_image(file, file_header,
+ toc);
+ if (!images->images[images->nimage])
+ break;
+ images->nimage++;
+ }
+ xcursor_file_header_destroy(file_header);
+ if (images->nimage != nsize) {
+ xcursor_images_destroy(images);
+ images = NULL;
+ }
+ return images;
}
/*
@@ -621,275 +491,213 @@ XcursorFileLoadImages (FILE *file, int size)
#define XCURSORPATH "~/.icons:/usr/share/icons:/usr/share/pixmaps:~/.cursors:/usr/share/cursors/xorg-x11:"ICONDIR
#endif
-static const char *
-XcursorLibraryPath (void)
+#define XDG_DATA_HOME_FALLBACK "~/.local/share"
+#define CURSORDIR "/icons"
+
+/** 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 const char *path;
+ const char *env_var, *suffix;
+ char *path;
+ size_t path_size;
- if (!path)
- {
- path = getenv ("XCURSOR_PATH");
- if (!path)
- path = XCURSORPATH;
- }
- return path;
-}
+ env_var = getenv("XCURSOR_PATH");
+ if (env_var)
+ return strdup(env_var);
-static void
-_XcursorAddPathElt (char *path, const char *elt, int len)
-{
- int pathlen = strlen (path);
-
- /* append / if the path doesn't currently have one */
- if (path[0] == '\0' || path[pathlen - 1] != '/')
- {
- strcat (path, "/");
- pathlen++;
- }
- if (len == -1)
- len = strlen (elt);
- /* strip leading slashes */
- while (len && elt[0] == '/')
- {
- elt++;
- len--;
- }
- strncpy (path + pathlen, elt, len);
- path[pathlen + len] = '\0';
+ env_var = getenv("XDG_DATA_HOME");
+ if (!env_var || env_var[0] != '/')
+ env_var = XDG_DATA_HOME_FALLBACK;
+
+ suffix = CURSORDIR ":" XCURSORPATH;
+ path_size = strlen(env_var) + strlen(suffix) + 1;
+ path = malloc(path_size);
+ if (!path)
+ return NULL;
+ snprintf(path, path_size, "%s%s", env_var, suffix);
+ return path;
}
static char *
-_XcursorBuildThemeDir (const char *dir, const char *theme)
+xcursor_build_theme_dir(const char *dir, const char *theme)
{
- const char *colon;
- const char *tcolon;
- char *full;
- char *home;
- int dirlen;
- int homelen;
- int themelen;
- int len;
-
- if (!dir || !theme)
- return NULL;
-
- colon = strchr (dir, ':');
- if (!colon)
- colon = dir + strlen (dir);
-
- dirlen = colon - dir;
-
- tcolon = strchr (theme, ':');
- if (!tcolon)
- tcolon = theme + strlen (theme);
-
- themelen = tcolon - theme;
-
- home = NULL;
- homelen = 0;
- if (*dir == '~')
- {
- home = getenv ("HOME");
- if (!home)
- return NULL;
- homelen = strlen (home);
- dir++;
- dirlen--;
- }
-
- /*
- * add space for any needed directory separators, one per component,
- * and one for the trailing null
- */
- len = 1 + homelen + 1 + dirlen + 1 + themelen + 1;
-
- full = malloc (len);
- if (!full)
- return NULL;
- full[0] = '\0';
-
- if (home)
- _XcursorAddPathElt (full, home, -1);
- _XcursorAddPathElt (full, dir, dirlen);
- _XcursorAddPathElt (full, theme, themelen);
- return full;
+ const char *colon;
+ const char *tcolon;
+ char *full;
+ const char *home, *homesep;
+ int dirlen;
+ int homelen;
+ int themelen;
+ size_t full_size;
+
+ if (!dir || !theme)
+ return NULL;
+
+ colon = strchr(dir, ':');
+ if (!colon)
+ colon = dir + strlen(dir);
+
+ dirlen = colon - dir;
+
+ tcolon = strchr(theme, ':');
+ if (!tcolon)
+ tcolon = theme + strlen(theme);
+
+ themelen = tcolon - theme;
+
+ home = "";
+ homelen = 0;
+ homesep = "";
+ if (*dir == '~') {
+ home = getenv("HOME");
+ if (!home)
+ return NULL;
+ homelen = strlen(home);
+ homesep = "/";
+ dir++;
+ dirlen--;
+ }
+
+ /*
+ * add space for any needed directory separators, one per component,
+ * and one for the trailing null
+ */
+ full_size = 1 + homelen + 1 + dirlen + 1 + themelen + 1;
+ full = malloc(full_size);
+ if (!full)
+ return NULL;
+ snprintf(full, full_size, "%s%s%.*s/%.*s", home, homesep,
+ dirlen, dir, themelen, theme);
+ return full;
}
static char *
-_XcursorBuildFullname (const char *dir, const char *subdir, const char *file)
+xcursor_build_fullname(const char *dir, const char *subdir, const char *file)
{
- char *full;
-
- if (!dir || !subdir || !file)
- return NULL;
-
- full = malloc (strlen (dir) + 1 + strlen (subdir) + 1 + strlen (file) + 1);
- if (!full)
- return NULL;
- full[0] = '\0';
- _XcursorAddPathElt (full, dir, -1);
- _XcursorAddPathElt (full, subdir, -1);
- _XcursorAddPathElt (full, file, -1);
- return full;
+ char *full;
+ size_t full_size;
+
+ if (!dir || !subdir || !file)
+ return NULL;
+
+ full_size = strlen(dir) + 1 + strlen(subdir) + 1 + strlen(file) + 1;
+ full = malloc(full_size);
+ if (!full)
+ return NULL;
+ snprintf(full, full_size, "%s/%s/%s", dir, subdir, file);
+ return full;
}
static const char *
-_XcursorNextPath (const char *path)
+xcursor_next_path(const char *path)
{
- char *colon = strchr (path, ':');
+ char *colon = strchr(path, ':');
- if (!colon)
- return NULL;
- return colon + 1;
+ if (!colon)
+ return NULL;
+ return colon + 1;
}
-#define XcursorWhite(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
-#define XcursorSep(c) ((c) == ';' || (c) == ',')
+static bool
+xcursor_white(char c)
+{
+ return c == ' ' || c == '\t' || c == '\n';
+}
+
+static bool
+xcursor_sep(char c)
+{
+ return c == ';' || c == ',';
+}
static char *
-_XcursorThemeInherits (const char *full)
+xcursor_theme_inherits(const char *full)
{
- char line[8192];
- char *result = NULL;
- FILE *f;
-
- if (!full)
- return NULL;
-
- f = fopen (full, "r");
- if (f)
- {
- while (fgets (line, sizeof (line), f))
- {
- if (!strncmp (line, "Inherits", 8))
- {
- char *l = line + 8;
- char *r;
- while (*l == ' ') l++;
- if (*l != '=') continue;
+ char *line = NULL;
+ size_t line_size = 0;
+ char *result = NULL;
+ FILE *f;
+
+ if (!full)
+ return NULL;
+
+ f = fopen(full, "r");
+ if (!f)
+ return NULL;
+
+ while (getline(&line, &line_size, f) >= 0) {
+ const char *l;
+ char *r;
+
+ if (strncmp(line, "Inherits", 8))
+ continue;
+
+ l = line + 8;
+ while (*l == ' ')
+ l++;
+ if (*l != '=')
+ continue;
l++;
- while (*l == ' ') l++;
- result = malloc (strlen (l) + 1);
- if (result)
- {
- r = result;
- while (*l)
- {
- while (XcursorSep(*l) || XcursorWhite (*l)) l++;
+ while (*l == ' ')
+ l++;
+ result = malloc(strlen(l) + 1);
+ if (!result)
+ break;
+
+ r = result;
+ while (*l) {
+ while (xcursor_sep(*l) || xcursor_white(*l))
+ l++;
if (!*l)
- break;
+ break;
if (r != result)
- *r++ = ':';
- while (*l && !XcursorWhite(*l) &&
- !XcursorSep(*l))
- *r++ = *l++;
- }
- *r++ = '\0';
+ *r++ = ':';
+ while (*l && !xcursor_white(*l) && !xcursor_sep(*l))
+ *r++ = *l++;
}
+ *r++ = '\0';
+
break;
- }
}
- fclose (f);
- }
- return result;
-}
-static FILE *
-XcursorScanTheme (const char *theme, const char *name)
-{
- FILE *f = NULL;
- char *full;
- char *dir;
- const char *path;
- char *inherits = NULL;
- const char *i;
-
- if (!theme || !name)
- return NULL;
-
- /*
- * Scan this theme
- */
- for (path = XcursorLibraryPath ();
- path && f == NULL;
- path = _XcursorNextPath (path))
- {
- dir = _XcursorBuildThemeDir (path, theme);
- if (dir)
- {
- full = _XcursorBuildFullname (dir, "cursors", name);
- if (full)
- {
- f = fopen (full, "r");
- free (full);
- }
- if (!f && !inherits)
- {
- full = _XcursorBuildFullname (dir, "", "index.theme");
- if (full)
- {
- inherits = _XcursorThemeInherits (full);
- free (full);
- }
- }
- free (dir);
- }
- }
- /*
- * Recurse to scan inherited themes
- */
- for (i = inherits; i && f == NULL; i = _XcursorNextPath (i))
- f = XcursorScanTheme (i, name);
- if (inherits != NULL)
- free (inherits);
- return f;
-}
+ fclose(f);
+ free(line);
-XcursorImages *
-XcursorLibraryLoadImages (const char *file, const char *theme, int size)
-{
- FILE *f = NULL;
- XcursorImages *images = NULL;
-
- if (!file)
- return NULL;
-
- if (theme)
- f = XcursorScanTheme (theme, file);
- if (!f)
- f = XcursorScanTheme ("default", file);
- if (f)
- {
- images = XcursorFileLoadImages (f, size);
- if (images)
- XcursorImagesSetName (images, file);
- fclose (f);
- }
- return images;
+ return result;
}
static void
load_all_cursors_from_dir(const char *path, int size,
- void (*load_callback)(XcursorImages *, void *),
+ void (*load_callback)(struct xcursor_images *, void *),
void *user_data)
{
FILE *f;
DIR *dir = opendir(path);
struct dirent *ent;
char *full;
- XcursorImages *images;
+ struct xcursor_images *images;
if (!dir)
return;
- for(ent = readdir(dir); ent; ent = readdir(dir)) {
+ for (ent = readdir(dir); ent; ent = readdir(dir)) {
#ifdef _DIRENT_HAVE_D_TYPE
if (ent->d_type != DT_UNKNOWN &&
- (ent->d_type != DT_REG && ent->d_type != DT_LNK))
+ ent->d_type != DT_REG &&
+ ent->d_type != DT_LNK)
continue;
#endif
- full = _XcursorBuildFullname(path, "", ent->d_name);
+ full = xcursor_build_fullname(path, "", ent->d_name);
if (!full)
continue;
@@ -899,14 +707,14 @@ load_all_cursors_from_dir(const char *path, int size,
continue;
}
- images = XcursorFileLoadImages(f, size);
+ images = xcursor_xc_file_load_images(f, size);
if (images) {
- XcursorImagesSetName(images, ent->d_name);
+ images->name = strdup(ent->d_name);
load_callback(images, user_data);
}
- fclose (f);
+ fclose(f);
free(full);
}
@@ -916,63 +724,60 @@ load_all_cursors_from_dir(const char *path, int size,
/** 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
+ * 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 XcursorImages
+ * will be called multiple times, with possibly different struct xcursor_images
* object which have the same name. The user is expected to destroy the
- * XcursorImages objects passed to the callback with
- * XcursorImagesDestroy().
+ * 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 XcursorImages
+ * 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)(XcursorImages *, void *),
- void *user_data)
+ void (*load_callback)(struct xcursor_images *, void *),
+ void *user_data)
{
char *full, *dir;
char *inherits = NULL;
const char *path, *i;
+ char *xcursor_path;
if (!theme)
theme = "default";
- for (path = XcursorLibraryPath();
+ xcursor_path = xcursor_library_path();
+ for (path = xcursor_path;
path;
- path = _XcursorNextPath(path)) {
- dir = _XcursorBuildThemeDir(path, theme);
+ path = xcursor_next_path(path)) {
+ dir = xcursor_build_theme_dir(path, theme);
if (!dir)
continue;
- full = _XcursorBuildFullname(dir, "cursors", "");
-
- if (full) {
- load_all_cursors_from_dir(full, size, load_callback,
- user_data);
- free(full);
- }
+ full = xcursor_build_fullname(dir, "cursors", "");
+ 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);
- }
+ full = xcursor_build_fullname(dir, "", "index.theme");
+ inherits = xcursor_theme_inherits(full);
+ free(full);
}
free(dir);
}
- for (i = inherits; i; i = _XcursorNextPath(i))
+ for (i = inherits; i; i = xcursor_next_path(i))
xcursor_load_theme(i, size, load_callback, user_data);
- if (inherits)
- free(inherits);
+ free(inherits);
+ free(xcursor_path);
}