mirror of
https://gitlab.freedesktop.org/xorg/lib/libxcursor.git
synced 2025-12-20 10:30:14 +01:00
Initial revision
This commit is contained in:
commit
3b84b14bf0
8 changed files with 3975 additions and 0 deletions
476
include/X11/Xcursor/Xcursor.h
Normal file
476
include/X11/Xcursor/Xcursor.h
Normal file
|
|
@ -0,0 +1,476 @@
|
||||||
|
/*
|
||||||
|
* $XFree86: xc/lib/Xcursor/Xcursor.h,v 1.4 2003/01/26 03:22:42 eich Exp $
|
||||||
|
*
|
||||||
|
* Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||||
|
* documentation for any purpose is hereby granted without fee, provided that
|
||||||
|
* the above copyright notice appear in all copies and that both that
|
||||||
|
* copyright notice and this permission notice appear in supporting
|
||||||
|
* documentation, and that the name of Keith Packard not be used in
|
||||||
|
* advertising or publicity pertaining to distribution of the software without
|
||||||
|
* specific, written prior permission. Keith Packard makes no
|
||||||
|
* representations about the suitability of this software for any purpose. It
|
||||||
|
* is provided "as is" without express or implied warranty.
|
||||||
|
*
|
||||||
|
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||||
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||||
|
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||||
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||||
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _XCURSOR_H_
|
||||||
|
#define _XCURSOR_H_
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <X11/Xfuncproto.h>
|
||||||
|
|
||||||
|
typedef int XcursorBool;
|
||||||
|
typedef unsigned int XcursorUInt;
|
||||||
|
|
||||||
|
typedef XcursorUInt XcursorDim;
|
||||||
|
typedef XcursorUInt XcursorPixel;
|
||||||
|
|
||||||
|
#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
|
||||||
|
* 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 0x72756358 /* "Xcur" LSBFirst */
|
||||||
|
|
||||||
|
#define XCURSOR_MAJOR 1
|
||||||
|
#define XCURSOR_MINOR 0
|
||||||
|
#define XCURSOR_VERSION ((XCURSOR_MAJOR << 16) | (XCURSOR_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;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 (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;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 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 _XcursorImage {
|
||||||
|
XcursorUInt version; /* version of the image data */
|
||||||
|
XcursorDim size; /* nominal size for matching */
|
||||||
|
XcursorDim width; /* actual width */
|
||||||
|
XcursorDim height; /* actual height */
|
||||||
|
XcursorDim xhot; /* hot spot x (must be inside image) */
|
||||||
|
XcursorDim yhot; /* hot spot y (must be inside image) */
|
||||||
|
XcursorUInt delay; /* animation delay to next frame (ms) */
|
||||||
|
XcursorPixel *pixels; /* pointer to pixels */
|
||||||
|
} XcursorImage;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Other data structures exposed by the library API
|
||||||
|
*/
|
||||||
|
typedef struct _XcursorImages {
|
||||||
|
int nimage; /* number of images */
|
||||||
|
XcursorImage **images; /* array of XcursorImage pointers */
|
||||||
|
} XcursorImages;
|
||||||
|
|
||||||
|
typedef struct _XcursorCursors {
|
||||||
|
Display *dpy; /* Display holding cursors */
|
||||||
|
int ref; /* reference count */
|
||||||
|
int ncursor; /* number of cursors */
|
||||||
|
Cursor *cursors; /* array of cursors */
|
||||||
|
} XcursorCursors;
|
||||||
|
|
||||||
|
typedef struct _XcursorAnimate {
|
||||||
|
XcursorCursors *cursors; /* list of cursors to use */
|
||||||
|
int sequence; /* which cursor is next */
|
||||||
|
} XcursorAnimate;
|
||||||
|
|
||||||
|
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_CORE_THEME "core"
|
||||||
|
|
||||||
|
_XFUNCPROTOBEGIN
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Manage Image objects
|
||||||
|
*/
|
||||||
|
XcursorImage *
|
||||||
|
XcursorImageCreate (int width, int height);
|
||||||
|
|
||||||
|
void
|
||||||
|
XcursorImageDestroy (XcursorImage *image);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Manage Images objects
|
||||||
|
*/
|
||||||
|
XcursorImages *
|
||||||
|
XcursorImagesCreate (int size);
|
||||||
|
|
||||||
|
void
|
||||||
|
XcursorImagesDestroy (XcursorImages *images);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Manage Cursor objects
|
||||||
|
*/
|
||||||
|
XcursorCursors *
|
||||||
|
XcursorCursorsCreate (Display *dpy, int size);
|
||||||
|
|
||||||
|
void
|
||||||
|
XcursorCursorsDestroy (XcursorCursors *cursors);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Manage Animate objects
|
||||||
|
*/
|
||||||
|
XcursorAnimate *
|
||||||
|
XcursorAnimateCreate (XcursorCursors *cursors);
|
||||||
|
|
||||||
|
void
|
||||||
|
XcursorAnimateDestroy (XcursorAnimate *animate);
|
||||||
|
|
||||||
|
Cursor
|
||||||
|
XcursorAnimateNext (XcursorAnimate *animate);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Manage Comment objects
|
||||||
|
*/
|
||||||
|
XcursorComment *
|
||||||
|
XcursorCommentCreate (XcursorUInt comment_type, int length);
|
||||||
|
|
||||||
|
void
|
||||||
|
XcursorCommentDestroy (XcursorComment *comment);
|
||||||
|
|
||||||
|
XcursorComments *
|
||||||
|
XcursorCommentsCreate (int size);
|
||||||
|
|
||||||
|
void
|
||||||
|
XcursorCommentsDestroy (XcursorComments *comments);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XcursorFile/Image APIs
|
||||||
|
*/
|
||||||
|
XcursorImage *
|
||||||
|
XcursorXcFileLoadImage (XcursorFile *file, int size);
|
||||||
|
|
||||||
|
XcursorImages *
|
||||||
|
XcursorXcFileLoadImages (XcursorFile *file, int size);
|
||||||
|
|
||||||
|
XcursorImages *
|
||||||
|
XcursorXcFileLoadAllImages (XcursorFile *file);
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorXcFileLoad (XcursorFile *file,
|
||||||
|
XcursorComments **commentsp,
|
||||||
|
XcursorImages **imagesp);
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorXcFileSave (XcursorFile *file,
|
||||||
|
const XcursorComments *comments,
|
||||||
|
const XcursorImages *images);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FILE/Image APIs
|
||||||
|
*/
|
||||||
|
XcursorImage *
|
||||||
|
XcursorFileLoadImage (FILE *file, int size);
|
||||||
|
|
||||||
|
XcursorImages *
|
||||||
|
XcursorFileLoadImages (FILE *file, int size);
|
||||||
|
|
||||||
|
XcursorImages *
|
||||||
|
XcursorFileLoadAllImages (FILE *file);
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorFileLoad (FILE *file,
|
||||||
|
XcursorComments **commentsp,
|
||||||
|
XcursorImages **imagesp);
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorFileSaveImages (FILE *file, const XcursorImages *images);
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorFileSave (FILE * file,
|
||||||
|
const XcursorComments *comments,
|
||||||
|
const XcursorImages *images);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Filename/Image APIs
|
||||||
|
*/
|
||||||
|
XcursorImage *
|
||||||
|
XcursorFilenameLoadImage (const char *filename, int size);
|
||||||
|
|
||||||
|
XcursorImages *
|
||||||
|
XcursorFilenameLoadImages (const char *filename, int size);
|
||||||
|
|
||||||
|
XcursorImages *
|
||||||
|
XcursorFilenameLoadAllImages (const char *filename);
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorFilenameLoad (const char *file,
|
||||||
|
XcursorComments **commentsp,
|
||||||
|
XcursorImages **imagesp);
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorFilenameSaveImages (const char *filename, const XcursorImages *images);
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorFilenameSave (const char *file,
|
||||||
|
const XcursorComments *comments,
|
||||||
|
const XcursorImages *images);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Library/Image APIs
|
||||||
|
*/
|
||||||
|
XcursorImage *
|
||||||
|
XcursorLibraryLoadImage (const char *library, const char *theme, int size);
|
||||||
|
|
||||||
|
XcursorImages *
|
||||||
|
XcursorLibraryLoadImages (const char *library, const char *theme, int size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Library/shape API
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
XcursorLibraryShape (const char *library);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Image/Cursor APIs
|
||||||
|
*/
|
||||||
|
|
||||||
|
Cursor
|
||||||
|
XcursorImageLoadCursor (Display *dpy, const XcursorImage *image);
|
||||||
|
|
||||||
|
XcursorCursors *
|
||||||
|
XcursorImagesLoadCursors (Display *dpy, const XcursorImages *images);
|
||||||
|
|
||||||
|
Cursor
|
||||||
|
XcursorImagesLoadCursor (Display *dpy, const XcursorImages *images);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Filename/Cursor APIs
|
||||||
|
*/
|
||||||
|
Cursor
|
||||||
|
XcursorFilenameLoadCursor (Display *dpy, const char *file);
|
||||||
|
|
||||||
|
XcursorCursors *
|
||||||
|
XcursorFilenameLoadCursors (Display *dpy, const char *file);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Library/Cursor APIs
|
||||||
|
*/
|
||||||
|
Cursor
|
||||||
|
XcursorLibraryLoadCursor (Display *dpy, const char *file);
|
||||||
|
|
||||||
|
XcursorCursors *
|
||||||
|
XcursorLibraryLoadCursors (Display *dpy, const char *file);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shape/Image APIs
|
||||||
|
*/
|
||||||
|
|
||||||
|
XcursorImage *
|
||||||
|
XcursorShapeLoadImage (unsigned int shape, const char *theme, int size);
|
||||||
|
|
||||||
|
XcursorImages *
|
||||||
|
XcursorShapeLoadImages (unsigned int shape, const char *theme, int size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shape/Cursor APIs
|
||||||
|
*/
|
||||||
|
Cursor
|
||||||
|
XcursorShapeLoadCursor (Display *dpy, unsigned int shape);
|
||||||
|
|
||||||
|
XcursorCursors *
|
||||||
|
XcursorShapeLoadCursors (Display *dpy, unsigned int shape);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the function called by Xlib when attempting to
|
||||||
|
* load cursors from XCreateGlyphCursor. The interface must
|
||||||
|
* not change as Xlib loads 'libXcursor.so' instead of
|
||||||
|
* a specific major version
|
||||||
|
*/
|
||||||
|
Cursor
|
||||||
|
XcursorTryShapeCursor (Display *dpy,
|
||||||
|
Font source_font,
|
||||||
|
Font mask_font,
|
||||||
|
unsigned int source_char,
|
||||||
|
unsigned int mask_char,
|
||||||
|
XColor _Xconst *foreground,
|
||||||
|
XColor _Xconst *background);
|
||||||
|
|
||||||
|
void
|
||||||
|
XcursorNoticeCreateBitmap (Display *dpy,
|
||||||
|
Pixmap pid,
|
||||||
|
unsigned int width,
|
||||||
|
unsigned int height);
|
||||||
|
|
||||||
|
void
|
||||||
|
XcursorNoticePutBitmap (Display *dpy,
|
||||||
|
Drawable draw,
|
||||||
|
XImage *image);
|
||||||
|
|
||||||
|
Cursor
|
||||||
|
XcursorTryShapeBitmapCursor (Display *dpy,
|
||||||
|
Pixmap source,
|
||||||
|
Pixmap mask,
|
||||||
|
XColor *foreground,
|
||||||
|
XColor *background,
|
||||||
|
unsigned int x,
|
||||||
|
unsigned int y);
|
||||||
|
|
||||||
|
#define XCURSOR_BITMAP_HASH_SIZE 16
|
||||||
|
|
||||||
|
void
|
||||||
|
XcursorImageHash (XImage *image,
|
||||||
|
unsigned char hash[XCURSOR_BITMAP_HASH_SIZE]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Display information APIs
|
||||||
|
*/
|
||||||
|
XcursorBool
|
||||||
|
XcursorSupportsARGB (Display *dpy);
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorSupportsAnim (Display *dpy);
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorSetDefaultSize (Display *dpy, int size);
|
||||||
|
|
||||||
|
int
|
||||||
|
XcursorGetDefaultSize (Display *dpy);
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorSetTheme (Display *dpy, const char *theme);
|
||||||
|
|
||||||
|
char *
|
||||||
|
XcursorGetTheme (Display *dpy);
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorGetThemeCore (Display *dpy);
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorSetThemeCore (Display *dpy, XcursorBool theme_core);
|
||||||
|
|
||||||
|
_XFUNCPROTOEND
|
||||||
|
|
||||||
|
#endif
|
||||||
379
man/Xcursor.man
Normal file
379
man/Xcursor.man
Normal file
|
|
@ -0,0 +1,379 @@
|
||||||
|
.\"
|
||||||
|
.\" $XFree86: xc/lib/Xcursor/Xcursor.man,v 1.2 2003/02/13 03:09:04 dawes Exp $
|
||||||
|
.\"
|
||||||
|
.\" Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
|
||||||
|
.\"
|
||||||
|
.\" Permission to use, copy, modify, distribute, and sell this software and its
|
||||||
|
.\" documentation for any purpose is hereby granted without fee, provided that
|
||||||
|
.\" the above copyright notice appear in all copies and that both that
|
||||||
|
.\" copyright notice and this permission notice appear in supporting
|
||||||
|
.\" documentation, and that the name of Keith Packard not be used in
|
||||||
|
.\" advertising or publicity pertaining to distribution of the software without
|
||||||
|
.\" specific, written prior permission. Keith Packard makes no
|
||||||
|
.\" representations about the suitability of this software for any purpose. It
|
||||||
|
.\" is provided "as is" without express or implied warranty.
|
||||||
|
.\"
|
||||||
|
.\" KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||||
|
.\" INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||||
|
.\" EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||||
|
.\" CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||||
|
.\" DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
.\" TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
.\" PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
.\"
|
||||||
|
.de TQ
|
||||||
|
.br
|
||||||
|
.ns
|
||||||
|
.TP \\$1
|
||||||
|
..
|
||||||
|
.TH XCURSOR 3 "Version 1.0" "XFree86"
|
||||||
|
|
||||||
|
.SH NAME
|
||||||
|
XCURSOR \- Cursor management library
|
||||||
|
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.nf
|
||||||
|
.B #include <X11/Xcursor/Xcursor.h>
|
||||||
|
.fi
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B Xcursor
|
||||||
|
is a simple library designed to help locate and load cursors. Cursors can
|
||||||
|
be loaded from files or memory. A library of common cursors exists which
|
||||||
|
map to the standard X cursor names. Cursors can exist in several sizes and
|
||||||
|
the library automatically picks the best size.
|
||||||
|
|
||||||
|
.SH FUNCTIONAL OVERVIEW
|
||||||
|
Xcursor is built in a couple of layers; at the bottom layer is code which
|
||||||
|
can load cursor images from files. Above that is a layer which locates
|
||||||
|
cursor files based on the library path and theme. At the top is a layer
|
||||||
|
which builds cursors either out of an image loaded from a file or one of the
|
||||||
|
standard X cursors. When using images loaded from files, Xcursor prefers
|
||||||
|
to use the Render extension CreateCursor request if supported by the X
|
||||||
|
server. Where not supported, Xcursor maps the cursor image to a standard X
|
||||||
|
cursor and uses the core CreateCursor request.
|
||||||
|
|
||||||
|
.SS CURSOR FILES
|
||||||
|
Xcursor defines a new format for cursors on disk. Each file holds
|
||||||
|
one or more cursor images. Each cursor image is tagged with a nominal size
|
||||||
|
so that the best size can be selected automatically. Multiple cursors of
|
||||||
|
the same nominal size can be loaded together; applications are expected to
|
||||||
|
use them as an animated sequence.
|
||||||
|
.P
|
||||||
|
Cursor files are stored as a header containing a table of contents followed
|
||||||
|
by a sequence of chunks. The table of contents indicates the type, subtype
|
||||||
|
and position in the file of each chunk. The file header looks like:
|
||||||
|
.LP
|
||||||
|
.in +.2i
|
||||||
|
\fImagic\fP\^: CARD32 'Xcur' (0x58, 0x63, 0x75, 0x72)
|
||||||
|
.br
|
||||||
|
\fIheader\fP\^: CARD32 bytes in this header
|
||||||
|
.br
|
||||||
|
\fIversion\fP\^: CARD32 file version number
|
||||||
|
.br
|
||||||
|
\fIntoc\fP\^: CARD32 number of toc entries
|
||||||
|
\fItoc\fP\^: LISTofTOC table of contents
|
||||||
|
.in -.2i
|
||||||
|
.P
|
||||||
|
Each table of contents entry looks like:
|
||||||
|
.LP
|
||||||
|
.in +.2i
|
||||||
|
\fItype\fP\^: CARD32 entry type
|
||||||
|
\fIsubtype\fP\^: CARD32 type-specific label - size for images
|
||||||
|
\fIposition\fP\^: CARD32 absolute byte position of table in file
|
||||||
|
.in -.2i
|
||||||
|
.P
|
||||||
|
.P
|
||||||
|
Each chunk in the file has set of common header fields followed by
|
||||||
|
additional type-specific fields:
|
||||||
|
.LP
|
||||||
|
.in +.2i
|
||||||
|
\fIheader\fP\^: CARD32 bytes in chunk header (including type-specific fields)
|
||||||
|
.br
|
||||||
|
\fItype\fP\^: CARD32 must match type in TOC for this chunk
|
||||||
|
.br
|
||||||
|
\fIsubtype\fP\^: CARD32 must match subtype in TOC for this chunk
|
||||||
|
.br
|
||||||
|
\fIversion\fP\^: CARD32 version number for this chunk type
|
||||||
|
.in -.2i
|
||||||
|
.P
|
||||||
|
There are currently two chunk types defined for cursor files; comments and
|
||||||
|
images. Comments look like:
|
||||||
|
.LP
|
||||||
|
.in +.2i
|
||||||
|
\fIheader\fP\^: 20 Comment headers are 20 bytes
|
||||||
|
.br
|
||||||
|
\fItype\fP\^: 0xfffe0001 Comment type is 0xfffe0001
|
||||||
|
.br
|
||||||
|
\fIsubtype\fP\^: { 1 (COPYRIGHT), 2 (LICENSE), 3 (OTHER) }
|
||||||
|
.br
|
||||||
|
\fIversion\fP\^: 1
|
||||||
|
.br
|
||||||
|
\fIlength\fP\^: CARD32 byte length of UTF-8 string
|
||||||
|
.br
|
||||||
|
\fIstring\fP\^: LISTofCARD8 UTF-8 string
|
||||||
|
.in -.2i
|
||||||
|
.P
|
||||||
|
Images look like:
|
||||||
|
.LP
|
||||||
|
.in +.2i
|
||||||
|
\fIheader\fP\^: 36 Image headers are 36 bytes
|
||||||
|
.br
|
||||||
|
\fItype\fP\^: 0xfffd0002 Image type is 0xfffd0002
|
||||||
|
.br
|
||||||
|
\fIsubtype\fP\^: CARD32 Image subtype is the nominal size
|
||||||
|
.br
|
||||||
|
\fIversion\fP\^: 1
|
||||||
|
.br
|
||||||
|
\fIwidth\fP\^: CARD32 Must be less than or equal to 0x7fff
|
||||||
|
.br
|
||||||
|
\fIheight\fP\^: CARD32 Must be less than or equal to 0x7fff
|
||||||
|
.br
|
||||||
|
\fIxhot\fP\^: CARD32 Must be less than or equal to width
|
||||||
|
.br
|
||||||
|
\fIyhot\fP\^: CARD32 Must be less than or equal to height
|
||||||
|
.br
|
||||||
|
\fIdelay\fP\^: CARD32 Delay between animation frames in milliseconds
|
||||||
|
.br
|
||||||
|
\fIpixels\fP\^: LISTofCARD32 Packed ARGB format pixels
|
||||||
|
.in -.2i
|
||||||
|
|
||||||
|
.SS THEMES
|
||||||
|
Xcursor (mostly) follows the freedesktop.org spec for theming icons. The
|
||||||
|
default search path it uses is $HOME/.icons, /usr/share/icons,
|
||||||
|
/usr/share/pimaps, /usr/X11R6/lib/X11/icons. Within each of these
|
||||||
|
directorys, it searches for a directory using the theme name. Within the
|
||||||
|
theme directory, it looks for cursor files in the 'cursors' subdirectory.
|
||||||
|
It uses the first cursor file found along the path.
|
||||||
|
.PP
|
||||||
|
If necessary, Xcursor also looks for a "index.theme" file in each theme
|
||||||
|
directory to find inherited themes and searches along the path for those
|
||||||
|
themes as well.
|
||||||
|
.PP
|
||||||
|
If no theme is set, or if no cursor is found for the specified theme,
|
||||||
|
Xcursor checks the "default" theme.
|
||||||
|
|
||||||
|
.SH DATATYPES
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B XcursorImage
|
||||||
|
holds a single cursor image in memory. Each pixel in the cursor is a 32-bit
|
||||||
|
value containing ARGB with A in the high byte.
|
||||||
|
.sp
|
||||||
|
.nf
|
||||||
|
.ft CR
|
||||||
|
typedef struct _XcursorImage {
|
||||||
|
XcursorDim size; /* nominal size for matching */
|
||||||
|
XcursorDim width; /* actual width */
|
||||||
|
XcursorDim height; /* actual height */
|
||||||
|
XcursorDim xhot; /* hot spot x (must be inside image) */
|
||||||
|
XcursorDim yhot; /* hot spot y (must be inside image) */
|
||||||
|
XcursorPixel *pixels; /* pointer to pixels */
|
||||||
|
} XcursorImage;
|
||||||
|
.ft
|
||||||
|
.fi
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B XcursorImages
|
||||||
|
holds multiple XcursorImage structures. They're all freed when the
|
||||||
|
XcursorImages is freed.
|
||||||
|
.sp
|
||||||
|
.nf
|
||||||
|
.ft CR
|
||||||
|
typedef struct _XcursorImages {
|
||||||
|
int nimage; /* number of images */
|
||||||
|
XcursorImage **images; /* array of XcursorImage pointers */
|
||||||
|
} XcursorImages;
|
||||||
|
.ft
|
||||||
|
.fi
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B XcursorCursors
|
||||||
|
Holds multiple Cursor objects. They're all freed when the XcursorCursors is
|
||||||
|
freed. These are reference counted so that multiple XcursorAnimate
|
||||||
|
structures can use the same XcursorCursors.
|
||||||
|
.sp
|
||||||
|
.nf
|
||||||
|
.ft CR
|
||||||
|
typedef struct _XcursorCursors {
|
||||||
|
Display *dpy; /* Display holding cursors */
|
||||||
|
int ref; /* reference count */
|
||||||
|
int ncursor; /* number of cursors */
|
||||||
|
Cursor *cursors; /* array of cursors */
|
||||||
|
} XcursorCursors;
|
||||||
|
.ft
|
||||||
|
.fi
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B XcursorAnimate
|
||||||
|
References a set of cursors and a sequence within that set. Multiple
|
||||||
|
XcursorAnimate structures may reference the same XcursorCursors; each
|
||||||
|
holds a reference which is removed when the XcursorAnimate is freed.
|
||||||
|
.sp
|
||||||
|
.nf
|
||||||
|
.ft CR
|
||||||
|
typedef struct _XcursorAnimate {
|
||||||
|
XcursorCursors *cursors; /* list of cursors to use */
|
||||||
|
int sequence; /* which cursor is next */
|
||||||
|
} XcursorAnimate;
|
||||||
|
.ft
|
||||||
|
.fi
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B XcursorFile
|
||||||
|
Xcursor provides an abstract API for accessing the file data. Xcursor
|
||||||
|
provides a stdio implementation of this abstract API; applications
|
||||||
|
are free to create additional implementations. These functions
|
||||||
|
parallel the stdio functions in return value and expected argument values;
|
||||||
|
the read and write functions flip the arguments around to match the POSIX
|
||||||
|
versions.
|
||||||
|
.sp
|
||||||
|
.nf
|
||||||
|
.ft CR
|
||||||
|
typedef 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);
|
||||||
|
};
|
||||||
|
.ft
|
||||||
|
.fi
|
||||||
|
|
||||||
|
.SH FUNCTIONS
|
||||||
|
|
||||||
|
.SS Object Management
|
||||||
|
.TP
|
||||||
|
XcursorImage *XcursorImageCreate (int width, int height)
|
||||||
|
.TQ
|
||||||
|
void XcursorImageDestroy (XcursorImage *image)
|
||||||
|
Allocate and free images. On allocation, the hotspot and the pixels are
|
||||||
|
left uninitialized. The size is set to the maximum of width and height.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
XcursorImages *XcursorImagesCreate (int size)
|
||||||
|
.TQ
|
||||||
|
void XcursorImagesDestroy (XcursorImages *images)
|
||||||
|
Allocate and free arrays to hold multiple cursor images. On allocation,
|
||||||
|
nimage is set to zero.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
XcursorCursors *XcursorCursorsCreate (Display *dpy, int size)
|
||||||
|
.TQ
|
||||||
|
void XcursorCursorsDestroy (XcursorCursors *cursors)
|
||||||
|
Allocate and free arrays to hold multiple cursors. On allocation,
|
||||||
|
ncursor is set to zero, ref is set to one.
|
||||||
|
|
||||||
|
.SS Reading and writing images.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
XcursorImage *XcursorXcFileLoadImage (XcursorFile *file, int size)
|
||||||
|
.TQ
|
||||||
|
XcursorImages *XcursorXcFileLoadImages (XcursorFile *file, int size)
|
||||||
|
.TQ
|
||||||
|
XcursorImages *XcursorXcFileLoadAllImages (XcursorFile *file)
|
||||||
|
.TQ
|
||||||
|
XcursorBool XcursorXcFileLoad (XcursorFile *file, XcursorComments **commentsp, XcursorImages **imagesp)
|
||||||
|
.TQ
|
||||||
|
XcursorBool XcursorXcFileSave (XcursorFile *file, const XcursorComments *comments, const XcursorImages *images)
|
||||||
|
These read and write cursors from an XcursorFile handle. After reading, the
|
||||||
|
file pointer will be left at some random place in the file.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
XcursorImage *XcursorFileLoadImage (FILE *file, int size)
|
||||||
|
.TQ
|
||||||
|
XcursorImages *XcursorFileLoadImages (FILE *file, int size)
|
||||||
|
.TQ
|
||||||
|
XcursorImages *XcursorFileLoadAllImages (FILE *file)
|
||||||
|
.TQ
|
||||||
|
XcursorBool XcursorFileLoad (FILE *file, XcursorComments **commentsp, XcursorImages **imagesp)
|
||||||
|
.TQ
|
||||||
|
XcursorBool XcursorFileSaveImages (FILE *file, const XcursorImages *images)
|
||||||
|
.TQ
|
||||||
|
XcursorBool XcursorFileSave (FILE * file, const XcursorComments *comments, const XcursorImages *images)
|
||||||
|
These read and write cursors from a stdio FILE handle. Writing flushes
|
||||||
|
before returning so that any errors should be detected.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
XcursorImage *XcursorFilenameLoadImage (const char *filename, int size)
|
||||||
|
.TQ
|
||||||
|
XcursorImages *XcursorFilenameLoadImages (const char *filename, int size)
|
||||||
|
.TQ
|
||||||
|
XcursorImages *XcursorFilenameLoadAllImages (FILE *file)
|
||||||
|
.TQ
|
||||||
|
XcursorBool XcursorFilenameLoad (const char *file, XcursorComments **commentsp, XcursorImages **imagesp)
|
||||||
|
.TQ
|
||||||
|
XcursorBool XcursorFilenameSaveImages (const char *filename, const XcursorImages *images)
|
||||||
|
.TQ
|
||||||
|
XcursorBool XcursorFilenameSave (const char *file, const XcursorComments *comments, const XcursorImages *images)
|
||||||
|
These parallel the stdio FILE interfaces above, but take filenames.
|
||||||
|
|
||||||
|
.SS Reading library images
|
||||||
|
.TP
|
||||||
|
XcursorImage *XcursorLibraryLoadImage (const char *name, const char *theme, int size)
|
||||||
|
.TQ
|
||||||
|
XcursorImages *XcursorLibraryLoadImages (const char *name, const char *theme, int size)
|
||||||
|
These search the library path, loading the first file found. If 'theme' is
|
||||||
|
not NULL, these functions first try appending -theme to name and then
|
||||||
|
name alone.
|
||||||
|
|
||||||
|
.SS Cursor APIs
|
||||||
|
|
||||||
|
.TP
|
||||||
|
Cursor XcursorFilenameLoadCursor (Display *dpy, const char *file)
|
||||||
|
.TQ
|
||||||
|
XcursorCursors *XcursorFilenameLoadCursors (Display *dpy, const char *file)
|
||||||
|
These load cursors from the specified file.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
Cursor XcursorLibraryLoadCursor (Display *dpy, const char *name)
|
||||||
|
.TQ
|
||||||
|
XcursorCursors *XcursorLibraryLoadCursors (Display *dpy, const char *name)
|
||||||
|
These load cursors using the specified library name. The theme
|
||||||
|
comes from the display.
|
||||||
|
|
||||||
|
.SS X Cursor Name APIs
|
||||||
|
|
||||||
|
.TP
|
||||||
|
XcursorImage *XcursorShapeLoadImage (unsigned int shape, const char *theme, int size)
|
||||||
|
.TQ
|
||||||
|
XcursorImages *XcursorShapeLoadImages (unsigned int shape, const char *theme, int size)
|
||||||
|
These map 'shape' to a library name using the standard X cursor names and
|
||||||
|
then load the images.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
Cursor XcursorShapeLoadCursor (Display *dpy, unsigned int shape)
|
||||||
|
.TQ
|
||||||
|
XcursorCursors *XcursorShapeLoadCursors (Display *dpy, unsigned int shape)
|
||||||
|
These map 'shape' to a library name and then load the cursors.
|
||||||
|
|
||||||
|
.SS Display Information APIs
|
||||||
|
|
||||||
|
.TP
|
||||||
|
XcursorBool XcursorSupportsARGB (Display *dpy)
|
||||||
|
Returns whether the display supports ARGB cursors or whether cursors will be
|
||||||
|
mapped to a core X cursor.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
XcursorBool XcursorSetDefaultSize (Display *dpy, int size)
|
||||||
|
Sets the default size for cursors on the specified display. When loading
|
||||||
|
cursors, those who's nominal size is closest to this size will be preferred.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
int XcursorGetDefaultSize (Display *dpy)
|
||||||
|
Gets the default cursor size.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
XcursorBool
|
||||||
|
XcursorSetTheme (Display *dpy, const char *theme)
|
||||||
|
Sets the current theme name.
|
||||||
|
|
||||||
|
char *
|
||||||
|
XcursorGetTheme (Display *dpy)
|
||||||
|
Gets the current theme name.
|
||||||
|
|
||||||
|
.SH RESTRICTIONS
|
||||||
|
.B Xcursor
|
||||||
|
will probably change radically in the future; weak attempts will be made to
|
||||||
|
retain some level of source-file compatibility.
|
||||||
|
|
||||||
|
.SH AUTHOR
|
||||||
|
Keith Packard, member of the XFree86 Project, Inc.
|
||||||
810
src/cursor.c
Normal file
810
src/cursor.c
Normal file
|
|
@ -0,0 +1,810 @@
|
||||||
|
/*
|
||||||
|
* $XFree86: xc/lib/Xcursor/cursor.c,v 1.5 2003/01/26 03:22:42 eich Exp $
|
||||||
|
*
|
||||||
|
* Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||||
|
* documentation for any purpose is hereby granted without fee, provided that
|
||||||
|
* the above copyright notice appear in all copies and that both that
|
||||||
|
* copyright notice and this permission notice appear in supporting
|
||||||
|
* documentation, and that the name of Keith Packard not be used in
|
||||||
|
* advertising or publicity pertaining to distribution of the software without
|
||||||
|
* specific, written prior permission. Keith Packard makes no
|
||||||
|
* representations about the suitability of this software for any purpose. It
|
||||||
|
* is provided "as is" without express or implied warranty.
|
||||||
|
*
|
||||||
|
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||||
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||||
|
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||||
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||||
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xcursorint.h"
|
||||||
|
#include <X11/Xlibint.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
|
||||||
|
XcursorCursors *
|
||||||
|
XcursorCursorsCreate (Display *dpy, int size)
|
||||||
|
{
|
||||||
|
XcursorCursors *cursors;
|
||||||
|
|
||||||
|
cursors = malloc (sizeof (XcursorCursors) +
|
||||||
|
size * sizeof (Cursor));
|
||||||
|
if (!cursors)
|
||||||
|
return 0;
|
||||||
|
cursors->ref = 1;
|
||||||
|
cursors->dpy = dpy;
|
||||||
|
cursors->ncursor = 0;
|
||||||
|
cursors->cursors = (Cursor *) (cursors + 1);
|
||||||
|
return cursors;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
XcursorCursorsDestroy (XcursorCursors *cursors)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
--cursors->ref;
|
||||||
|
if (cursors->ref > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (n = 0; n < cursors->ncursor; n++)
|
||||||
|
XFreeCursor (cursors->dpy, cursors->cursors[n]);
|
||||||
|
free (cursors);
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorAnimate *
|
||||||
|
XcursorAnimateCreate (XcursorCursors *cursors)
|
||||||
|
{
|
||||||
|
XcursorAnimate *animate;
|
||||||
|
|
||||||
|
animate = malloc (sizeof (XcursorAnimate));
|
||||||
|
if (!animate)
|
||||||
|
return 0;
|
||||||
|
animate->cursors = cursors;
|
||||||
|
cursors->ref++;
|
||||||
|
animate->sequence = 0;
|
||||||
|
return animate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
XcursorAnimateDestroy (XcursorAnimate *animate)
|
||||||
|
{
|
||||||
|
XcursorCursorsDestroy (animate->cursors);
|
||||||
|
free (animate);
|
||||||
|
}
|
||||||
|
|
||||||
|
Cursor
|
||||||
|
XcursorAnimateNext (XcursorAnimate *animate)
|
||||||
|
{
|
||||||
|
Cursor cursor = animate->cursors->cursors[animate->sequence++];
|
||||||
|
|
||||||
|
if (animate->sequence >= animate->cursors->ncursor)
|
||||||
|
animate->sequence = 0;
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nativeByteOrder (void)
|
||||||
|
{
|
||||||
|
int x = 1;
|
||||||
|
|
||||||
|
return (*((char *) &x) == 1) ? LSBFirst : MSBFirst;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XcursorUInt
|
||||||
|
_XcursorPixelBrightness (XcursorPixel p)
|
||||||
|
{
|
||||||
|
XcursorPixel alpha = p >> 24;
|
||||||
|
XcursorPixel r, g, b;
|
||||||
|
|
||||||
|
if (!alpha)
|
||||||
|
return 0;
|
||||||
|
r = ((p >> 8) & 0xff00) / alpha;
|
||||||
|
if (r > 0xff) r = 0xff;
|
||||||
|
g = ((p >> 0) & 0xff00) / alpha;
|
||||||
|
if (g > 0xff) g = 0xff;
|
||||||
|
b = ((p << 8) & 0xff00) / alpha;
|
||||||
|
if (b > 0xff) b = 0xff;
|
||||||
|
return (r * 153 + g * 301 + b * 58) >> 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned short
|
||||||
|
_XcursorDivideAlpha (XcursorUInt value, XcursorUInt alpha)
|
||||||
|
{
|
||||||
|
if (!alpha)
|
||||||
|
return 0;
|
||||||
|
value = value * 255 / alpha;
|
||||||
|
if (value > 255)
|
||||||
|
value = 255;
|
||||||
|
return value | (value << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_XcursorPixelToColor (XcursorPixel p, XColor *color)
|
||||||
|
{
|
||||||
|
XcursorPixel alpha = p >> 24;
|
||||||
|
|
||||||
|
color->pixel = 0;
|
||||||
|
color->red = _XcursorDivideAlpha ((p >> 16) & 0xff, alpha);
|
||||||
|
color->green = _XcursorDivideAlpha ((p >> 8) & 0xff, alpha);
|
||||||
|
color->blue = _XcursorDivideAlpha ((p >> 0) & 0xff, alpha);
|
||||||
|
color->flags = DoRed|DoGreen|DoBlue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef DEBUG_IMAGE
|
||||||
|
#ifdef DEBUG_IMAGE
|
||||||
|
static void
|
||||||
|
_XcursorDumpImage (XImage *image)
|
||||||
|
{
|
||||||
|
FILE *f = fopen ("/tmp/images", "a");
|
||||||
|
int x, y;
|
||||||
|
if (!f)
|
||||||
|
return;
|
||||||
|
fprintf (f, "%d x %x\n", image->width, image->height);
|
||||||
|
for (y = 0; y < image->height; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < image->width; x++)
|
||||||
|
fprintf (f, "%c", XGetPixel (image, x, y) ? '*' : ' ');
|
||||||
|
fprintf (f, "\n");
|
||||||
|
}
|
||||||
|
fflush (f);
|
||||||
|
fclose (f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_XcursorDumpColor (XColor *color, char *name)
|
||||||
|
{
|
||||||
|
FILE *f = fopen ("/tmp/images", "a");
|
||||||
|
fprintf (f, "%s: %x %x %x\n", name,
|
||||||
|
color->red, color->green, color->blue);
|
||||||
|
fflush (f);
|
||||||
|
fclose (f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int
|
||||||
|
_XcursorCompareRed (const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const XcursorPixel *ap = a, *bp = b;
|
||||||
|
|
||||||
|
return (int) (((*ap >> 16) & 0xff) - ((*bp >> 16) & 0xff));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_XcursorCompareGreen (const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const XcursorPixel *ap = a, *bp = b;
|
||||||
|
|
||||||
|
return (int) (((*ap >> 8) & 0xff) - ((*bp >> 8) & 0xff));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_XcursorCompareBlue (const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const XcursorPixel *ap = a, *bp = b;
|
||||||
|
|
||||||
|
return (int) (((*ap >> 0) & 0xff) - ((*bp >> 0) & 0xff));
|
||||||
|
}
|
||||||
|
|
||||||
|
static XcursorPixel
|
||||||
|
_XcursorAverageColor (XcursorPixel *pixels, int npixels)
|
||||||
|
{
|
||||||
|
XcursorPixel p;
|
||||||
|
XcursorPixel red, green, blue;
|
||||||
|
int n = npixels;
|
||||||
|
|
||||||
|
blue = green = red = 0;
|
||||||
|
while (n--)
|
||||||
|
{
|
||||||
|
p = *pixels++;
|
||||||
|
red += (p >> 16) & 0xff;
|
||||||
|
green += (p >> 8) & 0xff;
|
||||||
|
blue += (p >> 0) & 0xff;
|
||||||
|
}
|
||||||
|
if (!n)
|
||||||
|
return 0;
|
||||||
|
return (0xff << 24) | ((red/npixels) << 16) | ((green/npixels) << 8) | (blue/npixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct XcursorCoreCursor {
|
||||||
|
XImage *src_image;
|
||||||
|
XImage *msk_image;
|
||||||
|
XColor on_color;
|
||||||
|
XColor off_color;
|
||||||
|
} XcursorCoreCursor;
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
_XcursorHeckbertMedianCut (const XcursorImage *image, XcursorCoreCursor *core)
|
||||||
|
{
|
||||||
|
XImage *src_image = core->src_image, *msk_image = core->msk_image;
|
||||||
|
int npixels = image->width * image->height;
|
||||||
|
int ncolors;
|
||||||
|
int n;
|
||||||
|
XcursorPixel *po, *pn, *pc;
|
||||||
|
XcursorPixel p;
|
||||||
|
XcursorPixel red, green, blue, alpha;
|
||||||
|
XcursorPixel max_red, min_red, max_green, min_green, max_blue, min_blue;
|
||||||
|
XcursorPixel *temp, *pixels, *colors;
|
||||||
|
int split;
|
||||||
|
XcursorPixel leftColor, centerColor, rightColor;
|
||||||
|
int (*compare) (const void *, const void *);
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Temp space for converted image and converted colors
|
||||||
|
*/
|
||||||
|
temp = malloc (npixels * sizeof (XcursorPixel) * 2);
|
||||||
|
if (!temp)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
pixels = temp;
|
||||||
|
colors = pixels + npixels;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert to 2-value alpha and build
|
||||||
|
* array of opaque color values and an
|
||||||
|
*/
|
||||||
|
po = image->pixels;
|
||||||
|
pn = pixels;
|
||||||
|
pc = colors;
|
||||||
|
max_blue = max_green = max_red = 0;
|
||||||
|
min_blue = min_green = min_red = 255;
|
||||||
|
n = npixels;
|
||||||
|
while (n--)
|
||||||
|
{
|
||||||
|
p = *po++;
|
||||||
|
alpha = (p >> 24) & 0xff;
|
||||||
|
red = (p >> 16) & 0xff;
|
||||||
|
green = (p >> 8) & 0xff;
|
||||||
|
blue = (p >> 0) & 0xff;
|
||||||
|
if (alpha >= 0x80)
|
||||||
|
{
|
||||||
|
red = red * 255 / alpha;
|
||||||
|
green = green * 255 / alpha;
|
||||||
|
blue = blue * 255 / alpha;
|
||||||
|
if (red < min_red) min_red = red;
|
||||||
|
if (red > max_red) max_red = red;
|
||||||
|
if (green < min_green) min_green = green;
|
||||||
|
if (green > max_green) max_green = green;
|
||||||
|
if (blue < min_blue) min_blue = blue;
|
||||||
|
if (blue > max_blue) max_blue = blue;
|
||||||
|
p = ((0xff << 24) | (red << 16) |
|
||||||
|
(green << 8) | (blue << 0));
|
||||||
|
*pc++ = p;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
p = 0;
|
||||||
|
*pn++ = p;
|
||||||
|
}
|
||||||
|
ncolors = pc - colors;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute longest dimension and sort
|
||||||
|
*/
|
||||||
|
if ((max_green - min_green) >= (max_red - min_red) &&
|
||||||
|
(max_green - min_green) >= (max_blue - min_blue))
|
||||||
|
compare = _XcursorCompareGreen;
|
||||||
|
else if ((max_red - min_red) >= (max_blue - min_blue))
|
||||||
|
compare = _XcursorCompareRed;
|
||||||
|
else
|
||||||
|
compare = _XcursorCompareBlue;
|
||||||
|
qsort (colors, ncolors, sizeof (XcursorPixel), compare);
|
||||||
|
/*
|
||||||
|
* Compute average colors on both sides of the cut
|
||||||
|
*/
|
||||||
|
split = ncolors >> 1;
|
||||||
|
leftColor = _XcursorAverageColor (colors, split);
|
||||||
|
centerColor = colors[split];
|
||||||
|
rightColor = _XcursorAverageColor (colors + split, ncolors - split);
|
||||||
|
/*
|
||||||
|
* Select best color for each pixel
|
||||||
|
*/
|
||||||
|
pn = pixels;
|
||||||
|
for (y = 0; y < image->height; y++)
|
||||||
|
for (x = 0; x < image->width; x++)
|
||||||
|
{
|
||||||
|
p = *pn++;
|
||||||
|
if (p & 0xff000000)
|
||||||
|
{
|
||||||
|
XPutPixel (msk_image, x, y, 1);
|
||||||
|
if ((*compare) (&p, ¢erColor) >= 0)
|
||||||
|
XPutPixel (src_image, x, y, 0);
|
||||||
|
else
|
||||||
|
XPutPixel (src_image, x, y, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XPutPixel (msk_image, x, y, 0);
|
||||||
|
XPutPixel (src_image, x, y, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free (temp);
|
||||||
|
_XcursorPixelToColor (rightColor, &core->off_color);
|
||||||
|
_XcursorPixelToColor (leftColor, &core->on_color);
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#define DITHER_DIM 4
|
||||||
|
static XcursorPixel orderedDither[4][4] = {
|
||||||
|
{ 1, 9, 3, 11 },
|
||||||
|
{ 13, 5, 15, 7 },
|
||||||
|
{ 4, 12, 2, 10 },
|
||||||
|
{ 16, 8, 14, 6 }
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
#define DITHER_DIM 2
|
||||||
|
static XcursorPixel orderedDither[2][2] = {
|
||||||
|
{ 1, 3, },
|
||||||
|
{ 4, 2, },
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DITHER_SIZE ((sizeof orderedDither / sizeof orderedDither[0][0]) + 1)
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
_XcursorBayerOrderedDither (const XcursorImage *image, XcursorCoreCursor *core)
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
XcursorPixel *pixel, p;
|
||||||
|
XcursorPixel a, i, d;
|
||||||
|
|
||||||
|
pixel = image->pixels;
|
||||||
|
for (y = 0; y < image->height; y++)
|
||||||
|
for (x = 0; x < image->width; x++)
|
||||||
|
{
|
||||||
|
p = *pixel++;
|
||||||
|
a = ((p >> 24) * DITHER_SIZE + 127) / 255;
|
||||||
|
i = (_XcursorPixelBrightness (p) * DITHER_SIZE + 127) / 255;
|
||||||
|
d = orderedDither[y&(DITHER_DIM-1)][x&(DITHER_DIM-1)];
|
||||||
|
if (a > d)
|
||||||
|
{
|
||||||
|
XPutPixel (core->msk_image, x, y, 1);
|
||||||
|
if (i > d)
|
||||||
|
XPutPixel (core->src_image, x, y, 0); /* white */
|
||||||
|
else
|
||||||
|
XPutPixel (core->src_image, x, y, 1); /* black */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XPutPixel (core->msk_image, x, y, 0);
|
||||||
|
XPutPixel (core->src_image, x, y, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
core->on_color.red = 0;
|
||||||
|
core->on_color.green = 0;
|
||||||
|
core->on_color.blue = 0;
|
||||||
|
core->off_color.red = 0xffff;
|
||||||
|
core->off_color.green = 0xffff;
|
||||||
|
core->off_color.blue = 0xffff;
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
_XcursorFloydSteinberg (const XcursorImage *image, XcursorCoreCursor *core)
|
||||||
|
{
|
||||||
|
int *aPicture, *iPicture, *aP, *iP;
|
||||||
|
XcursorPixel *pixel, p;
|
||||||
|
int aR, iR, aA, iA;
|
||||||
|
int npixels = image->width * image->height;
|
||||||
|
int n;
|
||||||
|
int right = 1;
|
||||||
|
int belowLeft = image->width - 1;
|
||||||
|
int below = image->width;
|
||||||
|
int belowRight = image->width + 1;
|
||||||
|
int iError, aError;
|
||||||
|
int iErrorRight, aErrorRight;
|
||||||
|
int iErrorBelowLeft, aErrorBelowLeft;
|
||||||
|
int iErrorBelow, aErrorBelow;
|
||||||
|
int iErrorBelowRight, aErrorBelowRight;
|
||||||
|
int x, y;
|
||||||
|
int max_inten, min_inten, mean_inten;
|
||||||
|
|
||||||
|
iPicture = malloc (npixels * sizeof (int) * 2);
|
||||||
|
if (!iPicture)
|
||||||
|
return False;
|
||||||
|
aPicture = iPicture + npixels;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute raw gray and alpha arrays
|
||||||
|
*/
|
||||||
|
pixel = image->pixels;
|
||||||
|
iP = iPicture;
|
||||||
|
aP = aPicture;
|
||||||
|
n = npixels;
|
||||||
|
max_inten = 0;
|
||||||
|
min_inten = 0xff;
|
||||||
|
while (n--)
|
||||||
|
{
|
||||||
|
p = *pixel++;
|
||||||
|
*aP++ = (int) (p >> 24);
|
||||||
|
iR = (int) _XcursorPixelBrightness (p);
|
||||||
|
if (iR > max_inten) max_inten = iR;
|
||||||
|
if (iR < min_inten) min_inten = iR;
|
||||||
|
*iP++ = iR;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Draw the image while diffusing the error
|
||||||
|
*/
|
||||||
|
iP = iPicture;
|
||||||
|
aP = aPicture;
|
||||||
|
mean_inten = (max_inten + min_inten + 1) >> 1;
|
||||||
|
for (y = 0; y < image->height; y++)
|
||||||
|
for (x = 0; x < image->width; x++)
|
||||||
|
{
|
||||||
|
aR = *aP;
|
||||||
|
iR = *iP;
|
||||||
|
if (aR >= 0x80)
|
||||||
|
{
|
||||||
|
XPutPixel (core->msk_image, x, y, 1);
|
||||||
|
aA = 0xff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XPutPixel (core->msk_image, x, y, 0);
|
||||||
|
aA = 0x00;
|
||||||
|
}
|
||||||
|
if (iR >= mean_inten)
|
||||||
|
{
|
||||||
|
XPutPixel (core->src_image, x, y, 0);
|
||||||
|
iA = max_inten;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XPutPixel (core->src_image, x, y, 1);
|
||||||
|
iA = min_inten;
|
||||||
|
}
|
||||||
|
iError = iR - iA;
|
||||||
|
aError = aR - aA;
|
||||||
|
iErrorRight = (iError * 7) >> 4;
|
||||||
|
iErrorBelowLeft = (iError * 3) >> 4;
|
||||||
|
iErrorBelow = (iError * 5) >> 4;
|
||||||
|
iErrorBelowRight = (iError - iErrorRight -
|
||||||
|
iErrorBelowLeft - iErrorBelow);
|
||||||
|
aErrorRight = (aError * 7) >> 4;
|
||||||
|
aErrorBelowLeft = (aError * 3) >> 4;
|
||||||
|
aErrorBelow = (aError * 5) >> 4;
|
||||||
|
aErrorBelowRight = (aError - aErrorRight -
|
||||||
|
aErrorBelowLeft - aErrorBelow);
|
||||||
|
if (x < image->width - 1)
|
||||||
|
{
|
||||||
|
iP[right] += iErrorRight;
|
||||||
|
aP[right] += aErrorRight;
|
||||||
|
}
|
||||||
|
if (y < image->height - 1)
|
||||||
|
{
|
||||||
|
if (x)
|
||||||
|
{
|
||||||
|
iP[belowLeft] += iErrorBelowLeft;
|
||||||
|
aP[belowLeft] += aErrorBelowLeft;
|
||||||
|
}
|
||||||
|
iP[below] += iErrorBelow;
|
||||||
|
aP[below] += aErrorBelow;
|
||||||
|
if (x < image->width - 1)
|
||||||
|
{
|
||||||
|
iP[belowRight] += iErrorBelowRight;
|
||||||
|
aP[belowRight] += aErrorBelowRight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aP++;
|
||||||
|
iP++;
|
||||||
|
}
|
||||||
|
free (iPicture);
|
||||||
|
core->on_color.red =
|
||||||
|
core->on_color.green =
|
||||||
|
core->on_color.blue = (min_inten | min_inten << 8);
|
||||||
|
core->off_color.red =
|
||||||
|
core->off_color.green =
|
||||||
|
core->off_color.blue = (max_inten | max_inten << 8);
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
_XcursorThreshold (const XcursorImage *image, XcursorCoreCursor *core)
|
||||||
|
{
|
||||||
|
XcursorPixel *pixel, p;
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draw the image, picking black for dark pixels and white for light
|
||||||
|
*/
|
||||||
|
pixel = image->pixels;
|
||||||
|
for (y = 0; y < image->height; y++)
|
||||||
|
for (x = 0; x < image->width; x++)
|
||||||
|
{
|
||||||
|
p = *pixel++;
|
||||||
|
if ((p >> 24) >= 0x80)
|
||||||
|
{
|
||||||
|
XPutPixel (core->msk_image, x, y, 1);
|
||||||
|
if (_XcursorPixelBrightness (p) > 0x80)
|
||||||
|
XPutPixel (core->src_image, x, y, 0);
|
||||||
|
else
|
||||||
|
XPutPixel (core->src_image, x, y, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XPutPixel (core->msk_image, x, y, 0);
|
||||||
|
XPutPixel (core->src_image, x, y, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
core->on_color.red =
|
||||||
|
core->on_color.green =
|
||||||
|
core->on_color.blue = 0;
|
||||||
|
core->off_color.red =
|
||||||
|
core->off_color.green =
|
||||||
|
core->off_color.blue = 0xffff;
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cursor
|
||||||
|
XcursorImageLoadCursor (Display *dpy, const XcursorImage *image)
|
||||||
|
{
|
||||||
|
Cursor cursor;
|
||||||
|
|
||||||
|
#if RENDER_MAJOR > 0 || RENDER_MINOR >= 5
|
||||||
|
if (XcursorSupportsARGB (dpy))
|
||||||
|
{
|
||||||
|
XImage ximage;
|
||||||
|
int screen = DefaultScreen (dpy);
|
||||||
|
Pixmap pixmap;
|
||||||
|
Picture picture;
|
||||||
|
GC gc;
|
||||||
|
XRenderPictFormat *format;
|
||||||
|
|
||||||
|
ximage.width = image->width;
|
||||||
|
ximage.height = image->height;
|
||||||
|
ximage.xoffset = 0;
|
||||||
|
ximage.format = ZPixmap;
|
||||||
|
ximage.data = (char *) image->pixels;
|
||||||
|
ximage.byte_order = nativeByteOrder ();
|
||||||
|
ximage.bitmap_unit = 32;
|
||||||
|
ximage.bitmap_bit_order = ximage.byte_order;
|
||||||
|
ximage.bitmap_pad = 32;
|
||||||
|
ximage.depth = 32;
|
||||||
|
ximage.bits_per_pixel = 32;
|
||||||
|
ximage.bytes_per_line = image->width * 4;
|
||||||
|
ximage.red_mask = 0xff0000;
|
||||||
|
ximage.green_mask = 0x00ff00;
|
||||||
|
ximage.blue_mask = 0x0000ff;
|
||||||
|
ximage.obdata = 0;
|
||||||
|
if (!XInitImage (&ximage))
|
||||||
|
return None;
|
||||||
|
pixmap = XCreatePixmap (dpy, RootWindow (dpy, screen),
|
||||||
|
image->width, image->height, 32);
|
||||||
|
gc = XCreateGC (dpy, pixmap, 0, 0);
|
||||||
|
XPutImage (dpy, pixmap, gc, &ximage,
|
||||||
|
0, 0, 0, 0, image->width, image->height);
|
||||||
|
XFreeGC (dpy, gc);
|
||||||
|
format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
|
||||||
|
picture = XRenderCreatePicture (dpy, pixmap, format, 0, 0);
|
||||||
|
XFreePixmap (dpy, pixmap);
|
||||||
|
cursor = XRenderCreateCursor (dpy, picture,
|
||||||
|
image->xhot, image->yhot);
|
||||||
|
XRenderFreePicture (dpy, picture);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy);
|
||||||
|
int screen = DefaultScreen (dpy);
|
||||||
|
XcursorCoreCursor core;
|
||||||
|
Pixmap src_pixmap, msk_pixmap;
|
||||||
|
GC gc;
|
||||||
|
XGCValues gcv;
|
||||||
|
|
||||||
|
core.src_image = XCreateImage (dpy, 0, 1, ZPixmap,
|
||||||
|
0, 0, image->width, image->height,
|
||||||
|
32, 0);
|
||||||
|
core.src_image->data = Xmalloc (image->height *
|
||||||
|
core.src_image->bytes_per_line);
|
||||||
|
core.msk_image = XCreateImage (dpy, 0, 1, ZPixmap,
|
||||||
|
0, 0, image->width, image->height,
|
||||||
|
32, 0);
|
||||||
|
core.msk_image->data = Xmalloc (image->height *
|
||||||
|
core.msk_image->bytes_per_line);
|
||||||
|
|
||||||
|
switch (info->dither) {
|
||||||
|
case XcursorDitherThreshold:
|
||||||
|
if (!_XcursorThreshold (image, &core))
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case XcursorDitherMedian:
|
||||||
|
if (!_XcursorHeckbertMedianCut (image, &core))
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case XcursorDitherOrdered:
|
||||||
|
if (!_XcursorBayerOrderedDither (image, &core))
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case XcursorDitherDiffuse:
|
||||||
|
if (!_XcursorFloydSteinberg (image, &core))
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create the cursor
|
||||||
|
*/
|
||||||
|
src_pixmap = XCreatePixmap (dpy, RootWindow (dpy, screen),
|
||||||
|
image->width, image->height, 1);
|
||||||
|
msk_pixmap = XCreatePixmap (dpy, RootWindow (dpy, screen),
|
||||||
|
image->width, image->height, 1);
|
||||||
|
gcv.foreground = 1;
|
||||||
|
gcv.background = 0;
|
||||||
|
gc = XCreateGC (dpy, src_pixmap,
|
||||||
|
GCForeground|GCBackground,
|
||||||
|
&gcv);
|
||||||
|
XPutImage (dpy, src_pixmap, gc, core.src_image,
|
||||||
|
0, 0, 0, 0, image->width, image->height);
|
||||||
|
|
||||||
|
XPutImage (dpy, msk_pixmap, gc, core.msk_image,
|
||||||
|
0, 0, 0, 0, image->width, image->height);
|
||||||
|
XFreeGC (dpy, gc);
|
||||||
|
|
||||||
|
#ifdef DEBUG_IMAGE
|
||||||
|
_XcursorDumpColor (&core.on_color, "on_color");
|
||||||
|
_XcursorDumpColor (&core.off_color, "off_color");
|
||||||
|
_XcursorDumpImage (core.src_image);
|
||||||
|
_XcursorDumpImage (core.msk_image);
|
||||||
|
#endif
|
||||||
|
XDestroyImage (core.src_image);
|
||||||
|
XDestroyImage (core.msk_image);
|
||||||
|
|
||||||
|
cursor = XCreatePixmapCursor (dpy, src_pixmap, msk_pixmap,
|
||||||
|
&core.on_color, &core.off_color,
|
||||||
|
image->xhot, image->yhot);
|
||||||
|
XFreePixmap (dpy, src_pixmap);
|
||||||
|
XFreePixmap (dpy, msk_pixmap);
|
||||||
|
}
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorCursors *
|
||||||
|
XcursorImagesLoadCursors (Display *dpy, const XcursorImages *images)
|
||||||
|
{
|
||||||
|
XcursorCursors *cursors = XcursorCursorsCreate (dpy, images->nimage);
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (!cursors)
|
||||||
|
return 0;
|
||||||
|
for (n = 0; n < images->nimage; n++)
|
||||||
|
{
|
||||||
|
cursors->cursors[n] = XcursorImageLoadCursor (dpy, images->images[n]);
|
||||||
|
if (!cursors->cursors[n])
|
||||||
|
{
|
||||||
|
XcursorCursorsDestroy (cursors);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
cursors->ncursor++;
|
||||||
|
}
|
||||||
|
return cursors;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cursor
|
||||||
|
XcursorImagesLoadCursor (Display *dpy, const XcursorImages *images)
|
||||||
|
{
|
||||||
|
if (images->nimage == 1 || !XcursorSupportsAnim (dpy))
|
||||||
|
return XcursorImageLoadCursor (dpy, images->images[0]);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XcursorCursors *cursors = XcursorImagesLoadCursors (dpy, images);
|
||||||
|
XAnimCursor *anim;
|
||||||
|
int n;
|
||||||
|
Cursor cursor;
|
||||||
|
|
||||||
|
if (!cursors)
|
||||||
|
return 0;
|
||||||
|
anim = malloc (cursors->ncursor * sizeof (XAnimCursor));
|
||||||
|
if (!anim)
|
||||||
|
{
|
||||||
|
XcursorCursorsDestroy (cursors);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (n = 0; n < cursors->ncursor; n++)
|
||||||
|
{
|
||||||
|
anim[n].cursor = cursors->cursors[n];
|
||||||
|
anim[n].delay = images->images[n]->delay;
|
||||||
|
}
|
||||||
|
cursor = XRenderCreateAnimCursor (dpy, cursors->ncursor, anim);
|
||||||
|
free (anim);
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Cursor
|
||||||
|
XcursorFilenameLoadCursor (Display *dpy, const char *file)
|
||||||
|
{
|
||||||
|
int size = XcursorGetDefaultSize (dpy);
|
||||||
|
XcursorImages *images = XcursorFilenameLoadImages (file, size);
|
||||||
|
Cursor cursor;
|
||||||
|
|
||||||
|
if (!images)
|
||||||
|
return None;
|
||||||
|
cursor = XcursorImagesLoadCursor (dpy, images);
|
||||||
|
XcursorImagesDestroy (images);
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorCursors *
|
||||||
|
XcursorFilenameLoadCursors (Display *dpy, const char *file)
|
||||||
|
{
|
||||||
|
int size = XcursorGetDefaultSize (dpy);
|
||||||
|
XcursorImages *images = XcursorFilenameLoadImages (file, size);
|
||||||
|
XcursorCursors *cursors;
|
||||||
|
|
||||||
|
if (!images)
|
||||||
|
return 0;
|
||||||
|
cursors = XcursorImagesLoadCursors (dpy, images);
|
||||||
|
XcursorImagesDestroy (images);
|
||||||
|
return cursors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stolen from XCreateGlyphCursor (which we cruelly override)
|
||||||
|
*/
|
||||||
|
|
||||||
|
Cursor
|
||||||
|
_XcursorCreateGlyphCursor(Display *dpy,
|
||||||
|
Font source_font,
|
||||||
|
Font mask_font,
|
||||||
|
unsigned int source_char,
|
||||||
|
unsigned int mask_char,
|
||||||
|
XColor _Xconst *foreground,
|
||||||
|
XColor _Xconst *background)
|
||||||
|
{
|
||||||
|
Cursor cid;
|
||||||
|
register xCreateGlyphCursorReq *req;
|
||||||
|
|
||||||
|
LockDisplay(dpy);
|
||||||
|
GetReq(CreateGlyphCursor, req);
|
||||||
|
cid = req->cid = XAllocID(dpy);
|
||||||
|
req->source = source_font;
|
||||||
|
req->mask = mask_font;
|
||||||
|
req->sourceChar = source_char;
|
||||||
|
req->maskChar = mask_char;
|
||||||
|
req->foreRed = foreground->red;
|
||||||
|
req->foreGreen = foreground->green;
|
||||||
|
req->foreBlue = foreground->blue;
|
||||||
|
req->backRed = background->red;
|
||||||
|
req->backGreen = background->green;
|
||||||
|
req->backBlue = background->blue;
|
||||||
|
UnlockDisplay(dpy);
|
||||||
|
SyncHandle();
|
||||||
|
return (cid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stolen from XCreateFontCursor (which we cruelly override)
|
||||||
|
*/
|
||||||
|
|
||||||
|
Cursor
|
||||||
|
_XcursorCreateFontCursor (Display *dpy, unsigned int shape)
|
||||||
|
{
|
||||||
|
static XColor _Xconst foreground = { 0, 0, 0, 0 }; /* black */
|
||||||
|
static XColor _Xconst background = { 0, 65535, 65535, 65535 }; /* white */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the cursor font contains the shape glyph followed by the mask
|
||||||
|
* glyph; so character position 0 contains a shape, 1 the mask for 0,
|
||||||
|
* 2 a shape, etc. <X11/cursorfont.h> contains hash define names
|
||||||
|
* for all of these.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (dpy->cursor_font == None)
|
||||||
|
{
|
||||||
|
dpy->cursor_font = XLoadFont (dpy, CURSORFONT);
|
||||||
|
if (dpy->cursor_font == None)
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _XcursorCreateGlyphCursor (dpy, dpy->cursor_font, dpy->cursor_font,
|
||||||
|
shape, shape + 1, &foreground, &background);
|
||||||
|
}
|
||||||
|
|
||||||
361
src/display.c
Normal file
361
src/display.c
Normal file
|
|
@ -0,0 +1,361 @@
|
||||||
|
/*
|
||||||
|
* $XFree86: xc/lib/Xcursor/display.c,v 1.6 2003/02/20 03:13:50 dawes Exp $
|
||||||
|
*
|
||||||
|
* Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||||
|
* documentation for any purpose is hereby granted without fee, provided that
|
||||||
|
* the above copyright notice appear in all copies and that both that
|
||||||
|
* copyright notice and this permission notice appear in supporting
|
||||||
|
* documentation, and that the name of Keith Packard not be used in
|
||||||
|
* advertising or publicity pertaining to distribution of the software without
|
||||||
|
* specific, written prior permission. Keith Packard makes no
|
||||||
|
* representations about the suitability of this software for any purpose. It
|
||||||
|
* is provided "as is" without express or implied warranty.
|
||||||
|
*
|
||||||
|
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||||
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||||
|
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||||
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||||
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xcursorint.h"
|
||||||
|
#include <X11/Xlibint.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
static XcursorDisplayInfo *_XcursorDisplayInfo;
|
||||||
|
|
||||||
|
static int
|
||||||
|
_XcursorCloseDisplay (Display *dpy, XExtCodes *codes)
|
||||||
|
{
|
||||||
|
XcursorDisplayInfo *info, **prev;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unhook from the global list
|
||||||
|
*/
|
||||||
|
_XLockMutex (_Xglobal_lock);
|
||||||
|
for (prev = &_XcursorDisplayInfo; (info = *prev); prev = &(*prev)->next)
|
||||||
|
if (info->display == dpy)
|
||||||
|
{
|
||||||
|
*prev = info->next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_XUnlockMutex (_Xglobal_lock);
|
||||||
|
|
||||||
|
if (info->theme)
|
||||||
|
free (info->theme);
|
||||||
|
free (info);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_XcursorDefaultParseBool (char *v)
|
||||||
|
{
|
||||||
|
char c0, c1;
|
||||||
|
|
||||||
|
c0 = *v;
|
||||||
|
if (isupper ((int)c0))
|
||||||
|
c0 = tolower (c0);
|
||||||
|
if (c0 == 't' || c0 == 'y' || c0 == '1')
|
||||||
|
return 1;
|
||||||
|
if (c0 == 'f' || c0 == 'n' || c0 == '0')
|
||||||
|
return 0;
|
||||||
|
if (c0 == 'o')
|
||||||
|
{
|
||||||
|
c1 = v[1];
|
||||||
|
if (isupper ((int)c1))
|
||||||
|
c1 = tolower (c1);
|
||||||
|
if (c1 == 'n')
|
||||||
|
return 1;
|
||||||
|
if (c1 == 'f')
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorDisplayInfo *
|
||||||
|
_XcursorGetDisplayInfo (Display *dpy)
|
||||||
|
{
|
||||||
|
XcursorDisplayInfo *info, **prev, *old;
|
||||||
|
int event_base, error_base;
|
||||||
|
int major, minor;
|
||||||
|
char *v;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
_XLockMutex (_Xglobal_lock);
|
||||||
|
for (prev = &_XcursorDisplayInfo; (info = *prev); prev = &(*prev)->next)
|
||||||
|
{
|
||||||
|
if (info->display == dpy)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* MRU the list
|
||||||
|
*/
|
||||||
|
if (prev != &_XcursorDisplayInfo)
|
||||||
|
{
|
||||||
|
*prev = info->next;
|
||||||
|
info->next = _XcursorDisplayInfo;
|
||||||
|
_XcursorDisplayInfo = info;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_XUnlockMutex (_Xglobal_lock);
|
||||||
|
if (info)
|
||||||
|
return info;
|
||||||
|
info = (XcursorDisplayInfo *) malloc (sizeof (XcursorDisplayInfo));
|
||||||
|
if (!info)
|
||||||
|
return 0;
|
||||||
|
info->next = 0;
|
||||||
|
info->display = dpy;
|
||||||
|
|
||||||
|
info->codes = XAddExtension (dpy);
|
||||||
|
if (!info->codes)
|
||||||
|
{
|
||||||
|
free (info);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
(void) XESetCloseDisplay (dpy, info->codes->extension, _XcursorCloseDisplay);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether the display supports the Render CreateCursor request
|
||||||
|
*/
|
||||||
|
info->has_render_cursor = XcursorFalse;
|
||||||
|
info->has_anim_cursor = XcursorFalse;
|
||||||
|
if (XRenderQueryExtension (dpy, &event_base, &error_base) &&
|
||||||
|
XRenderQueryVersion (dpy, &major, &minor))
|
||||||
|
{
|
||||||
|
if (major > 0 || minor >= 5)
|
||||||
|
{
|
||||||
|
info->has_render_cursor = XcursorTrue;
|
||||||
|
v = getenv ("XCURSOR_CORE");
|
||||||
|
if (!v)
|
||||||
|
v = XGetDefault (dpy, "Xcursor", "core");
|
||||||
|
if (v && _XcursorDefaultParseBool (v) == 1)
|
||||||
|
info->has_render_cursor = XcursorFalse;
|
||||||
|
}
|
||||||
|
if (info->has_render_cursor && (major > 0 || minor >= 8))
|
||||||
|
{
|
||||||
|
info->has_anim_cursor = XcursorTrue;
|
||||||
|
v = getenv ("XCURSOR_ANIM");
|
||||||
|
if (!v)
|
||||||
|
v = XGetDefault (dpy, "Xcursor", "anim");
|
||||||
|
if (v && _XcursorDefaultParseBool (v) == 0)
|
||||||
|
info->has_anim_cursor = XcursorFalse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info->size = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get desired cursor size
|
||||||
|
*/
|
||||||
|
v = getenv ("XCURSOR_SIZE");
|
||||||
|
if (!v)
|
||||||
|
v = XGetDefault (dpy, "Xcursor", "size");
|
||||||
|
if (v)
|
||||||
|
info->size = atoi (v);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use the Xft size to guess a size; make cursors 16 "points" tall
|
||||||
|
*/
|
||||||
|
if (info->size == 0)
|
||||||
|
{
|
||||||
|
int dpi = 0;
|
||||||
|
v = XGetDefault (dpy, "Xft", "dpi");
|
||||||
|
if (v)
|
||||||
|
dpi = atoi (v);
|
||||||
|
if (dpi)
|
||||||
|
info->size = dpi * 16 / 72;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use display size to guess a size
|
||||||
|
*/
|
||||||
|
if (info->size == 0)
|
||||||
|
{
|
||||||
|
int dim;
|
||||||
|
|
||||||
|
if (DisplayHeight (dpy, DefaultScreen (dpy)) <
|
||||||
|
DisplayWidth (dpy, DefaultScreen (dpy)))
|
||||||
|
dim = DisplayHeight (dpy, DefaultScreen (dpy));
|
||||||
|
else
|
||||||
|
dim = DisplayWidth (dpy, DefaultScreen (dpy));
|
||||||
|
/*
|
||||||
|
* 16 pixels on a display of dimension 768
|
||||||
|
*/
|
||||||
|
info->size = dim / 48;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->theme = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the desired theme
|
||||||
|
*/
|
||||||
|
v = getenv ("XCURSOR_THEME");
|
||||||
|
if (!v)
|
||||||
|
v = XGetDefault (dpy, "Xcursor", "theme");
|
||||||
|
if (v)
|
||||||
|
{
|
||||||
|
info->theme = malloc (strlen (v) + 1);
|
||||||
|
if (info->theme)
|
||||||
|
strcpy (info->theme, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the desired dither
|
||||||
|
*/
|
||||||
|
info->dither = XcursorDitherThreshold;
|
||||||
|
v = getenv ("XCURSOR_DITHER");
|
||||||
|
if (!v)
|
||||||
|
v = XGetDefault (dpy, "Xcursor", "dither");
|
||||||
|
if (v)
|
||||||
|
{
|
||||||
|
if (!strcmp (v, "threshold"))
|
||||||
|
info->dither = XcursorDitherThreshold;
|
||||||
|
if (!strcmp (v, "median"))
|
||||||
|
info->dither = XcursorDitherMedian;
|
||||||
|
if (!strcmp (v, "ordered"))
|
||||||
|
info->dither = XcursorDitherOrdered;
|
||||||
|
if (!strcmp (v, "diffuse"))
|
||||||
|
info->dither = XcursorDitherDiffuse;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->theme_core = False;
|
||||||
|
/*
|
||||||
|
* Find out if core cursors should
|
||||||
|
* be themed
|
||||||
|
*/
|
||||||
|
v = getenv ("XCURSOR_THEME_CORE");
|
||||||
|
if (!v)
|
||||||
|
v = XGetDefault (dpy, "Xcursor", "theme_core");
|
||||||
|
if (v)
|
||||||
|
{
|
||||||
|
i = _XcursorDefaultParseBool (v);
|
||||||
|
if (i >= 0)
|
||||||
|
info->theme_core = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->fonts = 0;
|
||||||
|
for (i = 0; i < NUM_BITMAPS; i++)
|
||||||
|
info->bitmaps[i].bitmap = None;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Link new info info list, making sure another
|
||||||
|
* thread hasn't inserted something into the list while
|
||||||
|
* this one was busy setting up the data
|
||||||
|
*/
|
||||||
|
_XLockMutex (_Xglobal_lock);
|
||||||
|
for (old = _XcursorDisplayInfo; old; old = old->next)
|
||||||
|
if (old->display == dpy)
|
||||||
|
break;
|
||||||
|
if (old)
|
||||||
|
{
|
||||||
|
if (info->theme)
|
||||||
|
free (info->theme);
|
||||||
|
free (info);
|
||||||
|
info = old;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
info->next = _XcursorDisplayInfo;
|
||||||
|
_XcursorDisplayInfo = info;
|
||||||
|
}
|
||||||
|
_XUnlockMutex (_Xglobal_lock);
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorSupportsARGB (Display *dpy)
|
||||||
|
{
|
||||||
|
XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy);
|
||||||
|
|
||||||
|
return info && info->has_render_cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorSupportsAnim (Display *dpy)
|
||||||
|
{
|
||||||
|
XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy);
|
||||||
|
|
||||||
|
return info && info->has_anim_cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorSetDefaultSize (Display *dpy, int size)
|
||||||
|
{
|
||||||
|
XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy);
|
||||||
|
|
||||||
|
if (!info)
|
||||||
|
return XcursorFalse;
|
||||||
|
info->size = size;
|
||||||
|
return XcursorTrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
XcursorGetDefaultSize (Display *dpy)
|
||||||
|
{
|
||||||
|
XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy);
|
||||||
|
|
||||||
|
if (!info)
|
||||||
|
return 0;
|
||||||
|
return info->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorSetTheme (Display *dpy, const char *theme)
|
||||||
|
{
|
||||||
|
XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy);
|
||||||
|
char *copy;
|
||||||
|
|
||||||
|
if (!info)
|
||||||
|
return XcursorFalse;
|
||||||
|
if (theme)
|
||||||
|
{
|
||||||
|
copy = malloc (strlen (theme) + 1);
|
||||||
|
if (!copy)
|
||||||
|
return XcursorFalse;
|
||||||
|
strcpy (copy, theme);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
copy = 0;
|
||||||
|
if (info->theme)
|
||||||
|
free (info->theme);
|
||||||
|
info->theme = copy;
|
||||||
|
return XcursorTrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
XcursorGetTheme (Display *dpy)
|
||||||
|
{
|
||||||
|
XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy);
|
||||||
|
|
||||||
|
if (!info)
|
||||||
|
return 0;
|
||||||
|
return info->theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorGetThemeCore (Display *dpy)
|
||||||
|
{
|
||||||
|
XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy);
|
||||||
|
|
||||||
|
if (!info)
|
||||||
|
return XcursorFalse;
|
||||||
|
return info->theme_core;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorSetThemeCore (Display *dpy, XcursorBool theme_core)
|
||||||
|
{
|
||||||
|
XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy);
|
||||||
|
|
||||||
|
if (!info)
|
||||||
|
return XcursorFalse;
|
||||||
|
info->theme_core = theme_core;
|
||||||
|
return XcursorTrue;
|
||||||
|
}
|
||||||
992
src/file.c
Normal file
992
src/file.c
Normal file
|
|
@ -0,0 +1,992 @@
|
||||||
|
/*
|
||||||
|
* $XFree86: xc/lib/Xcursor/file.c,v 1.2 2002/09/18 17:11:42 tsi Exp $
|
||||||
|
*
|
||||||
|
* Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||||
|
* documentation for any purpose is hereby granted without fee, provided that
|
||||||
|
* the above copyright notice appear in all copies and that both that
|
||||||
|
* copyright notice and this permission notice appear in supporting
|
||||||
|
* documentation, and that the name of Keith Packard not be used in
|
||||||
|
* advertising or publicity pertaining to distribution of the software without
|
||||||
|
* specific, written prior permission. Keith Packard makes no
|
||||||
|
* representations about the suitability of this software for any purpose. It
|
||||||
|
* is provided "as is" without express or implied warranty.
|
||||||
|
*
|
||||||
|
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||||
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||||
|
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||||
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||||
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xcursorint.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
XcursorImage *
|
||||||
|
XcursorImageCreate (int width, int height)
|
||||||
|
{
|
||||||
|
XcursorImage *image;
|
||||||
|
|
||||||
|
image = malloc (sizeof (XcursorImage) +
|
||||||
|
width * height * sizeof (XcursorPixel));
|
||||||
|
if (!image)
|
||||||
|
return 0;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
XcursorImageDestroy (XcursorImage *image)
|
||||||
|
{
|
||||||
|
free (image);
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorImages *
|
||||||
|
XcursorImagesCreate (int size)
|
||||||
|
{
|
||||||
|
XcursorImages *images;
|
||||||
|
|
||||||
|
images = malloc (sizeof (XcursorImages) +
|
||||||
|
size * sizeof (XcursorImage *));
|
||||||
|
if (!images)
|
||||||
|
return 0;
|
||||||
|
images->nimage = 0;
|
||||||
|
images->images = (XcursorImage **) (images + 1);
|
||||||
|
return images;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
XcursorImagesDestroy (XcursorImages *images)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for (n = 0; n < images->nimage; n++)
|
||||||
|
XcursorImageDestroy (images->images[n]);
|
||||||
|
free (images);
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorComment *
|
||||||
|
XcursorCommentCreate (XcursorUInt comment_type, int length)
|
||||||
|
{
|
||||||
|
XcursorComment *comment;
|
||||||
|
|
||||||
|
if (length > XCURSOR_COMMENT_MAX_LEN)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
comment = malloc (sizeof (XcursorComment) + length + 1);
|
||||||
|
if (!comment)
|
||||||
|
return 0;
|
||||||
|
comment->version = XCURSOR_COMMENT_VERSION;
|
||||||
|
comment->comment_type = comment_type;
|
||||||
|
comment->comment = (char *) (comment + 1);
|
||||||
|
comment->comment[0] = '\0';
|
||||||
|
return comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
XcursorCommentDestroy (XcursorComment *comment)
|
||||||
|
{
|
||||||
|
free (comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorComments *
|
||||||
|
XcursorCommentsCreate (int size)
|
||||||
|
{
|
||||||
|
XcursorComments *comments;
|
||||||
|
|
||||||
|
comments = malloc (sizeof (XcursorComments) +
|
||||||
|
size * sizeof (XcursorComment *));
|
||||||
|
if (!comments)
|
||||||
|
return 0;
|
||||||
|
comments->ncomment = 0;
|
||||||
|
comments->comments = (XcursorComment **) (comments + 1);
|
||||||
|
return comments;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
XcursorCommentsDestroy (XcursorComments *comments)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for (n = 0; n < comments->ncomment; n++)
|
||||||
|
XcursorCommentDestroy (comments->comments[n]);
|
||||||
|
free (comments);
|
||||||
|
}
|
||||||
|
|
||||||
|
static XcursorBool
|
||||||
|
_XcursorReadUInt (XcursorFile *file, XcursorUInt *u)
|
||||||
|
{
|
||||||
|
unsigned char bytes[4];
|
||||||
|
|
||||||
|
if ((*file->read) (file, bytes, 4) != 4)
|
||||||
|
return XcursorFalse;
|
||||||
|
*u = ((bytes[0] << 0) |
|
||||||
|
(bytes[1] << 8) |
|
||||||
|
(bytes[2] << 16) |
|
||||||
|
(bytes[3] << 24));
|
||||||
|
return XcursorTrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XcursorBool
|
||||||
|
_XcursorReadBytes (XcursorFile *file, char *bytes, int length)
|
||||||
|
{
|
||||||
|
if ((*file->read) (file, (unsigned char *) bytes, length) != length)
|
||||||
|
return XcursorFalse;
|
||||||
|
return XcursorTrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XcursorBool
|
||||||
|
_XcursorWriteUInt (XcursorFile *file, XcursorUInt u)
|
||||||
|
{
|
||||||
|
unsigned char bytes[4];
|
||||||
|
|
||||||
|
bytes[0] = u;
|
||||||
|
bytes[1] = u >> 8;
|
||||||
|
bytes[2] = u >> 16;
|
||||||
|
bytes[3] = u >> 24;
|
||||||
|
if ((*file->write) (file, bytes, 4) != 4)
|
||||||
|
return XcursorFalse;
|
||||||
|
return XcursorTrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XcursorBool
|
||||||
|
_XcursorWriteBytes (XcursorFile *file, char *bytes, int length)
|
||||||
|
{
|
||||||
|
if ((*file->write) (file, (unsigned char *) bytes, length) != length)
|
||||||
|
return XcursorFalse;
|
||||||
|
return XcursorTrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_XcursorFileHeaderDestroy (XcursorFileHeader *fileHeader)
|
||||||
|
{
|
||||||
|
free (fileHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
static XcursorFileHeader *
|
||||||
|
_XcursorFileHeaderCreate (int ntoc)
|
||||||
|
{
|
||||||
|
XcursorFileHeader *fileHeader;
|
||||||
|
|
||||||
|
if (ntoc > 0x10000)
|
||||||
|
return 0;
|
||||||
|
fileHeader = malloc (sizeof (XcursorFileHeader) +
|
||||||
|
ntoc * sizeof (XcursorFileToc));
|
||||||
|
if (!fileHeader)
|
||||||
|
return 0;
|
||||||
|
fileHeader->magic = XCURSOR_MAGIC;
|
||||||
|
fileHeader->header = XCURSOR_FILE_HEADER_LEN;
|
||||||
|
fileHeader->version = XCURSOR_VERSION;
|
||||||
|
fileHeader->ntoc = ntoc;
|
||||||
|
fileHeader->tocs = (XcursorFileToc *) (fileHeader + 1);
|
||||||
|
return fileHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XcursorFileHeader *
|
||||||
|
_XcursorReadFileHeader (XcursorFile *file)
|
||||||
|
{
|
||||||
|
XcursorFileHeader head, *fileHeader;
|
||||||
|
XcursorUInt skip;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (!_XcursorReadUInt (file, &head.magic))
|
||||||
|
return 0;
|
||||||
|
if (head.magic != XCURSOR_MAGIC)
|
||||||
|
return 0;
|
||||||
|
if (!_XcursorReadUInt (file, &head.header))
|
||||||
|
return 0;
|
||||||
|
if (!_XcursorReadUInt (file, &head.version))
|
||||||
|
return 0;
|
||||||
|
if (!_XcursorReadUInt (file, &head.ntoc))
|
||||||
|
return 0;
|
||||||
|
skip = head.header - XCURSOR_FILE_HEADER_LEN;
|
||||||
|
if (skip)
|
||||||
|
if ((*file->seek) (file, skip, SEEK_CUR) == EOF)
|
||||||
|
return 0;
|
||||||
|
fileHeader = _XcursorFileHeaderCreate (head.ntoc);
|
||||||
|
if (!fileHeader)
|
||||||
|
return 0;
|
||||||
|
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 0;
|
||||||
|
}
|
||||||
|
return fileHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XcursorUInt
|
||||||
|
_XcursorFileHeaderLength (XcursorFileHeader *fileHeader)
|
||||||
|
{
|
||||||
|
return (XCURSOR_FILE_HEADER_LEN +
|
||||||
|
fileHeader->ntoc * XCURSOR_FILE_TOC_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static XcursorBool
|
||||||
|
_XcursorWriteFileHeader (XcursorFile *file, XcursorFileHeader *fileHeader)
|
||||||
|
{
|
||||||
|
int toc;
|
||||||
|
|
||||||
|
if (!_XcursorWriteUInt (file, fileHeader->magic))
|
||||||
|
return XcursorFalse;
|
||||||
|
if (!_XcursorWriteUInt (file, fileHeader->header))
|
||||||
|
return XcursorFalse;
|
||||||
|
if (!_XcursorWriteUInt (file, fileHeader->version))
|
||||||
|
return XcursorFalse;
|
||||||
|
if (!_XcursorWriteUInt (file, fileHeader->ntoc))
|
||||||
|
return XcursorFalse;
|
||||||
|
for (toc = 0; toc < fileHeader->ntoc; toc++)
|
||||||
|
{
|
||||||
|
if (!_XcursorWriteUInt (file, fileHeader->tocs[toc].type))
|
||||||
|
return XcursorFalse;
|
||||||
|
if (!_XcursorWriteUInt (file, fileHeader->tocs[toc].subtype))
|
||||||
|
return XcursorFalse;
|
||||||
|
if (!_XcursorWriteUInt (file, fileHeader->tocs[toc].position))
|
||||||
|
return XcursorFalse;
|
||||||
|
}
|
||||||
|
return XcursorTrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XcursorBool
|
||||||
|
_XcursorSeekToToc (XcursorFile *file,
|
||||||
|
XcursorFileHeader *fileHeader,
|
||||||
|
int toc)
|
||||||
|
{
|
||||||
|
if ((*file->seek) (file, fileHeader->tocs[toc].position, SEEK_SET) == EOF)
|
||||||
|
return XcursorFalse;
|
||||||
|
return XcursorTrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XcursorBool
|
||||||
|
_XcursorFileReadChunkHeader (XcursorFile *file,
|
||||||
|
XcursorFileHeader *fileHeader,
|
||||||
|
int toc,
|
||||||
|
XcursorChunkHeader *chunkHeader)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XcursorBool
|
||||||
|
_XcursorFileWriteChunkHeader (XcursorFile *file,
|
||||||
|
XcursorFileHeader *fileHeader,
|
||||||
|
int toc,
|
||||||
|
XcursorChunkHeader *chunkHeader)
|
||||||
|
{
|
||||||
|
if (!_XcursorSeekToToc (file, fileHeader, toc))
|
||||||
|
return XcursorFalse;
|
||||||
|
if (!_XcursorWriteUInt (file, chunkHeader->header))
|
||||||
|
return XcursorFalse;
|
||||||
|
if (!_XcursorWriteUInt (file, chunkHeader->type))
|
||||||
|
return XcursorFalse;
|
||||||
|
if (!_XcursorWriteUInt (file, chunkHeader->subtype))
|
||||||
|
return XcursorFalse;
|
||||||
|
if (!_XcursorWriteUInt (file, chunkHeader->version))
|
||||||
|
return XcursorFalse;
|
||||||
|
return XcursorTrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define dist(a,b) ((a) > (b) ? (a) - (b) : (b) - (a))
|
||||||
|
|
||||||
|
static XcursorDim
|
||||||
|
_XcursorFindBestSize (XcursorFileHeader *fileHeader,
|
||||||
|
XcursorDim size,
|
||||||
|
int *nsizesp)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
int nsizes = 0;
|
||||||
|
XcursorDim bestSize = 0;
|
||||||
|
XcursorDim thisSize;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_XcursorFindImageToc (XcursorFileHeader *fileHeader,
|
||||||
|
XcursorDim size,
|
||||||
|
int count)
|
||||||
|
{
|
||||||
|
int toc;
|
||||||
|
XcursorDim thisSize;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XcursorImage *
|
||||||
|
_XcursorReadImage (XcursorFile *file,
|
||||||
|
XcursorFileHeader *fileHeader,
|
||||||
|
int toc)
|
||||||
|
{
|
||||||
|
XcursorChunkHeader chunkHeader;
|
||||||
|
XcursorImage head;
|
||||||
|
XcursorImage *image;
|
||||||
|
int n;
|
||||||
|
XcursorPixel *p;
|
||||||
|
|
||||||
|
if (!_XcursorFileReadChunkHeader (file, fileHeader, toc, &chunkHeader))
|
||||||
|
return 0;
|
||||||
|
if (!_XcursorReadUInt (file, &head.width))
|
||||||
|
return 0;
|
||||||
|
if (!_XcursorReadUInt (file, &head.height))
|
||||||
|
return 0;
|
||||||
|
if (!_XcursorReadUInt (file, &head.xhot))
|
||||||
|
return 0;
|
||||||
|
if (!_XcursorReadUInt (file, &head.yhot))
|
||||||
|
return 0;
|
||||||
|
if (!_XcursorReadUInt (file, &head.delay))
|
||||||
|
return 0;
|
||||||
|
/* sanity check data */
|
||||||
|
if (head.width >= 0x10000 || head.height > 0x10000)
|
||||||
|
return 0;
|
||||||
|
if (head.width == 0 || head.height == 0)
|
||||||
|
return 0;
|
||||||
|
if (head.xhot > head.width || head.yhot > head.height)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Create the image and initialize it */
|
||||||
|
image = XcursorImageCreate (head.width, head.height);
|
||||||
|
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 0;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XcursorUInt
|
||||||
|
_XcursorImageLength (XcursorImage *image)
|
||||||
|
{
|
||||||
|
return XCURSOR_IMAGE_HEADER_LEN + (image->width * image->height) * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XcursorBool
|
||||||
|
_XcursorWriteImage (XcursorFile *file,
|
||||||
|
XcursorFileHeader *fileHeader,
|
||||||
|
int toc,
|
||||||
|
XcursorImage *image)
|
||||||
|
{
|
||||||
|
XcursorChunkHeader chunkHeader;
|
||||||
|
int n;
|
||||||
|
XcursorPixel *p;
|
||||||
|
|
||||||
|
/* sanity check data */
|
||||||
|
if (image->width > XCURSOR_IMAGE_MAX_SIZE ||
|
||||||
|
image->height > XCURSOR_IMAGE_MAX_SIZE)
|
||||||
|
return XcursorFalse;
|
||||||
|
if (image->width == 0 || image->height == 0)
|
||||||
|
return XcursorFalse;
|
||||||
|
if (image->xhot > image->width || image->yhot > image->height)
|
||||||
|
return XcursorFalse;
|
||||||
|
|
||||||
|
/* write chunk header */
|
||||||
|
chunkHeader.header = XCURSOR_IMAGE_HEADER_LEN;
|
||||||
|
chunkHeader.type = XCURSOR_IMAGE_TYPE;
|
||||||
|
chunkHeader.subtype = image->size;
|
||||||
|
chunkHeader.version = XCURSOR_IMAGE_VERSION;
|
||||||
|
|
||||||
|
if (!_XcursorFileWriteChunkHeader (file, fileHeader, toc, &chunkHeader))
|
||||||
|
return XcursorFalse;
|
||||||
|
|
||||||
|
/* write extra image header fields */
|
||||||
|
if (!_XcursorWriteUInt (file, image->width))
|
||||||
|
return XcursorFalse;
|
||||||
|
if (!_XcursorWriteUInt (file, image->height))
|
||||||
|
return XcursorFalse;
|
||||||
|
if (!_XcursorWriteUInt (file, image->xhot))
|
||||||
|
return XcursorFalse;
|
||||||
|
if (!_XcursorWriteUInt (file, image->yhot))
|
||||||
|
return XcursorFalse;
|
||||||
|
if (!_XcursorWriteUInt (file, image->delay))
|
||||||
|
return XcursorFalse;
|
||||||
|
|
||||||
|
/* write the image */
|
||||||
|
n = image->width * image->height;
|
||||||
|
p = image->pixels;
|
||||||
|
while (n--)
|
||||||
|
{
|
||||||
|
if (!_XcursorWriteUInt (file, *p))
|
||||||
|
return XcursorFalse;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
return XcursorTrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XcursorComment *
|
||||||
|
_XcursorReadComment (XcursorFile *file,
|
||||||
|
XcursorFileHeader *fileHeader,
|
||||||
|
int toc)
|
||||||
|
{
|
||||||
|
XcursorChunkHeader chunkHeader;
|
||||||
|
XcursorUInt length;
|
||||||
|
XcursorComment *comment;
|
||||||
|
|
||||||
|
/* read chunk header */
|
||||||
|
if (!_XcursorFileReadChunkHeader (file, fileHeader, toc, &chunkHeader))
|
||||||
|
return 0;
|
||||||
|
/* read extra comment header fields */
|
||||||
|
if (!_XcursorReadUInt (file, &length))
|
||||||
|
return 0;
|
||||||
|
comment = XcursorCommentCreate (chunkHeader.subtype, length);
|
||||||
|
if (!comment)
|
||||||
|
return 0;
|
||||||
|
if (!_XcursorReadBytes (file, comment->comment, length))
|
||||||
|
{
|
||||||
|
XcursorCommentDestroy (comment);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
comment->comment[length] = '\0';
|
||||||
|
return comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XcursorUInt
|
||||||
|
_XcursorCommentLength (XcursorComment *comment)
|
||||||
|
{
|
||||||
|
return XCURSOR_COMMENT_HEADER_LEN + strlen (comment->comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
static XcursorBool
|
||||||
|
_XcursorWriteComment (XcursorFile *file,
|
||||||
|
XcursorFileHeader *fileHeader,
|
||||||
|
int toc,
|
||||||
|
XcursorComment *comment)
|
||||||
|
{
|
||||||
|
XcursorChunkHeader chunkHeader;
|
||||||
|
XcursorUInt length;
|
||||||
|
|
||||||
|
length = strlen (comment->comment);
|
||||||
|
|
||||||
|
/* sanity check data */
|
||||||
|
if (length > XCURSOR_COMMENT_MAX_LEN)
|
||||||
|
return XcursorFalse;
|
||||||
|
|
||||||
|
/* read chunk header */
|
||||||
|
chunkHeader.header = XCURSOR_COMMENT_HEADER_LEN;
|
||||||
|
chunkHeader.type = XCURSOR_COMMENT_TYPE;
|
||||||
|
chunkHeader.subtype = comment->comment_type;
|
||||||
|
chunkHeader.version = XCURSOR_COMMENT_VERSION;
|
||||||
|
|
||||||
|
if (!_XcursorFileWriteChunkHeader (file, fileHeader, toc, &chunkHeader))
|
||||||
|
return XcursorFalse;
|
||||||
|
|
||||||
|
/* write extra comment header fields */
|
||||||
|
if (!_XcursorWriteUInt (file, length))
|
||||||
|
return XcursorFalse;
|
||||||
|
|
||||||
|
if (!_XcursorWriteBytes (file, comment->comment, length))
|
||||||
|
return XcursorFalse;
|
||||||
|
return XcursorTrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorImage *
|
||||||
|
XcursorXcFileLoadImage (XcursorFile *file, int size)
|
||||||
|
{
|
||||||
|
XcursorFileHeader *fileHeader;
|
||||||
|
XcursorDim bestSize;
|
||||||
|
int nsize;
|
||||||
|
int toc;
|
||||||
|
XcursorImage *image;
|
||||||
|
|
||||||
|
if (size < 0)
|
||||||
|
return 0;
|
||||||
|
fileHeader = _XcursorReadFileHeader (file);
|
||||||
|
if (!fileHeader)
|
||||||
|
return 0;
|
||||||
|
bestSize = _XcursorFindBestSize (fileHeader, (XcursorDim) size, &nsize);
|
||||||
|
if (!bestSize)
|
||||||
|
return 0;
|
||||||
|
toc = _XcursorFindImageToc (fileHeader, bestSize, 0);
|
||||||
|
if (toc < 0)
|
||||||
|
return 0;
|
||||||
|
image = _XcursorReadImage (file, fileHeader, toc);
|
||||||
|
_XcursorFileHeaderDestroy (fileHeader);
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorImages *
|
||||||
|
XcursorXcFileLoadImages (XcursorFile *file, int size)
|
||||||
|
{
|
||||||
|
XcursorFileHeader *fileHeader;
|
||||||
|
XcursorDim bestSize;
|
||||||
|
int nsize;
|
||||||
|
XcursorImages *images;
|
||||||
|
int n;
|
||||||
|
int toc;
|
||||||
|
|
||||||
|
if (size < 0)
|
||||||
|
return 0;
|
||||||
|
fileHeader = _XcursorReadFileHeader (file);
|
||||||
|
if (!fileHeader)
|
||||||
|
return 0;
|
||||||
|
bestSize = _XcursorFindBestSize (fileHeader, (XcursorDim) size, &nsize);
|
||||||
|
if (!bestSize)
|
||||||
|
return 0;
|
||||||
|
images = XcursorImagesCreate (nsize);
|
||||||
|
if (!images)
|
||||||
|
return 0;
|
||||||
|
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 = 0;
|
||||||
|
}
|
||||||
|
return images;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorImages *
|
||||||
|
XcursorXcFileLoadAllImages (XcursorFile *file)
|
||||||
|
{
|
||||||
|
XcursorFileHeader *fileHeader;
|
||||||
|
XcursorImage *image;
|
||||||
|
XcursorImages *images;
|
||||||
|
int nimage;
|
||||||
|
int n;
|
||||||
|
int toc;
|
||||||
|
|
||||||
|
fileHeader = _XcursorReadFileHeader (file);
|
||||||
|
if (!fileHeader)
|
||||||
|
return 0;
|
||||||
|
nimage = 0;
|
||||||
|
for (n = 0; n < fileHeader->ntoc; n++)
|
||||||
|
{
|
||||||
|
switch (fileHeader->tocs[n].type) {
|
||||||
|
case XCURSOR_IMAGE_TYPE:
|
||||||
|
nimage++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
images = XcursorImagesCreate (nimage);
|
||||||
|
if (!images)
|
||||||
|
return 0;
|
||||||
|
for (toc = 0; toc < fileHeader->ntoc; toc++)
|
||||||
|
{
|
||||||
|
switch (fileHeader->tocs[toc].type) {
|
||||||
|
case XCURSOR_IMAGE_TYPE:
|
||||||
|
image = _XcursorReadImage (file, fileHeader, toc);
|
||||||
|
if (image)
|
||||||
|
{
|
||||||
|
images->images[images->nimage] = image;
|
||||||
|
images->nimage++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_XcursorFileHeaderDestroy (fileHeader);
|
||||||
|
if (images->nimage != nimage)
|
||||||
|
{
|
||||||
|
XcursorImagesDestroy (images);
|
||||||
|
images = 0;
|
||||||
|
}
|
||||||
|
return images;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorXcFileLoad (XcursorFile *file,
|
||||||
|
XcursorComments **commentsp,
|
||||||
|
XcursorImages **imagesp)
|
||||||
|
{
|
||||||
|
XcursorFileHeader *fileHeader;
|
||||||
|
int nimage;
|
||||||
|
int ncomment;
|
||||||
|
XcursorImages *images;
|
||||||
|
XcursorImage *image;
|
||||||
|
XcursorComment *comment;
|
||||||
|
XcursorComments *comments;
|
||||||
|
int toc;
|
||||||
|
|
||||||
|
fileHeader = _XcursorReadFileHeader (file);
|
||||||
|
if (!fileHeader)
|
||||||
|
return 0;
|
||||||
|
nimage = 0;
|
||||||
|
ncomment = 0;
|
||||||
|
for (toc = 0; toc < fileHeader->ntoc; toc++)
|
||||||
|
{
|
||||||
|
switch (fileHeader->tocs[toc].type) {
|
||||||
|
case XCURSOR_COMMENT_TYPE:
|
||||||
|
ncomment++;
|
||||||
|
break;
|
||||||
|
case XCURSOR_IMAGE_TYPE:
|
||||||
|
nimage++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
images = XcursorImagesCreate (nimage);
|
||||||
|
if (!images)
|
||||||
|
return 0;
|
||||||
|
comments = XcursorCommentsCreate (ncomment);
|
||||||
|
if (!comments)
|
||||||
|
{
|
||||||
|
XcursorImagesDestroy (images);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (toc = 0; toc < fileHeader->ntoc; toc++)
|
||||||
|
{
|
||||||
|
switch (fileHeader->tocs[toc].type) {
|
||||||
|
case XCURSOR_COMMENT_TYPE:
|
||||||
|
comment = _XcursorReadComment (file, fileHeader, toc);
|
||||||
|
if (comment)
|
||||||
|
{
|
||||||
|
comments->comments[comments->ncomment] = comment;
|
||||||
|
comments->ncomment++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XCURSOR_IMAGE_TYPE:
|
||||||
|
image = _XcursorReadImage (file, fileHeader, toc);
|
||||||
|
if (image)
|
||||||
|
{
|
||||||
|
images->images[images->nimage] = image;
|
||||||
|
images->nimage++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_XcursorFileHeaderDestroy (fileHeader);
|
||||||
|
if (images->nimage != nimage || comments->ncomment != ncomment)
|
||||||
|
{
|
||||||
|
XcursorImagesDestroy (images);
|
||||||
|
XcursorCommentsDestroy (comments);
|
||||||
|
images = 0;
|
||||||
|
comments = 0;
|
||||||
|
return XcursorFalse;
|
||||||
|
}
|
||||||
|
*imagesp = images;
|
||||||
|
*commentsp = comments;
|
||||||
|
return XcursorTrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorXcFileSave (XcursorFile *file,
|
||||||
|
const XcursorComments *comments,
|
||||||
|
const XcursorImages *images)
|
||||||
|
{
|
||||||
|
XcursorFileHeader *fileHeader;
|
||||||
|
XcursorUInt position;
|
||||||
|
int n;
|
||||||
|
int toc;
|
||||||
|
|
||||||
|
fileHeader = _XcursorFileHeaderCreate (comments->ncomment + images->nimage);
|
||||||
|
if (!fileHeader)
|
||||||
|
return XcursorFalse;
|
||||||
|
|
||||||
|
position = _XcursorFileHeaderLength (fileHeader);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the toc. Place the images before the comments
|
||||||
|
* as they're more often read
|
||||||
|
*/
|
||||||
|
|
||||||
|
toc = 0;
|
||||||
|
for (n = 0; n < images->nimage; n++)
|
||||||
|
{
|
||||||
|
fileHeader->tocs[toc].type = XCURSOR_IMAGE_TYPE;
|
||||||
|
fileHeader->tocs[toc].subtype = images->images[n]->size;
|
||||||
|
fileHeader->tocs[toc].position = position;
|
||||||
|
position += _XcursorImageLength (images->images[n]);
|
||||||
|
toc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (n = 0; n < comments->ncomment; n++)
|
||||||
|
{
|
||||||
|
fileHeader->tocs[toc].type = XCURSOR_COMMENT_TYPE;
|
||||||
|
fileHeader->tocs[toc].subtype = comments->comments[n]->comment_type;
|
||||||
|
fileHeader->tocs[toc].position = position;
|
||||||
|
position += _XcursorCommentLength (comments->comments[n]);
|
||||||
|
toc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the header and the toc
|
||||||
|
*/
|
||||||
|
if (!_XcursorWriteFileHeader (file, fileHeader))
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the images
|
||||||
|
*/
|
||||||
|
toc = 0;
|
||||||
|
for (n = 0; n < images->nimage; n++)
|
||||||
|
{
|
||||||
|
if (!_XcursorWriteImage (file, fileHeader, toc, images->images[n]))
|
||||||
|
goto bail;
|
||||||
|
toc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the comments
|
||||||
|
*/
|
||||||
|
for (n = 0; n < comments->ncomment; n++)
|
||||||
|
{
|
||||||
|
if (!_XcursorWriteComment (file, fileHeader, toc, comments->comments[n]))
|
||||||
|
goto bail;
|
||||||
|
toc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
_XcursorFileHeaderDestroy (fileHeader);
|
||||||
|
return XcursorTrue;
|
||||||
|
bail:
|
||||||
|
_XcursorFileHeaderDestroy (fileHeader);
|
||||||
|
return XcursorFalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_XcursorStdioFileRead (XcursorFile *file, unsigned char *buf, int len)
|
||||||
|
{
|
||||||
|
FILE *f = file->closure;
|
||||||
|
return fread (buf, 1, len, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_XcursorStdioFileWrite (XcursorFile *file, unsigned char *buf, int len)
|
||||||
|
{
|
||||||
|
FILE *f = file->closure;
|
||||||
|
return fwrite (buf, 1, len, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_XcursorStdioFileSeek (XcursorFile *file, long offset, int whence)
|
||||||
|
{
|
||||||
|
FILE *f = file->closure;
|
||||||
|
return fseek (f, offset, whence);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_XcursorStdioFileInitialize (FILE *stdfile, XcursorFile *file)
|
||||||
|
{
|
||||||
|
file->closure = stdfile;
|
||||||
|
file->read = _XcursorStdioFileRead;
|
||||||
|
file->write = _XcursorStdioFileWrite;
|
||||||
|
file->seek = _XcursorStdioFileSeek;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorImage *
|
||||||
|
XcursorFileLoadImage (FILE *file, int size)
|
||||||
|
{
|
||||||
|
XcursorFile f;
|
||||||
|
|
||||||
|
_XcursorStdioFileInitialize (file, &f);
|
||||||
|
return XcursorXcFileLoadImage (&f, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorImages *
|
||||||
|
XcursorFileLoadImages (FILE *file, int size)
|
||||||
|
{
|
||||||
|
XcursorFile f;
|
||||||
|
|
||||||
|
_XcursorStdioFileInitialize (file, &f);
|
||||||
|
return XcursorXcFileLoadImages (&f, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorImages *
|
||||||
|
XcursorFileLoadAllImages (FILE *file)
|
||||||
|
{
|
||||||
|
XcursorFile f;
|
||||||
|
|
||||||
|
_XcursorStdioFileInitialize (file, &f);
|
||||||
|
return XcursorXcFileLoadAllImages (&f);
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorFileLoad (FILE *file,
|
||||||
|
XcursorComments **commentsp,
|
||||||
|
XcursorImages **imagesp)
|
||||||
|
{
|
||||||
|
XcursorFile f;
|
||||||
|
|
||||||
|
_XcursorStdioFileInitialize (file, &f);
|
||||||
|
return XcursorXcFileLoad (&f, commentsp, imagesp);
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorFileSaveImages (FILE *file, const XcursorImages *images)
|
||||||
|
{
|
||||||
|
XcursorComments *comments = XcursorCommentsCreate (0);
|
||||||
|
XcursorFile f;
|
||||||
|
XcursorBool ret;
|
||||||
|
if (!comments)
|
||||||
|
return 0;
|
||||||
|
_XcursorStdioFileInitialize (file, &f);
|
||||||
|
ret = XcursorXcFileSave (&f, comments, images) && fflush (file) != EOF;
|
||||||
|
XcursorCommentsDestroy (comments);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorFileSave (FILE * file,
|
||||||
|
const XcursorComments *comments,
|
||||||
|
const XcursorImages *images)
|
||||||
|
{
|
||||||
|
XcursorFile f;
|
||||||
|
|
||||||
|
_XcursorStdioFileInitialize (file, &f);
|
||||||
|
return XcursorXcFileSave (&f, comments, images) && fflush (file) != EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorImage *
|
||||||
|
XcursorFilenameLoadImage (const char *file, int size)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
XcursorImage *image;
|
||||||
|
|
||||||
|
f = fopen (file, "r");
|
||||||
|
if (!f)
|
||||||
|
return 0;
|
||||||
|
image = XcursorFileLoadImage (f, size);
|
||||||
|
fclose (f);
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorImages *
|
||||||
|
XcursorFilenameLoadImages (const char *file, int size)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
XcursorImages *images;
|
||||||
|
|
||||||
|
f = fopen (file, "r");
|
||||||
|
if (!f)
|
||||||
|
return 0;
|
||||||
|
images = XcursorFileLoadImages (f, size);
|
||||||
|
fclose (f);
|
||||||
|
return images;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorImages *
|
||||||
|
XcursorFilenameLoadAllImages (const char *file)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
XcursorImages *images;
|
||||||
|
|
||||||
|
f = fopen (file, "r");
|
||||||
|
if (!f)
|
||||||
|
return 0;
|
||||||
|
images = XcursorFileLoadAllImages (f);
|
||||||
|
fclose (f);
|
||||||
|
return images;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorFilenameLoad (const char *file,
|
||||||
|
XcursorComments **commentsp,
|
||||||
|
XcursorImages **imagesp)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
XcursorBool ret;
|
||||||
|
|
||||||
|
f = fopen (file, "r");
|
||||||
|
if (!f)
|
||||||
|
return 0;
|
||||||
|
ret = XcursorFileLoad (f, commentsp, imagesp);
|
||||||
|
fclose (f);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorFilenameSaveImages (const char *file, const XcursorImages *images)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
XcursorBool ret;
|
||||||
|
|
||||||
|
f = fopen (file, "w");
|
||||||
|
if (!f)
|
||||||
|
return 0;
|
||||||
|
ret = XcursorFileSaveImages (f, images);
|
||||||
|
return fclose (f) != EOF && ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorBool
|
||||||
|
XcursorFilenameSave (const char *file,
|
||||||
|
const XcursorComments *comments,
|
||||||
|
const XcursorImages *images)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
XcursorBool ret;
|
||||||
|
|
||||||
|
f = fopen (file, "w");
|
||||||
|
if (!f)
|
||||||
|
return 0;
|
||||||
|
ret = XcursorFileSave (f, comments, images);
|
||||||
|
return fclose (f) != EOF && ret;
|
||||||
|
}
|
||||||
|
|
||||||
460
src/library.c
Normal file
460
src/library.c
Normal file
|
|
@ -0,0 +1,460 @@
|
||||||
|
/*
|
||||||
|
* $XFree86: xc/lib/Xcursor/library.c,v 1.2 2003/01/26 03:22:42 eich Exp $
|
||||||
|
*
|
||||||
|
* Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||||
|
* documentation for any purpose is hereby granted without fee, provided that
|
||||||
|
* the above copyright notice appear in all copies and that both that
|
||||||
|
* copyright notice and this permission notice appear in supporting
|
||||||
|
* documentation, and that the name of Keith Packard not be used in
|
||||||
|
* advertising or publicity pertaining to distribution of the software without
|
||||||
|
* specific, written prior permission. Keith Packard makes no
|
||||||
|
* representations about the suitability of this software for any purpose. It
|
||||||
|
* is provided "as is" without express or implied warranty.
|
||||||
|
*
|
||||||
|
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||||
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||||
|
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||||
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||||
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xcursorint.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifndef ICONDIR
|
||||||
|
#define ICONDIR "/usr/X11R6/lib/X11/icons"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CURSORPATH "~/.icons:/usr/share/icons:/usr/share/pixmaps:"ICONDIR
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
_XcursorLibraryPath (void)
|
||||||
|
{
|
||||||
|
static const char *path;
|
||||||
|
|
||||||
|
if (!path)
|
||||||
|
{
|
||||||
|
path = getenv ("XCURSOR_PATH");
|
||||||
|
if (!path)
|
||||||
|
path = CURSORPATH;
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
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';
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
_XcursorBuildThemeDir (const char *dir, const char *theme)
|
||||||
|
{
|
||||||
|
const char *colon;
|
||||||
|
const char *tcolon;
|
||||||
|
char *full;
|
||||||
|
char *home;
|
||||||
|
int dirlen;
|
||||||
|
int homelen;
|
||||||
|
int themelen;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
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 = 0;
|
||||||
|
homelen = 0;
|
||||||
|
if (*dir == '~')
|
||||||
|
{
|
||||||
|
home = getenv ("HOME");
|
||||||
|
if (!home)
|
||||||
|
return 0;
|
||||||
|
homelen = strlen (home);
|
||||||
|
dir++;
|
||||||
|
dirlen--;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = homelen + dirlen + 1 + themelen + 1;
|
||||||
|
|
||||||
|
full = malloc (len);
|
||||||
|
if (!full)
|
||||||
|
return 0;
|
||||||
|
full[0] = '\0';
|
||||||
|
|
||||||
|
if (home)
|
||||||
|
_XcursorAddPathElt (full, home, -1);
|
||||||
|
_XcursorAddPathElt (full, dir, dirlen);
|
||||||
|
_XcursorAddPathElt (full, theme, themelen);
|
||||||
|
return full;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
_XcursorBuildFullname (const char *dir, const char *subdir, const char *file)
|
||||||
|
{
|
||||||
|
char *full;
|
||||||
|
|
||||||
|
full = malloc (strlen (dir) + 1 + strlen (subdir) + 1 + strlen (file) + 1);
|
||||||
|
if (!full)
|
||||||
|
return 0;
|
||||||
|
full[0] = '\0';
|
||||||
|
_XcursorAddPathElt (full, dir, -1);
|
||||||
|
_XcursorAddPathElt (full, subdir, -1);
|
||||||
|
_XcursorAddPathElt (full, file, -1);
|
||||||
|
return full;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
_XcursorNextPath (const char *path)
|
||||||
|
{
|
||||||
|
char *colon = strchr (path, ':');
|
||||||
|
|
||||||
|
if (!colon)
|
||||||
|
return 0;
|
||||||
|
return colon + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define XcursorWhite(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
|
||||||
|
#define XcursorSep(c) ((c) == ';' || (c) == ',')
|
||||||
|
|
||||||
|
static char *
|
||||||
|
_XcursorThemeInherits (const char *full)
|
||||||
|
{
|
||||||
|
char line[8192];
|
||||||
|
char *result = 0;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
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;
|
||||||
|
l++;
|
||||||
|
while (*l == ' ') l++;
|
||||||
|
result = malloc (strlen (l));
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
r = result;
|
||||||
|
while (*l)
|
||||||
|
{
|
||||||
|
while (XcursorSep(*l) || XcursorWhite (*l)) l++;
|
||||||
|
if (!*l)
|
||||||
|
break;
|
||||||
|
if (r != result)
|
||||||
|
*r++ = ':';
|
||||||
|
while (*l && !XcursorWhite(*l) &&
|
||||||
|
!XcursorSep(*l))
|
||||||
|
*r++ = *l++;
|
||||||
|
}
|
||||||
|
*r++ = '\0';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose (f);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define XCURSOR_SCAN_CORE ((FILE *) 1)
|
||||||
|
|
||||||
|
static FILE *
|
||||||
|
XcursorScanTheme (const char *theme, const char *name)
|
||||||
|
{
|
||||||
|
FILE *f = 0;
|
||||||
|
char *full;
|
||||||
|
char *dir;
|
||||||
|
const char *path;
|
||||||
|
char *inherits = 0;
|
||||||
|
const char *i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XCURSOR_CORE_THEME is a magic name; cursors from the core set
|
||||||
|
* are never found in any directory. Instead, a magic value is
|
||||||
|
* returned which truncates any search so that overlying functions
|
||||||
|
* can switch to equivalent core cursors
|
||||||
|
*/
|
||||||
|
if (!strcmp (theme, XCURSOR_CORE_THEME) && XcursorLibraryShape (name) >= 0)
|
||||||
|
return XCURSOR_SCAN_CORE;
|
||||||
|
/*
|
||||||
|
* Scan this theme
|
||||||
|
*/
|
||||||
|
for (path = _XcursorLibraryPath ();
|
||||||
|
path && f == 0;
|
||||||
|
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 == 0; i = _XcursorNextPath (i))
|
||||||
|
f = XcursorScanTheme (i, name);
|
||||||
|
if (inherits)
|
||||||
|
free (inherits);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorImage *
|
||||||
|
XcursorLibraryLoadImage (const char *file, const char *theme, int size)
|
||||||
|
{
|
||||||
|
FILE *f = 0;
|
||||||
|
XcursorImage *image = 0;
|
||||||
|
|
||||||
|
if (theme)
|
||||||
|
f = XcursorScanTheme (theme, file);
|
||||||
|
if (!f)
|
||||||
|
f = XcursorScanTheme ("default", file);
|
||||||
|
if (f == XCURSOR_SCAN_CORE)
|
||||||
|
return 0;
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
image = XcursorFileLoadImage (f, size);
|
||||||
|
fclose (f);
|
||||||
|
}
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorImages *
|
||||||
|
XcursorLibraryLoadImages (const char *file, const char *theme, int size)
|
||||||
|
{
|
||||||
|
FILE *f = 0;
|
||||||
|
XcursorImages *images = 0;
|
||||||
|
|
||||||
|
if (theme)
|
||||||
|
f = XcursorScanTheme (theme, file);
|
||||||
|
if (!f)
|
||||||
|
f = XcursorScanTheme ("default", file);
|
||||||
|
if (f == XCURSOR_SCAN_CORE)
|
||||||
|
return 0;
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
images = XcursorFileLoadImages (f, size);
|
||||||
|
fclose (f);
|
||||||
|
}
|
||||||
|
return images;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cursor
|
||||||
|
XcursorLibraryLoadCursor (Display *dpy, const char *file)
|
||||||
|
{
|
||||||
|
int size = XcursorGetDefaultSize (dpy);
|
||||||
|
char *theme = XcursorGetTheme (dpy);
|
||||||
|
XcursorImages *images = XcursorLibraryLoadImages (file, theme, size);
|
||||||
|
Cursor cursor;
|
||||||
|
|
||||||
|
if (!images)
|
||||||
|
{
|
||||||
|
int id = XcursorLibraryShape (file);
|
||||||
|
|
||||||
|
if (id >= 0)
|
||||||
|
return _XcursorCreateFontCursor (dpy, id);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
cursor = XcursorImagesLoadCursor (dpy, images);
|
||||||
|
XcursorImagesDestroy (images);
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorCursors *
|
||||||
|
XcursorLibraryLoadCursors (Display *dpy, const char *file)
|
||||||
|
{
|
||||||
|
int size = XcursorGetDefaultSize (dpy);
|
||||||
|
char *theme = XcursorGetTheme (dpy);
|
||||||
|
XcursorImages *images = XcursorLibraryLoadImages (file, theme, size);
|
||||||
|
XcursorCursors *cursors;
|
||||||
|
|
||||||
|
if (!images)
|
||||||
|
{
|
||||||
|
int id = XcursorLibraryShape (file);
|
||||||
|
|
||||||
|
if (id >= 0)
|
||||||
|
{
|
||||||
|
cursors = XcursorCursorsCreate (dpy, 1);
|
||||||
|
if (cursors)
|
||||||
|
{
|
||||||
|
cursors->cursors[0] = _XcursorCreateFontCursor (dpy, id);
|
||||||
|
if (cursors->cursors[0] == None)
|
||||||
|
{
|
||||||
|
XcursorCursorsDestroy (cursors);
|
||||||
|
cursors = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cursors->ncursor = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cursors = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cursors = XcursorImagesLoadCursors (dpy, images);
|
||||||
|
XcursorImagesDestroy (images);
|
||||||
|
}
|
||||||
|
return cursors;
|
||||||
|
}
|
||||||
|
|
||||||
|
const static char *_XcursorStandardNames[] = {
|
||||||
|
/* 0 */
|
||||||
|
"X_cursor", "arrow", "based_arrow_down", "based_arrow_up",
|
||||||
|
"boat", "bogosity", "bottom_left_corner", "bottom_right_corner",
|
||||||
|
"bottom_side", "bottom_tee", "box_spiral", "center_ptr",
|
||||||
|
"circle", "clock", "coffee_mug", "cross",
|
||||||
|
|
||||||
|
/* 32 */
|
||||||
|
"cross_reverse", "crosshair", "diamond_cross", "dot",
|
||||||
|
"dotbox", "double_arrow", "draft_large", "draft_small",
|
||||||
|
"draped_box", "exchange", "fleur", "gobbler",
|
||||||
|
"gumby", "hand1", "hand2", "heart",
|
||||||
|
|
||||||
|
/* 64 */
|
||||||
|
"icon", "iron_cross", "left_ptr", "left_side",
|
||||||
|
"left_tee", "leftbutton", "ll_angle", "lr_angle",
|
||||||
|
"man", "middlebutton", "mouse", "pencil",
|
||||||
|
"pirate", "plus", "question_arrow", "right_ptr",
|
||||||
|
|
||||||
|
/* 96 */
|
||||||
|
"right_side", "right_tee", "rightbutton", "rtl_logo",
|
||||||
|
"sailboat", "sb_down_arrow", "sb_h_double_arrow", "sb_left_arrow",
|
||||||
|
"sb_right_arrow", "sb_up_arrow", "sb_v_double_arrow", "shuttle",
|
||||||
|
"sizing", "spider", "spraycan", "star",
|
||||||
|
|
||||||
|
/* 128 */
|
||||||
|
"target", "tcross", "top_left_arrow", "top_left_corner",
|
||||||
|
"top_right_corner", "top_side", "top_tee", "trek",
|
||||||
|
"ul_angle", "umbrella", "ur_angle", "watch",
|
||||||
|
"xterm",
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NUM_STANDARD_NAMES (sizeof _XcursorStandardNames / sizeof _XcursorStandardNames[0])
|
||||||
|
|
||||||
|
XcursorImage *
|
||||||
|
XcursorShapeLoadImage (unsigned int shape, const char *theme, int size)
|
||||||
|
{
|
||||||
|
unsigned int id = shape >> 1;
|
||||||
|
|
||||||
|
if (id < NUM_STANDARD_NAMES)
|
||||||
|
return XcursorLibraryLoadImage (_XcursorStandardNames[id],
|
||||||
|
theme, size);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorImages *
|
||||||
|
XcursorShapeLoadImages (unsigned int shape, const char *theme, int size)
|
||||||
|
{
|
||||||
|
unsigned int id = shape >> 1;
|
||||||
|
|
||||||
|
if (id < NUM_STANDARD_NAMES)
|
||||||
|
return XcursorLibraryLoadImages (_XcursorStandardNames[id],
|
||||||
|
theme, size);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cursor
|
||||||
|
XcursorShapeLoadCursor (Display *dpy, unsigned int shape)
|
||||||
|
{
|
||||||
|
unsigned int id = shape >> 1;
|
||||||
|
|
||||||
|
if (id < NUM_STANDARD_NAMES)
|
||||||
|
return XcursorLibraryLoadCursor (dpy, _XcursorStandardNames[id]);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorCursors *
|
||||||
|
XcursorShapeLoadCursors (Display *dpy, unsigned int shape)
|
||||||
|
{
|
||||||
|
unsigned int id = shape >> 1;
|
||||||
|
|
||||||
|
if (id < NUM_STANDARD_NAMES)
|
||||||
|
return XcursorLibraryLoadCursors (dpy, _XcursorStandardNames[id]);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
XcursorLibraryShape (const char *library)
|
||||||
|
{
|
||||||
|
int low, high;
|
||||||
|
int mid;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
low = 0;
|
||||||
|
high = NUM_STANDARD_NAMES - 1;
|
||||||
|
while (low < high - 1)
|
||||||
|
{
|
||||||
|
mid = (low + high) >> 1;
|
||||||
|
c = strcmp (library, _XcursorStandardNames[mid]);
|
||||||
|
if (c == 0)
|
||||||
|
return (mid << 1);
|
||||||
|
if (c > 0)
|
||||||
|
low = mid;
|
||||||
|
else
|
||||||
|
high = mid;
|
||||||
|
}
|
||||||
|
while (low <= high)
|
||||||
|
{
|
||||||
|
if (!strcmp (library, _XcursorStandardNames[low]))
|
||||||
|
return (low << 1);
|
||||||
|
low++;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
98
src/xcursorint.h
Normal file
98
src/xcursorint.h
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* $XFree86: xc/lib/Xcursor/xcursorint.h,v 1.4 2003/01/26 03:22:42 eich Exp $
|
||||||
|
*
|
||||||
|
* Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||||
|
* documentation for any purpose is hereby granted without fee, provided that
|
||||||
|
* the above copyright notice appear in all copies and that both that
|
||||||
|
* copyright notice and this permission notice appear in supporting
|
||||||
|
* documentation, and that the name of Keith Packard not be used in
|
||||||
|
* advertising or publicity pertaining to distribution of the software without
|
||||||
|
* specific, written prior permission. Keith Packard makes no
|
||||||
|
* representations about the suitability of this software for any purpose. It
|
||||||
|
* is provided "as is" without express or implied warranty.
|
||||||
|
*
|
||||||
|
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||||
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||||
|
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||||
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||||
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _XCURSORINT_H_
|
||||||
|
#define _XCURSORINT_H_
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/cursorfont.h>
|
||||||
|
#include <X11/extensions/Xrender.h>
|
||||||
|
#include "Xcursor.h"
|
||||||
|
|
||||||
|
typedef struct _XcursorFontInfo {
|
||||||
|
struct _XcursorFontInfo *next;
|
||||||
|
Font font;
|
||||||
|
XcursorBool is_cursor_font;
|
||||||
|
} XcursorFontInfo;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Track a few recently created bitmaps to see
|
||||||
|
* if they get used to create cursors. This
|
||||||
|
* is done by hooking into Xlib and watching
|
||||||
|
* for XCreatePixmap, XPutImage, XCreatePixmapCursor
|
||||||
|
* with appropriate arguments. When this happens
|
||||||
|
* Xcursor computes a hash value for the source image
|
||||||
|
* and tries to load a library cursor of that name.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* large bitmaps are unlikely to be cursors */
|
||||||
|
#define MAX_BITMAP_CURSOR_SIZE 64
|
||||||
|
/* don't need to remember very many; in fact, 2 is likely sufficient */
|
||||||
|
#define NUM_BITMAPS 8
|
||||||
|
|
||||||
|
typedef struct _XcursorBitmapInfo {
|
||||||
|
Pixmap bitmap;
|
||||||
|
unsigned long sequence;
|
||||||
|
unsigned int width, height;
|
||||||
|
Bool has_image;
|
||||||
|
unsigned char hash[XCURSOR_BITMAP_HASH_SIZE];
|
||||||
|
} XcursorBitmapInfo;
|
||||||
|
|
||||||
|
typedef enum _XcursorDither {
|
||||||
|
XcursorDitherThreshold,
|
||||||
|
XcursorDitherMedian,
|
||||||
|
XcursorDitherOrdered,
|
||||||
|
XcursorDitherDiffuse
|
||||||
|
} XcursorDither;
|
||||||
|
|
||||||
|
typedef struct _XcursorDisplayInfo {
|
||||||
|
struct _XcursorDisplayInfo *next;
|
||||||
|
Display *display;
|
||||||
|
XExtCodes *codes;
|
||||||
|
XcursorBool has_render_cursor;
|
||||||
|
XcursorBool has_anim_cursor;
|
||||||
|
XcursorBool theme_core;
|
||||||
|
int size;
|
||||||
|
XcursorFontInfo *fonts;
|
||||||
|
char *theme;
|
||||||
|
XcursorDither dither;
|
||||||
|
XcursorBitmapInfo bitmaps[NUM_BITMAPS];
|
||||||
|
} XcursorDisplayInfo;
|
||||||
|
|
||||||
|
XcursorDisplayInfo *
|
||||||
|
_XcursorGetDisplayInfo (Display *dpy);
|
||||||
|
|
||||||
|
Cursor
|
||||||
|
_XcursorCreateGlyphCursor(Display *dpy,
|
||||||
|
Font source_font,
|
||||||
|
Font mask_font,
|
||||||
|
unsigned int source_char,
|
||||||
|
unsigned int mask_char,
|
||||||
|
XColor _Xconst *foreground,
|
||||||
|
XColor _Xconst *background);
|
||||||
|
|
||||||
|
Cursor
|
||||||
|
_XcursorCreateFontCursor (Display *dpy, unsigned int shape);
|
||||||
|
|
||||||
|
#endif /* _XCURSORINT_H_ */
|
||||||
399
src/xlib.c
Normal file
399
src/xlib.c
Normal file
|
|
@ -0,0 +1,399 @@
|
||||||
|
/*
|
||||||
|
* $XFree86: xc/lib/Xcursor/xlib.c,v 1.4 2003/02/22 06:16:15 dawes Exp $
|
||||||
|
*
|
||||||
|
* Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||||
|
* documentation for any purpose is hereby granted without fee, provided that
|
||||||
|
* the above copyright notice appear in all copies and that both that
|
||||||
|
* copyright notice and this permission notice appear in supporting
|
||||||
|
* documentation, and that the name of Keith Packard not be used in
|
||||||
|
* advertising or publicity pertaining to distribution of the software without
|
||||||
|
* specific, written prior permission. Keith Packard makes no
|
||||||
|
* representations about the suitability of this software for any purpose. It
|
||||||
|
* is provided "as is" without express or implied warranty.
|
||||||
|
*
|
||||||
|
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||||
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||||
|
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||||
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||||
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xcursorint.h"
|
||||||
|
#include <X11/Xlibint.h>
|
||||||
|
#include <X11/Xatom.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static XcursorBool
|
||||||
|
_XcursorFontIsCursor (Display *dpy, Font font)
|
||||||
|
{
|
||||||
|
XcursorFontInfo *fi;
|
||||||
|
XcursorDisplayInfo *info;
|
||||||
|
XcursorBool ret;
|
||||||
|
XFontStruct *fs;
|
||||||
|
int n;
|
||||||
|
Atom cursor;
|
||||||
|
|
||||||
|
if (font == dpy->cursor_font)
|
||||||
|
return XcursorTrue;
|
||||||
|
|
||||||
|
info = _XcursorGetDisplayInfo (dpy);
|
||||||
|
if (!info)
|
||||||
|
return XcursorFalse;
|
||||||
|
LockDisplay (dpy);
|
||||||
|
for (fi = info->fonts; fi; fi = fi->next)
|
||||||
|
if (fi->font == font)
|
||||||
|
{
|
||||||
|
ret = fi->is_cursor_font;
|
||||||
|
UnlockDisplay (dpy);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
UnlockDisplay (dpy);
|
||||||
|
ret = XcursorFalse;
|
||||||
|
fs = XQueryFont (dpy, font);
|
||||||
|
if (fs)
|
||||||
|
{
|
||||||
|
cursor = XInternAtom (dpy, "cursor", False);
|
||||||
|
for (n = 0; n < fs->n_properties; n++)
|
||||||
|
if (fs->properties[n].name == XA_FONT)
|
||||||
|
{
|
||||||
|
ret = (fs->properties[n].card32 == cursor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fi = malloc (sizeof (XcursorFontInfo));
|
||||||
|
if (fi)
|
||||||
|
{
|
||||||
|
fi->font = font;
|
||||||
|
fi->is_cursor_font = ret;
|
||||||
|
LockDisplay (dpy);
|
||||||
|
fi->next = info->fonts;
|
||||||
|
info->fonts = fi;
|
||||||
|
UnlockDisplay (dpy);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cursor
|
||||||
|
XcursorTryShapeCursor (Display *dpy,
|
||||||
|
Font source_font,
|
||||||
|
Font mask_font,
|
||||||
|
unsigned int source_char,
|
||||||
|
unsigned int mask_char,
|
||||||
|
XColor _Xconst *foreground,
|
||||||
|
XColor _Xconst *background)
|
||||||
|
{
|
||||||
|
Cursor cursor = None;
|
||||||
|
|
||||||
|
if (!XcursorSupportsARGB (dpy) && !XcursorGetThemeCore (dpy))
|
||||||
|
return None;
|
||||||
|
|
||||||
|
if (source_font == mask_font &&
|
||||||
|
_XcursorFontIsCursor (dpy, source_font) &&
|
||||||
|
source_char + 1 == mask_char)
|
||||||
|
{
|
||||||
|
int size = XcursorGetDefaultSize (dpy);
|
||||||
|
char *theme = XcursorGetTheme (dpy);
|
||||||
|
XcursorImages *images = XcursorShapeLoadImages (source_char, theme, size);
|
||||||
|
|
||||||
|
if (images)
|
||||||
|
{
|
||||||
|
cursor = XcursorImagesLoadCursor (dpy, images);
|
||||||
|
XcursorImagesDestroy (images);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
XcursorNoticeCreateBitmap (Display *dpy,
|
||||||
|
Pixmap pid,
|
||||||
|
unsigned int width,
|
||||||
|
unsigned int height)
|
||||||
|
{
|
||||||
|
XcursorDisplayInfo *info;
|
||||||
|
unsigned long oldest;
|
||||||
|
unsigned long now;
|
||||||
|
int i;
|
||||||
|
int replace = 0;
|
||||||
|
XcursorBitmapInfo *bmi;
|
||||||
|
|
||||||
|
if (!XcursorSupportsARGB (dpy) && !XcursorGetThemeCore (dpy))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (width > MAX_BITMAP_CURSOR_SIZE || height > MAX_BITMAP_CURSOR_SIZE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
info = _XcursorGetDisplayInfo (dpy);
|
||||||
|
if (!info)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LockDisplay (dpy);
|
||||||
|
replace = 0;
|
||||||
|
now = dpy->request;
|
||||||
|
oldest = now;
|
||||||
|
for (i = 0; i < NUM_BITMAPS; i++)
|
||||||
|
{
|
||||||
|
if (!info->bitmaps[i].bitmap)
|
||||||
|
{
|
||||||
|
replace = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((long) (now - info->bitmaps[i].sequence) >
|
||||||
|
(long) (now - oldest))
|
||||||
|
{
|
||||||
|
replace = i;
|
||||||
|
oldest = info->bitmaps[i].sequence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bmi = &info->bitmaps[replace];
|
||||||
|
bmi->bitmap = pid;
|
||||||
|
bmi->sequence = now;
|
||||||
|
bmi->width = width;
|
||||||
|
bmi->height = height;
|
||||||
|
bmi->has_image = False;
|
||||||
|
UnlockDisplay (dpy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static XcursorBitmapInfo *
|
||||||
|
_XcursorGetBitmap (Display *dpy, Pixmap bitmap)
|
||||||
|
{
|
||||||
|
XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!info)
|
||||||
|
return 0;
|
||||||
|
LockDisplay (dpy);
|
||||||
|
for (i = 0; i < NUM_BITMAPS; i++)
|
||||||
|
if (info->bitmaps[i].bitmap == bitmap)
|
||||||
|
{
|
||||||
|
info->bitmaps[i].sequence = dpy->request;
|
||||||
|
UnlockDisplay (dpy);
|
||||||
|
return &info->bitmaps[i];
|
||||||
|
}
|
||||||
|
UnlockDisplay (dpy);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
_XcursorClientLSB (void)
|
||||||
|
{
|
||||||
|
int v = 1;
|
||||||
|
return *((char *) &v) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stolen from Xlib */
|
||||||
|
static unsigned char const _reverse_byte[0x100] = {
|
||||||
|
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
|
||||||
|
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
|
||||||
|
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
|
||||||
|
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
|
||||||
|
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
|
||||||
|
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
|
||||||
|
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
|
||||||
|
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
|
||||||
|
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
|
||||||
|
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
|
||||||
|
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
|
||||||
|
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
|
||||||
|
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
|
||||||
|
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
|
||||||
|
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
|
||||||
|
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
|
||||||
|
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
|
||||||
|
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
|
||||||
|
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
|
||||||
|
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
|
||||||
|
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
|
||||||
|
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
|
||||||
|
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
|
||||||
|
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
|
||||||
|
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
|
||||||
|
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
|
||||||
|
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
|
||||||
|
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
|
||||||
|
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
|
||||||
|
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
|
||||||
|
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
|
||||||
|
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RotByte(t,i) (((t) << (i)) | ((t) >> (8 - (i))))
|
||||||
|
|
||||||
|
void
|
||||||
|
XcursorImageHash (XImage *image,
|
||||||
|
unsigned char hash[XCURSOR_BITMAP_HASH_SIZE])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int x, y;
|
||||||
|
unsigned char *line;
|
||||||
|
unsigned char t;
|
||||||
|
int low_addr;
|
||||||
|
Bool bit_swap;
|
||||||
|
|
||||||
|
for (i = 0; i < XCURSOR_BITMAP_HASH_SIZE; i++)
|
||||||
|
hash[i] = 0;
|
||||||
|
/*
|
||||||
|
* Flip byte order on MSB machines where the bitmap_unit isn't
|
||||||
|
* in bytes
|
||||||
|
*/
|
||||||
|
low_addr = 0;
|
||||||
|
if (image->bitmap_unit != 8)
|
||||||
|
{
|
||||||
|
if (!_XcursorClientLSB())
|
||||||
|
switch (image->bitmap_unit) {
|
||||||
|
case 16:
|
||||||
|
low_addr = 1;
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
low_addr = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Flip bit order on MSB images
|
||||||
|
*/
|
||||||
|
bit_swap = (image->bitmap_bit_order != LSBFirst);
|
||||||
|
|
||||||
|
line = (unsigned char *) image->data;
|
||||||
|
i = 0;
|
||||||
|
/*
|
||||||
|
* Compute the hash. Yes, it might be nice to use
|
||||||
|
* a stronger hash function, but MD5 and SHA1 are both
|
||||||
|
* a bit to expensive in time and space for this,
|
||||||
|
* and cursors are generally small enough that a weak
|
||||||
|
* hash is sufficient to distinguish among them.
|
||||||
|
*/
|
||||||
|
for (y = 0; y < image->height; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < image->bytes_per_line; x++)
|
||||||
|
{
|
||||||
|
t = line[x^low_addr];
|
||||||
|
if (bit_swap)
|
||||||
|
t = _reverse_byte[t];
|
||||||
|
if (t)
|
||||||
|
hash[(i++) & (XCURSOR_BITMAP_HASH_SIZE - 1)] ^= RotByte (t, y & 7);
|
||||||
|
}
|
||||||
|
line += image->bytes_per_line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
_XcursorLogDiscover (void)
|
||||||
|
{
|
||||||
|
static Bool been_here;
|
||||||
|
static Bool log;
|
||||||
|
|
||||||
|
if (!been_here)
|
||||||
|
{
|
||||||
|
been_here = True;
|
||||||
|
|
||||||
|
if (getenv ("XCURSOR_DISCOVER"))
|
||||||
|
log = True;
|
||||||
|
}
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
XcursorNoticePutBitmap (Display *dpy,
|
||||||
|
Drawable draw,
|
||||||
|
XImage *image)
|
||||||
|
{
|
||||||
|
XcursorBitmapInfo *bmi;
|
||||||
|
|
||||||
|
if (!XcursorSupportsARGB (dpy) && !XcursorGetThemeCore (dpy))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (image->width > MAX_BITMAP_CURSOR_SIZE ||
|
||||||
|
image->height > MAX_BITMAP_CURSOR_SIZE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bmi = _XcursorGetBitmap (dpy, (Pixmap) draw);
|
||||||
|
if (!bmi)
|
||||||
|
return;
|
||||||
|
/*
|
||||||
|
* Make sure the image fills the bitmap
|
||||||
|
*/
|
||||||
|
if (image->width != bmi->width || image->height != bmi->height)
|
||||||
|
{
|
||||||
|
bmi->bitmap = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If multiple images are placed in the same bitmap,
|
||||||
|
* assume it's not going to be a cursor
|
||||||
|
*/
|
||||||
|
if (bmi->has_image)
|
||||||
|
{
|
||||||
|
bmi->bitmap = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Make sure the image is valid
|
||||||
|
*/
|
||||||
|
if (image->bytes_per_line & ((image->bitmap_unit >> 3) - 1))
|
||||||
|
{
|
||||||
|
bmi->bitmap = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Hash the image
|
||||||
|
*/
|
||||||
|
XcursorImageHash (image, bmi->hash);
|
||||||
|
/*
|
||||||
|
* Display the hash value and the image if
|
||||||
|
* requested so that users can find out what
|
||||||
|
* cursor name is associated with each image
|
||||||
|
*/
|
||||||
|
if (_XcursorLogDiscover())
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
int i;
|
||||||
|
XImage t = *image;
|
||||||
|
|
||||||
|
XInitImage (&t);
|
||||||
|
|
||||||
|
printf ("Cursor image name: ");
|
||||||
|
for (i = 0; i < XCURSOR_BITMAP_HASH_SIZE; i++)
|
||||||
|
printf ("%02x", bmi->hash[i]);
|
||||||
|
printf ("\n");
|
||||||
|
for (y = 0; y < image->height; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < image->width; x++)
|
||||||
|
putchar (XGetPixel (&t, x, y) ? '*' : ' ');
|
||||||
|
putchar ('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bmi->has_image = True;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cursor
|
||||||
|
XcursorTryShapeBitmapCursor (Display *dpy,
|
||||||
|
Pixmap source,
|
||||||
|
Pixmap mask,
|
||||||
|
XColor *foreground,
|
||||||
|
XColor *background,
|
||||||
|
unsigned int x,
|
||||||
|
unsigned int y)
|
||||||
|
{
|
||||||
|
XcursorBitmapInfo *bmi;
|
||||||
|
char name[8 * XCURSOR_BITMAP_HASH_SIZE];
|
||||||
|
int i;
|
||||||
|
Cursor cursor;
|
||||||
|
|
||||||
|
if (!XcursorSupportsARGB (dpy) && !XcursorGetThemeCore (dpy))
|
||||||
|
return None;
|
||||||
|
|
||||||
|
bmi = _XcursorGetBitmap (dpy, source);
|
||||||
|
if (!bmi || !bmi->has_image)
|
||||||
|
return None;
|
||||||
|
for (i = 0; i < XCURSOR_BITMAP_HASH_SIZE; i++)
|
||||||
|
sprintf (name + 2 * i, "%02x", bmi->hash[i]);
|
||||||
|
cursor = XcursorLibraryLoadCursor (dpy, name);
|
||||||
|
if (_XcursorLogDiscover())
|
||||||
|
printf ("Cursor hash %s returns 0x%x\n", name, (unsigned int) cursor);
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue