summaryrefslogtreecommitdiff
path: root/lib/libXcursor/src
diff options
context:
space:
mode:
authorMatthieu Herrb <matthieu@cvs.openbsd.org>2006-11-25 17:02:54 +0000
committerMatthieu Herrb <matthieu@cvs.openbsd.org>2006-11-25 17:02:54 +0000
commitf5f6cabf0983a22f8bb256d604ffc21c1a6cf8ca (patch)
tree4ee1fb346ef12f424b40b9c2669b60ed1b01ddb7 /lib/libXcursor/src
parenta789231d9f4882130ff12ea5b5702c08f911ed4d (diff)
import from X.Org 7.2RC1
Diffstat (limited to 'lib/libXcursor/src')
-rw-r--r--lib/libXcursor/src/Makefile.am28
-rw-r--r--lib/libXcursor/src/Makefile.in523
-rw-r--r--lib/libXcursor/src/cursor.c821
-rw-r--r--lib/libXcursor/src/display.c383
-rw-r--r--lib/libXcursor/src/file.c1104
-rw-r--r--lib/libXcursor/src/library.c495
-rw-r--r--lib/libXcursor/src/xcursorint.h109
-rw-r--r--lib/libXcursor/src/xlib.c422
8 files changed, 3885 insertions, 0 deletions
diff --git a/lib/libXcursor/src/Makefile.am b/lib/libXcursor/src/Makefile.am
new file mode 100644
index 000000000..a8734f382
--- /dev/null
+++ b/lib/libXcursor/src/Makefile.am
@@ -0,0 +1,28 @@
+lib_LTLIBRARIES = libXcursor.la
+
+libXcursor_la_SOURCES = xcursorint.h cursor.c display.c file.c library.c xlib.c
+
+ICONDIR=@ICONDIR@
+XCURSORPATH=@XCURSORPATH@
+
+libXcursor_la_LIBADD = $(XCURSOR_LIBS)
+AM_CFLAGS = $(XCURSOR_CFLAGS) \
+ -DICONDIR=\"$(ICONDIR)\" -DXCURSORPATH=\"$(XCURSORPATH)\"
+
+INCLUDES = -I$(top_srcdir)/include/X11/Xcursor
+
+#
+# Shared library version info. This is not the same as the package version
+#
+libXcursor_la_LDFLAGS = -version-number 1:0:2 -no-undefined
+
+libXcursorincludedir = $(includedir)/X11/Xcursor
+libXcursorinclude_HEADERS = $(top_srcdir)/include/X11/Xcursor/Xcursor.h
+
+if LINT
+ALL_LINT_FLAGS=$(LINT_FLAGS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS)
+
+lint:
+ $(LINT) $(ALL_LINT_FLAGS) $(libXcursor_la_SOURCES) $(XCURSOR_LIBS)
+endif LINT
diff --git a/lib/libXcursor/src/Makefile.in b/lib/libXcursor/src/Makefile.in
new file mode 100644
index 000000000..c58bbe25b
--- /dev/null
+++ b/lib/libXcursor/src/Makefile.in
@@ -0,0 +1,523 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src
+DIST_COMMON = $(libXcursorinclude_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(libdir)" \
+ "$(DESTDIR)$(libXcursorincludedir)"
+libLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(lib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libXcursor_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_libXcursor_la_OBJECTS = cursor.lo display.lo file.lo library.lo \
+ xlib.lo
+libXcursor_la_OBJECTS = $(am_libXcursor_la_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libXcursor_la_SOURCES)
+DIST_SOURCES = $(libXcursor_la_SOURCES)
+libXcursorincludeHEADERS_INSTALL = $(INSTALL_HEADER)
+HEADERS = $(libXcursorinclude_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ADMIN_MAN_DIR = @ADMIN_MAN_DIR@
+ADMIN_MAN_SUFFIX = @ADMIN_MAN_SUFFIX@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+APP_MAN_DIR = @APP_MAN_DIR@
+APP_MAN_SUFFIX = @APP_MAN_SUFFIX@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DRIVER_MAN_DIR = @DRIVER_MAN_DIR@
+DRIVER_MAN_SUFFIX = @DRIVER_MAN_SUFFIX@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+FILE_MAN_DIR = @FILE_MAN_DIR@
+FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@
+ICONDIR = @ICONDIR@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_MAN_DIR = @LIB_MAN_DIR@
+LIB_MAN_SUFFIX = @LIB_MAN_SUFFIX@
+LINT = @LINT@
+LINT_FALSE = @LINT_FALSE@
+LINT_FLAGS = @LINT_FLAGS@
+LINT_TRUE = @LINT_TRUE@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MISC_MAN_DIR = @MISC_MAN_DIR@
+MISC_MAN_SUFFIX = @MISC_MAN_SUFFIX@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XCURSORPATH = @XCURSORPATH@
+XCURSOR_CFLAGS = @XCURSOR_CFLAGS@
+XCURSOR_LIBS = @XCURSOR_LIBS@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+ac_pt_PKG_CONFIG = @ac_pt_PKG_CONFIG@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+lib_LTLIBRARIES = libXcursor.la
+libXcursor_la_SOURCES = xcursorint.h cursor.c display.c file.c library.c xlib.c
+libXcursor_la_LIBADD = $(XCURSOR_LIBS)
+AM_CFLAGS = $(XCURSOR_CFLAGS) \
+ -DICONDIR=\"$(ICONDIR)\" -DXCURSORPATH=\"$(XCURSORPATH)\"
+
+INCLUDES = -I$(top_srcdir)/include/X11/Xcursor
+
+#
+# Shared library version info. This is not the same as the package version
+#
+libXcursor_la_LDFLAGS = -version-number 1:0:2 -no-undefined
+libXcursorincludedir = $(includedir)/X11/Xcursor
+libXcursorinclude_HEADERS = $(top_srcdir)/include/X11/Xcursor/Xcursor.h
+@LINT_TRUE@ALL_LINT_FLAGS = $(LINT_FLAGS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+@LINT_TRUE@ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
+ $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libXcursor.la: $(libXcursor_la_OBJECTS) $(libXcursor_la_DEPENDENCIES)
+ $(LINK) -rpath $(libdir) $(libXcursor_la_LDFLAGS) $(libXcursor_la_OBJECTS) $(libXcursor_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cursor.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/display.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/library.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlib.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+install-libXcursorincludeHEADERS: $(libXcursorinclude_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(libXcursorincludedir)" || $(mkdir_p) "$(DESTDIR)$(libXcursorincludedir)"
+ @list='$(libXcursorinclude_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(libXcursorincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(libXcursorincludedir)/$$f'"; \
+ $(libXcursorincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(libXcursorincludedir)/$$f"; \
+ done
+
+uninstall-libXcursorincludeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(libXcursorinclude_HEADERS)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(libXcursorincludedir)/$$f'"; \
+ rm -f "$(DESTDIR)$(libXcursorincludedir)/$$f"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ $(mkdir_p) $(distdir)/../include/X11/Xcursor
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(libXcursorincludedir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-libXcursorincludeHEADERS
+
+install-exec-am: install-libLTLIBRARIES
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES \
+ uninstall-libXcursorincludeHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am \
+ install-libLTLIBRARIES install-libXcursorincludeHEADERS \
+ install-man install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-info-am uninstall-libLTLIBRARIES \
+ uninstall-libXcursorincludeHEADERS
+
+
+@LINT_TRUE@lint:
+@LINT_TRUE@ $(LINT) $(ALL_LINT_FLAGS) $(libXcursor_la_SOURCES) $(XCURSOR_LIBS)
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lib/libXcursor/src/cursor.c b/lib/libXcursor/src/cursor.c
new file mode 100644
index 000000000..1e6b084cb
--- /dev/null
+++ b/lib/libXcursor/src/cursor.c
@@ -0,0 +1,821 @@
+/*
+ * $Id: cursor.c,v 1.1 2006/11/25 17:00:28 matthieu 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 NULL;
+ cursors->ref = 1;
+ cursors->dpy = dpy;
+ cursors->ncursor = 0;
+ cursors->cursors = (Cursor *) (cursors + 1);
+ return cursors;
+}
+
+void
+XcursorCursorsDestroy (XcursorCursors *cursors)
+{
+ int n;
+
+ if (!cursors)
+ return;
+
+ --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 NULL;
+ animate->cursors = cursors;
+ cursors->ref++;
+ animate->sequence = 0;
+ return animate;
+}
+
+void
+XcursorAnimateDestroy (XcursorAnimate *animate)
+{
+ if (!animate)
+ return;
+
+ XcursorCursorsDestroy (animate->cursors);
+ free (animate);
+}
+
+Cursor
+XcursorAnimateNext (XcursorAnimate *animate)
+{
+ Cursor cursor = animate->cursors->cursors[animate->sequence++];
+
+ if (animate->sequence >= animate->cursors->ncursor)
+ animate->sequence = 0;
+ return cursor;
+}
+
+static int
+nativeByteOrder (void)
+{
+ int x = 1;
+
+ return (*((char *) &x) == 1) ? LSBFirst : MSBFirst;
+}
+
+static XcursorUInt
+_XcursorPixelBrightness (XcursorPixel p)
+{
+ XcursorPixel alpha = p >> 24;
+ XcursorPixel r, g, b;
+
+ if (!alpha)
+ return 0;
+ r = ((p >> 8) & 0xff00) / alpha;
+ if (r > 0xff) r = 0xff;
+ g = ((p >> 0) & 0xff00) / alpha;
+ if (g > 0xff) g = 0xff;
+ b = ((p << 8) & 0xff00) / alpha;
+ if (b > 0xff) b = 0xff;
+ return (r * 153 + g * 301 + b * 58) >> 9;
+}
+
+static unsigned short
+_XcursorDivideAlpha (XcursorUInt value, XcursorUInt alpha)
+{
+ if (!alpha)
+ return 0;
+ value = value * 255 / alpha;
+ if (value > 255)
+ value = 255;
+ return value | (value << 8);
+}
+
+static void
+_XcursorPixelToColor (XcursorPixel p, XColor *color)
+{
+ XcursorPixel alpha = p >> 24;
+
+ color->pixel = 0;
+ color->red = _XcursorDivideAlpha ((p >> 16) & 0xff, alpha);
+ color->green = _XcursorDivideAlpha ((p >> 8) & 0xff, alpha);
+ color->blue = _XcursorDivideAlpha ((p >> 0) & 0xff, alpha);
+ color->flags = DoRed|DoGreen|DoBlue;
+}
+
+#undef DEBUG_IMAGE
+#ifdef DEBUG_IMAGE
+static void
+_XcursorDumpImage (XImage *image)
+{
+ FILE *f = fopen ("/tmp/images", "a");
+ int x, y;
+ if (!f)
+ return;
+ fprintf (f, "%d x %x\n", image->width, image->height);
+ for (y = 0; y < image->height; y++)
+ {
+ for (x = 0; x < image->width; x++)
+ fprintf (f, "%c", XGetPixel (image, x, y) ? '*' : ' ');
+ fprintf (f, "\n");
+ }
+ fflush (f);
+ fclose (f);
+}
+
+static void
+_XcursorDumpColor (XColor *color, char *name)
+{
+ FILE *f = fopen ("/tmp/images", "a");
+ fprintf (f, "%s: %x %x %x\n", name,
+ color->red, color->green, color->blue);
+ fflush (f);
+ fclose (f);
+}
+#endif
+
+static int
+_XcursorCompareRed (const void *a, const void *b)
+{
+ const XcursorPixel *ap = a, *bp = b;
+
+ return (int) (((*ap >> 16) & 0xff) - ((*bp >> 16) & 0xff));
+}
+
+static int
+_XcursorCompareGreen (const void *a, const void *b)
+{
+ const XcursorPixel *ap = a, *bp = b;
+
+ return (int) (((*ap >> 8) & 0xff) - ((*bp >> 8) & 0xff));
+}
+
+static int
+_XcursorCompareBlue (const void *a, const void *b)
+{
+ const XcursorPixel *ap = a, *bp = b;
+
+ return (int) (((*ap >> 0) & 0xff) - ((*bp >> 0) & 0xff));
+}
+
+static XcursorPixel
+_XcursorAverageColor (XcursorPixel *pixels, int npixels)
+{
+ XcursorPixel p;
+ XcursorPixel red, green, blue;
+ int n = npixels;
+
+ blue = green = red = 0;
+ while (n--)
+ {
+ p = *pixels++;
+ red += (p >> 16) & 0xff;
+ green += (p >> 8) & 0xff;
+ blue += (p >> 0) & 0xff;
+ }
+ if (!n)
+ return 0;
+ return (0xff << 24) | ((red/npixels) << 16) | ((green/npixels) << 8) | (blue/npixels);
+}
+
+typedef struct XcursorCoreCursor {
+ XImage *src_image;
+ XImage *msk_image;
+ XColor on_color;
+ XColor off_color;
+} XcursorCoreCursor;
+
+static Bool
+_XcursorHeckbertMedianCut (const XcursorImage *image, XcursorCoreCursor *core)
+{
+ XImage *src_image = core->src_image, *msk_image = core->msk_image;
+ int npixels = image->width * image->height;
+ int ncolors;
+ int n;
+ XcursorPixel *po, *pn, *pc;
+ XcursorPixel p;
+ XcursorPixel red, green, blue, alpha;
+ XcursorPixel max_red, min_red, max_green, min_green, max_blue, min_blue;
+ XcursorPixel *temp, *pixels, *colors;
+ int split;
+ XcursorPixel leftColor, centerColor, rightColor;
+ int (*compare) (const void *, const void *);
+ int x, y;
+
+ /*
+ * Temp space for converted image and converted colors
+ */
+ temp = malloc (npixels * sizeof (XcursorPixel) * 2);
+ if (!temp)
+ return False;
+
+ pixels = temp;
+ colors = pixels + npixels;
+
+ /*
+ * Convert to 2-value alpha and build
+ * array of opaque color values and an
+ */
+ po = image->pixels;
+ pn = pixels;
+ pc = colors;
+ max_blue = max_green = max_red = 0;
+ min_blue = min_green = min_red = 255;
+ n = npixels;
+ while (n--)
+ {
+ p = *po++;
+ alpha = (p >> 24) & 0xff;
+ red = (p >> 16) & 0xff;
+ green = (p >> 8) & 0xff;
+ blue = (p >> 0) & 0xff;
+ if (alpha >= 0x80)
+ {
+ red = red * 255 / alpha;
+ green = green * 255 / alpha;
+ blue = blue * 255 / alpha;
+ if (red < min_red) min_red = red;
+ if (red > max_red) max_red = red;
+ if (green < min_green) min_green = green;
+ if (green > max_green) max_green = green;
+ if (blue < min_blue) min_blue = blue;
+ if (blue > max_blue) max_blue = blue;
+ p = ((0xff << 24) | (red << 16) |
+ (green << 8) | (blue << 0));
+ *pc++ = p;
+ }
+ else
+ p = 0;
+ *pn++ = p;
+ }
+ ncolors = pc - colors;
+
+ /*
+ * Compute longest dimension and sort
+ */
+ if ((max_green - min_green) >= (max_red - min_red) &&
+ (max_green - min_green) >= (max_blue - min_blue))
+ compare = _XcursorCompareGreen;
+ else if ((max_red - min_red) >= (max_blue - min_blue))
+ compare = _XcursorCompareRed;
+ else
+ compare = _XcursorCompareBlue;
+ qsort (colors, ncolors, sizeof (XcursorPixel), compare);
+ /*
+ * Compute average colors on both sides of the cut
+ */
+ split = ncolors >> 1;
+ leftColor = _XcursorAverageColor (colors, split);
+ centerColor = colors[split];
+ rightColor = _XcursorAverageColor (colors + split, ncolors - split);
+ /*
+ * Select best color for each pixel
+ */
+ pn = pixels;
+ for (y = 0; y < image->height; y++)
+ for (x = 0; x < image->width; x++)
+ {
+ p = *pn++;
+ if (p & 0xff000000)
+ {
+ XPutPixel (msk_image, x, y, 1);
+ if ((*compare) (&p, &centerColor) >= 0)
+ XPutPixel (src_image, x, y, 0);
+ else
+ XPutPixel (src_image, x, y, 1);
+ }
+ else
+ {
+ XPutPixel (msk_image, x, y, 0);
+ XPutPixel (src_image, x, y, 0);
+ }
+ }
+ free (temp);
+ _XcursorPixelToColor (rightColor, &core->off_color);
+ _XcursorPixelToColor (leftColor, &core->on_color);
+ return True;
+}
+
+#if 0
+#define DITHER_DIM 4
+static XcursorPixel orderedDither[4][4] = {
+ { 1, 9, 3, 11 },
+ { 13, 5, 15, 7 },
+ { 4, 12, 2, 10 },
+ { 16, 8, 14, 6 }
+};
+#else
+#define DITHER_DIM 2
+static XcursorPixel orderedDither[2][2] = {
+ { 1, 3, },
+ { 4, 2, },
+};
+#endif
+
+#define DITHER_SIZE ((sizeof orderedDither / sizeof orderedDither[0][0]) + 1)
+
+static Bool
+_XcursorBayerOrderedDither (const XcursorImage *image, XcursorCoreCursor *core)
+{
+ int x, y;
+ XcursorPixel *pixel, p;
+ XcursorPixel a, i, d;
+
+ pixel = image->pixels;
+ for (y = 0; y < image->height; y++)
+ for (x = 0; x < image->width; x++)
+ {
+ p = *pixel++;
+ a = ((p >> 24) * DITHER_SIZE + 127) / 255;
+ i = (_XcursorPixelBrightness (p) * DITHER_SIZE + 127) / 255;
+ d = orderedDither[y&(DITHER_DIM-1)][x&(DITHER_DIM-1)];
+ if (a > d)
+ {
+ XPutPixel (core->msk_image, x, y, 1);
+ if (i > d)
+ XPutPixel (core->src_image, x, y, 0); /* white */
+ else
+ XPutPixel (core->src_image, x, y, 1); /* black */
+ }
+ else
+ {
+ XPutPixel (core->msk_image, x, y, 0);
+ XPutPixel (core->src_image, x, y, 0);
+ }
+ }
+ core->on_color.red = 0;
+ core->on_color.green = 0;
+ core->on_color.blue = 0;
+ core->off_color.red = 0xffff;
+ core->off_color.green = 0xffff;
+ core->off_color.blue = 0xffff;
+ return True;
+}
+
+static Bool
+_XcursorFloydSteinberg (const XcursorImage *image, XcursorCoreCursor *core)
+{
+ int *aPicture, *iPicture, *aP, *iP;
+ XcursorPixel *pixel, p;
+ int aR, iR, aA, iA;
+ int npixels = image->width * image->height;
+ int n;
+ int right = 1;
+ int belowLeft = image->width - 1;
+ int below = image->width;
+ int belowRight = image->width + 1;
+ int iError, aError;
+ int iErrorRight, aErrorRight;
+ int iErrorBelowLeft, aErrorBelowLeft;
+ int iErrorBelow, aErrorBelow;
+ int iErrorBelowRight, aErrorBelowRight;
+ int x, y;
+ int max_inten, min_inten, mean_inten;
+
+ iPicture = malloc (npixels * sizeof (int) * 2);
+ if (!iPicture)
+ return False;
+ aPicture = iPicture + npixels;
+
+ /*
+ * Compute raw gray and alpha arrays
+ */
+ pixel = image->pixels;
+ iP = iPicture;
+ aP = aPicture;
+ n = npixels;
+ max_inten = 0;
+ min_inten = 0xff;
+ while (n--)
+ {
+ p = *pixel++;
+ *aP++ = (int) (p >> 24);
+ iR = (int) _XcursorPixelBrightness (p);
+ if (iR > max_inten) max_inten = iR;
+ if (iR < min_inten) min_inten = iR;
+ *iP++ = iR;
+ }
+ /*
+ * Draw the image while diffusing the error
+ */
+ iP = iPicture;
+ aP = aPicture;
+ mean_inten = (max_inten + min_inten + 1) >> 1;
+ for (y = 0; y < image->height; y++)
+ for (x = 0; x < image->width; x++)
+ {
+ aR = *aP;
+ iR = *iP;
+ if (aR >= 0x80)
+ {
+ XPutPixel (core->msk_image, x, y, 1);
+ aA = 0xff;
+ }
+ else
+ {
+ XPutPixel (core->msk_image, x, y, 0);
+ aA = 0x00;
+ }
+ if (iR >= mean_inten)
+ {
+ XPutPixel (core->src_image, x, y, 0);
+ iA = max_inten;
+ }
+ else
+ {
+ XPutPixel (core->src_image, x, y, 1);
+ iA = min_inten;
+ }
+ iError = iR - iA;
+ aError = aR - aA;
+ iErrorRight = (iError * 7) >> 4;
+ iErrorBelowLeft = (iError * 3) >> 4;
+ iErrorBelow = (iError * 5) >> 4;
+ iErrorBelowRight = (iError - iErrorRight -
+ iErrorBelowLeft - iErrorBelow);
+ aErrorRight = (aError * 7) >> 4;
+ aErrorBelowLeft = (aError * 3) >> 4;
+ aErrorBelow = (aError * 5) >> 4;
+ aErrorBelowRight = (aError - aErrorRight -
+ aErrorBelowLeft - aErrorBelow);
+ if (x < image->width - 1)
+ {
+ iP[right] += iErrorRight;
+ aP[right] += aErrorRight;
+ }
+ if (y < image->height - 1)
+ {
+ if (x)
+ {
+ iP[belowLeft] += iErrorBelowLeft;
+ aP[belowLeft] += aErrorBelowLeft;
+ }
+ iP[below] += iErrorBelow;
+ aP[below] += aErrorBelow;
+ if (x < image->width - 1)
+ {
+ iP[belowRight] += iErrorBelowRight;
+ aP[belowRight] += aErrorBelowRight;
+ }
+ }
+ aP++;
+ iP++;
+ }
+ free (iPicture);
+ core->on_color.red =
+ core->on_color.green =
+ core->on_color.blue = (min_inten | min_inten << 8);
+ core->off_color.red =
+ core->off_color.green =
+ core->off_color.blue = (max_inten | max_inten << 8);
+ return True;
+}
+
+static Bool
+_XcursorThreshold (const XcursorImage *image, XcursorCoreCursor *core)
+{
+ XcursorPixel *pixel, p;
+ int x, y;
+
+ /*
+ * Draw the image, picking black for dark pixels and white for light
+ */
+ pixel = image->pixels;
+ for (y = 0; y < image->height; y++)
+ for (x = 0; x < image->width; x++)
+ {
+ p = *pixel++;
+ if ((p >> 24) >= 0x80)
+ {
+ XPutPixel (core->msk_image, x, y, 1);
+ if (_XcursorPixelBrightness (p) > 0x80)
+ XPutPixel (core->src_image, x, y, 0);
+ else
+ XPutPixel (core->src_image, x, y, 1);
+ }
+ else
+ {
+ XPutPixel (core->msk_image, x, y, 0);
+ XPutPixel (core->src_image, x, y, 0);
+ }
+ }
+ core->on_color.red =
+ core->on_color.green =
+ core->on_color.blue = 0;
+ core->off_color.red =
+ core->off_color.green =
+ core->off_color.blue = 0xffff;
+ return True;
+}
+
+Cursor
+XcursorImageLoadCursor (Display *dpy, const XcursorImage *image)
+{
+ Cursor cursor;
+
+#if RENDER_MAJOR > 0 || RENDER_MINOR >= 5
+ if (XcursorSupportsARGB (dpy))
+ {
+ XImage ximage;
+ int screen = DefaultScreen (dpy);
+ Pixmap pixmap;
+ Picture picture;
+ GC gc;
+ XRenderPictFormat *format;
+
+ ximage.width = image->width;
+ ximage.height = image->height;
+ ximage.xoffset = 0;
+ ximage.format = ZPixmap;
+ ximage.data = (char *) image->pixels;
+ ximage.byte_order = nativeByteOrder ();
+ ximage.bitmap_unit = 32;
+ ximage.bitmap_bit_order = ximage.byte_order;
+ ximage.bitmap_pad = 32;
+ ximage.depth = 32;
+ ximage.bits_per_pixel = 32;
+ ximage.bytes_per_line = image->width * 4;
+ ximage.red_mask = 0xff0000;
+ ximage.green_mask = 0x00ff00;
+ ximage.blue_mask = 0x0000ff;
+ ximage.obdata = NULL;
+ if (!XInitImage (&ximage))
+ return None;
+ pixmap = XCreatePixmap (dpy, RootWindow (dpy, screen),
+ image->width, image->height, 32);
+ gc = XCreateGC (dpy, pixmap, 0, NULL);
+ 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, NULL);
+ 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, NULL, 1, ZPixmap,
+ 0, NULL, image->width, image->height,
+ 32, 0);
+ core.src_image->data = Xmalloc (image->height *
+ core.src_image->bytes_per_line);
+ core.msk_image = XCreateImage (dpy, NULL, 1, ZPixmap,
+ 0, NULL, 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 NULL;
+ for (n = 0; n < images->nimage; n++)
+ {
+ cursors->cursors[n] = XcursorImageLoadCursor (dpy, images->images[n]);
+ if (!cursors->cursors[n])
+ {
+ XcursorCursorsDestroy (cursors);
+ return NULL;
+ }
+ 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 NULL;
+ 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/lib/libXcursor/src/display.c b/lib/libXcursor/src/display.c
new file mode 100644
index 000000000..34ef29474
--- /dev/null
+++ b/lib/libXcursor/src/display.c
@@ -0,0 +1,383 @@
+/*
+ * $Id: display.c,v 1.1 2006/11/25 17:00:28 matthieu 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);
+
+ if (info)
+ _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 NULL;
+ info->next = NULL;
+ info->display = dpy;
+
+ info->codes = XAddExtension (dpy);
+ if (!info->codes)
+ {
+ free (info);
+ return NULL;
+ }
+ (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 = NULL;
+ info->theme_from_config = NULL;
+
+ /*
+ * 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 = NULL;
+ 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 = NULL;
+ if (info->theme)
+ free (info->theme);
+ info->theme = copy;
+ return XcursorTrue;
+}
+
+char *
+XcursorGetTheme (Display *dpy)
+{
+ XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy);
+
+ if (!info)
+ return NULL;
+ 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/lib/libXcursor/src/file.c b/lib/libXcursor/src/file.c
new file mode 100644
index 000000000..789757151
--- /dev/null
+++ b/lib/libXcursor/src/file.c
@@ -0,0 +1,1104 @@
+/*
+ * $Id: file.c,v 1.1 2006/11/25 17:00:29 matthieu 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 NULL;
+ image->version = XCURSOR_IMAGE_VERSION;
+ image->pixels = (XcursorPixel *) (image + 1);
+ image->size = width > height ? width : height;
+ image->width = width;
+ image->height = height;
+ image->delay = 0;
+ return image;
+}
+
+void
+XcursorImageDestroy (XcursorImage *image)
+{
+ free (image);
+}
+
+XcursorImages *
+XcursorImagesCreate (int size)
+{
+ XcursorImages *images;
+
+ images = malloc (sizeof (XcursorImages) +
+ size * sizeof (XcursorImage *));
+ if (!images)
+ return NULL;
+ images->nimage = 0;
+ images->images = (XcursorImage **) (images + 1);
+ images->name = NULL;
+ 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 NULL;
+
+ comment = malloc (sizeof (XcursorComment) + length + 1);
+ if (!comment)
+ return NULL;
+ comment->version = XCURSOR_COMMENT_VERSION;
+ comment->comment_type = comment_type;
+ comment->comment = (char *) (comment + 1);
+ comment->comment[0] = '\0';
+ return comment;
+}
+
+void
+XcursorCommentDestroy (XcursorComment *comment)
+{
+ free (comment);
+}
+
+XcursorComments *
+XcursorCommentsCreate (int size)
+{
+ XcursorComments *comments;
+
+ comments = malloc (sizeof (XcursorComments) +
+ size * sizeof (XcursorComment *));
+ if (!comments)
+ return NULL;
+ 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)
+{
+ free (fileHeader);
+}
+
+static XcursorFileHeader *
+_XcursorFileHeaderCreate (int ntoc)
+{
+ XcursorFileHeader *fileHeader;
+
+ if (ntoc > 0x10000)
+ return NULL;
+ fileHeader = malloc (sizeof (XcursorFileHeader) +
+ ntoc * sizeof (XcursorFileToc));
+ if (!fileHeader)
+ return NULL;
+ 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 NULL;
+ if (head.magic != XCURSOR_MAGIC)
+ return NULL;
+ if (!_XcursorReadUInt (file, &head.header))
+ return NULL;
+ if (!_XcursorReadUInt (file, &head.version))
+ return NULL;
+ if (!_XcursorReadUInt (file, &head.ntoc))
+ return NULL;
+ skip = head.header - XCURSOR_FILE_HEADER_LEN;
+ if (skip)
+ if ((*file->seek) (file, skip, SEEK_CUR) == EOF)
+ return NULL;
+ fileHeader = _XcursorFileHeaderCreate (head.ntoc);
+ if (!fileHeader)
+ return NULL;
+ 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 NULL;
+ }
+ 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 NULL;
+ if (!_XcursorReadUInt (file, &head.width))
+ return NULL;
+ if (!_XcursorReadUInt (file, &head.height))
+ return NULL;
+ if (!_XcursorReadUInt (file, &head.xhot))
+ return NULL;
+ if (!_XcursorReadUInt (file, &head.yhot))
+ return NULL;
+ if (!_XcursorReadUInt (file, &head.delay))
+ return NULL;
+ /* sanity check data */
+ if (head.width >= 0x10000 || head.height > 0x10000)
+ return NULL;
+ if (head.width == 0 || head.height == 0)
+ return NULL;
+ if (head.xhot > head.width || head.yhot > head.height)
+ return NULL;
+
+ /* 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 NULL;
+ }
+ 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 NULL;
+ /* read extra comment header fields */
+ if (!_XcursorReadUInt (file, &length))
+ return NULL;
+ comment = XcursorCommentCreate (chunkHeader.subtype, length);
+ if (!comment)
+ return NULL;
+ if (!_XcursorReadBytes (file, comment->comment, length))
+ {
+ XcursorCommentDestroy (comment);
+ return NULL;
+ }
+ 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 NULL;
+ fileHeader = _XcursorReadFileHeader (file);
+ if (!fileHeader)
+ return NULL;
+ bestSize = _XcursorFindBestSize (fileHeader, (XcursorDim) size, &nsize);
+ if (!bestSize)
+ return NULL;
+ toc = _XcursorFindImageToc (fileHeader, bestSize, 0);
+ if (toc < 0)
+ return NULL;
+ 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 NULL;
+ fileHeader = _XcursorReadFileHeader (file);
+ if (!fileHeader)
+ return NULL;
+ bestSize = _XcursorFindBestSize (fileHeader, (XcursorDim) size, &nsize);
+ if (!bestSize)
+ {
+ _XcursorFileHeaderDestroy (fileHeader);
+ return NULL;
+ }
+ images = XcursorImagesCreate (nsize);
+ if (!images)
+ {
+ _XcursorFileHeaderDestroy (fileHeader);
+ return NULL;
+ }
+ 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 = NULL;
+ }
+ return images;
+}
+
+XcursorImages *
+XcursorXcFileLoadAllImages (XcursorFile *file)
+{
+ XcursorFileHeader *fileHeader;
+ XcursorImage *image;
+ XcursorImages *images;
+ int nimage;
+ int n;
+ int toc;
+
+ if (!file)
+ return NULL;
+
+ fileHeader = _XcursorReadFileHeader (file);
+ if (!fileHeader)
+ return NULL;
+ 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 NULL;
+ 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 = NULL;
+ }
+ 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 = NULL;
+ comments = NULL;
+ 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 NULL;
+ 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 NULL;
+ 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 NULL;
+ 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/lib/libXcursor/src/library.c b/lib/libXcursor/src/library.c
new file mode 100644
index 000000000..830433ae1
--- /dev/null
+++ b/lib/libXcursor/src/library.c
@@ -0,0 +1,495 @@
+/*
+ * $Id: library.c,v 1.1 2006/11/25 17:00:28 matthieu 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 = NULL;
+ homelen = 0;
+ if (*dir == '~')
+ {
+ home = getenv ("HOME");
+ if (!home)
+ return NULL;
+ 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 NULL;
+ 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 NULL;
+ 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 NULL;
+ 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 = NULL;
+ 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 = NULL;
+ char *full;
+ char *dir;
+ const char *path;
+ char *inherits = NULL;
+ 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 != NULL)
+ free (inherits);
+ return f;
+}
+
+XcursorImage *
+XcursorLibraryLoadImage (const char *file, const char *theme, int size)
+{
+ FILE *f = NULL;
+ XcursorImage *image = NULL;
+
+ if (!file)
+ return NULL;
+
+ if (theme)
+ f = XcursorScanTheme (theme, file);
+ if (!f)
+ f = XcursorScanTheme ("default", file);
+ if (f == XCURSOR_SCAN_CORE)
+ return NULL;
+ if (f)
+ {
+ image = XcursorFileLoadImage (f, size);
+ fclose (f);
+ }
+ return image;
+}
+
+XcursorImages *
+XcursorLibraryLoadImages (const char *file, const char *theme, int size)
+{
+ FILE *f = NULL;
+ XcursorImages *images = NULL;
+
+ if (!file)
+ return NULL;
+
+ if (theme)
+ f = XcursorScanTheme (theme, file);
+ if (!f)
+ f = XcursorScanTheme ("default", file);
+ if (f == XCURSOR_SCAN_CORE)
+ return NULL;
+ 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 = NULL;
+ }
+ else
+ cursors->ncursor = 1;
+ }
+ }
+ else
+ cursors = NULL;
+ }
+ 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 NULL;
+}
+
+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 NULL;
+}
+
+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 NULL;
+}
+
+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/lib/libXcursor/src/xcursorint.h b/lib/libXcursor/src/xcursorint.h
new file mode 100644
index 000000000..90763299f
--- /dev/null
+++ b/lib/libXcursor/src/xcursorint.h
@@ -0,0 +1,109 @@
+/*
+ * $Id: xcursorint.h,v 1.1 2006/11/25 17:00:28 matthieu 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/lib/libXcursor/src/xlib.c b/lib/libXcursor/src/xlib.c
new file mode 100644
index 000000000..fbabd8bb4
--- /dev/null
+++ b/lib/libXcursor/src/xlib.c
@@ -0,0 +1,422 @@
+/*
+ * $Id: xlib.c,v 1.1 2006/11/25 17:00:29 matthieu 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 NULL;
+ 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 NULL;
+}
+
+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;
+}