mirror of
https://gitlab.freedesktop.org/xorg/lib/libxcursor.git
synced 2025-12-20 16:20:04 +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