Unverified Commit 0d921712 authored by Mihai Moldovan's avatar Mihai Moldovan

Merge branch 'sunweaver-pr/xcursor-cleanup' into arctica-3.6.x

parents cfc0202b 422fe907
Copyright © 2002 Keith Packard
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.
2005-06-30 Daniel Stone <daniel@freedesktop.org>
* lib/Xcursor/file.c:
* lib/Xcursor/library.c:
* lib/Xcursor/xlib.c:
Check arguments for validity on almost all functions.
2005-06-17 Branden Robinson <branden@deadbeast.net>
Merge changes from freedesktop.org xorg CVS trunk.
* cursor.c:
* library.c:
Add preprocessor test for HAVE_XFIXES being defined before testing
its value. [merged by Egbert Eich; author unknown]
* COPYING:
* ChangeLog:
* Xcursor.3:
* Xcursor.h:
* cursor.c:
* display.c:
* file.c:
* library.c:
* xcursorint.h:
* xlib.c:
Encoding of numerous files changed to UTF-8 [Markus Kuhn]
* cursor.c:
Bug #1043: Fix leak when creating animated cursors. [Daniel Stone]
Tue Feb 8 14:26:32 2005 Owen Taylor <otaylor@redhat.com>
* configure.ac: Remove AC_CONFIG_AUX_DIR()
2004-04-13 Daniel Stone <daniel@freedesktop.org>
* ChangeLog:
Tag 1.1.3, for xlibs 1.0.1.
2004-04-07 Keith Packard <keithp@keithp.com>
reviewed by: Michel Dänzer <michel@daenzer.net>
* configure.ac:
Make sure X_CFLAGS/X_LIBS are substituted in the xcursor.pc file
2004-02-24 Fredrik Höglund <fredrik@kde.org>
* configure.ac:
* xcursorint.h:
Make the Xfixes code actually work by including the Xfixes.h
header file.
2004-02-03 Jim Gettys <jg@freedesktop.org>
* AUTHORS: Add contents to author's file
2004-01-17 Daniel Stone <daniel@fooishbar.org>
* Xcursor.h:
* configure.ac:
Bump package version to 1.1.2, slated for first fd.o platform release.
2004-01-15 Harold L Hunt II <huntharo@msu.edu>
* Makefile.am: Pass -no-undefined to libtool via LDFLAGS.
2003-11-10 Keith Packard <keithp@keithp.com>
* library.c: (_XcursorBuildThemeDir):
Make sure the allocated path has space for directory separators
2003-10-29 Keith Packard <keithp@keithp.com>
* Xcursor.h:
* configure.ac:
Bump package version to 1.1.1 and library info to 1.2.0 as
the library exports new name-based APIs and uses Xfixes
2003-10-28 Keith Packard <keithp@keithp.com>
* Makefile.am:
* Xcursor.h:
* configure.ac:
* cursor.c: (XcursorImagesLoadCursor):
* file.c: (XcursorImagesCreate), (XcursorImagesDestroy),
(XcursorImagesSetName):
* library.c: (XcursorLibraryLoadImages),
(XcursorLibraryLoadCursor):
Add support for XFixes version 2 cursor naming functions
2003-10-16 23:45 fredrik
* Xcursor-def.cpp, Xcursor.h, configure.ac, library.c:
Rename _XcursorLibraryPath() to XcursorLibraryPath() and make
it a public function, since it's useful for theme selectors.
Bump version to 1.1.0
2003-05-21 10:21 keithp
* Makefile.am, Xcursor.h, configure.ac, xcursorint.h: Package
Xcursor.3, bump version to 1.0.2
2003-05-06 11:20 keithp
* ChangeLog: Add initial change log
2003-05-06 11:09 keithp
* .cvsignore, Makefile.am, Xcursor-def.cpp, Xcursor.3, Xcursor.h,
Xcursor.man, cursor.c, display.c, file.c, library.c, xcursorint.h,
xlib.c: Update .cvsignore, move manual and install, fix CVS ident
lines
2003-05-06 11:00 keithp
* configure.ac: replace Xrender test with fragment from Xft
2003-05-06 10:52 keithp
* Makefile.am: Add xcursorint.h to library sources list
2003-05-06 10:49 keithp
* Imakefile, Makefile.am, Xcursor.h, autogen.sh, configure.ac,
file.c, xcursor.pc.in: Convert Xcursor to autotools
2003-02-21 22:16 dawes
* xlib.c: 941. Fix a problem where a malformed Ximage can cause
Xcursor to step
outside the image data (#A.1636, Keith Packard, reported by
Michel Dänzer).
2003-02-19 19:13 dawes
* display.c: 924. Fix a memory leak in XCloseDisplay, and a
potential race condition
when multiple threads attempt to initialize the Xcursor
library
simultaneously (#A.1623, Keith Packard).
2003-02-12 19:09 dawes
* Xcursor.man: 880. Fix the Xcursor include path in the man page
(#5617, Kevin Brosius).
2003-01-25 19:22 eich
* Xcursor.h, cursor.c, library.c, xcursorint.h: 787. Add "core"
theme to Xcursor to force old behaviour (Keith Packard).
2002-11-26 21:35 keithp
* display.c: Fix XcursorSetTheme to permit NULL theme
2002-11-22 18:34 keithp
* Xcursor.h, cursor.c, display.c, xcursorint.h, xlib.c: Add animate
cursor support, client side
2002-10-11 10:06 keithp
* cursor.c: Off by one in XcursorAnimateNext (from Anders Carlsson)
2002-09-30 15:02 alanh
* Xcursor-def.cpp: add Xv-def.cpp file add $XFree86$ tags
2002-09-26 00:52 alanh
* Imakefile: #elif -> #else
2002-09-25 16:27 alanh
* Xcursor-def.cpp: #5350, add Xcursor-def.cpp
2002-09-25 09:10 torrey
* Imakefile: Add SharedXcursorReqs for operating systems that
require it.
2002-09-18 10:11 tsi
* file.c: Pacify gcc 3.2
2002-09-05 00:55 keithp
* display.c: Clean up parsing of option that forces use of core
cursors
2002-09-05 00:29 keithp
* Xcursor.h, cursor.c, display.c, xcursorint.h, xlib.c: Add
themeable app-specific cursors. Add dithers for core cursors.
Dont theme servers without Render by default
2002-08-28 21:40 keithp
* Imakefile, Xcursor.h, Xcursor.man, config-subst, cursor.c,
display.c, file.c, library.c, xcursor-config.in, xcursor.pc.in,
xcursorint.h, xlib.c: Add Xcursor library and Xlib hooks for it
XCOMM $XdotOrg: xc/lib/Xcursor/Imakefile,v 1.5 2005/10/09 21:52:42 alanc Exp $
XCOMM $XFree86: xc/lib/Xcursor/Imakefile,v 1.3 2002/09/26 07:52:01 alanh Exp $
#ifndef NormalLibXcursor
#define NormalLibXcursor YES
SOXCURSORREV=1.0.2
#endif
#ifndef SharedLibXcursor
#define SharedLibXcursor YES
#endif
#define DoNormalLib NormalLibXcursor
#define DoSharedLib SharedLibXcursor
#define DoDebugLib DebugLibXcursor
#define DoProfileLib ProfileLibXcursor
#define LibName NX_Xcursor
#define SoRev SOXCURSORREV
#define IncSubdir X11
#define IncSubSubdir Xcursor
#include <Threads.tmpl>
#ifdef SharedXcursorReqs
REQUIREDLIBS = SharedXcursorReqs
#else
REQUIREDLIBS = $(LDPRELIB) $(XRENDERLIB)
#endif
XCURSOR_VERSION=1.1.4
XRENDER_LIBS=$(XRENDERLIB)
XRENDER_CFLAGS=$(XRENDERINCLUDES)
X_LIBS=-L$(SHLIBDIR) $(XONLYLIB)
X_CFLAGS=-I$(INCROOT) $(THREADS_DEFINES)
#if BuildRenderLibrary
XRENDER_LIBS=-L$(USRLIBDIR) $(XRENDERLIB)
XRENDER_CFLAGS=-I$(INCROOT)
#endif
#if BuildXfixesLibrary
XFIXES_DEFINES = -DHAVE_XFIXES
REQUIREDLIBS += $(XFIXESLIB)
#endif
RPATH_CFLAG = HardCodeLibdirFlag
ICONDIR=$(LIBDIR)/icons
DEFINES=-DICONDIR=\"$(ICONDIR)\" $(XFIXES_DEFINES)
SRCS = cursor.c display.c file.c library.c xlib.c
OBJS = cursor.o display.o file.o library.o xlib.o
HEADERS = Xcursor.h
SUBSTVARS=prefix="$(PROJECTROOT)" \
exec_prefix="$(BINDIR)" \
libdir="$(USRLIBDIR)" \
hardcode_libdir_flag_spec="$(RPATH_CFLAG)" \
includedir="$(INCROOT)" \
XRENDER_LIBS="$(XRENDER_LIBS)"\
XRENDER_CFLAGS="$(XRENDER_CFLAGS)"\
X_LIBS="$(X_LIBS)" \
X_CFLAGS="$(X_CFLAGS)" \
VERSION="$(XCURSOR_VERSION)"
#include <Library.tmpl>
MANSUFFIX=$(LIBMANSUFFIX)
InstallManPage(Xcursor,$(LIBMANDIR))
DependTarget()
all:: xcursor-config.script
xcursor-config.script: xcursor-config.in
RemoveFile($@)
sh config-subst $(SUBSTVARS) < xcursor-config.in > $@
InstallScript(xcursor-config,$(BINDIR))
clean::
RemoveFile(xcursor-config.script)
all:: xcursor.pc
xcursor.pc: xcursor.pc.in
RemoveFile($@)
sh config-subst $(SUBSTVARS) < xcursor.pc.in > $@
InstallNonExecFile(xcursor.pc,$(USRLIBDIR)/pkgconfig)
clean::
RemoveFile(xcursor.pc)
LIBRARY Xcursor
VERSION LIBRARY_VERSION
EXPORTS
XcursorAnimateCreate
XcursorAnimateDestroy
XcursorAnimateNext
XcursorCursorsCreate
XcursorCursorsDestroy
XcursorFilenameLoadCursor
XcursorFilenameLoadCursors
XcursorImageLoadCursor
XcursorImagesLoadCursors
XcursorLibraryLoadCursor
XcursorLibraryLoadCursors
XcursorShapeLoadCursor
XcursorShapeLoadCursors
_XcursorCreateGlyphCursor
XcursorGetDefaultSize
XcursorGetTheme
XcursorSetDefaultSize
XcursorSetTheme
XcursorSupportsARGB
_XcursorGetDisplayInfo
XcursorCommentCreate
XcursorCommentDestroy
XcursorCommentsCreate
XcursorCommentsDestroy
XcursorFileLoad
XcursorFileLoadAllImages
XcursorFileLoadImage
XcursorFileLoadImages
XcursorFileSave
XcursorFileSaveImages
XcursorFilenameLoad
XcursorFilenameLoadAllImages
XcursorFilenameLoadImage
XcursorFilenameLoadImages
XcursorFilenameSave
XcursorFilenameSaveImages
XcursorImageCreate
XcursorImageDestroy
XcursorImagesCreate
XcursorImagesDestroy
XcursorXcFileLoad
XcursorXcFileLoadAllImages
XcursorXcFileLoadImage
XcursorXcFileLoadImages
XcursorXcFileSave
XcursorLibraryPath
XcursorLibraryLoadImage
XcursorLibraryLoadImages
XcursorShapeLoadImage
XcursorShapeLoadImages
XcursorTryShapeCursor
/*
* $Id: Xcursor.h,v 1.6 2005/11/09 21:31:19 kem Exp $
*
* Copyright © 2002 Keith Packard
*
* 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 */
/*
* Current Xcursor version number. This same number
* must appear in the Xcursor configure.ac file. Yes,
* it'a a pain to synchronize version numbers like this.
*/
#define XCURSOR_LIB_MAJOR 1
#define XCURSOR_LIB_MINOR 1
#define XCURSOR_LIB_REVISION 5
#define XCURSOR_LIB_VERSION ((XCURSOR_LIB_MAJOR * 10000) + \
(XCURSOR_LIB_MINOR * 100) + \
(XCURSOR_LIB_REVISION))
/*
* This version number is stored in cursor files; changes to the
* file format require updating this version number
*/
#define XCURSOR_FILE_MAJOR 1
#define XCURSOR_FILE_MINOR 0
#define XCURSOR_FILE_VERSION ((XCURSOR_FILE_MAJOR << 16) | (XCURSOR_FILE_MINOR))
#define XCURSOR_FILE_HEADER_LEN (4 * 4)
#define XCURSOR_FILE_TOC_LEN (3 * 4)
typedef struct _XcursorFileToc {
XcursorUInt type; /* chunk type */
XcursorUInt subtype; /* subtype (size for images) */
XcursorUInt position; /* absolute position in file */
} XcursorFileToc;
typedef struct _XcursorFileHeader {
XcursorUInt magic; /* magic number */
XcursorUInt header; /* byte length of header */
XcursorUInt version; /* file version number */
XcursorUInt ntoc; /* number of toc entries */
XcursorFileToc *tocs; /* table of contents */
} XcursorFileHeader;
/*
* 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 */
char *name; /* name used to load images */
} 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);
void
XcursorImagesSetName (XcursorImages *images, const char *name);
/*
* 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
*/
const char *
XcursorLibraryPath (void);
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
.\"
.\" $Id: Xcursor.man,v 1.4 2005/10/13 02:22:47 alanc Exp $
.\"
.\" Copyright © 2002 Keith Packard
.\"
.\" 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" "Keith Packard"
.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
#! /bin/sh
srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.
ORIGDIR=`pwd`
cd $srcdir
autoreconf -v --install || exit 1
cd $ORIGDIR || exit $?
$srcdir/configure --enable-maintainer-mode "$@"
dnl
dnl $Id: configure.ac,v 1.3 2005/06/29 18:46:53 daniels Exp $
dnl
dnl Copyright © 2003 Keith Packard
dnl
dnl Permission to use, copy, modify, distribute, and sell this software and its
dnl documentation for any purpose is hereby granted without fee, provided that
dnl the above copyright notice appear in all copies and that both that
dnl copyright notice and this permission notice appear in supporting
dnl documentation, and that the name of Keith Packard not be used in
dnl advertising or publicity pertaining to distribution of the software without
dnl specific, written prior permission. Keith Packard makes no
dnl representations about the suitability of this software for any purpose. It
dnl is provided "as is" without express or implied warranty.
dnl
dnl KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
dnl INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
dnl EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
dnl CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
dnl DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
dnl TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
dnl PERFORMANCE OF THIS SOFTWARE.
dnl
dnl Process this file with autoconf to create configure.
AC_PREREQ([2.57])
dnl
dnl This is the package version number, not the shared library
dnl version. This same version number must appear in Xcursor.h
dnl Yes, it is a pain to synchronize version numbers. Unfortunately, it's
dnl not possible to extract the version number here from Xcursor.h
dnl
AC_INIT([libXcursor],1.1.4,[keithp@keithp.com],[libXcursor])
AM_INIT_AUTOMAKE([dist-bzip2])
AC_CONFIG_SRCDIR([Makefile.am])
AM_MAINTAINER_MODE
AM_CONFIG_HEADER(config.h)
dnl libtool versioning
LT_CURRENT=1
LT_REVISION=2
LT_AGE=0
AC_SUBST(LT_CURRENT)
AC_SUBST(LT_REVISION)
LT_AGE=0
LT_VERSION_INFO="$LT_CURRENT:$LT_REVISION:$LT_AGE"
AC_SUBST(LT_VERSION_INFO)
LT_CURRENT_MINUS_AGE=`expr $LT_CURRENT - $LT_AGE`
AC_SUBST(LT_CURRENT_MINUS_AGE)
# Check for progs
AC_PROG_CC
AC_PROG_LIBTOOL
# Check for X
PKG_CHECK_MODULES(X, x11,
[x_found_with_pkgconfig=yes],
[x_found_with_pkgconfig=no])
if test "$x_found_with_pkgconfig" = "no"
then
AC_PATH_XTRA
X_LIBS="$X_LIBS -lX11"
if test "x$no_x" = "xyes"
then
AC_MSG_ERROR([X is required, but it was either disabled or not found.])
fi
# Check for XTHREADS
save_LIBS="$LIBS"
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $X_CFLAGS"
LIBS="$LIBS $X_LIBS"
AC_MSG_CHECKING([for XTHREADS in Xlib])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[#include <X11/Xlib.h>]],
[[return XInitThreads() == 0 ? 0 : 1;]])],
[xthreads=no],
[xthreads=yes],
[xthreads=yes])
AC_MSG_RESULT($xthreads)
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
if test "x$xthreads" = "xyes"
then
X_CFLAGS="$X_CFLAGS -DXTHREADS"
fi
if test "x$no_x" = "xyes"
then
AC_MSG_ERROR([X is required, but it was either disabled or not found.])
fi
fi
AC_SUBST(X_CFLAGS)
AC_SUBST(X_LIBS)
PKG_CHECK_MODULES(XRENDER, xrender >= 0.8.2, [xrender_found_with_pkgconfig=yes],
[xrender_found_with_pkgconfig=no])
case "$xrender_found_with_pkgconfig" in
no)
PKG_CHECK_MODULES(XRENDER, xrender >= 0.8, [old_xrender_found_with_pkgconfig=yes],
[old_xrender_found_with_pkgconfig=no])
case "$old_xrender_found_with_pkgconfig" in
no)
# checks for X
AC_PATH_X
XRENDER_CFLAGS="-I$x_includes"
XRENDER_LIBS="-L$x_libraries -lXrender -lXext -lX11"
saved_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $XRENDER_CFLAGS"
AC_CHECK_HEADERS([X11/extensions/Xrender.h], [], [AC_MSG_ERROR([Xrender.h not found.])])
CPPFLAGS="$saved_CPPFLAGS"
saved_LIBS="$LIBS"
LIBS="$LIBS $XRENDER_LIBS"
AC_CHECK_FUNCS([XRenderCreateAnimCursor], [], [AC_MSG_ERROR([libXrender not found.])])
LIBS="$saved_LIBS"
;;
yes)
XRENDER_LIBS="$XRENDER_LIBS -lXext -lX11"
;;
esac
;;
esac
PKG_CHECK_MODULES(XFIXES, xfixes, [AC_DEFINE_UNQUOTED(HAVE_XFIXES, 1, [Define to 1 if you have Xfixes])])
AC_SUBST(XRENDER_LIBS)
AC_SUBST(XRENDER_CFLAGS)
AC_OUTPUT([Makefile
xcursor.pc])
/*
* $Id: cursor.c,v 1.6 2005/07/03 07:00:56 daniels Exp $
*
* Copyright © 2002 Keith Packard
*
* 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, &centerColor) >= 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)
{
Cursor cursor;
if (images->nimage == 1 || !XcursorSupportsAnim (dpy))
cursor = XcursorImageLoadCursor (dpy, images->images[0]);
else
{
XcursorCursors *cursors = XcursorImagesLoadCursors (dpy, images);
XAnimCursor *anim;
int n;
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);
XcursorCursorsDestroy(cursors);
free (anim);
}
#if defined HAVE_XFIXES && XFIXES_MAJOR >= 2
if (images->name)
XFixesSetCursorName (dpy, cursor, images->name);
#endif
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);
}
/*
* $Id: display.c,v 1.6 2005/10/19 22:26:55 ajax Exp $
*
* Copyright © 2002 Keith Packard
*
* 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 void
_XcursorFreeDisplayInfo (XcursorDisplayInfo *info)
{
if (info->theme)
free (info->theme);
if (info->theme_from_config)
free (info->theme_from_config);
free (info);
}
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);
_XcursorFreeDisplayInfo (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;
info->theme_from_config = 0;
/*
* Get the desired theme
*/
v = getenv ("XCURSOR_THEME");
if (!v)
v = XGetDefault (dpy, "Xcursor", "theme");
if (v)
{
int len;
len = strlen (v) + 1;
info->theme = malloc (len);
if (info->theme)
strcpy (info->theme, v);
info->theme_from_config = malloc (len);
if (info->theme_from_config)
strcpy (info->theme_from_config, 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)
{
_XcursorFreeDisplayInfo (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)
theme = info->theme_from_config;
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;
}
/*
* $Id: file.c,v 1.5 2005/07/03 07:00:56 daniels Exp $
*
* Copyright © 2002 Keith Packard
*
* 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)
{
if (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);
images->name = 0;
return images;
}
void
XcursorImagesDestroy (XcursorImages *images)
{
int n;
if (!images)
return;
for (n = 0; n < images->nimage; n++)
XcursorImageDestroy (images->images[n]);
if (images->name)
free (images->name);
free (images);
}
void
XcursorImagesSetName (XcursorImages *images, const char *name)
{
char *new;
if (!images || !name)
return;
new = malloc (strlen (name) + 1);
if (!new)
return;
strcpy (new, name);
if (images->name)
free (images->name);
images->name = new;
}
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)
{
if (!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;
if (!comments)
return;
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 || !u)
return XcursorFalse;
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 || !bytes || (*file->read) (file, (unsigned char *) bytes, length) != length)
return XcursorFalse;
return XcursorTrue;
}
static XcursorBool
_XcursorWriteUInt (XcursorFile *file, XcursorUInt u)
{
unsigned char bytes[4];
if (!file)
return XcursorFalse;
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 || !bytes || (*file->write) (file, (unsigned char *) bytes, length) != length)
return XcursorFalse;
return XcursorTrue;
}
static void
_XcursorFileHeaderDestroy (XcursorFileHeader *fileHeader)
{
if (!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_FILE_VERSION;
fileHeader->ntoc = ntoc;
fileHeader->tocs = (XcursorFileToc *) (fileHeader + 1);
return fileHeader;
}
static XcursorFileHeader *
_XcursorReadFileHeader (XcursorFile *file)
{
XcursorFileHeader head, *fileHeader;
XcursorUInt skip;
int n;
if (!file)
return NULL;
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 (!file || !fileHeader)
return XcursorFalse;
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 || !fileHeader || \
(*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 (!file || !fileHeader || !chunkHeader)
return XcursorFalse;
if (!_XcursorSeekToToc (file, fileHeader, toc))
return XcursorFalse;
if (!_XcursorReadUInt (file, &chunkHeader->header))
return XcursorFalse;
if (!_XcursorReadUInt (file, &chunkHeader->type))
return XcursorFalse;
if (!_XcursorReadUInt (file, &chunkHeader->subtype))
return XcursorFalse;
if (!_XcursorReadUInt (file, &chunkHeader->version))
return XcursorFalse;
/* sanity check */
if (chunkHeader->type != fileHeader->tocs[toc].type ||
chunkHeader->subtype != fileHeader->tocs[toc].subtype)
return XcursorFalse;
return XcursorTrue;
}
static XcursorBool
_XcursorFileWriteChunkHeader (XcursorFile *file,
XcursorFileHeader *fileHeader,
int toc,
XcursorChunkHeader *chunkHeader)
{
if (!file || !fileHeader || !chunkHeader)
return XcursorFalse;
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;
if (!fileHeader || !nsizesp)
return 0;
for (n = 0; n < fileHeader->ntoc; n++)
{
if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE)
continue;
thisSize = fileHeader->tocs[n].subtype;
if (!bestSize || dist (thisSize, size) < dist (bestSize, size))
{
bestSize = thisSize;
nsizes = 1;
}
else if (thisSize == bestSize)
nsizes++;
}
*nsizesp = nsizes;
return bestSize;
}
static int
_XcursorFindImageToc (XcursorFileHeader *fileHeader,
XcursorDim size,
int count)
{
int toc;
XcursorDim thisSize;
if (!fileHeader)
return 0;
for (toc = 0; toc < fileHeader->ntoc; toc++)
{
if (fileHeader->tocs[toc].type != XCURSOR_IMAGE_TYPE)
continue;
thisSize = fileHeader->tocs[toc].subtype;
if (thisSize != size)
continue;
if (!count)
break;
count--;
}
if (toc == fileHeader->ntoc)
return -1;
return toc;
}
static XcursorImage *
_XcursorReadImage (XcursorFile *file,
XcursorFileHeader *fileHeader,
int toc)
{
XcursorChunkHeader chunkHeader;
XcursorImage head;
XcursorImage *image;
int n;
XcursorPixel *p;
if (!file || !fileHeader)
return NULL;
if (!_XcursorFileReadChunkHeader (file, fileHeader, toc, &chunkHeader))
return 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)
{
if (!image)
return 0;
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;
if (!file || !fileHeader || !image)
return XcursorFalse;
/* 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;
if (!file || !fileHeader)
return NULL;
/* 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;
if (!file || !fileHeader || !comment || !comment->comment)
return XcursorFalse;
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 (!file || 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;
if (!file)
return 0;
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;
if (!file)
return 0;
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;
if (!file || !comments || !images)
return XcursorFalse;
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;
if (!file)
return NULL;
_XcursorStdioFileInitialize (file, &f);
return XcursorXcFileLoadImage (&f, size);
}
XcursorImages *
XcursorFileLoadImages (FILE *file, int size)
{
XcursorFile f;
if (!file)
return NULL;
_XcursorStdioFileInitialize (file, &f);
return XcursorXcFileLoadImages (&f, size);
}
XcursorImages *
XcursorFileLoadAllImages (FILE *file)
{
XcursorFile f;
if (!file)
return NULL;
_XcursorStdioFileInitialize (file, &f);
return XcursorXcFileLoadAllImages (&f);
}
XcursorBool
XcursorFileLoad (FILE *file,
XcursorComments **commentsp,
XcursorImages **imagesp)
{
XcursorFile f;
if (!file || !commentsp || !imagesp)
return XcursorFalse;
_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 || !file || !images)
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;
if (!file || !comments || !images)
return XcursorFalse;
_XcursorStdioFileInitialize (file, &f);
return XcursorXcFileSave (&f, comments, images) && fflush (file) != EOF;
}
XcursorImage *
XcursorFilenameLoadImage (const char *file, int size)
{
FILE *f;
XcursorImage *image;
if (!file || size < 0)
return NULL;
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;
if (!file || size < 0)
return NULL;
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;
if (!file)
return NULL;
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;
if (!file)
return XcursorFalse;
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;
if (!file || !images)
return XcursorFalse;
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;
if (!file || !comments || !images)
return XcursorFalse;
f = fopen (file, "w");
if (!f)
return 0;
ret = XcursorFileSave (f, comments, images);
return fclose (f) != EOF && ret;
}
/*
* $Id: library.c,v 1.6 2005/12/08 17:54:40 kem Exp $
*
* Copyright © 2002 Keith Packard
*
* 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
#ifndef XCURSORPATH
#define XCURSORPATH "~/.icons:/usr/share/icons:/usr/share/pixmaps:"ICONDIR
#endif
const char *
XcursorLibraryPath (void)
{
static const char *path;
if (!path)
{
path = getenv ("XCURSOR_PATH");
if (!path)
path = XCURSORPATH;
}
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;
if (!dir || !theme)
return NULL;
colon = strchr (dir, ':');
if (!colon)
colon = dir + strlen (dir);
dirlen = colon - dir;
tcolon = strchr (theme, ':');
if (!tcolon)
tcolon = theme + strlen (theme);
themelen = tcolon - theme;
home = 0;
homelen = 0;
if (*dir == '~')
{
home = getenv ("HOME");
if (!home)
return 0;
homelen = strlen (home);
dir++;
dirlen--;
}
/*
* add space for any needed directory separators, one per component,
* and one for the trailing null
*/
len = 1 + homelen + 1 + dirlen + 1 + themelen + 1;
full = malloc (len);
if (!full)
return 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;
if (!dir || !subdir || !file)
return NULL;
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;
if (!full)
return NULL;
f = fopen (full, "r");
if (f)
{
while (fgets (line, sizeof (line), f))
{
if (!strncmp (line, "Inherits", 8))
{
char *l = line + 8;
char *r;
while (*l == ' ') l++;
if (*l != '=') continue;
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;
if (!theme || !name)
return NULL;
/*
* 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 (!file)
return NULL;
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 (!file)
return NULL;
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);
if (images)
XcursorImagesSetName (images, file);
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 (!file)
return 0;
if (!images)
{
int id = XcursorLibraryShape (file);
if (id >= 0)
return _XcursorCreateFontCursor (dpy, id);
else
return 0;
}
cursor = XcursorImagesLoadCursor (dpy, images);
XcursorImagesDestroy (images);
#if defined HAVE_XFIXES && XFIXES_MAJOR >= 2
XFixesSetCursorName (dpy, cursor, file);
#endif
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 (!file)
return NULL;
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;
}
#! /bin/sh
prefix="@prefix@"
exec_prefix="@exec_prefix@"
libdir="@libdir@"
hardcode_libdir_flag_spec=@hardcode_libdir_flag_spec@
includedir="@includedir@"
version="@VERSION@"
usage()
{
cat <<EOF
Usage: xcursor-config [OPTIONS] [LIBRARIES]
Options:
[--prefix[=DIR]]
[--exec-prefix[=DIR]]
[--version]
[--libs]
[--cflags]
EOF
exit $1
}
if test $# -eq 0 ; then
usage 1 1>&2
fi
while test $# -gt 0 ; do
case "$1" in
-*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
*) optarg= ;;
esac
case $1 in
--prefix=*)
prefix=$optarg
local_prefix=yes
;;
--prefix)
echo_prefix=yes
;;
--exec-prefix=*)
exec_prefix=$optarg
exec_prefix_set=yes
local_prefix=yes
;;
--exec-prefix)
echo_exec_prefix=yes
;;
--version)
echo $version
exit 0
;;
--cflags)
echo_cflags=yes
;;
--libs)
echo_libs=yes
;;
*)
usage 1 1>&2
;;
esac
shift
done
if test "$local_prefix" = "yes" ; then
if test "$exec_prefix_set" != "yes" ; then
exec_prefix=$prefix
fi
fi
if test "$echo_prefix" = "yes" ; then
echo $prefix
fi
if test "$echo_exec_prefix" = "yes" ; then
echo $exec_prefix
fi
if test "$echo_cflags" = "yes" ; then
cflags="-I${includedir}"
echo $cflags
fi
if test "$echo_libs" = "yes" ; then
libs="-lXcursor"
if test "${libdir}" != "/usr/lib" ; then
echo ${hardcode_libdir_flag_spec} -L${libdir} $libs
else
echo $libs
fi
fi
# EOF
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
xrenderlibs=@XRENDER_LIBS@
xrendercflags=@XRENDER_CFLAGS@
xlibs=@X_LIBS@
xcflags=@X_CFLAGS@
Name: Xcursor
Description: X Cursor Library
Version: @VERSION@
Requires: xrender
Cflags: -I${includedir} ${xrendercflags} ${xcflags}
Libs: -L${libdir} -lNX_Xcursor ${xrenderlibs} ${xlibs}
/*
* $Id: xcursorint.h,v 1.6 2005/10/19 22:26:55 ajax Exp $
*
* Copyright © 2002 Keith Packard
*
* 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_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <X11/Xlib.h>
#include <X11/cursorfont.h>
#include <X11/extensions/Xrender.h>
#ifdef HAVE_XFIXES
#include <X11/extensions/Xfixes.h>
#endif
#include "Xcursor.h"
#include "config.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;
char *theme_from_config;
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_ */
/*
* $Id: xlib.c,v 1.5 2005/07/03 07:00:56 daniels Exp $
*
* Copyright © 2002 Keith Packard
*
* 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 (!dpy || !font)
return XcursorFalse;
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 (!dpy || !source_font || !mask_font || !foreground || !background)
return 0;
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 (!dpy)
return;
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;
int i;
if (!dpy || !bitmap)
return NULL;
info = _XcursorGetDisplayInfo (dpy);
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;
if (!image)
return;
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 (!dpy || !image)
return;
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 (!dpy || !foreground || !background)
return 0;
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;
}
......@@ -159,7 +159,7 @@ all:: xrender.pc
xrender.pc: xrender.pc.in
RemoveFile($@)
sh ../Xcursor/config-subst $(SUBSTVARS) < xrender.pc.in > $@
sh config-subst $(SUBSTVARS) < xrender.pc.in > $@
InstallNonExecFile(xrender.pc,$(USRLIBDIR)/pkgconfig)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment