diff options
author | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2006-11-25 17:02:54 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2006-11-25 17:02:54 +0000 |
commit | f5f6cabf0983a22f8bb256d604ffc21c1a6cf8ca (patch) | |
tree | 4ee1fb346ef12f424b40b9c2669b60ed1b01ddb7 /lib/libXcursor/src | |
parent | a789231d9f4882130ff12ea5b5702c08f911ed4d (diff) |
import from X.Org 7.2RC1
Diffstat (limited to 'lib/libXcursor/src')
-rw-r--r-- | lib/libXcursor/src/Makefile.am | 28 | ||||
-rw-r--r-- | lib/libXcursor/src/Makefile.in | 523 | ||||
-rw-r--r-- | lib/libXcursor/src/cursor.c | 821 | ||||
-rw-r--r-- | lib/libXcursor/src/display.c | 383 | ||||
-rw-r--r-- | lib/libXcursor/src/file.c | 1104 | ||||
-rw-r--r-- | lib/libXcursor/src/library.c | 495 | ||||
-rw-r--r-- | lib/libXcursor/src/xcursorint.h | 109 | ||||
-rw-r--r-- | lib/libXcursor/src/xlib.c | 422 |
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, ¢erColor) >= 0) + XPutPixel (src_image, x, y, 0); + else + XPutPixel (src_image, x, y, 1); + } + else + { + XPutPixel (msk_image, x, y, 0); + XPutPixel (src_image, x, y, 0); + } + } + free (temp); + _XcursorPixelToColor (rightColor, &core->off_color); + _XcursorPixelToColor (leftColor, &core->on_color); + return True; +} + +#if 0 +#define DITHER_DIM 4 +static XcursorPixel orderedDither[4][4] = { + { 1, 9, 3, 11 }, + { 13, 5, 15, 7 }, + { 4, 12, 2, 10 }, + { 16, 8, 14, 6 } +}; +#else +#define DITHER_DIM 2 +static XcursorPixel orderedDither[2][2] = { + { 1, 3, }, + { 4, 2, }, +}; +#endif + +#define DITHER_SIZE ((sizeof orderedDither / sizeof orderedDither[0][0]) + 1) + +static Bool +_XcursorBayerOrderedDither (const XcursorImage *image, XcursorCoreCursor *core) +{ + int x, y; + XcursorPixel *pixel, p; + XcursorPixel a, i, d; + + pixel = image->pixels; + for (y = 0; y < image->height; y++) + for (x = 0; x < image->width; x++) + { + p = *pixel++; + a = ((p >> 24) * DITHER_SIZE + 127) / 255; + i = (_XcursorPixelBrightness (p) * DITHER_SIZE + 127) / 255; + d = orderedDither[y&(DITHER_DIM-1)][x&(DITHER_DIM-1)]; + if (a > d) + { + XPutPixel (core->msk_image, x, y, 1); + if (i > d) + XPutPixel (core->src_image, x, y, 0); /* white */ + else + XPutPixel (core->src_image, x, y, 1); /* black */ + } + else + { + XPutPixel (core->msk_image, x, y, 0); + XPutPixel (core->src_image, x, y, 0); + } + } + core->on_color.red = 0; + core->on_color.green = 0; + core->on_color.blue = 0; + core->off_color.red = 0xffff; + core->off_color.green = 0xffff; + core->off_color.blue = 0xffff; + return True; +} + +static Bool +_XcursorFloydSteinberg (const XcursorImage *image, XcursorCoreCursor *core) +{ + int *aPicture, *iPicture, *aP, *iP; + XcursorPixel *pixel, p; + int aR, iR, aA, iA; + int npixels = image->width * image->height; + int n; + int right = 1; + int belowLeft = image->width - 1; + int below = image->width; + int belowRight = image->width + 1; + int iError, aError; + int iErrorRight, aErrorRight; + int iErrorBelowLeft, aErrorBelowLeft; + int iErrorBelow, aErrorBelow; + int iErrorBelowRight, aErrorBelowRight; + int x, y; + int max_inten, min_inten, mean_inten; + + iPicture = malloc (npixels * sizeof (int) * 2); + if (!iPicture) + return False; + aPicture = iPicture + npixels; + + /* + * Compute raw gray and alpha arrays + */ + pixel = image->pixels; + iP = iPicture; + aP = aPicture; + n = npixels; + max_inten = 0; + min_inten = 0xff; + while (n--) + { + p = *pixel++; + *aP++ = (int) (p >> 24); + iR = (int) _XcursorPixelBrightness (p); + if (iR > max_inten) max_inten = iR; + if (iR < min_inten) min_inten = iR; + *iP++ = iR; + } + /* + * Draw the image while diffusing the error + */ + iP = iPicture; + aP = aPicture; + mean_inten = (max_inten + min_inten + 1) >> 1; + for (y = 0; y < image->height; y++) + for (x = 0; x < image->width; x++) + { + aR = *aP; + iR = *iP; + if (aR >= 0x80) + { + XPutPixel (core->msk_image, x, y, 1); + aA = 0xff; + } + else + { + XPutPixel (core->msk_image, x, y, 0); + aA = 0x00; + } + if (iR >= mean_inten) + { + XPutPixel (core->src_image, x, y, 0); + iA = max_inten; + } + else + { + XPutPixel (core->src_image, x, y, 1); + iA = min_inten; + } + iError = iR - iA; + aError = aR - aA; + iErrorRight = (iError * 7) >> 4; + iErrorBelowLeft = (iError * 3) >> 4; + iErrorBelow = (iError * 5) >> 4; + iErrorBelowRight = (iError - iErrorRight - + iErrorBelowLeft - iErrorBelow); + aErrorRight = (aError * 7) >> 4; + aErrorBelowLeft = (aError * 3) >> 4; + aErrorBelow = (aError * 5) >> 4; + aErrorBelowRight = (aError - aErrorRight - + aErrorBelowLeft - aErrorBelow); + if (x < image->width - 1) + { + iP[right] += iErrorRight; + aP[right] += aErrorRight; + } + if (y < image->height - 1) + { + if (x) + { + iP[belowLeft] += iErrorBelowLeft; + aP[belowLeft] += aErrorBelowLeft; + } + iP[below] += iErrorBelow; + aP[below] += aErrorBelow; + if (x < image->width - 1) + { + iP[belowRight] += iErrorBelowRight; + aP[belowRight] += aErrorBelowRight; + } + } + aP++; + iP++; + } + free (iPicture); + core->on_color.red = + core->on_color.green = + core->on_color.blue = (min_inten | min_inten << 8); + core->off_color.red = + core->off_color.green = + core->off_color.blue = (max_inten | max_inten << 8); + return True; +} + +static Bool +_XcursorThreshold (const XcursorImage *image, XcursorCoreCursor *core) +{ + XcursorPixel *pixel, p; + int x, y; + + /* + * Draw the image, picking black for dark pixels and white for light + */ + pixel = image->pixels; + for (y = 0; y < image->height; y++) + for (x = 0; x < image->width; x++) + { + p = *pixel++; + if ((p >> 24) >= 0x80) + { + XPutPixel (core->msk_image, x, y, 1); + if (_XcursorPixelBrightness (p) > 0x80) + XPutPixel (core->src_image, x, y, 0); + else + XPutPixel (core->src_image, x, y, 1); + } + else + { + XPutPixel (core->msk_image, x, y, 0); + XPutPixel (core->src_image, x, y, 0); + } + } + core->on_color.red = + core->on_color.green = + core->on_color.blue = 0; + core->off_color.red = + core->off_color.green = + core->off_color.blue = 0xffff; + return True; +} + +Cursor +XcursorImageLoadCursor (Display *dpy, const XcursorImage *image) +{ + Cursor cursor; + +#if RENDER_MAJOR > 0 || RENDER_MINOR >= 5 + if (XcursorSupportsARGB (dpy)) + { + XImage ximage; + int screen = DefaultScreen (dpy); + Pixmap pixmap; + Picture picture; + GC gc; + XRenderPictFormat *format; + + ximage.width = image->width; + ximage.height = image->height; + ximage.xoffset = 0; + ximage.format = ZPixmap; + ximage.data = (char *) image->pixels; + ximage.byte_order = nativeByteOrder (); + ximage.bitmap_unit = 32; + ximage.bitmap_bit_order = ximage.byte_order; + ximage.bitmap_pad = 32; + ximage.depth = 32; + ximage.bits_per_pixel = 32; + ximage.bytes_per_line = image->width * 4; + ximage.red_mask = 0xff0000; + ximage.green_mask = 0x00ff00; + ximage.blue_mask = 0x0000ff; + ximage.obdata = 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; +} |