diff options
author | Reinhard Tartler <siretart@tauware.de> | 2011-10-10 17:43:39 +0200 |
---|---|---|
committer | Reinhard Tartler <siretart@tauware.de> | 2011-10-10 17:43:39 +0200 |
commit | f4092abdf94af6a99aff944d6264bc1284e8bdd4 (patch) | |
tree | 2ac1c9cc16ceb93edb2c4382c088dac5aeafdf0f /nx-X11/lib/Xcursor | |
parent | a840692edc9c6d19cd7c057f68e39c7d95eb767d (diff) | |
download | nx-libs-f4092abdf94af6a99aff944d6264bc1284e8bdd4.tar.gz nx-libs-f4092abdf94af6a99aff944d6264bc1284e8bdd4.tar.bz2 nx-libs-f4092abdf94af6a99aff944d6264bc1284e8bdd4.zip |
Imported nx-X11-3.1.0-1.tar.gznx-X11/3.1.0-1
Summary: Imported nx-X11-3.1.0-1.tar.gz
Keywords:
Imported nx-X11-3.1.0-1.tar.gz
into Git repository
Diffstat (limited to 'nx-X11/lib/Xcursor')
-rw-r--r-- | nx-X11/lib/Xcursor/AUTHORS | 2 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/COPYING | 19 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/ChangeLog | 202 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/INSTALL | 0 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/Imakefile | 100 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/Makefile.am | 45 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/NEWS | 0 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/README | 0 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/Xcursor-def.cpp | 54 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/Xcursor.h | 501 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/Xcursor.man | 379 | ||||
-rwxr-xr-x | nx-X11/lib/Xcursor/autogen.sh | 12 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/config-subst | 10 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/config.h | 0 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/configure.ac | 143 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/cursor.c | 815 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/display.c | 382 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/file.c | 1101 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/library.c | 495 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/xcursor-config.in | 95 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/xcursor.pc.in | 15 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/xcursorint.h | 109 | ||||
-rw-r--r-- | nx-X11/lib/Xcursor/xlib.c | 422 |
23 files changed, 4901 insertions, 0 deletions
diff --git a/nx-X11/lib/Xcursor/AUTHORS b/nx-X11/lib/Xcursor/AUTHORS new file mode 100644 index 000000000..57c4efd4e --- /dev/null +++ b/nx-X11/lib/Xcursor/AUTHORS @@ -0,0 +1,2 @@ +Keith Packard, HP + diff --git a/nx-X11/lib/Xcursor/COPYING b/nx-X11/lib/Xcursor/COPYING new file mode 100644 index 000000000..6d9f423cd --- /dev/null +++ b/nx-X11/lib/Xcursor/COPYING @@ -0,0 +1,19 @@ +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. diff --git a/nx-X11/lib/Xcursor/ChangeLog b/nx-X11/lib/Xcursor/ChangeLog new file mode 100644 index 000000000..8d5721187 --- /dev/null +++ b/nx-X11/lib/Xcursor/ChangeLog @@ -0,0 +1,202 @@ +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 + diff --git a/nx-X11/lib/Xcursor/INSTALL b/nx-X11/lib/Xcursor/INSTALL new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/nx-X11/lib/Xcursor/INSTALL diff --git a/nx-X11/lib/Xcursor/Imakefile b/nx-X11/lib/Xcursor/Imakefile new file mode 100644 index 000000000..3e50841ff --- /dev/null +++ b/nx-X11/lib/Xcursor/Imakefile @@ -0,0 +1,100 @@ +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 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) + diff --git a/nx-X11/lib/Xcursor/Makefile.am b/nx-X11/lib/Xcursor/Makefile.am new file mode 100644 index 000000000..995f86886 --- /dev/null +++ b/nx-X11/lib/Xcursor/Makefile.am @@ -0,0 +1,45 @@ +# +# $Id: Makefile.am,v 1.3 2005/06/29 18:46:53 daniels Exp $ +# +# Copyright © 2003 Keith Packard, Noah Levitt +# +# 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. + +AM_CFLAGS = $(XRENDER_CFLAGS) $(XFIXES_CFLAGS) $(X_CFLAGS) + +lib_LTLIBRARIES = libXcursor.la + +man_MANS = Xcursor.3 + +libXcursor_la_SOURCES = xcursorint.h cursor.c display.c file.c library.c xlib.c + +libXcursor_la_LIBADD = $(XRENDER_LIBS) $(XFIXES_LIBS) $(X_LIBS) + +# +# Shared library version info. This is not the same as the package version +# +libXcursor_la_LDFLAGS = -version-info @LT_VERSION_INFO@ -no-undefined + +libXcursorincludedir = $(includedir)/X11/Xcursor +libXcursorinclude_HEADERS = Xcursor.h + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = xcursor.pc + +EXTRA_DIST = $(man_MANS) xcursor.pc.in autogen.sh diff --git a/nx-X11/lib/Xcursor/NEWS b/nx-X11/lib/Xcursor/NEWS new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/nx-X11/lib/Xcursor/NEWS diff --git a/nx-X11/lib/Xcursor/README b/nx-X11/lib/Xcursor/README new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/nx-X11/lib/Xcursor/README diff --git a/nx-X11/lib/Xcursor/Xcursor-def.cpp b/nx-X11/lib/Xcursor/Xcursor-def.cpp new file mode 100644 index 000000000..e60212f01 --- /dev/null +++ b/nx-X11/lib/Xcursor/Xcursor-def.cpp @@ -0,0 +1,54 @@ +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 diff --git a/nx-X11/lib/Xcursor/Xcursor.h b/nx-X11/lib/Xcursor/Xcursor.h new file mode 100644 index 000000000..d8a7ac320 --- /dev/null +++ b/nx-X11/lib/Xcursor/Xcursor.h @@ -0,0 +1,501 @@ +/* + * $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 diff --git a/nx-X11/lib/Xcursor/Xcursor.man b/nx-X11/lib/Xcursor/Xcursor.man new file mode 100644 index 000000000..99b7213d9 --- /dev/null +++ b/nx-X11/lib/Xcursor/Xcursor.man @@ -0,0 +1,379 @@ +.\" +.\" $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 diff --git a/nx-X11/lib/Xcursor/autogen.sh b/nx-X11/lib/Xcursor/autogen.sh new file mode 100755 index 000000000..904cd6746 --- /dev/null +++ b/nx-X11/lib/Xcursor/autogen.sh @@ -0,0 +1,12 @@ +#! /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 "$@" diff --git a/nx-X11/lib/Xcursor/config-subst b/nx-X11/lib/Xcursor/config-subst new file mode 100644 index 000000000..5907e0328 --- /dev/null +++ b/nx-X11/lib/Xcursor/config-subst @@ -0,0 +1,10 @@ +#!/bin/sh +script=config-subst.$$ +trap "rm $script" 0 +rm -f $script +for i in ${1+"$@"}; do + var="`echo "$i" | sed 's/=.*$//'`" + val="`echo "$i" | sed 's/^[^=]*=//'`" + echo "s;@$var@;$val;" >> $script +done +sed -f $script diff --git a/nx-X11/lib/Xcursor/config.h b/nx-X11/lib/Xcursor/config.h new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/nx-X11/lib/Xcursor/config.h diff --git a/nx-X11/lib/Xcursor/configure.ac b/nx-X11/lib/Xcursor/configure.ac new file mode 100644 index 000000000..8ec0d2e71 --- /dev/null +++ b/nx-X11/lib/Xcursor/configure.ac @@ -0,0 +1,143 @@ +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]) diff --git a/nx-X11/lib/Xcursor/cursor.c b/nx-X11/lib/Xcursor/cursor.c new file mode 100644 index 000000000..df9610625 --- /dev/null +++ b/nx-X11/lib/Xcursor/cursor.c @@ -0,0 +1,815 @@ +/* + * $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, ¢erColor) >= 0) + XPutPixel (src_image, x, y, 0); + else + XPutPixel (src_image, x, y, 1); + } + else + { + XPutPixel (msk_image, x, y, 0); + XPutPixel (src_image, x, y, 0); + } + } + free (temp); + _XcursorPixelToColor (rightColor, &core->off_color); + _XcursorPixelToColor (leftColor, &core->on_color); + return True; +} + +#if 0 +#define DITHER_DIM 4 +static XcursorPixel orderedDither[4][4] = { + { 1, 9, 3, 11 }, + { 13, 5, 15, 7 }, + { 4, 12, 2, 10 }, + { 16, 8, 14, 6 } +}; +#else +#define DITHER_DIM 2 +static XcursorPixel orderedDither[2][2] = { + { 1, 3, }, + { 4, 2, }, +}; +#endif + +#define DITHER_SIZE ((sizeof orderedDither / sizeof orderedDither[0][0]) + 1) + +static Bool +_XcursorBayerOrderedDither (const XcursorImage *image, XcursorCoreCursor *core) +{ + int x, y; + XcursorPixel *pixel, p; + XcursorPixel a, i, d; + + pixel = image->pixels; + for (y = 0; y < image->height; y++) + for (x = 0; x < image->width; x++) + { + p = *pixel++; + a = ((p >> 24) * DITHER_SIZE + 127) / 255; + i = (_XcursorPixelBrightness (p) * DITHER_SIZE + 127) / 255; + d = orderedDither[y&(DITHER_DIM-1)][x&(DITHER_DIM-1)]; + if (a > d) + { + XPutPixel (core->msk_image, x, y, 1); + if (i > d) + XPutPixel (core->src_image, x, y, 0); /* white */ + else + XPutPixel (core->src_image, x, y, 1); /* black */ + } + else + { + XPutPixel (core->msk_image, x, y, 0); + XPutPixel (core->src_image, x, y, 0); + } + } + core->on_color.red = 0; + core->on_color.green = 0; + core->on_color.blue = 0; + core->off_color.red = 0xffff; + core->off_color.green = 0xffff; + core->off_color.blue = 0xffff; + return True; +} + +static Bool +_XcursorFloydSteinberg (const XcursorImage *image, XcursorCoreCursor *core) +{ + int *aPicture, *iPicture, *aP, *iP; + XcursorPixel *pixel, p; + int aR, iR, aA, iA; + int npixels = image->width * image->height; + int n; + int right = 1; + int belowLeft = image->width - 1; + int below = image->width; + int belowRight = image->width + 1; + int iError, aError; + int iErrorRight, aErrorRight; + int iErrorBelowLeft, aErrorBelowLeft; + int iErrorBelow, aErrorBelow; + int iErrorBelowRight, aErrorBelowRight; + int x, y; + int max_inten, min_inten, mean_inten; + + iPicture = malloc (npixels * sizeof (int) * 2); + if (!iPicture) + return False; + aPicture = iPicture + npixels; + + /* + * Compute raw gray and alpha arrays + */ + pixel = image->pixels; + iP = iPicture; + aP = aPicture; + n = npixels; + max_inten = 0; + min_inten = 0xff; + while (n--) + { + p = *pixel++; + *aP++ = (int) (p >> 24); + iR = (int) _XcursorPixelBrightness (p); + if (iR > max_inten) max_inten = iR; + if (iR < min_inten) min_inten = iR; + *iP++ = iR; + } + /* + * Draw the image while diffusing the error + */ + iP = iPicture; + aP = aPicture; + mean_inten = (max_inten + min_inten + 1) >> 1; + for (y = 0; y < image->height; y++) + for (x = 0; x < image->width; x++) + { + aR = *aP; + iR = *iP; + if (aR >= 0x80) + { + XPutPixel (core->msk_image, x, y, 1); + aA = 0xff; + } + else + { + XPutPixel (core->msk_image, x, y, 0); + aA = 0x00; + } + if (iR >= mean_inten) + { + XPutPixel (core->src_image, x, y, 0); + iA = max_inten; + } + else + { + XPutPixel (core->src_image, x, y, 1); + iA = min_inten; + } + iError = iR - iA; + aError = aR - aA; + iErrorRight = (iError * 7) >> 4; + iErrorBelowLeft = (iError * 3) >> 4; + iErrorBelow = (iError * 5) >> 4; + iErrorBelowRight = (iError - iErrorRight - + iErrorBelowLeft - iErrorBelow); + aErrorRight = (aError * 7) >> 4; + aErrorBelowLeft = (aError * 3) >> 4; + aErrorBelow = (aError * 5) >> 4; + aErrorBelowRight = (aError - aErrorRight - + aErrorBelowLeft - aErrorBelow); + if (x < image->width - 1) + { + iP[right] += iErrorRight; + aP[right] += aErrorRight; + } + if (y < image->height - 1) + { + if (x) + { + iP[belowLeft] += iErrorBelowLeft; + aP[belowLeft] += aErrorBelowLeft; + } + iP[below] += iErrorBelow; + aP[below] += aErrorBelow; + if (x < image->width - 1) + { + iP[belowRight] += iErrorBelowRight; + aP[belowRight] += aErrorBelowRight; + } + } + aP++; + iP++; + } + free (iPicture); + core->on_color.red = + core->on_color.green = + core->on_color.blue = (min_inten | min_inten << 8); + core->off_color.red = + core->off_color.green = + core->off_color.blue = (max_inten | max_inten << 8); + return True; +} + +static Bool +_XcursorThreshold (const XcursorImage *image, XcursorCoreCursor *core) +{ + XcursorPixel *pixel, p; + int x, y; + + /* + * Draw the image, picking black for dark pixels and white for light + */ + pixel = image->pixels; + for (y = 0; y < image->height; y++) + for (x = 0; x < image->width; x++) + { + p = *pixel++; + if ((p >> 24) >= 0x80) + { + XPutPixel (core->msk_image, x, y, 1); + if (_XcursorPixelBrightness (p) > 0x80) + XPutPixel (core->src_image, x, y, 0); + else + XPutPixel (core->src_image, x, y, 1); + } + else + { + XPutPixel (core->msk_image, x, y, 0); + XPutPixel (core->src_image, x, y, 0); + } + } + core->on_color.red = + core->on_color.green = + core->on_color.blue = 0; + core->off_color.red = + core->off_color.green = + core->off_color.blue = 0xffff; + return True; +} + +Cursor +XcursorImageLoadCursor (Display *dpy, const XcursorImage *image) +{ + Cursor cursor; + +#if RENDER_MAJOR > 0 || RENDER_MINOR >= 5 + if (XcursorSupportsARGB (dpy)) + { + XImage ximage; + int screen = DefaultScreen (dpy); + Pixmap pixmap; + Picture picture; + GC gc; + XRenderPictFormat *format; + + ximage.width = image->width; + ximage.height = image->height; + ximage.xoffset = 0; + ximage.format = ZPixmap; + ximage.data = (char *) image->pixels; + ximage.byte_order = nativeByteOrder (); + ximage.bitmap_unit = 32; + ximage.bitmap_bit_order = ximage.byte_order; + ximage.bitmap_pad = 32; + ximage.depth = 32; + ximage.bits_per_pixel = 32; + ximage.bytes_per_line = image->width * 4; + ximage.red_mask = 0xff0000; + ximage.green_mask = 0x00ff00; + ximage.blue_mask = 0x0000ff; + ximage.obdata = 0; + if (!XInitImage (&ximage)) + return None; + pixmap = XCreatePixmap (dpy, RootWindow (dpy, screen), + image->width, image->height, 32); + gc = XCreateGC (dpy, pixmap, 0, 0); + XPutImage (dpy, pixmap, gc, &ximage, + 0, 0, 0, 0, image->width, image->height); + XFreeGC (dpy, gc); + format = XRenderFindStandardFormat (dpy, PictStandardARGB32); + picture = XRenderCreatePicture (dpy, pixmap, format, 0, 0); + XFreePixmap (dpy, pixmap); + cursor = XRenderCreateCursor (dpy, picture, + image->xhot, image->yhot); + XRenderFreePicture (dpy, picture); + } + else +#endif + { + XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); + int screen = DefaultScreen (dpy); + XcursorCoreCursor core; + Pixmap src_pixmap, msk_pixmap; + GC gc; + XGCValues gcv; + + core.src_image = XCreateImage (dpy, 0, 1, ZPixmap, + 0, 0, image->width, image->height, + 32, 0); + core.src_image->data = Xmalloc (image->height * + core.src_image->bytes_per_line); + core.msk_image = XCreateImage (dpy, 0, 1, ZPixmap, + 0, 0, image->width, image->height, + 32, 0); + core.msk_image->data = Xmalloc (image->height * + core.msk_image->bytes_per_line); + + switch (info->dither) { + case XcursorDitherThreshold: + if (!_XcursorThreshold (image, &core)) + return 0; + break; + case XcursorDitherMedian: + if (!_XcursorHeckbertMedianCut (image, &core)) + return 0; + break; + case XcursorDitherOrdered: + if (!_XcursorBayerOrderedDither (image, &core)) + return 0; + break; + case XcursorDitherDiffuse: + if (!_XcursorFloydSteinberg (image, &core)) + return 0; + break; + default: + return 0; + } + + /* + * Create the cursor + */ + src_pixmap = XCreatePixmap (dpy, RootWindow (dpy, screen), + image->width, image->height, 1); + msk_pixmap = XCreatePixmap (dpy, RootWindow (dpy, screen), + image->width, image->height, 1); + gcv.foreground = 1; + gcv.background = 0; + gc = XCreateGC (dpy, src_pixmap, + GCForeground|GCBackground, + &gcv); + XPutImage (dpy, src_pixmap, gc, core.src_image, + 0, 0, 0, 0, image->width, image->height); + + XPutImage (dpy, msk_pixmap, gc, core.msk_image, + 0, 0, 0, 0, image->width, image->height); + XFreeGC (dpy, gc); + +#ifdef DEBUG_IMAGE + _XcursorDumpColor (&core.on_color, "on_color"); + _XcursorDumpColor (&core.off_color, "off_color"); + _XcursorDumpImage (core.src_image); + _XcursorDumpImage (core.msk_image); +#endif + XDestroyImage (core.src_image); + XDestroyImage (core.msk_image); + + cursor = XCreatePixmapCursor (dpy, src_pixmap, msk_pixmap, + &core.on_color, &core.off_color, + image->xhot, image->yhot); + XFreePixmap (dpy, src_pixmap); + XFreePixmap (dpy, msk_pixmap); + } + return cursor; +} + +XcursorCursors * +XcursorImagesLoadCursors (Display *dpy, const XcursorImages *images) +{ + XcursorCursors *cursors = XcursorCursorsCreate (dpy, images->nimage); + int n; + + if (!cursors) + return 0; + for (n = 0; n < images->nimage; n++) + { + cursors->cursors[n] = XcursorImageLoadCursor (dpy, images->images[n]); + if (!cursors->cursors[n]) + { + XcursorCursorsDestroy (cursors); + return 0; + } + cursors->ncursor++; + } + return cursors; +} + +Cursor +XcursorImagesLoadCursor (Display *dpy, const XcursorImages *images) +{ + 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); +} + diff --git a/nx-X11/lib/Xcursor/display.c b/nx-X11/lib/Xcursor/display.c new file mode 100644 index 000000000..ef941257f --- /dev/null +++ b/nx-X11/lib/Xcursor/display.c @@ -0,0 +1,382 @@ +/* + * $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; +} diff --git a/nx-X11/lib/Xcursor/file.c b/nx-X11/lib/Xcursor/file.c new file mode 100644 index 000000000..175676cc3 --- /dev/null +++ b/nx-X11/lib/Xcursor/file.c @@ -0,0 +1,1101 @@ +/* + * $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; +} diff --git a/nx-X11/lib/Xcursor/library.c b/nx-X11/lib/Xcursor/library.c new file mode 100644 index 000000000..6774f802f --- /dev/null +++ b/nx-X11/lib/Xcursor/library.c @@ -0,0 +1,495 @@ +/* + * $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; +} diff --git a/nx-X11/lib/Xcursor/xcursor-config.in b/nx-X11/lib/Xcursor/xcursor-config.in new file mode 100644 index 000000000..af59f9974 --- /dev/null +++ b/nx-X11/lib/Xcursor/xcursor-config.in @@ -0,0 +1,95 @@ +#! /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 diff --git a/nx-X11/lib/Xcursor/xcursor.pc.in b/nx-X11/lib/Xcursor/xcursor.pc.in new file mode 100644 index 000000000..c39fce712 --- /dev/null +++ b/nx-X11/lib/Xcursor/xcursor.pc.in @@ -0,0 +1,15 @@ +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} -lXcursor ${xrenderlibs} ${xlibs} diff --git a/nx-X11/lib/Xcursor/xcursorint.h b/nx-X11/lib/Xcursor/xcursorint.h new file mode 100644 index 000000000..83913a094 --- /dev/null +++ b/nx-X11/lib/Xcursor/xcursorint.h @@ -0,0 +1,109 @@ +/* + * $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_ */ diff --git a/nx-X11/lib/Xcursor/xlib.c b/nx-X11/lib/Xcursor/xlib.c new file mode 100644 index 000000000..7d10caf18 --- /dev/null +++ b/nx-X11/lib/Xcursor/xlib.c @@ -0,0 +1,422 @@ +/* + * $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; +} |