/* * Manipulating twin cursor images * * Copyright 2006 Benjamin Herrenschmidt * * This Library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This Library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with the Twin Library; see the file COPYING. If not, * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include "twin.h" /* Make something better here ! */ static unsigned int twin_def_cursor_image[] = { 0x00000000, 0x88ffffff, 0x88ffffff, 0x00000000, 0x88ffffff, 0xff000000, 0xff000000, 0x88ffffff, 0x88ffffff, 0xff000000, 0xff000000, 0x88ffffff, 0x00000000, 0x88ffffff, 0x88ffffff, 0x00000000, }; twin_pixmap_t *twin_get_default_cursor(int *hx, int *hy) { twin_pixmap_t *cur; twin_pointer_t data; data.argb32 = twin_def_cursor_image; cur = twin_pixmap_create_const(TWIN_ARGB32, 4, 4, 16, data); if (cur == NULL) return NULL; *hx = *hy = 2; return cur; } /* * Bits extracted from Xcursor */ #define XCURSOR_MAGIC 0x72756358 /* "Xcur" LSBFirst */ #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) /* * 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: * 0 CARD32 magic magic number * 1 CARD32 header bytes in file header * 2 CARD32 version file version * 3 CARD32 ntoc number of toc entries * LISTofFileToc toc table of contents * * FileToc: * 0 CARD32 type entry type * 1 CARD32 subtype entry subtype (size for images) * 2 CARD32 position absolute file position */ /* * The rest of the file is a list of chunks, each tagged by type * and version. * * Chunk: * ChunkHeader * * * * ChunkHeader: * 0 CARD32 header bytes in chunk header + type header * 1 CARD32 type chunk type * 2 CARD32 subtype chunk subtype * 3 CARD32 version chunk type version */ #define XCURSOR_CHUNK_HEADER_LEN (4 * 4) /* * 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: * 0 ChunkHeader header chunk header * 4 CARD32 width actual width * 5 CARD32 height actual height * 6 CARD32 xhot hot spot x * 7 CARD32 yhot hot spot y * 8 CARD32 delay animation delay * 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 */ static inline int twin_read_header(int fd, uint32_t *buf, int size) { int i, len; len = read(fd, buf, size); if (len != size) return 0; #if __BYTE_ORDER == __BIG_ENDIAN for (i = 0; i < (len / 4); i++) buf[i] = bswap_32(buf[i]); #endif return 1; } twin_pixmap_t *twin_load_X_cursor(const char *file, int index, int *hx, int *hy) { int fd, img, i, toccnt; uint32_t buffer[32], filepos, size; twin_pixmap_t *cur = NULL; fd = open(file, O_RDONLY); if (fd < 0) return NULL; if (!twin_read_header(fd, buffer, XCURSOR_FILE_HEADER_LEN)) goto bail; /* check magic */ if (buffer[0] != XCURSOR_MAGIC) goto bail; /* check version. assume we support all minor versions */ if ((buffer[2] >> 16) != XCURSOR_FILE_MAJOR) goto bail; /* get number of TOC entries */ toccnt = buffer[3]; /* seek to first toc entry (header len) */ lseek(fd, buffer[1] , SEEK_SET); /* look for the index'th image in TOC */ img = 0; filepos = 0; for (i = 0; filepos == 0 && i < toccnt; i++) { if (!twin_read_header(fd, buffer, XCURSOR_FILE_TOC_LEN)) goto bail; if (buffer[0] == XCURSOR_IMAGE_TYPE) { if (img == index) filepos = buffer[2]; img++; } } /* check if found */ if (filepos == 0) goto bail; /* seek to image header and read it */ lseek(fd, filepos, SEEK_SET); if (!twin_read_header(fd, buffer, XCURSOR_IMAGE_HEADER_LEN)) goto bail; /* check chunk type */ if (buffer[1] != XCURSOR_IMAGE_TYPE) goto bail; /* check image version */ if (buffer[3] != XCURSOR_IMAGE_VERSION) goto bail; /* get hotspot */ *hx = buffer[6]; *hy = buffer[7]; /* create pixmap */ cur = twin_pixmap_create(TWIN_ARGB32, buffer[4], buffer[5]); if (cur == NULL) goto bail; /* load pixels */ size = buffer[4] * buffer[5] * 4; lseek(fd, filepos + buffer[0], SEEK_SET); if (read(fd, cur->p.v, size) != size) { twin_pixmap_destroy(cur); goto bail; } #if __BYTE_ORDER == __BIG_ENDIAN for (i = 0; i < (size / 4); i++) cur->p.argb32[i] = bswap_32(cur->p.argb32[i]); #endif bail: close(fd); return cur; }