summaryrefslogtreecommitdiff
path: root/dix
diff options
context:
space:
mode:
Diffstat (limited to 'dix')
-rw-r--r--dix/BuiltInAtoms329
-rw-r--r--dix/Makefile.am75
-rw-r--r--dix/Makefile.in877
-rw-r--r--dix/Xserver-dtrace.h.in94
-rw-r--r--dix/Xserver.d58
-rw-r--r--dix/atom.c218
-rw-r--r--dix/buildatoms43
-rw-r--r--dix/colormap.c2771
-rw-r--r--dix/cursor.c515
-rw-r--r--dix/deprecated.c165
-rw-r--r--dix/devices.c2633
-rw-r--r--dix/dispatch.c3901
-rw-r--r--dix/dispatch.h145
-rw-r--r--dix/dix.c0
-rw-r--r--dix/dixfonts.c2072
-rw-r--r--dix/dixutils.c893
-rw-r--r--dix/enterleave.c1389
-rw-r--r--dix/enterleave.h97
-rw-r--r--dix/eventconvert.c739
-rw-r--r--dix/events.c5812
-rw-r--r--dix/extension.c360
-rw-r--r--dix/ffs.c48
-rw-r--r--dix/gc.c1149
-rw-r--r--dix/getevents.c1327
-rw-r--r--dix/globals.c131
-rw-r--r--dix/glyphcurs.c191
-rw-r--r--dix/grabs.c557
-rw-r--r--dix/initatoms.c84
-rw-r--r--dix/inpututils.c558
-rw-r--r--dix/main.c358
-rw-r--r--dix/pixmap.c137
-rw-r--r--dix/privates.c502
-rw-r--r--dix/property.c644
-rw-r--r--dix/protocol.txt1103
-rw-r--r--dix/ptrveloc.c1175
-rw-r--r--dix/region.c1659
-rw-r--r--dix/registry.c336
-rw-r--r--dix/resource.c965
-rw-r--r--dix/selection.c311
-rw-r--r--dix/swaprep.c1308
-rw-r--r--dix/swapreq.c1099
-rw-r--r--dix/tables.c986
-rw-r--r--dix/window.c3686
43 files changed, 41500 insertions, 0 deletions
diff --git a/dix/BuiltInAtoms b/dix/BuiltInAtoms
new file mode 100644
index 0000000..910c627
--- /dev/null
+++ b/dix/BuiltInAtoms
@@ -0,0 +1,329 @@
+File: .../x11/server/dix/BuiltInAtoms
+
+This file is of a fixed format and is used to generate both the file
+include/XAtom.h and dix/initatoms.c. Neither of those files should be
+edited directly. Changing the atoms in this file, or even the order in
+which they occur, is equivalent to forcing a new (minor) version number
+on the server. Take care.
+
+The format of the file is that each built in atom starts in column 1
+with no text, other than spaces and tabs, on that line other than a
+mandatory trailing "@" at the end of the line. For each atom (Foo)
+below the defines will be of the form
+ #define XA_Foo <n>
+and the string value of the atom will be "Foo".
+
+The comment lines in this file are not guaranteed to be accurate. To see the
+current truth, look at the Xlib documentation as well as the protocol spec.
+
+Atoms occur in five distinct name spaces within the protocol. Any particular
+atom may or may not have some client interpretation within each of the name
+spaces. For each of the built in atoms, the intended semantics and the space
+within which it is defined is indicated.
+
+Those name spaces are
+ Property names
+ Property types
+ Selections
+ Font properties
+ Type of a ClientMessage event (none built into server)
+
+For the font properties mentioned here, see the spec for more information.
+
+ -- Selections --
+
+PRIMARY @
+ Selection.
+SECONDARY @
+ Selection.
+
+ -- Property types and names --
+
+ARC @
+ Property type:
+ x, y: INT16
+ width, height: CARD16,
+ angle1, angle2: INT16
+ATOM @
+ Property type:
+ atom: ATOM
+BITMAP @
+ Property type:
+ bitmap: PIXMAP
+ This is asserted to be of depth 1.
+CARDINAL @
+ Property type:
+ card: CARD32 or CARD16 or CARD8
+ the datum size is dependent on the property format
+COLORMAP @
+ Property type:
+ colormap: COLORMAP
+CURSOR @
+ Property type:
+ cursor: CURSOR
+CUT_BUFFER0 @
+CUT_BUFFER1 @
+CUT_BUFFER2 @
+CUT_BUFFER3 @
+CUT_BUFFER4 @
+CUT_BUFFER5 @
+CUT_BUFFER6 @
+CUT_BUFFER7 @
+ Property name: (type: STRING)
+ Used to implement cut buffer ring, in particular Andrew uses
+ this mechanism. Anyone else using this sort of IPC mechanism
+ should use these properties.
+
+ Data is normally fetched and stored out of CUT_BUFFER0; the
+ RotateProperties request is used to rotate these buffers.
+DRAWABLE @
+ Property type:
+ drawable: DRAWABLE
+FONT @
+ Property type:
+ font: FONT
+INTEGER @
+ Property type:
+ card: INT32 or INT16 or INT8
+ the datum size is dependent on the property format
+PIXMAP @
+ Property type:
+ pixmap: PIXMAP
+POINT @
+ Property type:
+ x, y: INT16
+RECTANGLE @
+ Property type:
+ x, y: INT16
+ width, height: CARD16
+RESOURCE_MANAGER @
+ Property name: (type: STRING)
+ Contents of the user's resource manager data base.
+RGB_COLOR_MAP @
+ Property type:
+ colormap: COLORMAP
+ red-max: CARD32
+ red-mult: CARD32
+ green-max: CARD32
+ green-mult: CARD32
+ blue-max: CARD32
+ blue-mult: CARD32
+ base-pixel: CARD32
+
+ The fields `red_max', `green_max', and `blue_max' give the maximum
+ red, green, and blue values, respectively. Each color
+ coefficient ranges from 0 to its max, inclusive. For example,
+ a common colormap allocation is 3/3/2: 3 planes for red, 3
+ planes for green, and 2 planes for blue. Such a colormap would
+ have red_max == 7, green_max = 7, and blue_max = 3. An alternate
+ allocation that uses only 216 colors is red_max = 5, green_max =
+ 5, and blue_max = 5.
+
+ The fields `red_mult', `green_mult', and `blue_mult' give the
+ scale factors used to compose a full pixel value. (See next
+ paragraph.) For a 3/3/2 allocation red_mult might be 32,
+ green_mult might be 4, and blue_mult might be 1. For a
+ 6-colors-each allocation, red_mult might be 36, green_mult might
+ be 6, and blue_mult might be 1.
+
+ The field `base_pixel' gives the base pixel value used to
+ compose a full pixel value. Normally base_pixel is obtained
+ from a call to XAllocColorPlanes(). Given integer red, green,
+ and blue coefficients in their appropriate ranges, one can
+ compute a corresponding pixel value with the expression:
+
+ r * red_mult + g * green_mult + b * blue_mult + base_pixel
+
+ For gray-scale colormaps, only the colormap, red_max, red_mult,
+ and base_pixel fields are defined; the other fields are
+ ignored. To compute a gray-scale pixel value, use:
+
+ gray * red_mult + base_pixel
+
+ This is provided to allow applications to share color maps.
+
+RGB_BEST_MAP @
+RGB_BLUE_MAP @
+RGB_DEFAULT_MAP @
+RGB_GRAY_MAP @
+RGB_GREEN_MAP @
+RGB_RED_MAP @
+ Property name: (type: RGB_COLOR_MAP)
+ The needs of most applications can be met with five colormaps.
+ Polite applications may need only a small RGB space, and can
+ use a portion of the default color map. Applications doing
+ high-quality RGB rendering will need an entire colormap,
+ filled with as large an RGB space as possible, e.g. 332. For
+ color separations, an application may need maximum device
+ resolution for each of red, green, and blue, even if this
+ requires three renderings with three colormaps.
+
+ Each of the above five names would be used for sharing color
+ maps.
+STRING @
+ Property type:
+ sequence of Bytes
+VISUALID @
+ Property type:
+ visual: VISUALID
+WINDOW @
+ Property type:
+ window: WINDOW
+WM_COMMAND @
+ Property name: (type: STRING)
+ Command line arguments used to invoke this application. The
+ arguments are delimited by null characters (ASCII 0).
+WM_HINTS @
+ Property type:
+ flags: CARD32
+ input: BOOL32
+ initial-state: CARD32
+ icon-pixmap: PIXMAP
+ icon-window: WINDOW
+ icon_mask: BITMAP
+ icon-x, icon-y: INT32
+ flags contains the following bits
+ 0x00000001 input hint
+ 0x00000002 state hint
+ 0x00000004 icon pixmap hint
+ 0x00000008 icon window hint
+ 0x00000010 icon position hint
+ values for initial-state
+ 0 unspecified -> application does not
+ care and WM should pick one.
+ 1 normal
+ 2 zoomed
+ 3 iconic
+ 4 inactive -> application believes
+ itself to be seldomly used. WM may wish to
+ place it on an inactive menu.
+ This type is potentially extensible. The order is critical;
+ append to the end only.
+ Property name: (type: WM_HINTS)
+ Additional hints set by the client for use by the window
+ manager.
+WM_CLIENT_MACHINE @
+ Property name: (type: STRING)
+ used to communicate with the window manager. The host name
+ of the machine the client is running on may be set here.
+WM_ICON_NAME @
+ Property name: (type: STRING)
+ what the application would like the label to be for
+ the iconic form of the window.
+WM_ICON_SIZE @
+ Property type:
+ minWidth, min-height: CARD32
+ maxWidth, max-height: CARD32
+ widthInc, height-inc: CARD32
+ Property name: (type: ICON_SIZE)
+ The window manager may set this property on the root window
+ to specify the icon sizes it allows.
+WM_NAME @
+ Property name: (type: STRING)
+ used to communicate with the window manager. This is
+ what the application would like the label for the window.
+WM_NORMAL_HINTS @
+ Property name: (type: SIZE_HINTS)
+ used to communicate with the window manager. This is size
+ hints for a window in its "normal" state.
+WM_SIZE_HINTS @
+ Property type:
+ flags: CARD32
+ x, y: INT32
+ width, height: CARD32
+ min-width, min-height: CARD32
+ max-width, max-height: CARD32
+ width-inc, height-inc: CARD32
+ min-aspect-x, min-aspect-y: CARD32
+ max-aspect-x, max-aspect-y: CARD32
+ flags contains the following bits
+ 0x00000001 user specified x and y
+ 0x00000002 user specified width and height
+ 0x00000004 program specified position
+ 0x00000008 program specified size
+ 0x00000010 program specified minimum size
+ 0x00000020 program specified maximum size
+ 0x00000040 program specified resize increment
+ 0x00000080 program specified aspect ratio
+ This type is potentially extensible. The order is critical;
+ append to the end only.
+WM_ZOOM_HINTS @
+ Property name: (type: SIZE_HINTS)
+ used to communicate with the window manager. This is size
+ hints for a window in its "zoomed" state.
+
+ -- Font properties --
+
+MIN_SPACE @
+ Font property: CARD32
+NORM_SPACE @
+ Font property: CARD32
+MAX_SPACE @
+ Font property: CARD32
+END_SPACE @
+ Font property: CARD32
+SUPERSCRIPT_X @
+ Font property: INT32
+SUPERSCRIPT_Y @
+ Font property: INT32
+SUBSCRIPT_X @
+ Font property: INT32
+SUBSCRIPT_Y @
+ Font property: INT32
+UNDERLINE_POSITION @
+ Font property: INT32
+UNDERLINE_THICKNESS @
+ Font property: CARD32
+STRIKEOUT_ASCENT @
+ Font property: INT32
+STRIKEOUT_DESCENT @
+ Font property: INT32
+ITALIC_ANGLE @
+ Font property: INT32
+X_HEIGHT @
+ Font property: INT32
+QUAD_WIDTH @
+ Font property: INT32
+WEIGHT @
+ Font property: CARD32
+POINT_SIZE @
+ Font property: CARD32
+RESOLUTION @
+ Font property: CARD32
+
+The following optional properties on fonts have values that are atoms. The
+atom print name is the useful information.
+
+COPYRIGHT @
+ of the font distribution
+NOTICE @
+ trademark/copyright of the character shapes
+FONT_NAME @
+ name of this particular instance of a font
+FAMILY_NAME @
+ name of the 'font family' to which it belongs
+FULL_NAME @
+ full text name of the font
+
+The following aren't in order but putting them at the end avoids encoding
+changes.
+
+CAP_HEIGHT @
+ Font property: CARD32
+
+
+WM_CLASS @
+ Property name: (type: STRING)
+ Used (possibly by some window managers; definitely by
+ session managers) to look up resources in the resource
+ data base on behalf of the client who set this property.
+ There are 2 elements:
+ {char *resource_name; char *resource_class;}
+ delimited by a null character (ascii 0)
+
+WM_TRANSIENT_FOR @
+ Property name: (type: WINDOW)
+ Used by transient top-level windows, such as dialog
+ boxes, to point to their logical "parents". The window
+ manager can then take down the dialog boxes when the
+ "parent" gets iconified, for instance.
diff --git a/dix/Makefile.am b/dix/Makefile.am
new file mode 100644
index 0000000..59e512b
--- /dev/null
+++ b/dix/Makefile.am
@@ -0,0 +1,75 @@
+noinst_LTLIBRARIES = libdix.la libmain.la
+
+AM_CPPFLAGS = -I$(top_srcdir)/include
+AM_CFLAGS = $(DIX_CFLAGS)
+
+libmain_la_SOURCES = \
+ main.c
+
+libdix_la_SOURCES = \
+ atom.c \
+ colormap.c \
+ cursor.c \
+ deprecated.c \
+ devices.c \
+ dispatch.c \
+ dispatch.h \
+ dixfonts.c \
+ dixutils.c \
+ enterleave.c \
+ enterleave.h \
+ events.c \
+ eventconvert.c \
+ extension.c \
+ ffs.c \
+ gc.c \
+ getevents.c \
+ globals.c \
+ glyphcurs.c \
+ grabs.c \
+ initatoms.c \
+ inpututils.c \
+ pixmap.c \
+ privates.c \
+ property.c \
+ ptrveloc.c \
+ region.c \
+ registry.c \
+ resource.c \
+ selection.c \
+ swaprep.c \
+ swapreq.c \
+ tables.c \
+ window.c
+
+EXTRA_DIST = buildatoms BuiltInAtoms Xserver.d Xserver-dtrace.h.in
+
+# Install list of protocol names
+miscconfigdir = $(SERVER_MISC_CONFIG_PATH)
+dist_miscconfig_DATA = protocol.txt
+
+if XSERVER_DTRACE
+# Generate dtrace header file for C sources to include
+BUILT_SOURCES = Xserver-dtrace.h
+
+Xserver-dtrace.h: $(srcdir)/Xserver.d
+ $(AM_V_GEN)$(DTRACE) -C -h -o $@ -s $(srcdir)/Xserver.d \
+ || cp Xserver-dtrace.h.in $@
+
+endif
+
+if SPECIAL_DTRACE_OBJECTS
+# Generate dtrace object code for probes in libdix
+dtrace-dix.o: $(top_srcdir)/dix/Xserver.d $(am_libdix_la_OBJECTS)
+ $(AM_V_GEN)$(DTRACE) -G -C -o $@ -s $(top_srcdir)/dix/Xserver.d $(am_libdix_la_OBJECTS:%.lo=.libs/%.o)
+
+noinst_PROGRAMS = dix.O
+
+dix.O: dtrace-dix.o $(am_libdix_la_OBJECTS)
+ $(AM_V_GEN)ld -r -o $@ $(am_libdix_la_OBJECTS:%.lo=.libs/%.o)
+endif
+
+dix.c:
+ touch $@
+
+CLEANFILES = dix.c Xserver-dtrace.h
diff --git a/dix/Makefile.in b/dix/Makefile.in
new file mode 100644
index 0000000..736a54e
--- /dev/null
+++ b/dix/Makefile.in
@@ -0,0 +1,877 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 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@
+
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+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@
+@SPECIAL_DTRACE_OBJECTS_TRUE@noinst_PROGRAMS = dix.O$(EXEEXT)
+subdir = dix
+DIST_COMMON = $(dist_miscconfig_DATA) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ac_define_dir.m4 \
+ $(top_srcdir)/m4/ax_tls.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/include/do-not-use-config.h \
+ $(top_builddir)/include/xorg-server.h \
+ $(top_builddir)/include/dix-config.h \
+ $(top_builddir)/include/xorg-config.h \
+ $(top_builddir)/include/xkb-config.h \
+ $(top_builddir)/include/xwin-config.h \
+ $(top_builddir)/include/kdrive-config.h \
+ $(top_builddir)/include/version-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libdix_la_LIBADD =
+am_libdix_la_OBJECTS = atom.lo colormap.lo cursor.lo deprecated.lo \
+ devices.lo dispatch.lo dixfonts.lo dixutils.lo enterleave.lo \
+ events.lo eventconvert.lo extension.lo ffs.lo gc.lo \
+ getevents.lo globals.lo glyphcurs.lo grabs.lo initatoms.lo \
+ inpututils.lo pixmap.lo privates.lo property.lo ptrveloc.lo \
+ region.lo registry.lo resource.lo selection.lo swaprep.lo \
+ swapreq.lo tables.lo window.lo
+libdix_la_OBJECTS = $(am_libdix_la_OBJECTS)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+libmain_la_LIBADD =
+am_libmain_la_OBJECTS = main.lo
+libmain_la_OBJECTS = $(am_libmain_la_OBJECTS)
+PROGRAMS = $(noinst_PROGRAMS)
+dix_O_SOURCES = dix.c
+dix_O_OBJECTS = dix.$(OBJEXT)
+dix_O_LDADD = $(LDADD)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libdix_la_SOURCES) $(libmain_la_SOURCES) dix.c
+DIST_SOURCES = $(libdix_la_SOURCES) $(libmain_la_SOURCES) dix.c
+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 = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(miscconfigdir)"
+DATA = $(dist_miscconfig_DATA)
+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@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPLE_APPLICATIONS_DIR = @APPLE_APPLICATIONS_DIR@
+APPLE_APPLICATION_NAME = @APPLE_APPLICATION_NAME@
+APP_MAN_DIR = @APP_MAN_DIR@
+APP_MAN_SUFFIX = @APP_MAN_SUFFIX@
+AR = @AR@
+ARM_BACKTRACE_CFLAGS = @ARM_BACKTRACE_CFLAGS@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BASE_FONT_PATH = @BASE_FONT_PATH@
+BUILD_DATE = @BUILD_DATE@
+BUILD_TIME = @BUILD_TIME@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CHANGELOG_CMD = @CHANGELOG_CMD@
+COMPILEDDEFAULTFONTPATH = @COMPILEDDEFAULTFONTPATH@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWARNFLAGS = @CWARNFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DARWIN_LIBS = @DARWIN_LIBS@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFAULT_LIBRARY_PATH = @DEFAULT_LIBRARY_PATH@
+DEFAULT_LOGDIR = @DEFAULT_LOGDIR@
+DEFAULT_LOGPREFIX = @DEFAULT_LOGPREFIX@
+DEFAULT_MODULE_PATH = @DEFAULT_MODULE_PATH@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DGA_CFLAGS = @DGA_CFLAGS@
+DGA_LIBS = @DGA_LIBS@
+DIX_CFLAGS = @DIX_CFLAGS@
+DIX_LIB = @DIX_LIB@
+DLLTOOL = @DLLTOOL@
+DLOPEN_LIBS = @DLOPEN_LIBS@
+DMXEXAMPLES_DEP_CFLAGS = @DMXEXAMPLES_DEP_CFLAGS@
+DMXEXAMPLES_DEP_LIBS = @DMXEXAMPLES_DEP_LIBS@
+DMXMODULES_CFLAGS = @DMXMODULES_CFLAGS@
+DMXMODULES_LIBS = @DMXMODULES_LIBS@
+DMXXIEXAMPLES_DEP_CFLAGS = @DMXXIEXAMPLES_DEP_CFLAGS@
+DMXXIEXAMPLES_DEP_LIBS = @DMXXIEXAMPLES_DEP_LIBS@
+DMXXMUEXAMPLES_DEP_CFLAGS = @DMXXMUEXAMPLES_DEP_CFLAGS@
+DMXXMUEXAMPLES_DEP_LIBS = @DMXXMUEXAMPLES_DEP_LIBS@
+DOXYGEN = @DOXYGEN@
+DRI2PROTO_CFLAGS = @DRI2PROTO_CFLAGS@
+DRI2PROTO_LIBS = @DRI2PROTO_LIBS@
+DRIPROTO_CFLAGS = @DRIPROTO_CFLAGS@
+DRIPROTO_LIBS = @DRIPROTO_LIBS@
+DRIVER_MAN_DIR = @DRIVER_MAN_DIR@
+DRIVER_MAN_SUFFIX = @DRIVER_MAN_SUFFIX@
+DRI_CFLAGS = @DRI_CFLAGS@
+DRI_DRIVER_PATH = @DRI_DRIVER_PATH@
+DRI_LIBS = @DRI_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DTRACE = @DTRACE@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILE_MAN_DIR = @FILE_MAN_DIR@
+FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@
+FONT100DPIDIR = @FONT100DPIDIR@
+FONT75DPIDIR = @FONT75DPIDIR@
+FONTMISCDIR = @FONTMISCDIR@
+FONTOTFDIR = @FONTOTFDIR@
+FONTROOTDIR = @FONTROOTDIR@
+FONTTTFDIR = @FONTTTFDIR@
+FONTTYPE1DIR = @FONTTYPE1DIR@
+FOP = @FOP@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLX_ARCH_DEFINES = @GLX_ARCH_DEFINES@
+GLX_DEFINES = @GLX_DEFINES@
+GLX_TLS = @GLX_TLS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+INSTALL = @INSTALL@
+INSTALL_CMD = @INSTALL_CMD@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+KDRIVE_CFLAGS = @KDRIVE_CFLAGS@
+KDRIVE_INCS = @KDRIVE_INCS@
+KDRIVE_LIBS = @KDRIVE_LIBS@
+KDRIVE_LOCAL_LIBS = @KDRIVE_LOCAL_LIBS@
+KDRIVE_PURE_INCS = @KDRIVE_PURE_INCS@
+KDRIVE_PURE_LIBS = @KDRIVE_PURE_LIBS@
+LAUNCHD_ID_PREFIX = @LAUNCHD_ID_PREFIX@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LD_EXPORT_SYMBOLS_FLAG = @LD_EXPORT_SYMBOLS_FLAG@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBDRM_CFLAGS = @LIBDRM_CFLAGS@
+LIBDRM_LIBS = @LIBDRM_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSHA1_CFLAGS = @LIBSHA1_CFLAGS@
+LIBSHA1_LIBS = @LIBSHA1_LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_MAN_DIR = @LIB_MAN_DIR@
+LIB_MAN_SUFFIX = @LIB_MAN_SUFFIX@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAIN_LIB = @MAIN_LIB@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAN_SUBSTS = @MAN_SUBSTS@
+MISC_MAN_DIR = @MISC_MAN_DIR@
+MISC_MAN_SUFFIX = @MISC_MAN_SUFFIX@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCCLD = @OBJCCLD@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJCFLAGS = @OBJCFLAGS@
+OBJCLINK = @OBJCLINK@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OS_LIB = @OS_LIB@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PCIACCESS_CFLAGS = @PCIACCESS_CFLAGS@
+PCIACCESS_LIBS = @PCIACCESS_LIBS@
+PCI_TXT_IDS_PATH = @PCI_TXT_IDS_PATH@
+PERL = @PERL@
+PIXMAN_CFLAGS = @PIXMAN_CFLAGS@
+PIXMAN_LIBS = @PIXMAN_LIBS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROJECTROOT = @PROJECTROOT@
+RANLIB = @RANLIB@
+RAWCPP = @RAWCPP@
+RAWCPPFLAGS = @RAWCPPFLAGS@
+RELEASE_DATE = @RELEASE_DATE@
+SDK_REQUIRED_MODULES = @SDK_REQUIRED_MODULES@
+SED = @SED@
+SELINUX_CFLAGS = @SELINUX_CFLAGS@
+SELINUX_LIBS = @SELINUX_LIBS@
+SERVER_MISC_CONFIG_PATH = @SERVER_MISC_CONFIG_PATH@
+SET_MAKE = @SET_MAKE@
+SHA1_CFLAGS = @SHA1_CFLAGS@
+SHA1_LIBS = @SHA1_LIBS@
+SHELL = @SHELL@
+SOLARIS_ASM_CFLAGS = @SOLARIS_ASM_CFLAGS@
+SOLARIS_INOUT_ARCH = @SOLARIS_INOUT_ARCH@
+STRIP = @STRIP@
+STYLESHEET_SRCDIR = @STYLESHEET_SRCDIR@
+SYSCONFDIR = @SYSCONFDIR@
+TSLIB_CFLAGS = @TSLIB_CFLAGS@
+TSLIB_LIBS = @TSLIB_LIBS@
+UDEV_CFLAGS = @UDEV_CFLAGS@
+UDEV_LIBS = @UDEV_LIBS@
+UTILS_SYS_LIBS = @UTILS_SYS_LIBS@
+VENDOR_NAME_SHORT = @VENDOR_NAME_SHORT@
+VERSION = @VERSION@
+WINDOWSWM_CFLAGS = @WINDOWSWM_CFLAGS@
+WINDOWSWM_LIBS = @WINDOWSWM_LIBS@
+WINDRES = @WINDRES@
+X11EXAMPLES_DEP_CFLAGS = @X11EXAMPLES_DEP_CFLAGS@
+X11EXAMPLES_DEP_LIBS = @X11EXAMPLES_DEP_LIBS@
+XDMCP_CFLAGS = @XDMCP_CFLAGS@
+XDMCP_LIBS = @XDMCP_LIBS@
+XDMXCONFIG_DEP_CFLAGS = @XDMXCONFIG_DEP_CFLAGS@
+XDMXCONFIG_DEP_LIBS = @XDMXCONFIG_DEP_LIBS@
+XDMX_CFLAGS = @XDMX_CFLAGS@
+XDMX_LIBS = @XDMX_LIBS@
+XDMX_SYS_LIBS = @XDMX_SYS_LIBS@
+XEPHYR_CFLAGS = @XEPHYR_CFLAGS@
+XEPHYR_INCS = @XEPHYR_INCS@
+XEPHYR_LIBS = @XEPHYR_LIBS@
+XF86CONFIGDIR = @XF86CONFIGDIR@
+XF86CONFIGFILE = @XF86CONFIGFILE@
+XF86VIDMODE_CFLAGS = @XF86VIDMODE_CFLAGS@
+XF86VIDMODE_LIBS = @XF86VIDMODE_LIBS@
+XKB_BASE_DIRECTORY = @XKB_BASE_DIRECTORY@
+XKB_BIN_DIRECTORY = @XKB_BIN_DIRECTORY@
+XKB_COMPILED_DIR = @XKB_COMPILED_DIR@
+XKM_OUTPUT_DIR = @XKM_OUTPUT_DIR@
+XLIB_CFLAGS = @XLIB_CFLAGS@
+XLIB_LIBS = @XLIB_LIBS@
+XMLTO = @XMLTO@
+XNESTMODULES_CFLAGS = @XNESTMODULES_CFLAGS@
+XNESTMODULES_LIBS = @XNESTMODULES_LIBS@
+XNEST_LIBS = @XNEST_LIBS@
+XNEST_SYS_LIBS = @XNEST_SYS_LIBS@
+XORG_CFLAGS = @XORG_CFLAGS@
+XORG_INCS = @XORG_INCS@
+XORG_LIBS = @XORG_LIBS@
+XORG_MAN_PAGE = @XORG_MAN_PAGE@
+XORG_MODULES_CFLAGS = @XORG_MODULES_CFLAGS@
+XORG_MODULES_LIBS = @XORG_MODULES_LIBS@
+XORG_OS = @XORG_OS@
+XORG_OS_SUBDIR = @XORG_OS_SUBDIR@
+XORG_SGML_PATH = @XORG_SGML_PATH@
+XORG_SYS_LIBS = @XORG_SYS_LIBS@
+XPBPROXY_CFLAGS = @XPBPROXY_CFLAGS@
+XPBPROXY_LIBS = @XPBPROXY_LIBS@
+XQUARTZ_SPARKLE = @XQUARTZ_SPARKLE@
+XRESEXAMPLES_DEP_CFLAGS = @XRESEXAMPLES_DEP_CFLAGS@
+XRESEXAMPLES_DEP_LIBS = @XRESEXAMPLES_DEP_LIBS@
+XSERVERCFLAGS_CFLAGS = @XSERVERCFLAGS_CFLAGS@
+XSERVERCFLAGS_LIBS = @XSERVERCFLAGS_LIBS@
+XSERVERLIBS_CFLAGS = @XSERVERLIBS_CFLAGS@
+XSERVERLIBS_LIBS = @XSERVERLIBS_LIBS@
+XSERVER_LIBS = @XSERVER_LIBS@
+XSERVER_SYS_LIBS = @XSERVER_SYS_LIBS@
+XSL_STYLESHEET = @XSL_STYLESHEET@
+XTSTEXAMPLES_DEP_CFLAGS = @XTSTEXAMPLES_DEP_CFLAGS@
+XTSTEXAMPLES_DEP_LIBS = @XTSTEXAMPLES_DEP_LIBS@
+XVFB_LIBS = @XVFB_LIBS@
+XVFB_SYS_LIBS = @XVFB_SYS_LIBS@
+XWINMODULES_CFLAGS = @XWINMODULES_CFLAGS@
+XWINMODULES_LIBS = @XWINMODULES_LIBS@
+XWIN_LIBS = @XWIN_LIBS@
+XWIN_SERVER_NAME = @XWIN_SERVER_NAME@
+XWIN_SYS_LIBS = @XWIN_SYS_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+__XCONFIGDIR__ = @__XCONFIGDIR__@
+__XCONFIGFILE__ = @__XCONFIGFILE__@
+abi_ansic = @abi_ansic@
+abi_extension = @abi_extension@
+abi_videodrv = @abi_videodrv@
+abi_xinput = @abi_xinput@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+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@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+driverdir = @driverdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+extdir = @extdir@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sdkdir = @sdkdir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+symbol_visibility = @symbol_visibility@
+sysconfdir = @sysconfdir@
+sysconfigdir = @sysconfigdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libdix.la libmain.la
+AM_CPPFLAGS = -I$(top_srcdir)/include
+AM_CFLAGS = $(DIX_CFLAGS)
+libmain_la_SOURCES = \
+ main.c
+
+libdix_la_SOURCES = \
+ atom.c \
+ colormap.c \
+ cursor.c \
+ deprecated.c \
+ devices.c \
+ dispatch.c \
+ dispatch.h \
+ dixfonts.c \
+ dixutils.c \
+ enterleave.c \
+ enterleave.h \
+ events.c \
+ eventconvert.c \
+ extension.c \
+ ffs.c \
+ gc.c \
+ getevents.c \
+ globals.c \
+ glyphcurs.c \
+ grabs.c \
+ initatoms.c \
+ inpututils.c \
+ pixmap.c \
+ privates.c \
+ property.c \
+ ptrveloc.c \
+ region.c \
+ registry.c \
+ resource.c \
+ selection.c \
+ swaprep.c \
+ swapreq.c \
+ tables.c \
+ window.c
+
+EXTRA_DIST = buildatoms BuiltInAtoms Xserver.d Xserver-dtrace.h.in
+
+# Install list of protocol names
+miscconfigdir = $(SERVER_MISC_CONFIG_PATH)
+dist_miscconfig_DATA = protocol.txt
+
+# Generate dtrace header file for C sources to include
+@XSERVER_DTRACE_TRUE@BUILT_SOURCES = Xserver-dtrace.h
+CLEANFILES = dix.c Xserver-dtrace.h
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) 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 ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign dix/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign dix/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
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_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
+libdix.la: $(libdix_la_OBJECTS) $(libdix_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libdix_la_OBJECTS) $(libdix_la_LIBADD) $(LIBS)
+libmain.la: $(libmain_la_OBJECTS) $(libmain_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libmain_la_OBJECTS) $(libmain_la_LIBADD) $(LIBS)
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+@SPECIAL_DTRACE_OBJECTS_FALSE@dix.O$(EXEEXT): $(dix_O_OBJECTS) $(dix_O_DEPENDENCIES)
+@SPECIAL_DTRACE_OBJECTS_FALSE@ @rm -f dix.O$(EXEEXT)
+@SPECIAL_DTRACE_OBJECTS_FALSE@ $(AM_V_CCLD)$(LINK) $(dix_O_OBJECTS) $(dix_O_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atom.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/colormap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cursor.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/deprecated.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/devices.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dispatch.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dix.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dixfonts.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dixutils.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/enterleave.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eventconvert.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/events.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/extension.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ffs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getevents.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/globals.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glyphcurs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grabs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/initatoms.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inpututils.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pixmap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/privates.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/property.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ptrveloc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/region.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/registry.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resource.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/selection.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/swaprep.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/swapreq.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tables.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/window.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@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@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@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@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@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
+install-dist_miscconfigDATA: $(dist_miscconfig_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(miscconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(miscconfigdir)"
+ @list='$(dist_miscconfig_DATA)'; test -n "$(miscconfigdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(miscconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(miscconfigdir)" || exit $$?; \
+ done
+
+uninstall-dist_miscconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_miscconfig_DATA)'; test -n "$(miscconfigdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(miscconfigdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(miscconfigdir)" && rm -f $$files
+
+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; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ 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; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ 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; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$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: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(miscconfigdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) 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:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_miscconfigDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+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-dist_miscconfigDATA
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES clean-noinstPROGRAMS \
+ 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-dist_miscconfigDATA install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ 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-dist_miscconfigDATA
+
+
+@XSERVER_DTRACE_TRUE@Xserver-dtrace.h: $(srcdir)/Xserver.d
+@XSERVER_DTRACE_TRUE@ $(AM_V_GEN)$(DTRACE) -C -h -o $@ -s $(srcdir)/Xserver.d \
+@XSERVER_DTRACE_TRUE@ || cp Xserver-dtrace.h.in $@
+
+# Generate dtrace object code for probes in libdix
+@SPECIAL_DTRACE_OBJECTS_TRUE@dtrace-dix.o: $(top_srcdir)/dix/Xserver.d $(am_libdix_la_OBJECTS)
+@SPECIAL_DTRACE_OBJECTS_TRUE@ $(AM_V_GEN)$(DTRACE) -G -C -o $@ -s $(top_srcdir)/dix/Xserver.d $(am_libdix_la_OBJECTS:%.lo=.libs/%.o)
+
+@SPECIAL_DTRACE_OBJECTS_TRUE@dix.O: dtrace-dix.o $(am_libdix_la_OBJECTS)
+@SPECIAL_DTRACE_OBJECTS_TRUE@ $(AM_V_GEN)ld -r -o $@ $(am_libdix_la_OBJECTS:%.lo=.libs/%.o)
+
+dix.c:
+ touch $@
+
+# 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/dix/Xserver-dtrace.h.in b/dix/Xserver-dtrace.h.in
new file mode 100644
index 0000000..daf3faf
--- /dev/null
+++ b/dix/Xserver-dtrace.h.in
@@ -0,0 +1,94 @@
+/* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * Generated by dtrace(1M), and then modified for backwards compatibility
+ * with older versions of dtrace. Used if dtrace -h fails.
+ * (Since _ENABLED support was added after dtrace -h, this assumes if
+ * dtrace -h fails, _ENABLED will too.)
+ */
+
+#ifndef _XSERVER_DTRACE_H
+#define _XSERVER_DTRACE_H
+
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if _DTRACE_VERSION
+
+#define XSERVER_CLIENT_AUTH(arg0, arg1, arg2, arg3) \
+ __dtrace_Xserver___client__auth(arg0, arg1, arg2, arg3)
+#define XSERVER_CLIENT_CONNECT(arg0, arg1) \
+ __dtrace_Xserver___client__connect(arg0, arg1)
+#define XSERVER_CLIENT_DISCONNECT(arg0) \
+ __dtrace_Xserver___client__disconnect(arg0)
+#define XSERVER_REQUEST_DONE(arg0, arg1, arg2, arg3, arg4) \
+ __dtrace_Xserver___request__done(arg0, arg1, arg2, arg3, arg4)
+#define XSERVER_REQUEST_START(arg0, arg1, arg2, arg3, arg4) \
+ __dtrace_Xserver___request__start(arg0, arg1, arg2, arg3, arg4)
+#define XSERVER_RESOURCE_ALLOC(arg0, arg1, arg2, arg3) \
+ __dtrace_Xserver___resource__alloc(arg0, arg1, arg2, arg3)
+#define XSERVER_RESOURCE_FREE(arg0, arg1, arg2, arg3) \
+ __dtrace_Xserver___resource__free(arg0, arg1, arg2, arg3)
+#define XSERVER_SEND_EVENT(arg0, arg1, arg2) \
+ __dtrace_Xserver___send__event(arg0, arg1, arg2)
+
+
+extern void __dtrace_Xserver___client__auth(int, string, pid_t, zoneid_t);
+extern void __dtrace_Xserver___client__connect(int, int);
+extern void __dtrace_Xserver___client__disconnect(int);
+extern void __dtrace_Xserver___request__done(string, uint8_t, uint32_t, int, int);
+extern void __dtrace_Xserver___request__start(string, uint8_t, uint16_t, int, void *);
+extern void __dtrace_Xserver___resource__alloc(uint32_t, uint32_t, void *, string);
+extern void __dtrace_Xserver___resource__free(uint32_t, uint32_t, void *, string);
+extern void __dtrace_Xserver___send__event(int, uint8_t, void *);
+
+#else
+
+#define XSERVER_CLIENT_AUTH(arg0, arg1, arg2, arg3)
+#define XSERVER_CLIENT_CONNECT(arg0, arg1)
+#define XSERVER_CLIENT_DISCONNECT(arg0)
+#define XSERVER_REQUEST_DONE(arg0, arg1, arg2, arg3, arg4)
+#define XSERVER_REQUEST_START(arg0, arg1, arg2, arg3, arg4)
+#define XSERVER_RESOURCE_ALLOC(arg0, arg1, arg2, arg3)
+#define XSERVER_RESOURCE_FREE(arg0, arg1, arg2, arg3)
+#define XSERVER_SEND_EVENT(arg0, arg1, arg2)
+
+#endif
+
+#define XSERVER_CLIENT_AUTH_ENABLED() (1)
+#define XSERVER_CLIENT_CONNECT_ENABLED() (1)
+#define XSERVER_CLIENT_DISCONNECT_ENABLED() (1)
+#define XSERVER_REQUEST_DONE_ENABLED() (1)
+#define XSERVER_REQUEST_START_ENABLED() (1)
+#define XSERVER_RESOURCE_ALLOC_ENABLED() (1)
+#define XSERVER_RESOURCE_FREE_ENABLED() (1)
+#define XSERVER_SEND_EVENT_ENABLED() (1)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _XSERVER_DTRACE_H */
diff --git a/dix/Xserver.d b/dix/Xserver.d
new file mode 100644
index 0000000..2ad3373
--- /dev/null
+++ b/dix/Xserver.d
@@ -0,0 +1,58 @@
+/* Copyright (c) 2005-2006, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * Xserver dtrace provider definition
+ */
+#ifdef __APPLE__
+#define string char *
+#define pid_t uint32_t
+#define zoneid_t uint32_t
+#else
+#include <sys/types.h>
+#endif
+
+provider Xserver {
+ /* reqType, data, length, client id, request buffer */
+ probe request__start(string, uint8_t, uint16_t, int, void *);
+ /* reqType, data, sequence, client id, result */
+ probe request__done(string, uint8_t, uint32_t, int, int);
+ /* client id, client fd */
+ probe client__connect(int, int);
+ /* client id, client address, client pid, client zone id */
+ probe client__auth(int, string, pid_t, zoneid_t);
+ /* client id */
+ probe client__disconnect(int);
+ /* resource id, resource type, value, resource type name */
+ probe resource__alloc(uint32_t, uint32_t, void *, string);
+ /* resource id, resource type, value, resource type name */
+ probe resource__free(uint32_t, uint32_t, void *, string);
+ /* client id, event type, event* */
+ probe send__event(int, uint8_t, void *);
+};
+
+#pragma D attributes Unstable/Unstable/Common provider Xserver provider
+#pragma D attributes Private/Private/Unknown provider Xserver module
+#pragma D attributes Private/Private/Unknown provider Xserver function
+#pragma D attributes Unstable/Unstable/Common provider Xserver name
+#pragma D attributes Unstable/Unstable/Common provider Xserver args
+
diff --git a/dix/atom.c b/dix/atom.c
new file mode 100644
index 0000000..88b40db
--- /dev/null
+++ b/dix/atom.c
@@ -0,0 +1,218 @@
+/***********************************************************
+
+Copyright 1987, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+******************************************************************/
+
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/Xatom.h>
+#include <stdio.h>
+#include <string.h>
+#include "misc.h"
+#include "resource.h"
+#include "dix.h"
+
+#define InitialTableSize 100
+
+typedef struct _Node {
+ struct _Node *left, *right;
+ Atom a;
+ unsigned int fingerPrint;
+ const char *string;
+} NodeRec, *NodePtr;
+
+static Atom lastAtom = None;
+static NodePtr atomRoot = NULL;
+static unsigned long tableLength;
+static NodePtr *nodeTable;
+
+void FreeAtom(NodePtr patom);
+
+Atom
+MakeAtom(const char *string, unsigned len, Bool makeit)
+{
+ NodePtr * np;
+ unsigned i;
+ int comp;
+ unsigned int fp = 0;
+
+ np = &atomRoot;
+ for (i = 0; i < (len+1)/2; i++)
+ {
+ fp = fp * 27 + string[i];
+ fp = fp * 27 + string[len - 1 - i];
+ }
+ while (*np != NULL)
+ {
+ if (fp < (*np)->fingerPrint)
+ np = &((*np)->left);
+ else if (fp > (*np)->fingerPrint)
+ np = &((*np)->right);
+ else
+ { /* now start testing the strings */
+ comp = strncmp(string, (*np)->string, (int)len);
+ if ((comp < 0) || ((comp == 0) && (len < strlen((*np)->string))))
+ np = &((*np)->left);
+ else if (comp > 0)
+ np = &((*np)->right);
+ else
+ return(*np)->a;
+ }
+ }
+ if (makeit)
+ {
+ NodePtr nd;
+
+ nd = malloc(sizeof(NodeRec));
+ if (!nd)
+ return BAD_RESOURCE;
+ if (lastAtom < XA_LAST_PREDEFINED)
+ {
+ nd->string = string;
+ }
+ else
+ {
+ char *newstring = malloc(len + 1);
+ if (!newstring) {
+ free(nd);
+ return BAD_RESOURCE;
+ }
+ strncpy(newstring, string, (int)len);
+ newstring[len] = 0;
+ nd->string = newstring;
+ }
+ if ((lastAtom + 1) >= tableLength) {
+ NodePtr *table;
+
+ table = realloc(nodeTable, tableLength * (2 * sizeof(NodePtr)));
+ if (!table) {
+ if (nd->string != string) {
+ /* nd->string has been strdup'ed */
+ free((char *)nd->string);
+ }
+ free(nd);
+ return BAD_RESOURCE;
+ }
+ tableLength <<= 1;
+ nodeTable = table;
+ }
+ *np = nd;
+ nd->left = nd->right = NULL;
+ nd->fingerPrint = fp;
+ nd->a = ++lastAtom;
+ nodeTable[lastAtom] = nd;
+ return nd->a;
+ }
+ else
+ return None;
+}
+
+Bool
+ValidAtom(Atom atom)
+{
+ return (atom != None) && (atom <= lastAtom);
+}
+
+const char *
+NameForAtom(Atom atom)
+{
+ NodePtr node;
+ if (atom > lastAtom) return 0;
+ if ((node = nodeTable[atom]) == NULL) return 0;
+ return node->string;
+}
+
+void
+AtomError(void)
+{
+ FatalError("initializing atoms");
+}
+
+void
+FreeAtom(NodePtr patom)
+{
+ if(patom->left)
+ FreeAtom(patom->left);
+ if(patom->right)
+ FreeAtom(patom->right);
+ if (patom->a > XA_LAST_PREDEFINED) {
+ /*
+ * All strings above XA_LAST_PREDEFINED are strdup'ed, so it's safe to
+ * cast here
+ */
+ free((char *)patom->string);
+ }
+ free(patom);
+}
+
+void
+FreeAllAtoms(void)
+{
+ if (atomRoot == NULL)
+ return;
+ FreeAtom(atomRoot);
+ atomRoot = NULL;
+ free(nodeTable);
+ nodeTable = NULL;
+ lastAtom = None;
+}
+
+void
+InitAtoms(void)
+{
+ FreeAllAtoms();
+ tableLength = InitialTableSize;
+ nodeTable = malloc(InitialTableSize * sizeof(NodePtr));
+ if (!nodeTable)
+ AtomError();
+ nodeTable[None] = NULL;
+ MakePredeclaredAtoms();
+ if (lastAtom != XA_LAST_PREDEFINED)
+ AtomError();
+}
diff --git a/dix/buildatoms b/dix/buildatoms
new file mode 100644
index 0000000..dfbbca8
--- /dev/null
+++ b/dix/buildatoms
@@ -0,0 +1,43 @@
+#!/bin/sh
+hfile=../../../include/Xatom.h
+cfile=initatoms.c
+rm -f $hfile $cfile
+umask 222
+awk '
+BEGIN {
+ hfile = "'$hfile'";
+ cfile = "'$cfile'";
+ hformat = "#define XA_%s ((Atom) %d)\n";
+ printf("#ifndef XATOM_H\n") > hfile;
+ printf("#define XATOM_H 1\n\n") > hfile;
+ printf("/* THIS IS A GENERATED FILE\n") > hfile;
+ printf(" *\n") > hfile;
+ printf(" * Do not change! Changing this file implies a protocol change!\n") > hfile;
+ printf(" */\n\n") > hfile;
+
+ printf("/* THIS IS A GENERATED FILE\n") > cfile;
+ printf(" *\n") > cfile;
+ printf(" * Do not change! Changing this file implies a protocol change!\n") > cfile;
+ printf(" */\n\n") > cfile;
+ printf("#include \"X.h\"\n") > cfile;
+ printf("#include \"Xatom.h\"\n") > cfile;
+ printf("#include \"misc.h\"\n") > cfile;
+ printf("#include \"dix.h\"\n") > cfile;
+ printf("void MakePredeclaredAtoms()\n") > cfile;
+ printf("{\n") > cfile;
+
+ }
+
+NF == 2 && $2 == "@" {
+ printf(hformat, $1, ++atomno) > hfile ;
+ printf(" if (MakeAtom(\"%s\", %d, 1) != XA_%s) AtomError();\n", $1, length($1), $1) > cfile ;
+ }
+
+END {
+ printf("\n") > hfile;
+ printf(hformat, "LAST_PREDEFINED", atomno) > hfile ;
+ printf("#endif /* XATOM_H */\n") > hfile;
+ printf("}\n") > cfile ;
+ }
+' BuiltInAtoms
+exit 0
diff --git a/dix/colormap.c b/dix/colormap.c
new file mode 100644
index 0000000..0e1feb6
--- /dev/null
+++ b/dix/colormap.c
@@ -0,0 +1,2771 @@
+/***********************************************************
+
+Copyright 1987, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+******************************************************************/
+
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include "misc.h"
+#include "dix.h"
+#include "dixstruct.h"
+#include "colormapst.h"
+#include "os.h"
+#include "scrnintstr.h"
+#include "resource.h"
+#include "windowstr.h"
+#include "privates.h"
+#include "xace.h"
+
+static Pixel FindBestPixel(
+ EntryPtr /*pentFirst*/,
+ int /*size*/,
+ xrgb * /*prgb*/,
+ int /*channel*/
+);
+
+static int AllComp(
+ EntryPtr /*pent*/,
+ xrgb * /*prgb*/
+);
+
+static int RedComp(
+ EntryPtr /*pent*/,
+ xrgb * /*prgb*/
+);
+
+static int GreenComp(
+ EntryPtr /*pent*/,
+ xrgb * /*prgb*/
+);
+
+static int BlueComp(
+ EntryPtr /*pent*/,
+ xrgb * /*prgb*/
+);
+
+static void FreePixels(
+ ColormapPtr /*pmap*/,
+ int /*client*/
+);
+
+static void CopyFree(
+ int /*channel*/,
+ int /*client*/,
+ ColormapPtr /*pmapSrc*/,
+ ColormapPtr /*pmapDst*/
+);
+
+static void FreeCell(
+ ColormapPtr /*pmap*/,
+ Pixel /*i*/,
+ int /*channel*/
+);
+
+static void UpdateColors(
+ ColormapPtr /*pmap*/
+);
+
+static int AllocDirect(
+ int /*client*/,
+ ColormapPtr /*pmap*/,
+ int /*c*/,
+ int /*r*/,
+ int /*g*/,
+ int /*b*/,
+ Bool /*contig*/,
+ Pixel * /*pixels*/,
+ Pixel * /*prmask*/,
+ Pixel * /*pgmask*/,
+ Pixel * /*pbmask*/
+);
+
+static int AllocPseudo(
+ int /*client*/,
+ ColormapPtr /*pmap*/,
+ int /*c*/,
+ int /*r*/,
+ Bool /*contig*/,
+ Pixel * /*pixels*/,
+ Pixel * /*pmask*/,
+ Pixel ** /*pppixFirst*/
+);
+
+static Bool AllocCP(
+ ColormapPtr /*pmap*/,
+ EntryPtr /*pentFirst*/,
+ int /*count*/,
+ int /*planes*/,
+ Bool /*contig*/,
+ Pixel * /*pixels*/,
+ Pixel * /*pMask*/
+);
+
+static Bool AllocShared(
+ ColormapPtr /*pmap*/,
+ Pixel * /*ppix*/,
+ int /*c*/,
+ int /*r*/,
+ int /*g*/,
+ int /*b*/,
+ Pixel /*rmask*/,
+ Pixel /*gmask*/,
+ Pixel /*bmask*/,
+ Pixel * /*ppixFirst*/
+);
+
+static int FreeCo(
+ ColormapPtr /*pmap*/,
+ int /*client*/,
+ int /*color*/,
+ int /*npixIn*/,
+ Pixel * /*ppixIn*/,
+ Pixel /*mask*/
+);
+
+static int TellNoMap(
+ WindowPtr /*pwin*/,
+ Colormap * /*pmid*/
+);
+
+static void FindColorInRootCmap (
+ ColormapPtr /* pmap */,
+ EntryPtr /* pentFirst */,
+ int /* size */,
+ xrgb* /* prgb */,
+ Pixel* /* pPixel */,
+ int /* channel */,
+ ColorCompareProcPtr /* comp */
+);
+
+#define NUMRED(vis) ((vis->redMask >> vis->offsetRed) + 1)
+#define NUMGREEN(vis) ((vis->greenMask >> vis->offsetGreen) + 1)
+#define NUMBLUE(vis) ((vis->blueMask >> vis->offsetBlue) + 1)
+#if COMPOSITE
+#define ALPHAMASK(vis) ((vis)->nplanes < 32 ? 0 : \
+ (CARD32) ~((vis)->redMask|(vis)->greenMask|(vis)->blueMask))
+#else
+#define ALPHAMASK(vis) 0
+#endif
+
+#define RGBMASK(vis) (vis->redMask | vis->greenMask | vis->blueMask | ALPHAMASK(vis))
+
+/* GetNextBitsOrBreak(bits, mask, base) --
+ * (Suggestion: First read the macro, then read this explanation.
+ *
+ * Either generate the next value to OR in to a pixel or break out of this
+ * while loop
+ *
+ * This macro is used when we're trying to generate all 2^n combinations of
+ * bits in mask. What we're doing here is counting in binary, except that
+ * the bits we use to count may not be contiguous. This macro will be
+ * called 2^n times, returning a different value in bits each time. Then
+ * it will cause us to break out of a surrounding loop. (It will always be
+ * called from within a while loop.)
+ * On call: mask is the value we want to find all the combinations for
+ * base has 1 bit set where the least significant bit of mask is set
+ *
+ * For example,if mask is 01010, base should be 0010 and we count like this:
+ * 00010 (see this isn't so hard),
+ * then we add base to bits and get 0100. (bits & ~mask) is (0100 & 0100) so
+ * we add that to bits getting (0100 + 0100) =
+ * 01000 for our next value.
+ * then we add 0010 to get
+ * 01010 and we're done (easy as 1, 2, 3)
+ */
+#define GetNextBitsOrBreak(bits, mask, base) \
+ if((bits) == (mask)) \
+ break; \
+ (bits) += (base); \
+ while((bits) & ~(mask)) \
+ (bits) += ((bits) & ~(mask));
+/* ID of server as client */
+#define SERVER_ID 0
+
+typedef struct _colorResource
+{
+ Colormap mid;
+ int client;
+} colorResource;
+
+/* Invariants:
+ * refcnt == 0 means entry is empty
+ * refcnt > 0 means entry is useable by many clients, so it can't be changed
+ * refcnt == AllocPrivate means entry owned by one client only
+ * fShared should only be set if refcnt == AllocPrivate, and only in red map
+ */
+
+
+/**
+ * Create and initialize the color map
+ *
+ * \param mid resource to use for this colormap
+ * \param alloc 1 iff all entries are allocated writable
+ */
+int
+CreateColormap (Colormap mid, ScreenPtr pScreen, VisualPtr pVisual,
+ ColormapPtr *ppcmap, int alloc, int client)
+{
+ int class, size;
+ unsigned long sizebytes;
+ ColormapPtr pmap;
+ EntryPtr pent;
+ int i;
+ Pixel *ppix, **pptr;
+
+ class = pVisual->class;
+ if(!(class & DynamicClass) && (alloc != AllocNone) && (client != SERVER_ID))
+ return BadMatch;
+
+ size = pVisual->ColormapEntries;
+ sizebytes = (size * sizeof(Entry)) +
+ (MAXCLIENTS * sizeof(Pixel *)) +
+ (MAXCLIENTS * sizeof(int));
+ if ((class | DynamicClass) == DirectColor)
+ sizebytes *= 3;
+ sizebytes += sizeof(ColormapRec);
+ if (mid == pScreen->defColormap) {
+ pmap = malloc(sizebytes);
+ if (!pmap)
+ return BadAlloc;
+ if (!dixAllocatePrivates(&pmap->devPrivates, PRIVATE_COLORMAP)) {
+ free (pmap);
+ return BadAlloc;
+ }
+ } else {
+ pmap = _dixAllocateObjectWithPrivates(sizebytes, sizebytes,
+ offsetof(ColormapRec, devPrivates), PRIVATE_COLORMAP);
+ if (!pmap)
+ return BadAlloc;
+ }
+#if defined(_XSERVER64)
+ pmap->pad0 = 0;
+ pmap->pad1 = 0;
+#if (X_BYTE_ORDER == X_LITTLE_ENDIAN)
+ pmap->pad2 = 0;
+#endif
+#endif
+ pmap->red = (EntryPtr)((char *)pmap + sizeof(ColormapRec));
+ sizebytes = size * sizeof(Entry);
+ pmap->clientPixelsRed = (Pixel **)((char *)pmap->red + sizebytes);
+ pmap->numPixelsRed = (int *)((char *)pmap->clientPixelsRed +
+ (MAXCLIENTS * sizeof(Pixel *)));
+ pmap->mid = mid;
+ pmap->flags = 0; /* start out with all flags clear */
+ if(mid == pScreen->defColormap)
+ pmap->flags |= IsDefault;
+ pmap->pScreen = pScreen;
+ pmap->pVisual = pVisual;
+ pmap->class = class;
+ if ((class | DynamicClass) == DirectColor)
+ size = NUMRED(pVisual);
+ pmap->freeRed = size;
+ memset((char *) pmap->red, 0, (int)sizebytes);
+ memset((char *) pmap->numPixelsRed, 0, MAXCLIENTS * sizeof(int));
+ for (pptr = &pmap->clientPixelsRed[MAXCLIENTS]; --pptr >= pmap->clientPixelsRed; )
+ *pptr = (Pixel *)NULL;
+ if (alloc == AllocAll)
+ {
+ if (class & DynamicClass)
+ pmap->flags |= AllAllocated;
+ for (pent = &pmap->red[size - 1]; pent >= pmap->red; pent--)
+ pent->refcnt = AllocPrivate;
+ pmap->freeRed = 0;
+ ppix = malloc(size * sizeof(Pixel));
+ if (!ppix)
+ {
+ free(pmap);
+ return BadAlloc;
+ }
+ pmap->clientPixelsRed[client] = ppix;
+ for(i = 0; i < size; i++)
+ ppix[i] = i;
+ pmap->numPixelsRed[client] = size;
+ }
+
+ if ((class | DynamicClass) == DirectColor)
+ {
+ pmap->freeGreen = NUMGREEN(pVisual);
+ pmap->green = (EntryPtr)((char *)pmap->numPixelsRed +
+ (MAXCLIENTS * sizeof(int)));
+ pmap->clientPixelsGreen = (Pixel **)((char *)pmap->green + sizebytes);
+ pmap->numPixelsGreen = (int *)((char *)pmap->clientPixelsGreen +
+ (MAXCLIENTS * sizeof(Pixel *)));
+ pmap->freeBlue = NUMBLUE(pVisual);
+ pmap->blue = (EntryPtr)((char *)pmap->numPixelsGreen +
+ (MAXCLIENTS * sizeof(int)));
+ pmap->clientPixelsBlue = (Pixel **)((char *)pmap->blue + sizebytes);
+ pmap->numPixelsBlue = (int *)((char *)pmap->clientPixelsBlue +
+ (MAXCLIENTS * sizeof(Pixel *)));
+
+ memset((char *) pmap->green, 0, (int)sizebytes);
+ memset((char *) pmap->blue, 0, (int)sizebytes);
+
+ memmove((char *) pmap->clientPixelsGreen,
+ (char *) pmap->clientPixelsRed,
+ MAXCLIENTS * sizeof(Pixel *));
+ memmove((char *) pmap->clientPixelsBlue,
+ (char *) pmap->clientPixelsRed,
+ MAXCLIENTS * sizeof(Pixel *));
+ memset((char *) pmap->numPixelsGreen, 0, MAXCLIENTS * sizeof(int));
+ memset((char *) pmap->numPixelsBlue, 0, MAXCLIENTS * sizeof(int));
+
+ /* If every cell is allocated, mark its refcnt */
+ if (alloc == AllocAll)
+ {
+ size = pmap->freeGreen;
+ for(pent = &pmap->green[size-1]; pent >= pmap->green; pent--)
+ pent->refcnt = AllocPrivate;
+ pmap->freeGreen = 0;
+ ppix = malloc(size * sizeof(Pixel));
+ if (!ppix)
+ {
+ free(pmap->clientPixelsRed[client]);
+ free(pmap);
+ return BadAlloc;
+ }
+ pmap->clientPixelsGreen[client] = ppix;
+ for(i = 0; i < size; i++)
+ ppix[i] = i;
+ pmap->numPixelsGreen[client] = size;
+
+ size = pmap->freeBlue;
+ for(pent = &pmap->blue[size-1]; pent >= pmap->blue; pent--)
+ pent->refcnt = AllocPrivate;
+ pmap->freeBlue = 0;
+ ppix = malloc(size * sizeof(Pixel));
+ if (!ppix)
+ {
+ free(pmap->clientPixelsGreen[client]);
+ free(pmap->clientPixelsRed[client]);
+ free(pmap);
+ return BadAlloc;
+ }
+ pmap->clientPixelsBlue[client] = ppix;
+ for(i = 0; i < size; i++)
+ ppix[i] = i;
+ pmap->numPixelsBlue[client] = size;
+ }
+ }
+ pmap->flags |= BeingCreated;
+
+ if (!AddResource(mid, RT_COLORMAP, (pointer)pmap))
+ return BadAlloc;
+
+ /*
+ * Security creation/labeling check
+ */
+ i = XaceHook(XACE_RESOURCE_ACCESS, clients[client], mid, RT_COLORMAP,
+ pmap, RT_NONE, NULL, DixCreateAccess);
+ if (i != Success) {
+ FreeResource(mid, RT_NONE);
+ return i;
+ }
+
+ /* If the device wants a chance to initialize the colormap in any way,
+ * this is it. In specific, if this is a Static colormap, this is the
+ * time to fill in the colormap's values */
+ if (!(*pScreen->CreateColormap)(pmap))
+ {
+ FreeResource (mid, RT_NONE);
+ return BadAlloc;
+ }
+ pmap->flags &= ~BeingCreated;
+ *ppcmap = pmap;
+ return Success;
+}
+
+/**
+ *
+ * \param value must conform to DeleteType
+ */
+int
+FreeColormap (pointer value, XID mid)
+{
+ int i;
+ EntryPtr pent;
+ ColormapPtr pmap = (ColormapPtr)value;
+
+ if(CLIENT_ID(mid) != SERVER_ID)
+ {
+ (*pmap->pScreen->UninstallColormap) (pmap);
+ WalkTree(pmap->pScreen, (VisitWindowProcPtr)TellNoMap, (pointer) &mid);
+ }
+
+ /* This is the device's chance to undo anything it needs to, especially
+ * to free any storage it allocated */
+ (*pmap->pScreen->DestroyColormap)(pmap);
+
+ if(pmap->clientPixelsRed)
+ {
+ for(i = 0; i < MAXCLIENTS; i++)
+ free(pmap->clientPixelsRed[i]);
+ }
+
+ if ((pmap->class == PseudoColor) || (pmap->class == GrayScale))
+ {
+ for(pent = &pmap->red[pmap->pVisual->ColormapEntries - 1];
+ pent >= pmap->red;
+ pent--)
+ {
+ if(pent->fShared)
+ {
+ if (--pent->co.shco.red->refcnt == 0)
+ free(pent->co.shco.red);
+ if (--pent->co.shco.green->refcnt == 0)
+ free(pent->co.shco.green);
+ if (--pent->co.shco.blue->refcnt == 0)
+ free(pent->co.shco.blue);
+ }
+ }
+ }
+ if((pmap->class | DynamicClass) == DirectColor)
+ {
+ for(i = 0; i < MAXCLIENTS; i++)
+ {
+ free(pmap->clientPixelsGreen[i]);
+ free(pmap->clientPixelsBlue[i]);
+ }
+ }
+
+ if (pmap->flags & IsDefault) {
+ dixFreePrivates(pmap->devPrivates, PRIVATE_COLORMAP);
+ free(pmap);
+ } else
+ dixFreeObjectWithPrivates(pmap, PRIVATE_COLORMAP);
+ return Success;
+}
+
+/* Tell window that pmid has disappeared */
+static int
+TellNoMap (WindowPtr pwin, Colormap *pmid)
+{
+ xEvent xE;
+
+ if (wColormap(pwin) == *pmid)
+ {
+ /* This should be call to DeliverEvent */
+ xE.u.u.type = ColormapNotify;
+ xE.u.colormap.window = pwin->drawable.id;
+ xE.u.colormap.colormap = None;
+ xE.u.colormap.new = TRUE;
+ xE.u.colormap.state = ColormapUninstalled;
+#ifdef PANORAMIX
+ if(noPanoramiXExtension || !pwin->drawable.pScreen->myNum)
+#endif
+ DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL);
+ if (pwin->optional) {
+ pwin->optional->colormap = None;
+ CheckWindowOptionalNeed (pwin);
+ }
+ }
+
+ return WT_WALKCHILDREN;
+}
+
+/* Tell window that pmid got uninstalled */
+int
+TellLostMap (WindowPtr pwin, pointer value)
+{
+ Colormap *pmid = (Colormap *)value;
+ xEvent xE;
+
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension && pwin->drawable.pScreen->myNum)
+ return WT_STOPWALKING;
+#endif
+ if (wColormap(pwin) == *pmid)
+ {
+ /* This should be call to DeliverEvent */
+ xE.u.u.type = ColormapNotify;
+ xE.u.colormap.window = pwin->drawable.id;
+ xE.u.colormap.colormap = *pmid;
+ xE.u.colormap.new = FALSE;
+ xE.u.colormap.state = ColormapUninstalled;
+ DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL);
+ }
+
+ return WT_WALKCHILDREN;
+}
+
+/* Tell window that pmid got installed */
+int
+TellGainedMap (WindowPtr pwin, pointer value)
+{
+ Colormap *pmid = (Colormap *)value;
+ xEvent xE;
+
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension && pwin->drawable.pScreen->myNum)
+ return WT_STOPWALKING;
+#endif
+ if (wColormap (pwin) == *pmid)
+ {
+ /* This should be call to DeliverEvent */
+ xE.u.u.type = ColormapNotify;
+ xE.u.colormap.window = pwin->drawable.id;
+ xE.u.colormap.colormap = *pmid;
+ xE.u.colormap.new = FALSE;
+ xE.u.colormap.state = ColormapInstalled;
+ DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL);
+ }
+
+ return WT_WALKCHILDREN;
+}
+
+
+int
+CopyColormapAndFree (Colormap mid, ColormapPtr pSrc, int client)
+{
+ ColormapPtr pmap = (ColormapPtr) NULL;
+ int result, alloc, size;
+ Colormap midSrc;
+ ScreenPtr pScreen;
+ VisualPtr pVisual;
+
+ pScreen = pSrc->pScreen;
+ pVisual = pSrc->pVisual;
+ midSrc = pSrc->mid;
+ alloc = ((pSrc->flags & AllAllocated) && CLIENT_ID(midSrc) == client) ?
+ AllocAll : AllocNone;
+ size = pVisual->ColormapEntries;
+
+ /* If the create returns non-0, it failed */
+ result = CreateColormap (mid, pScreen, pVisual, &pmap, alloc, client);
+ if(result != Success)
+ return result;
+ if(alloc == AllocAll)
+ {
+ memmove((char *)pmap->red, (char *)pSrc->red, size * sizeof(Entry));
+ if((pmap->class | DynamicClass) == DirectColor)
+ {
+ memmove((char *)pmap->green, (char *)pSrc->green, size * sizeof(Entry));
+ memmove((char *)pmap->blue, (char *)pSrc->blue, size * sizeof(Entry));
+ }
+ pSrc->flags &= ~AllAllocated;
+ FreePixels(pSrc, client);
+ UpdateColors(pmap);
+ return Success;
+ }
+
+ CopyFree(REDMAP, client, pSrc, pmap);
+ if ((pmap->class | DynamicClass) == DirectColor)
+ {
+ CopyFree(GREENMAP, client, pSrc, pmap);
+ CopyFree(BLUEMAP, client, pSrc, pmap);
+ }
+ if (pmap->class & DynamicClass)
+ UpdateColors(pmap);
+ /* XXX should worry about removing any RT_CMAPENTRY resource */
+ return Success;
+}
+
+/* Helper routine for freeing large numbers of cells from a map */
+static void
+CopyFree (int channel, int client, ColormapPtr pmapSrc, ColormapPtr pmapDst)
+{
+ int z, npix;
+ EntryPtr pentSrcFirst, pentDstFirst;
+ EntryPtr pentSrc, pentDst;
+ Pixel *ppix;
+ int nalloc;
+
+ switch(channel)
+ {
+ default: /* so compiler can see that everything gets initialized */
+ case REDMAP:
+ ppix = (pmapSrc->clientPixelsRed)[client];
+ npix = (pmapSrc->numPixelsRed)[client];
+ pentSrcFirst = pmapSrc->red;
+ pentDstFirst = pmapDst->red;
+ break;
+ case GREENMAP:
+ ppix = (pmapSrc->clientPixelsGreen)[client];
+ npix = (pmapSrc->numPixelsGreen)[client];
+ pentSrcFirst = pmapSrc->green;
+ pentDstFirst = pmapDst->green;
+ break;
+ case BLUEMAP:
+ ppix = (pmapSrc->clientPixelsBlue)[client];
+ npix = (pmapSrc->numPixelsBlue)[client];
+ pentSrcFirst = pmapSrc->blue;
+ pentDstFirst = pmapDst->blue;
+ break;
+ }
+ nalloc = 0;
+ if (pmapSrc->class & DynamicClass)
+ {
+ for(z = npix; --z >= 0; ppix++)
+ {
+ /* Copy entries */
+ pentSrc = pentSrcFirst + *ppix;
+ pentDst = pentDstFirst + *ppix;
+ if (pentDst->refcnt > 0)
+ {
+ pentDst->refcnt++;
+ }
+ else
+ {
+ *pentDst = *pentSrc;
+ nalloc++;
+ if (pentSrc->refcnt > 0)
+ pentDst->refcnt = 1;
+ else
+ pentSrc->fShared = FALSE;
+ }
+ FreeCell(pmapSrc, *ppix, channel);
+ }
+ }
+
+ /* Note that FreeCell has already fixed pmapSrc->free{Color} */
+ switch(channel)
+ {
+ case REDMAP:
+ pmapDst->freeRed -= nalloc;
+ (pmapDst->clientPixelsRed)[client] =
+ (pmapSrc->clientPixelsRed)[client];
+ (pmapSrc->clientPixelsRed)[client] = (Pixel *) NULL;
+ (pmapDst->numPixelsRed)[client] = (pmapSrc->numPixelsRed)[client];
+ (pmapSrc->numPixelsRed)[client] = 0;
+ break;
+ case GREENMAP:
+ pmapDst->freeGreen -= nalloc;
+ (pmapDst->clientPixelsGreen)[client] =
+ (pmapSrc->clientPixelsGreen)[client];
+ (pmapSrc->clientPixelsGreen)[client] = (Pixel *) NULL;
+ (pmapDst->numPixelsGreen)[client] = (pmapSrc->numPixelsGreen)[client];
+ (pmapSrc->numPixelsGreen)[client] = 0;
+ break;
+ case BLUEMAP:
+ pmapDst->freeBlue -= nalloc;
+ pmapDst->clientPixelsBlue[client] = pmapSrc->clientPixelsBlue[client];
+ pmapSrc->clientPixelsBlue[client] = (Pixel *) NULL;
+ pmapDst->numPixelsBlue[client] = pmapSrc->numPixelsBlue[client];
+ pmapSrc->numPixelsBlue[client] = 0;
+ break;
+ }
+}
+
+/* Free the ith entry in a color map. Must handle freeing of
+ * colors allocated through AllocColorPlanes */
+static void
+FreeCell (ColormapPtr pmap, Pixel i, int channel)
+{
+ EntryPtr pent;
+ int *pCount;
+
+
+ switch (channel)
+ {
+ default: /* so compiler can see that everything gets initialized */
+ case PSEUDOMAP:
+ case REDMAP:
+ pent = (EntryPtr) &pmap->red[i];
+ pCount = &pmap->freeRed;
+ break;
+ case GREENMAP:
+ pent = (EntryPtr) &pmap->green[i];
+ pCount = &pmap->freeGreen;
+ break;
+ case BLUEMAP:
+ pent = (EntryPtr) &pmap->blue[i];
+ pCount = &pmap->freeBlue;
+ break;
+ }
+ /* If it's not privately allocated and it's not time to free it, just
+ * decrement the count */
+ if (pent->refcnt > 1)
+ pent->refcnt--;
+ else
+ {
+ /* If the color type is shared, find the sharedcolor. If decremented
+ * refcnt is 0, free the shared cell. */
+ if (pent->fShared)
+ {
+ if(--pent->co.shco.red->refcnt == 0)
+ free(pent->co.shco.red);
+ if(--pent->co.shco.green->refcnt == 0)
+ free(pent->co.shco.green);
+ if(--pent->co.shco.blue->refcnt == 0)
+ free(pent->co.shco.blue);
+ pent->fShared = FALSE;
+ }
+ pent->refcnt = 0;
+ *pCount += 1;
+ }
+}
+
+static void
+UpdateColors (ColormapPtr pmap)
+{
+ xColorItem *defs;
+ xColorItem *pdef;
+ EntryPtr pent;
+ VisualPtr pVisual;
+ int i, n, size;
+
+ pVisual = pmap->pVisual;
+ size = pVisual->ColormapEntries;
+ defs = malloc(size * sizeof(xColorItem));
+ if (!defs)
+ return;
+ n = 0;
+ pdef = defs;
+ if (pmap->class == DirectColor)
+ {
+ for (i = 0; i < size; i++)
+ {
+ if (!pmap->red[i].refcnt &&
+ !pmap->green[i].refcnt &&
+ !pmap->blue[i].refcnt)
+ continue;
+ pdef->pixel = ((Pixel)i << pVisual->offsetRed) |
+ ((Pixel)i << pVisual->offsetGreen) |
+ ((Pixel)i << pVisual->offsetBlue);
+ pdef->red = pmap->red[i].co.local.red;
+ pdef->green = pmap->green[i].co.local.green;
+ pdef->blue = pmap->blue[i].co.local.blue;
+ pdef->flags = DoRed|DoGreen|DoBlue;
+ pdef++;
+ n++;
+ }
+ }
+ else
+ {
+ for (i = 0, pent = pmap->red; i < size; i++, pent++)
+ {
+ if (!pent->refcnt)
+ continue;
+ pdef->pixel = i;
+ if(pent->fShared)
+ {
+ pdef->red = pent->co.shco.red->color;
+ pdef->green = pent->co.shco.green->color;
+ pdef->blue = pent->co.shco.blue->color;
+ }
+ else
+ {
+ pdef->red = pent->co.local.red;
+ pdef->green = pent->co.local.green;
+ pdef->blue = pent->co.local.blue;
+ }
+ pdef->flags = DoRed|DoGreen|DoBlue;
+ pdef++;
+ n++;
+ }
+ }
+ if (n)
+ (*pmap->pScreen->StoreColors)(pmap, n, defs);
+ free(defs);
+}
+
+/* Get a read-only color from a ColorMap (probably slow for large maps)
+ * Returns by changing the value in pred, pgreen, pblue and pPix
+ */
+int
+AllocColor (ColormapPtr pmap,
+ unsigned short *pred, unsigned short *pgreen, unsigned short *pblue,
+ Pixel *pPix, int client)
+{
+ Pixel pixR, pixG, pixB;
+ int entries;
+ xrgb rgb;
+ int class;
+ VisualPtr pVisual;
+ int npix;
+ Pixel *ppix;
+
+ pVisual = pmap->pVisual;
+ (*pmap->pScreen->ResolveColor) (pred, pgreen, pblue, pVisual);
+ rgb.red = *pred;
+ rgb.green = *pgreen;
+ rgb.blue = *pblue;
+ class = pmap->class;
+ entries = pVisual->ColormapEntries;
+
+ /* If the colormap is being created, then we want to be able to change
+ * the colormap, even if it's a static type. Otherwise, we'd never be
+ * able to initialize static colormaps
+ */
+ if(pmap->flags & BeingCreated)
+ class |= DynamicClass;
+
+ /* If this is one of the static storage classes, and we're not initializing
+ * it, the best we can do is to find the closest color entry to the
+ * requested one and return that.
+ */
+ switch (class) {
+ case StaticColor:
+ case StaticGray:
+ /* Look up all three components in the same pmap */
+ *pPix = pixR = FindBestPixel(pmap->red, entries, &rgb, PSEUDOMAP);
+ *pred = pmap->red[pixR].co.local.red;
+ *pgreen = pmap->red[pixR].co.local.green;
+ *pblue = pmap->red[pixR].co.local.blue;
+ npix = pmap->numPixelsRed[client];
+ ppix = (Pixel *) realloc(pmap->clientPixelsRed[client],
+ (npix + 1) * sizeof(Pixel));
+ if (!ppix)
+ return BadAlloc;
+ ppix[npix] = pixR;
+ pmap->clientPixelsRed[client] = ppix;
+ pmap->numPixelsRed[client]++;
+ break;
+
+ case TrueColor:
+ /* Look up each component in its own map, then OR them together */
+ pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP);
+ pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb, GREENMAP);
+ pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP);
+ *pPix = (pixR << pVisual->offsetRed) |
+ (pixG << pVisual->offsetGreen) |
+ (pixB << pVisual->offsetBlue) |
+ ALPHAMASK(pVisual);
+
+ *pred = pmap->red[pixR].co.local.red;
+ *pgreen = pmap->green[pixG].co.local.green;
+ *pblue = pmap->blue[pixB].co.local.blue;
+ npix = pmap->numPixelsRed[client];
+ ppix = (Pixel *) realloc(pmap->clientPixelsRed[client],
+ (npix + 1) * sizeof(Pixel));
+ if (!ppix)
+ return BadAlloc;
+ ppix[npix] = pixR;
+ pmap->clientPixelsRed[client] = ppix;
+ npix = pmap->numPixelsGreen[client];
+ ppix = (Pixel *) realloc(pmap->clientPixelsGreen[client],
+ (npix + 1) * sizeof(Pixel));
+ if (!ppix)
+ return BadAlloc;
+ ppix[npix] = pixG;
+ pmap->clientPixelsGreen[client] = ppix;
+ npix = pmap->numPixelsBlue[client];
+ ppix = (Pixel *) realloc(pmap->clientPixelsBlue[client],
+ (npix + 1) * sizeof(Pixel));
+ if (!ppix)
+ return BadAlloc;
+ ppix[npix] = pixB;
+ pmap->clientPixelsBlue[client] = ppix;
+ pmap->numPixelsRed[client]++;
+ pmap->numPixelsGreen[client]++;
+ pmap->numPixelsBlue[client]++;
+ break;
+
+ case GrayScale:
+ case PseudoColor:
+ if (pmap->mid != pmap->pScreen->defColormap &&
+ pmap->pVisual->vid == pmap->pScreen->rootVisual)
+ {
+ ColormapPtr prootmap;
+ dixLookupResourceByType((pointer *)&prootmap, pmap->pScreen->defColormap,
+ RT_COLORMAP, clients[client], DixReadAccess);
+
+ if (pmap->class == prootmap->class)
+ FindColorInRootCmap (prootmap, prootmap->red, entries, &rgb,
+ pPix, PSEUDOMAP, AllComp);
+ }
+ if (FindColor(pmap, pmap->red, entries, &rgb, pPix, PSEUDOMAP,
+ client, AllComp) != Success)
+ return BadAlloc;
+ break;
+
+ case DirectColor:
+ if (pmap->mid != pmap->pScreen->defColormap &&
+ pmap->pVisual->vid == pmap->pScreen->rootVisual)
+ {
+ ColormapPtr prootmap;
+ dixLookupResourceByType((pointer *)&prootmap, pmap->pScreen->defColormap,
+ RT_COLORMAP, clients[client], DixReadAccess);
+
+ if (pmap->class == prootmap->class)
+ {
+ pixR = (*pPix & pVisual->redMask) >> pVisual->offsetRed;
+ FindColorInRootCmap (prootmap, prootmap->red, entries, &rgb,
+ &pixR, REDMAP, RedComp);
+ pixG = (*pPix & pVisual->greenMask) >> pVisual->offsetGreen;
+ FindColorInRootCmap (prootmap, prootmap->green, entries, &rgb,
+ &pixG, GREENMAP, GreenComp);
+ pixB = (*pPix & pVisual->blueMask) >> pVisual->offsetBlue;
+ FindColorInRootCmap (prootmap, prootmap->blue, entries, &rgb,
+ &pixB, BLUEMAP, BlueComp);
+ *pPix = pixR | pixG | pixB;
+ }
+ }
+
+ pixR = (*pPix & pVisual->redMask) >> pVisual->offsetRed;
+ if (FindColor(pmap, pmap->red, NUMRED(pVisual), &rgb, &pixR, REDMAP,
+ client, RedComp) != Success)
+ return BadAlloc;
+ pixG = (*pPix & pVisual->greenMask) >> pVisual->offsetGreen;
+ if (FindColor(pmap, pmap->green, NUMGREEN(pVisual), &rgb, &pixG,
+ GREENMAP, client, GreenComp) != Success)
+ {
+ (void)FreeCo(pmap, client, REDMAP, 1, &pixR, (Pixel)0);
+ return BadAlloc;
+ }
+ pixB = (*pPix & pVisual->blueMask) >> pVisual->offsetBlue;
+ if (FindColor(pmap, pmap->blue, NUMBLUE(pVisual), &rgb, &pixB, BLUEMAP,
+ client, BlueComp) != Success)
+ {
+ (void)FreeCo(pmap, client, GREENMAP, 1, &pixG, (Pixel)0);
+ (void)FreeCo(pmap, client, REDMAP, 1, &pixR, (Pixel)0);
+ return BadAlloc;
+ }
+ *pPix = pixR | pixG | pixB | ALPHAMASK(pVisual);
+
+ break;
+ }
+
+ /* if this is the client's first pixel in this colormap, tell the
+ * resource manager that the client has pixels in this colormap which
+ * should be freed when the client dies */
+ if ((pmap->numPixelsRed[client] == 1) &&
+ (CLIENT_ID(pmap->mid) != client) &&
+ !(pmap->flags & BeingCreated))
+ {
+ colorResource *pcr;
+
+ pcr = malloc(sizeof(colorResource));
+ if (!pcr)
+ {
+ (void)FreeColors(pmap, client, 1, pPix, (Pixel)0);
+ return BadAlloc;
+ }
+ pcr->mid = pmap->mid;
+ pcr->client = client;
+ if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr))
+ return BadAlloc;
+ }
+ return Success;
+}
+
+/*
+ * FakeAllocColor -- fake an AllocColor request by
+ * returning a free pixel if availible, otherwise returning
+ * the closest matching pixel. This is used by the mi
+ * software sprite code to recolor cursors. A nice side-effect
+ * is that this routine will never return failure.
+ */
+
+void
+FakeAllocColor (ColormapPtr pmap, xColorItem *item)
+{
+ Pixel pixR, pixG, pixB;
+ Pixel temp;
+ int entries;
+ xrgb rgb;
+ int class;
+ VisualPtr pVisual;
+
+ pVisual = pmap->pVisual;
+ rgb.red = item->red;
+ rgb.green = item->green;
+ rgb.blue = item->blue;
+ (*pmap->pScreen->ResolveColor) (&rgb.red, &rgb.green, &rgb.blue, pVisual);
+ class = pmap->class;
+ entries = pVisual->ColormapEntries;
+
+ switch (class) {
+ case GrayScale:
+ case PseudoColor:
+ temp = 0;
+ item->pixel = 0;
+ if (FindColor(pmap, pmap->red, entries, &rgb, &temp, PSEUDOMAP,
+ -1, AllComp) == Success) {
+ item->pixel = temp;
+ break;
+ }
+ /* fall through ... */
+ case StaticColor:
+ case StaticGray:
+ item->pixel = FindBestPixel(pmap->red, entries, &rgb, PSEUDOMAP);
+ break;
+
+ case DirectColor:
+ /* Look up each component in its own map, then OR them together */
+ pixR = (item->pixel & pVisual->redMask) >> pVisual->offsetRed;
+ pixG = (item->pixel & pVisual->greenMask) >> pVisual->offsetGreen;
+ pixB = (item->pixel & pVisual->blueMask) >> pVisual->offsetBlue;
+ if (FindColor(pmap, pmap->red, NUMRED(pVisual), &rgb, &pixR, REDMAP,
+ -1, RedComp) != Success)
+ pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP)
+ << pVisual->offsetRed;
+ if (FindColor(pmap, pmap->green, NUMGREEN(pVisual), &rgb, &pixG,
+ GREENMAP, -1, GreenComp) != Success)
+ pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb,
+ GREENMAP) << pVisual->offsetGreen;
+ if (FindColor(pmap, pmap->blue, NUMBLUE(pVisual), &rgb, &pixB, BLUEMAP,
+ -1, BlueComp) != Success)
+ pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP)
+ << pVisual->offsetBlue;
+ item->pixel = pixR | pixG | pixB;
+ break;
+
+ case TrueColor:
+ /* Look up each component in its own map, then OR them together */
+ pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP);
+ pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb, GREENMAP);
+ pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP);
+ item->pixel = (pixR << pVisual->offsetRed) |
+ (pixG << pVisual->offsetGreen) |
+ (pixB << pVisual->offsetBlue);
+ break;
+ }
+}
+
+/* free a pixel value obtained from FakeAllocColor */
+void
+FakeFreeColor(ColormapPtr pmap, Pixel pixel)
+{
+ VisualPtr pVisual;
+ Pixel pixR, pixG, pixB;
+
+ switch (pmap->class) {
+ case GrayScale:
+ case PseudoColor:
+ if (pmap->red[pixel].refcnt == AllocTemporary)
+ pmap->red[pixel].refcnt = 0;
+ break;
+ case DirectColor:
+ pVisual = pmap->pVisual;
+ pixR = (pixel & pVisual->redMask) >> pVisual->offsetRed;
+ pixG = (pixel & pVisual->greenMask) >> pVisual->offsetGreen;
+ pixB = (pixel & pVisual->blueMask) >> pVisual->offsetBlue;
+ if (pmap->red[pixR].refcnt == AllocTemporary)
+ pmap->red[pixR].refcnt = 0;
+ if (pmap->green[pixG].refcnt == AllocTemporary)
+ pmap->green[pixG].refcnt = 0;
+ if (pmap->blue[pixB].refcnt == AllocTemporary)
+ pmap->blue[pixB].refcnt = 0;
+ break;
+ }
+}
+
+typedef unsigned short BigNumUpper;
+typedef unsigned long BigNumLower;
+
+#define BIGNUMLOWERBITS 24
+#define BIGNUMUPPERBITS 16
+#define BIGNUMLOWER (1 << BIGNUMLOWERBITS)
+#define BIGNUMUPPER (1 << BIGNUMUPPERBITS)
+#define UPPERPART(i) ((i) >> BIGNUMLOWERBITS)
+#define LOWERPART(i) ((i) & (BIGNUMLOWER - 1))
+
+typedef struct _bignum {
+ BigNumUpper upper;
+ BigNumLower lower;
+} BigNumRec, *BigNumPtr;
+
+#define BigNumGreater(x,y) (((x)->upper > (y)->upper) ||\
+ ((x)->upper == (y)->upper && (x)->lower > (y)->lower))
+
+#define UnsignedToBigNum(u,r) (((r)->upper = UPPERPART(u)), \
+ ((r)->lower = LOWERPART(u)))
+
+#define MaxBigNum(r) (((r)->upper = BIGNUMUPPER-1), \
+ ((r)->lower = BIGNUMLOWER-1))
+
+static void
+BigNumAdd (BigNumPtr x, BigNumPtr y, BigNumPtr r)
+{
+ BigNumLower lower, carry = 0;
+
+ lower = x->lower + y->lower;
+ if (lower >= BIGNUMLOWER) {
+ lower -= BIGNUMLOWER;
+ carry = 1;
+ }
+ r->lower = lower;
+ r->upper = x->upper + y->upper + carry;
+}
+
+static Pixel
+FindBestPixel(EntryPtr pentFirst, int size, xrgb *prgb, int channel)
+{
+ EntryPtr pent;
+ Pixel pixel, final;
+ long dr, dg, db;
+ unsigned long sq;
+ BigNumRec minval, sum, temp;
+
+ final = 0;
+ MaxBigNum(&minval);
+ /* look for the minimal difference */
+ for (pent = pentFirst, pixel = 0; pixel < size; pent++, pixel++)
+ {
+ dr = dg = db = 0;
+ switch(channel)
+ {
+ case PSEUDOMAP:
+ dg = (long) pent->co.local.green - prgb->green;
+ db = (long) pent->co.local.blue - prgb->blue;
+ case REDMAP:
+ dr = (long) pent->co.local.red - prgb->red;
+ break;
+ case GREENMAP:
+ dg = (long) pent->co.local.green - prgb->green;
+ break;
+ case BLUEMAP:
+ db = (long) pent->co.local.blue - prgb->blue;
+ break;
+ }
+ sq = dr * dr;
+ UnsignedToBigNum (sq, &sum);
+ sq = dg * dg;
+ UnsignedToBigNum (sq, &temp);
+ BigNumAdd (&sum, &temp, &sum);
+ sq = db * db;
+ UnsignedToBigNum (sq, &temp);
+ BigNumAdd (&sum, &temp, &sum);
+ if (BigNumGreater (&minval, &sum))
+ {
+ final = pixel;
+ minval = sum;
+ }
+ }
+ return final;
+}
+
+static void
+FindColorInRootCmap (ColormapPtr pmap, EntryPtr pentFirst, int size,
+ xrgb *prgb, Pixel *pPixel, int channel,
+ ColorCompareProcPtr comp)
+{
+ EntryPtr pent;
+ Pixel pixel;
+ int count;
+
+ if ((pixel = *pPixel) >= size)
+ pixel = 0;
+ for (pent = pentFirst + pixel, count = size; --count >= 0; pent++, pixel++)
+ {
+ if (pent->refcnt > 0 && (*comp) (pent, prgb))
+ {
+ switch (channel)
+ {
+ case REDMAP:
+ pixel <<= pmap->pVisual->offsetRed;
+ break;
+ case GREENMAP:
+ pixel <<= pmap->pVisual->offsetGreen;
+ break;
+ case BLUEMAP:
+ pixel <<= pmap->pVisual->offsetBlue;
+ break;
+ default: /* PSEUDOMAP */
+ break;
+ }
+ *pPixel = pixel;
+ }
+ }
+}
+
+/* Tries to find a color in pmap that exactly matches the one requested in prgb
+ * if it can't it allocates one.
+ * Starts looking at pentFirst + *pPixel, so if you want a specific pixel,
+ * load *pPixel with that value, otherwise set it to 0
+ */
+int
+FindColor (ColormapPtr pmap, EntryPtr pentFirst, int size, xrgb *prgb,
+ Pixel *pPixel, int channel, int client,
+ ColorCompareProcPtr comp)
+{
+ EntryPtr pent;
+ Bool foundFree;
+ Pixel pixel, Free = 0;
+ int npix, count, *nump = NULL;
+ Pixel **pixp = NULL, *ppix;
+ xColorItem def;
+
+ foundFree = FALSE;
+
+ if((pixel = *pPixel) >= size)
+ pixel = 0;
+ /* see if there is a match, and also look for a free entry */
+ for (pent = pentFirst + pixel, count = size; --count >= 0; )
+ {
+ if (pent->refcnt > 0)
+ {
+ if ((*comp) (pent, prgb))
+ {
+ if (client >= 0)
+ pent->refcnt++;
+ *pPixel = pixel;
+ switch(channel)
+ {
+ case REDMAP:
+ *pPixel <<= pmap->pVisual->offsetRed;
+ case PSEUDOMAP:
+ break;
+ case GREENMAP:
+ *pPixel <<= pmap->pVisual->offsetGreen;
+ break;
+ case BLUEMAP:
+ *pPixel <<= pmap->pVisual->offsetBlue;
+ break;
+ }
+ goto gotit;
+ }
+ }
+ else if (!foundFree && pent->refcnt == 0)
+ {
+ Free = pixel;
+ foundFree = TRUE;
+ /* If we're initializing the colormap, then we are looking for
+ * the first free cell we can find, not to minimize the number
+ * of entries we use. So don't look any further. */
+ if(pmap->flags & BeingCreated)
+ break;
+ }
+ pixel++;
+ if(pixel >= size)
+ {
+ pent = pentFirst;
+ pixel = 0;
+ }
+ else
+ pent++;
+ }
+
+ /* If we got here, we didn't find a match. If we also didn't find
+ * a free entry, we're out of luck. Otherwise, we'll usurp a free
+ * entry and fill it in */
+ if (!foundFree)
+ return BadAlloc;
+ pent = pentFirst + Free;
+ pent->fShared = FALSE;
+ pent->refcnt = (client >= 0) ? 1 : AllocTemporary;
+
+ switch (channel)
+ {
+ case PSEUDOMAP:
+ pent->co.local.red = prgb->red;
+ pent->co.local.green = prgb->green;
+ pent->co.local.blue = prgb->blue;
+ def.red = prgb->red;
+ def.green = prgb->green;
+ def.blue = prgb->blue;
+ def.flags = (DoRed|DoGreen|DoBlue);
+ if (client >= 0)
+ pmap->freeRed--;
+ def.pixel = Free;
+ break;
+
+ case REDMAP:
+ pent->co.local.red = prgb->red;
+ def.red = prgb->red;
+ def.green = pmap->green[0].co.local.green;
+ def.blue = pmap->blue[0].co.local.blue;
+ def.flags = DoRed;
+ if (client >= 0)
+ pmap->freeRed--;
+ def.pixel = Free << pmap->pVisual->offsetRed;
+ break;
+
+ case GREENMAP:
+ pent->co.local.green = prgb->green;
+ def.red = pmap->red[0].co.local.red;
+ def.green = prgb->green;
+ def.blue = pmap->blue[0].co.local.blue;
+ def.flags = DoGreen;
+ if (client >= 0)
+ pmap->freeGreen--;
+ def.pixel = Free << pmap->pVisual->offsetGreen;
+ break;
+
+ case BLUEMAP:
+ pent->co.local.blue = prgb->blue;
+ def.red = pmap->red[0].co.local.red;
+ def.green = pmap->green[0].co.local.green;
+ def.blue = prgb->blue;
+ def.flags = DoBlue;
+ if (client >= 0)
+ pmap->freeBlue--;
+ def.pixel = Free << pmap->pVisual->offsetBlue;
+ break;
+ }
+ (*pmap->pScreen->StoreColors) (pmap, 1, &def);
+ pixel = Free;
+ *pPixel = def.pixel;
+
+gotit:
+ if (pmap->flags & BeingCreated || client == -1)
+ return Success;
+ /* Now remember the pixel, for freeing later */
+ switch (channel)
+ {
+ case PSEUDOMAP:
+ case REDMAP:
+ nump = pmap->numPixelsRed;
+ pixp = pmap->clientPixelsRed;
+ break;
+
+ case GREENMAP:
+ nump = pmap->numPixelsGreen;
+ pixp = pmap->clientPixelsGreen;
+ break;
+
+ case BLUEMAP:
+ nump = pmap->numPixelsBlue;
+ pixp = pmap->clientPixelsBlue;
+ break;
+ }
+ npix = nump[client];
+ ppix = (Pixel *) realloc(pixp[client], (npix + 1) * sizeof(Pixel));
+ if (!ppix)
+ {
+ pent->refcnt--;
+ if (!pent->fShared)
+ switch (channel)
+ {
+ case PSEUDOMAP:
+ case REDMAP:
+ pmap->freeRed++;
+ break;
+ case GREENMAP:
+ pmap->freeGreen++;
+ break;
+ case BLUEMAP:
+ pmap->freeBlue++;
+ break;
+ }
+ return BadAlloc;
+ }
+ ppix[npix] = pixel;
+ pixp[client] = ppix;
+ nump[client]++;
+
+ return Success;
+}
+
+/* Comparison functions -- passed to FindColor to determine if an
+ * entry is already the color we're looking for or not */
+static int
+AllComp (EntryPtr pent, xrgb *prgb)
+{
+ if((pent->co.local.red == prgb->red) &&
+ (pent->co.local.green == prgb->green) &&
+ (pent->co.local.blue == prgb->blue) )
+ return 1;
+ return 0;
+}
+
+static int
+RedComp (EntryPtr pent, xrgb *prgb)
+{
+ if (pent->co.local.red == prgb->red)
+ return 1;
+ return 0;
+}
+
+static int
+GreenComp (EntryPtr pent, xrgb *prgb)
+{
+ if (pent->co.local.green == prgb->green)
+ return 1;
+ return 0;
+}
+
+static int
+BlueComp (EntryPtr pent, xrgb *prgb)
+{
+ if (pent->co.local.blue == prgb->blue)
+ return 1;
+ return 0;
+}
+
+
+/* Read the color value of a cell */
+
+int
+QueryColors (ColormapPtr pmap, int count, Pixel *ppixIn, xrgb *prgbList, ClientPtr client)
+{
+ Pixel *ppix, pixel;
+ xrgb *prgb;
+ VisualPtr pVisual;
+ EntryPtr pent;
+ Pixel i;
+ int errVal = Success;
+
+ pVisual = pmap->pVisual;
+ if ((pmap->class | DynamicClass) == DirectColor)
+ {
+ int numred, numgreen, numblue;
+ Pixel rgbbad;
+
+ numred = NUMRED(pVisual);
+ numgreen = NUMGREEN(pVisual);
+ numblue = NUMBLUE(pVisual);
+ rgbbad = ~RGBMASK(pVisual);
+ for( ppix = ppixIn, prgb = prgbList; --count >= 0; ppix++, prgb++)
+ {
+ pixel = *ppix;
+ if (pixel & rgbbad) {
+ client->errorValue = pixel;
+ errVal = BadValue;
+ continue;
+ }
+ i = (pixel & pVisual->redMask) >> pVisual->offsetRed;
+ if (i >= numred)
+ {
+ client->errorValue = pixel;
+ errVal = BadValue;
+ continue;
+ }
+ prgb->red = pmap->red[i].co.local.red;
+ i = (pixel & pVisual->greenMask) >> pVisual->offsetGreen;
+ if (i >= numgreen)
+ {
+ client->errorValue = pixel;
+ errVal = BadValue;
+ continue;
+ }
+ prgb->green = pmap->green[i].co.local.green;
+ i = (pixel & pVisual->blueMask) >> pVisual->offsetBlue;
+ if (i >= numblue)
+ {
+ client->errorValue = pixel;
+ errVal = BadValue;
+ continue;
+ }
+ prgb->blue = pmap->blue[i].co.local.blue;
+ }
+ }
+ else
+ {
+ for( ppix = ppixIn, prgb = prgbList; --count >= 0; ppix++, prgb++)
+ {
+ pixel = *ppix;
+ if (pixel >= pVisual->ColormapEntries)
+ {
+ client->errorValue = pixel;
+ errVal = BadValue;
+ }
+ else
+ {
+ pent = (EntryPtr)&pmap->red[pixel];
+ if (pent->fShared)
+ {
+ prgb->red = pent->co.shco.red->color;
+ prgb->green = pent->co.shco.green->color;
+ prgb->blue = pent->co.shco.blue->color;
+ }
+ else
+ {
+ prgb->red = pent->co.local.red;
+ prgb->green = pent->co.local.green;
+ prgb->blue = pent->co.local.blue;
+ }
+ }
+ }
+ }
+ return errVal;
+}
+
+static void
+FreePixels(ColormapPtr pmap, int client)
+{
+ Pixel *ppix, *ppixStart;
+ int n;
+ int class;
+
+ class = pmap->class;
+ ppixStart = pmap->clientPixelsRed[client];
+ if (class & DynamicClass)
+ {
+ n = pmap->numPixelsRed[client];
+ for (ppix = ppixStart; --n >= 0; )
+ {
+ FreeCell(pmap, *ppix, REDMAP);
+ ppix++;
+ }
+ }
+
+ free(ppixStart);
+ pmap->clientPixelsRed[client] = (Pixel *) NULL;
+ pmap->numPixelsRed[client] = 0;
+ if ((class | DynamicClass) == DirectColor)
+ {
+ ppixStart = pmap->clientPixelsGreen[client];
+ if (class & DynamicClass)
+ for (ppix = ppixStart, n = pmap->numPixelsGreen[client]; --n >= 0;)
+ FreeCell(pmap, *ppix++, GREENMAP);
+ free(ppixStart);
+ pmap->clientPixelsGreen[client] = (Pixel *) NULL;
+ pmap->numPixelsGreen[client] = 0;
+
+ ppixStart = pmap->clientPixelsBlue[client];
+ if (class & DynamicClass)
+ for (ppix = ppixStart, n = pmap->numPixelsBlue[client]; --n >= 0; )
+ FreeCell(pmap, *ppix++, BLUEMAP);
+ free(ppixStart);
+ pmap->clientPixelsBlue[client] = (Pixel *) NULL;
+ pmap->numPixelsBlue[client] = 0;
+ }
+}
+
+/**
+ * Frees all of a client's colors and cells.
+ *
+ * \param value must conform to DeleteType
+ * \unused fakeid
+ */
+int
+FreeClientPixels (pointer value, XID fakeid)
+{
+ pointer pmap;
+ colorResource *pcr = value;
+ int rc;
+
+ rc = dixLookupResourceByType(&pmap, pcr->mid, RT_COLORMAP, serverClient,
+ DixRemoveAccess);
+ if (rc == Success)
+ FreePixels((ColormapPtr)pmap, pcr->client);
+ free(pcr);
+ return Success;
+}
+
+int
+AllocColorCells (int client, ColormapPtr pmap, int colors, int planes,
+ Bool contig, Pixel *ppix, Pixel *masks)
+{
+ Pixel rmask, gmask, bmask, *ppixFirst, r, g, b;
+ int n, class;
+ int ok;
+ int oldcount;
+ colorResource *pcr = (colorResource *)NULL;
+
+ class = pmap->class;
+ if (!(class & DynamicClass))
+ return BadAlloc; /* Shouldn't try on this type */
+ oldcount = pmap->numPixelsRed[client];
+ if (pmap->class == DirectColor)
+ oldcount += pmap->numPixelsGreen[client] + pmap->numPixelsBlue[client];
+ if (!oldcount && (CLIENT_ID(pmap->mid) != client))
+ {
+ pcr = malloc(sizeof(colorResource));
+ if (!pcr)
+ return BadAlloc;
+ }
+
+ if (pmap->class == DirectColor)
+ {
+ ok = AllocDirect (client, pmap, colors, planes, planes, planes,
+ contig, ppix, &rmask, &gmask, &bmask);
+ if(ok == Success)
+ {
+ for (r = g = b = 1, n = planes; --n >= 0; r += r, g += g, b += b)
+ {
+ while(!(rmask & r))
+ r += r;
+ while(!(gmask & g))
+ g += g;
+ while(!(bmask & b))
+ b += b;
+ *masks++ = r | g | b;
+ }
+ }
+ }
+ else
+ {
+ ok = AllocPseudo (client, pmap, colors, planes, contig, ppix, &rmask,
+ &ppixFirst);
+ if(ok == Success)
+ {
+ for (r = 1, n = planes; --n >= 0; r += r)
+ {
+ while(!(rmask & r))
+ r += r;
+ *masks++ = r;
+ }
+ }
+ }
+
+ /* if this is the client's first pixels in this colormap, tell the
+ * resource manager that the client has pixels in this colormap which
+ * should be freed when the client dies */
+ if ((ok == Success) && pcr)
+ {
+ pcr->mid = pmap->mid;
+ pcr->client = client;
+ if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr))
+ ok = BadAlloc;
+ } else free(pcr);
+
+ return ok;
+}
+
+
+int
+AllocColorPlanes (int client, ColormapPtr pmap, int colors,
+ int r, int g, int b, Bool contig, Pixel *pixels,
+ Pixel *prmask, Pixel *pgmask, Pixel *pbmask)
+{
+ int ok;
+ Pixel mask, *ppixFirst;
+ Pixel shift;
+ int i;
+ int class;
+ int oldcount;
+ colorResource *pcr = (colorResource *)NULL;
+
+ class = pmap->class;
+ if (!(class & DynamicClass))
+ return BadAlloc; /* Shouldn't try on this type */
+ oldcount = pmap->numPixelsRed[client];
+ if (class == DirectColor)
+ oldcount += pmap->numPixelsGreen[client] + pmap->numPixelsBlue[client];
+ if (!oldcount && (CLIENT_ID(pmap->mid) != client))
+ {
+ pcr = malloc(sizeof(colorResource));
+ if (!pcr)
+ return BadAlloc;
+ }
+
+ if (class == DirectColor)
+ {
+ ok = AllocDirect (client, pmap, colors, r, g, b, contig, pixels,
+ prmask, pgmask, pbmask);
+ }
+ else
+ {
+ /* Allocate the proper pixels */
+ /* XXX This is sort of bad, because of contig is set, we force all
+ * r + g + b bits to be contiguous. Should only force contiguity
+ * per mask
+ */
+ ok = AllocPseudo (client, pmap, colors, r + g + b, contig, pixels,
+ &mask, &ppixFirst);
+
+ if(ok == Success)
+ {
+ /* now split that mask into three */
+ *prmask = *pgmask = *pbmask = 0;
+ shift = 1;
+ for (i = r; --i >= 0; shift += shift)
+ {
+ while (!(mask & shift))
+ shift += shift;
+ *prmask |= shift;
+ }
+ for (i = g; --i >= 0; shift += shift)
+ {
+ while (!(mask & shift))
+ shift += shift;
+ *pgmask |= shift;
+ }
+ for (i = b; --i >= 0; shift += shift)
+ {
+ while (!(mask & shift))
+ shift += shift;
+ *pbmask |= shift;
+ }
+
+ /* set up the shared color cells */
+ if (!AllocShared(pmap, pixels, colors, r, g, b,
+ *prmask, *pgmask, *pbmask, ppixFirst))
+ {
+ (void)FreeColors(pmap, client, colors, pixels, mask);
+ ok = BadAlloc;
+ }
+ }
+ }
+
+ /* if this is the client's first pixels in this colormap, tell the
+ * resource manager that the client has pixels in this colormap which
+ * should be freed when the client dies */
+ if ((ok == Success) && pcr)
+ {
+ pcr->mid = pmap->mid;
+ pcr->client = client;
+ if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr))
+ ok = BadAlloc;
+ } else free(pcr);
+
+ return ok;
+}
+
+static int
+AllocDirect (int client, ColormapPtr pmap, int c, int r, int g, int b, Bool contig,
+ Pixel *pixels, Pixel *prmask, Pixel *pgmask, Pixel *pbmask)
+{
+ Pixel *ppixRed, *ppixGreen, *ppixBlue;
+ Pixel *ppix, *pDst, *p;
+ int npix, npixR, npixG, npixB;
+ Bool okR, okG, okB;
+ Pixel *rpix = 0, *gpix = 0, *bpix = 0;
+
+ npixR = c << r;
+ npixG = c << g;
+ npixB = c << b;
+ if ((r >= 32) || (g >= 32) || (b >= 32) ||
+ (npixR > pmap->freeRed) || (npixR < c) ||
+ (npixG > pmap->freeGreen) || (npixG < c) ||
+ (npixB > pmap->freeBlue) || (npixB < c))
+ return BadAlloc;
+
+ /* start out with empty pixels */
+ for(p = pixels; p < pixels + c; p++)
+ *p = 0;
+
+ ppixRed = malloc(npixR * sizeof(Pixel));
+ ppixGreen = malloc(npixG * sizeof(Pixel));
+ ppixBlue = malloc(npixB * sizeof(Pixel));
+ if (!ppixRed || !ppixGreen || !ppixBlue)
+ {
+ free(ppixBlue);
+ free(ppixGreen);
+ free(ppixRed);
+ return BadAlloc;
+ }
+
+ okR = AllocCP(pmap, pmap->red, c, r, contig, ppixRed, prmask);
+ okG = AllocCP(pmap, pmap->green, c, g, contig, ppixGreen, pgmask);
+ okB = AllocCP(pmap, pmap->blue, c, b, contig, ppixBlue, pbmask);
+
+ if (okR && okG && okB)
+ {
+ rpix = (Pixel *) realloc(pmap->clientPixelsRed[client],
+ (pmap->numPixelsRed[client] + (c << r)) *
+ sizeof(Pixel));
+ if (rpix)
+ pmap->clientPixelsRed[client] = rpix;
+ gpix = (Pixel *) realloc(pmap->clientPixelsGreen[client],
+ (pmap->numPixelsGreen[client] + (c << g)) *
+ sizeof(Pixel));
+ if (gpix)
+ pmap->clientPixelsGreen[client] = gpix;
+ bpix = (Pixel *) realloc(pmap->clientPixelsBlue[client],
+ (pmap->numPixelsBlue[client] + (c << b)) *
+ sizeof(Pixel));
+ if (bpix)
+ pmap->clientPixelsBlue[client] = bpix;
+ }
+
+ if (!okR || !okG || !okB || !rpix || !gpix || !bpix)
+ {
+ if (okR)
+ for(ppix = ppixRed, npix = npixR; --npix >= 0; ppix++)
+ pmap->red[*ppix].refcnt = 0;
+ if (okG)
+ for(ppix = ppixGreen, npix = npixG; --npix >= 0; ppix++)
+ pmap->green[*ppix].refcnt = 0;
+ if (okB)
+ for(ppix = ppixBlue, npix = npixB; --npix >= 0; ppix++)
+ pmap->blue[*ppix].refcnt = 0;
+ free(ppixBlue);
+ free(ppixGreen);
+ free(ppixRed);
+ return BadAlloc;
+ }
+
+ *prmask <<= pmap->pVisual->offsetRed;
+ *pgmask <<= pmap->pVisual->offsetGreen;
+ *pbmask <<= pmap->pVisual->offsetBlue;
+
+ ppix = rpix + pmap->numPixelsRed[client];
+ for (pDst = pixels, p = ppixRed; p < ppixRed + npixR; p++)
+ {
+ *ppix++ = *p;
+ if(p < ppixRed + c)
+ *pDst++ |= *p << pmap->pVisual->offsetRed;
+ }
+ pmap->numPixelsRed[client] += npixR;
+ pmap->freeRed -= npixR;
+
+ ppix = gpix + pmap->numPixelsGreen[client];
+ for (pDst = pixels, p = ppixGreen; p < ppixGreen + npixG; p++)
+ {
+ *ppix++ = *p;
+ if(p < ppixGreen + c)
+ *pDst++ |= *p << pmap->pVisual->offsetGreen;
+ }
+ pmap->numPixelsGreen[client] += npixG;
+ pmap->freeGreen -= npixG;
+
+ ppix = bpix + pmap->numPixelsBlue[client];
+ for (pDst = pixels, p = ppixBlue; p < ppixBlue + npixB; p++)
+ {
+ *ppix++ = *p;
+ if(p < ppixBlue + c)
+ *pDst++ |= *p << pmap->pVisual->offsetBlue;
+ }
+ pmap->numPixelsBlue[client] += npixB;
+ pmap->freeBlue -= npixB;
+
+
+ for (pDst = pixels; pDst < pixels + c; pDst++)
+ *pDst |= ALPHAMASK(pmap->pVisual);
+
+ free(ppixBlue);
+ free(ppixGreen);
+ free(ppixRed);
+
+ return Success;
+}
+
+static int
+AllocPseudo (int client, ColormapPtr pmap, int c, int r, Bool contig,
+ Pixel *pixels, Pixel *pmask, Pixel **pppixFirst)
+{
+ Pixel *ppix, *p, *pDst, *ppixTemp;
+ int npix;
+ Bool ok;
+
+ npix = c << r;
+ if ((r >= 32) || (npix > pmap->freeRed) || (npix < c))
+ return BadAlloc;
+ if(!(ppixTemp = malloc(npix * sizeof(Pixel))))
+ return BadAlloc;
+ ok = AllocCP(pmap, pmap->red, c, r, contig, ppixTemp, pmask);
+
+ if (ok)
+ {
+
+ /* all the allocated pixels are added to the client pixel list,
+ * but only the unique ones are returned to the client */
+ ppix = (Pixel *)realloc(pmap->clientPixelsRed[client],
+ (pmap->numPixelsRed[client] + npix) * sizeof(Pixel));
+ if (!ppix)
+ {
+ for (p = ppixTemp; p < ppixTemp + npix; p++)
+ pmap->red[*p].refcnt = 0;
+ free(ppixTemp);
+ return BadAlloc;
+ }
+ pmap->clientPixelsRed[client] = ppix;
+ ppix += pmap->numPixelsRed[client];
+ *pppixFirst = ppix;
+ pDst = pixels;
+ for (p = ppixTemp; p < ppixTemp + npix; p++)
+ {
+ *ppix++ = *p;
+ if(p < ppixTemp + c)
+ *pDst++ = *p;
+ }
+ pmap->numPixelsRed[client] += npix;
+ pmap->freeRed -= npix;
+ }
+ free(ppixTemp);
+ return ok ? Success : BadAlloc;
+}
+
+/* Allocates count << planes pixels from colormap pmap for client. If
+ * contig, then the plane mask is made of consecutive bits. Returns
+ * all count << pixels in the array pixels. The first count of those
+ * pixels are the unique pixels. *pMask has the mask to Or with the
+ * unique pixels to get the rest of them.
+ *
+ * Returns True iff all pixels could be allocated
+ * All cells allocated will have refcnt set to AllocPrivate and shared to FALSE
+ * (see AllocShared for why we care)
+ */
+static Bool
+AllocCP (ColormapPtr pmap, EntryPtr pentFirst, int count, int planes,
+ Bool contig, Pixel *pixels, Pixel *pMask)
+{
+ EntryPtr ent;
+ Pixel pixel, base, entries, maxp, save;
+ int dplanes, found;
+ Pixel *ppix;
+ Pixel mask;
+ Pixel finalmask;
+
+ dplanes = pmap->pVisual->nplanes;
+
+ /* Easy case. Allocate pixels only */
+ if (planes == 0)
+ {
+ /* allocate writable entries */
+ ppix = pixels;
+ ent = pentFirst;
+ pixel = 0;
+ while (--count >= 0)
+ {
+ /* Just find count unallocated cells */
+ while (ent->refcnt)
+ {
+ ent++;
+ pixel++;
+ }
+ ent->refcnt = AllocPrivate;
+ *ppix++ = pixel;
+ ent->fShared = FALSE;
+ }
+ *pMask = 0;
+ return TRUE;
+ }
+ else if (planes > dplanes)
+ {
+ return FALSE;
+ }
+
+ /* General case count pixels * 2 ^ planes cells to be allocated */
+
+ /* make room for new pixels */
+ ent = pentFirst;
+
+ /* first try for contiguous planes, since it's fastest */
+ for (mask = (((Pixel)1) << planes) - 1, base = 1, dplanes -= (planes - 1);
+ --dplanes >= 0;
+ mask += mask, base += base)
+ {
+ ppix = pixels;
+ found = 0;
+ pixel = 0;
+ entries = pmap->pVisual->ColormapEntries - mask;
+ while (pixel < entries)
+ {
+ save = pixel;
+ maxp = pixel + mask + base;
+ /* check if all are free */
+ while (pixel != maxp && ent[pixel].refcnt == 0)
+ pixel += base;
+ if (pixel == maxp)
+ {
+ /* this one works */
+ *ppix++ = save;
+ found++;
+ if (found == count)
+ {
+ /* found enough, allocate them all */
+ while (--count >= 0)
+ {
+ pixel = pixels[count];
+ maxp = pixel + mask;
+ while (1)
+ {
+ ent[pixel].refcnt = AllocPrivate;
+ ent[pixel].fShared = FALSE;
+ if (pixel == maxp)
+ break;
+ pixel += base;
+ *ppix++ = pixel;
+ }
+ }
+ *pMask = mask;
+ return TRUE;
+ }
+ }
+ pixel = save + 1;
+ if (pixel & mask)
+ pixel += mask;
+ }
+ }
+
+ dplanes = pmap->pVisual->nplanes;
+ if (contig || planes == 1 || dplanes < 3)
+ return FALSE;
+
+ /* this will be very slow for large maps, need a better algorithm */
+
+ /*
+ we can generate the smallest and largest numbers that fits in dplanes
+ bits and contain exactly planes bits set as follows. First, we need to
+ check that it is possible to generate such a mask at all.
+ (Non-contiguous masks need one more bit than contiguous masks). Then
+ the smallest such mask consists of the rightmost planes-1 bits set, then
+ a zero, then a one in position planes + 1. The formula is
+ (3 << (planes-1)) -1
+ The largest such masks consists of the leftmost planes-1 bits set, then
+ a zero, then a one bit in position dplanes-planes-1. If dplanes is
+ smaller than 32 (the number of bits in a word) then the formula is:
+ (1<<dplanes) - (1<<(dplanes-planes+1) + (1<<dplanes-planes-1)
+ If dplanes = 32, then we can't calculate (1<<dplanes) and we have
+ to use:
+ ( (1<<(planes-1)) - 1) << (dplanes-planes+1) + (1<<(dplanes-planes-1))
+
+ << Thank you, Loretta>>>
+
+ */
+
+ finalmask =
+ (((((Pixel)1)<<(planes-1)) - 1) << (dplanes-planes+1)) +
+ (((Pixel)1)<<(dplanes-planes-1));
+ for (mask = (((Pixel)3) << (planes -1)) - 1; mask <= finalmask; mask++)
+ {
+ /* next 3 magic statements count number of ones (HAKMEM #169) */
+ pixel = (mask >> 1) & 033333333333;
+ pixel = mask - pixel - ((pixel >> 1) & 033333333333);
+ if ((((pixel + (pixel >> 3)) & 030707070707) % 077) != planes)
+ continue;
+ ppix = pixels;
+ found = 0;
+ entries = pmap->pVisual->ColormapEntries - mask;
+ base = lowbit (mask);
+ for (pixel = 0; pixel < entries; pixel++)
+ {
+ if (pixel & mask)
+ continue;
+ maxp = 0;
+ /* check if all are free */
+ while (ent[pixel + maxp].refcnt == 0)
+ {
+ GetNextBitsOrBreak(maxp, mask, base);
+ }
+ if ((maxp < mask) || (ent[pixel + mask].refcnt != 0))
+ continue;
+ /* this one works */
+ *ppix++ = pixel;
+ found++;
+ if (found < count)
+ continue;
+ /* found enough, allocate them all */
+ while (--count >= 0)
+ {
+ pixel = (pixels)[count];
+ maxp = 0;
+ while (1)
+ {
+ ent[pixel + maxp].refcnt = AllocPrivate;
+ ent[pixel + maxp].fShared = FALSE;
+ GetNextBitsOrBreak(maxp, mask, base);
+ *ppix++ = pixel + maxp;
+ }
+ }
+
+ *pMask = mask;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ *
+ * \param ppixFirst First of the client's new pixels
+ */
+static Bool
+AllocShared (ColormapPtr pmap, Pixel *ppix, int c, int r, int g, int b,
+ Pixel rmask, Pixel gmask, Pixel bmask, Pixel *ppixFirst)
+{
+ Pixel *pptr, *cptr;
+ int npix, z, npixClientNew, npixShared;
+ Pixel basemask, base, bits, common;
+ SHAREDCOLOR *pshared, **ppshared, **psharedList;
+
+ npixClientNew = c << (r + g + b);
+ npixShared = (c << r) + (c << g) + (c << b);
+ psharedList = malloc(npixShared * sizeof(SHAREDCOLOR *));
+ if (!psharedList)
+ return FALSE;
+ ppshared = psharedList;
+ for (z = npixShared; --z >= 0; )
+ {
+ if (!(ppshared[z] = malloc(sizeof(SHAREDCOLOR))))
+ {
+ for (z++ ; z < npixShared; z++)
+ free(ppshared[z]);
+ free(psharedList);
+ return FALSE;
+ }
+ }
+ for(pptr = ppix, npix = c; --npix >= 0; pptr++)
+ {
+ basemask = ~(gmask | bmask);
+ common = *pptr & basemask;
+ if (rmask)
+ {
+ bits = 0;
+ base = lowbit (rmask);
+ while(1)
+ {
+ pshared = *ppshared++;
+ pshared->refcnt = 1 << (g + b);
+ for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
+ {
+ if ((*cptr & basemask) == (common | bits))
+ {
+ pmap->red[*cptr].fShared = TRUE;
+ pmap->red[*cptr].co.shco.red = pshared;
+ }
+ }
+ GetNextBitsOrBreak(bits, rmask, base);
+ }
+ }
+ else
+ {
+ pshared = *ppshared++;
+ pshared->refcnt = 1 << (g + b);
+ for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
+ {
+ if ((*cptr & basemask) == common)
+ {
+ pmap->red[*cptr].fShared = TRUE;
+ pmap->red[*cptr].co.shco.red = pshared;
+ }
+ }
+ }
+ basemask = ~(rmask | bmask);
+ common = *pptr & basemask;
+ if (gmask)
+ {
+ bits = 0;
+ base = lowbit (gmask);
+ while(1)
+ {
+ pshared = *ppshared++;
+ pshared->refcnt = 1 << (r + b);
+ for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
+ {
+ if ((*cptr & basemask) == (common | bits))
+ {
+ pmap->red[*cptr].co.shco.green = pshared;
+ }
+ }
+ GetNextBitsOrBreak(bits, gmask, base);
+ }
+ }
+ else
+ {
+ pshared = *ppshared++;
+ pshared->refcnt = 1 << (g + b);
+ for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
+ {
+ if ((*cptr & basemask) == common)
+ {
+ pmap->red[*cptr].co.shco.green = pshared;
+ }
+ }
+ }
+ basemask = ~(rmask | gmask);
+ common = *pptr & basemask;
+ if (bmask)
+ {
+ bits = 0;
+ base = lowbit (bmask);
+ while(1)
+ {
+ pshared = *ppshared++;
+ pshared->refcnt = 1 << (r + g);
+ for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
+ {
+ if ((*cptr & basemask) == (common | bits))
+ {
+ pmap->red[*cptr].co.shco.blue = pshared;
+ }
+ }
+ GetNextBitsOrBreak(bits, bmask, base);
+ }
+ }
+ else
+ {
+ pshared = *ppshared++;
+ pshared->refcnt = 1 << (g + b);
+ for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++)
+ {
+ if ((*cptr & basemask) == common)
+ {
+ pmap->red[*cptr].co.shco.blue = pshared;
+ }
+ }
+ }
+ }
+ free(psharedList);
+ return TRUE;
+}
+
+
+/** FreeColors
+ * Free colors and/or cells (probably slow for large numbers)
+ */
+int
+FreeColors (ColormapPtr pmap, int client, int count, Pixel *pixels, Pixel mask)
+{
+ int rval, result, class;
+ Pixel rmask;
+
+ class = pmap->class;
+ if (pmap->flags & AllAllocated)
+ return BadAccess;
+ if ((class | DynamicClass) == DirectColor)
+ {
+ rmask = mask & RGBMASK(pmap->pVisual);
+ result = FreeCo(pmap, client, REDMAP, count, pixels,
+ mask & pmap->pVisual->redMask);
+ /* If any of the three calls fails, we must report that, if more
+ * than one fails, it's ok that we report the last one */
+ rval = FreeCo(pmap, client, GREENMAP, count, pixels,
+ mask & pmap->pVisual->greenMask);
+ if(rval != Success)
+ result = rval;
+ rval = FreeCo(pmap, client, BLUEMAP, count, pixels,
+ mask & pmap->pVisual->blueMask);
+ if(rval != Success)
+ result = rval;
+ }
+ else
+ {
+ rmask = mask & ((((Pixel)1) << pmap->pVisual->nplanes) - 1);
+ result = FreeCo(pmap, client, PSEUDOMAP, count, pixels, rmask);
+ }
+ if ((mask != rmask) && count)
+ {
+ clients[client]->errorValue = *pixels | mask;
+ result = BadValue;
+ }
+ /* XXX should worry about removing any RT_CMAPENTRY resource */
+ return result;
+}
+
+/**
+ * Helper for FreeColors -- frees all combinations of *newpixels and mask bits
+ * which the client has allocated in channel colormap cells of pmap.
+ * doesn't change newpixels if it doesn't need to
+ *
+ * \param pmap which colormap head
+ * \param color which sub-map, eg, RED, BLUE, PSEUDO
+ * \param npixIn number of pixels passed in
+ * \param ppixIn number of base pixels
+ * \param mask mask client gave us
+ */
+static int
+FreeCo (ColormapPtr pmap, int client, int color, int npixIn, Pixel *ppixIn, Pixel mask)
+{
+ Pixel *ppixClient, pixTest;
+ int npixClient, npixNew, npix;
+ Pixel bits, base, cmask, rgbbad;
+ Pixel *pptr, *cptr;
+ int n, zapped;
+ int errVal = Success;
+ int offset, numents;
+
+ if (npixIn == 0)
+ return errVal;
+ bits = 0;
+ zapped = 0;
+ base = lowbit (mask);
+
+ switch(color)
+ {
+ case REDMAP:
+ cmask = pmap->pVisual->redMask;
+ rgbbad = ~RGBMASK(pmap->pVisual);
+ offset = pmap->pVisual->offsetRed;
+ numents = (cmask >> offset) + 1;
+ ppixClient = pmap->clientPixelsRed[client];
+ npixClient = pmap->numPixelsRed[client];
+ break;
+ case GREENMAP:
+ cmask = pmap->pVisual->greenMask;
+ rgbbad = ~RGBMASK(pmap->pVisual);
+ offset = pmap->pVisual->offsetGreen;
+ numents = (cmask >> offset) + 1;
+ ppixClient = pmap->clientPixelsGreen[client];
+ npixClient = pmap->numPixelsGreen[client];
+ break;
+ case BLUEMAP:
+ cmask = pmap->pVisual->blueMask;
+ rgbbad = ~RGBMASK(pmap->pVisual);
+ offset = pmap->pVisual->offsetBlue;
+ numents = (cmask >> offset) + 1;
+ ppixClient = pmap->clientPixelsBlue[client];
+ npixClient = pmap->numPixelsBlue[client];
+ break;
+ default: /* so compiler can see that everything gets initialized */
+ case PSEUDOMAP:
+ cmask = ~((Pixel)0);
+ rgbbad = 0;
+ offset = 0;
+ numents = pmap->pVisual->ColormapEntries;
+ ppixClient = pmap->clientPixelsRed[client];
+ npixClient = pmap->numPixelsRed[client];
+ break;
+ }
+
+
+ /* zap all pixels which match */
+ while (1)
+ {
+ /* go through pixel list */
+ for (pptr = ppixIn, n = npixIn; --n >= 0; pptr++)
+ {
+ pixTest = ((*pptr | bits) & cmask) >> offset;
+ if ((pixTest >= numents) || (*pptr & rgbbad))
+ {
+ clients[client]->errorValue = *pptr | bits;
+ errVal = BadValue;
+ continue;
+ }
+
+ /* find match in client list */
+ for (cptr = ppixClient, npix = npixClient;
+ --npix >= 0 && *cptr != pixTest;
+ cptr++) ;
+
+ if (npix >= 0)
+ {
+ if (pmap->class & DynamicClass)
+ {
+ FreeCell(pmap, pixTest, color);
+ }
+ *cptr = ~((Pixel)0);
+ zapped++;
+ }
+ else
+ errVal = BadAccess;
+ }
+ /* generate next bits value */
+ GetNextBitsOrBreak(bits, mask, base);
+ }
+
+ /* delete freed pixels from client pixel list */
+ if (zapped)
+ {
+ npixNew = npixClient - zapped;
+ if (npixNew)
+ {
+ /* Since the list can only get smaller, we can do a copy in
+ * place and then realloc to a smaller size */
+ pptr = cptr = ppixClient;
+
+ /* If we have all the new pixels, we don't have to examine the
+ * rest of the old ones */
+ for(npix = 0; npix < npixNew; cptr++)
+ {
+ if (*cptr != ~((Pixel)0))
+ {
+ *pptr++ = *cptr;
+ npix++;
+ }
+ }
+ pptr = (Pixel *)realloc(ppixClient, npixNew * sizeof(Pixel));
+ if (pptr)
+ ppixClient = pptr;
+ npixClient = npixNew;
+ }
+ else
+ {
+ npixClient = 0;
+ free(ppixClient);
+ ppixClient = (Pixel *)NULL;
+ }
+ switch(color)
+ {
+ case PSEUDOMAP:
+ case REDMAP:
+ pmap->clientPixelsRed[client] = ppixClient;
+ pmap->numPixelsRed[client] = npixClient;
+ break;
+ case GREENMAP:
+ pmap->clientPixelsGreen[client] = ppixClient;
+ pmap->numPixelsGreen[client] = npixClient;
+ break;
+ case BLUEMAP:
+ pmap->clientPixelsBlue[client] = ppixClient;
+ pmap->numPixelsBlue[client] = npixClient;
+ break;
+ }
+ }
+ return errVal;
+}
+
+
+
+/* Redefine color values */
+int
+StoreColors (ColormapPtr pmap, int count, xColorItem *defs, ClientPtr client)
+{
+ Pixel pix;
+ xColorItem *pdef;
+ EntryPtr pent, pentT, pentLast;
+ VisualPtr pVisual;
+ SHAREDCOLOR *pred, *pgreen, *pblue;
+ int n, ChgRed, ChgGreen, ChgBlue, idef;
+ int class, errVal = Success;
+ int ok;
+
+
+ class = pmap->class;
+ if(!(class & DynamicClass) && !(pmap->flags & BeingCreated))
+ {
+ return BadAccess;
+ }
+ pVisual = pmap->pVisual;
+
+ idef = 0;
+ if((class | DynamicClass) == DirectColor)
+ {
+ int numred, numgreen, numblue;
+ Pixel rgbbad;
+
+ numred = NUMRED(pVisual);
+ numgreen = NUMGREEN(pVisual);
+ numblue = NUMBLUE(pVisual);
+ rgbbad = ~RGBMASK(pVisual);
+ for (pdef = defs, n = 0; n < count; pdef++, n++)
+ {
+ ok = TRUE;
+ (*pmap->pScreen->ResolveColor)
+ (&pdef->red, &pdef->green, &pdef->blue, pmap->pVisual);
+
+ if (pdef->pixel & rgbbad)
+ {
+ errVal = BadValue;
+ client->errorValue = pdef->pixel;
+ continue;
+ }
+ pix = (pdef->pixel & pVisual->redMask) >> pVisual->offsetRed;
+ if (pix >= numred)
+ {
+ errVal = BadValue;
+ ok = FALSE;
+ }
+ else if (pmap->red[pix].refcnt != AllocPrivate)
+ {
+ errVal = BadAccess;
+ ok = FALSE;
+ }
+ else if (pdef->flags & DoRed)
+ {
+ pmap->red[pix].co.local.red = pdef->red;
+ }
+ else
+ {
+ pdef->red = pmap->red[pix].co.local.red;
+ }
+
+ pix = (pdef->pixel & pVisual->greenMask) >> pVisual->offsetGreen;
+ if (pix >= numgreen)
+ {
+ errVal = BadValue;
+ ok = FALSE;
+ }
+ else if (pmap->green[pix].refcnt != AllocPrivate)
+ {
+ errVal = BadAccess;
+ ok = FALSE;
+ }
+ else if (pdef->flags & DoGreen)
+ {
+ pmap->green[pix].co.local.green = pdef->green;
+ }
+ else
+ {
+ pdef->green = pmap->green[pix].co.local.green;
+ }
+
+ pix = (pdef->pixel & pVisual->blueMask) >> pVisual->offsetBlue;
+ if (pix >= numblue)
+ {
+ errVal = BadValue;
+ ok = FALSE;
+ }
+ else if (pmap->blue[pix].refcnt != AllocPrivate)
+ {
+ errVal = BadAccess;
+ ok = FALSE;
+ }
+ else if (pdef->flags & DoBlue)
+ {
+ pmap->blue[pix].co.local.blue = pdef->blue;
+ }
+ else
+ {
+ pdef->blue = pmap->blue[pix].co.local.blue;
+ }
+ /* If this is an o.k. entry, then it gets added to the list
+ * to be sent to the hardware. If not, skip it. Once we've
+ * skipped one, we have to copy all the others.
+ */
+ if(ok)
+ {
+ if(idef != n)
+ defs[idef] = defs[n];
+ idef++;
+ } else
+ client->errorValue = pdef->pixel;
+ }
+ }
+ else
+ {
+ for (pdef = defs, n = 0; n < count; pdef++, n++)
+ {
+
+ ok = TRUE;
+ if (pdef->pixel >= pVisual->ColormapEntries)
+ {
+ client->errorValue = pdef->pixel;
+ errVal = BadValue;
+ ok = FALSE;
+ }
+ else if (pmap->red[pdef->pixel].refcnt != AllocPrivate)
+ {
+ errVal = BadAccess;
+ ok = FALSE;
+ }
+
+ /* If this is an o.k. entry, then it gets added to the list
+ * to be sent to the hardware. If not, skip it. Once we've
+ * skipped one, we have to copy all the others.
+ */
+ if(ok)
+ {
+ if(idef != n)
+ defs[idef] = defs[n];
+ idef++;
+ }
+ else
+ continue;
+
+ (*pmap->pScreen->ResolveColor)
+ (&pdef->red, &pdef->green, &pdef->blue, pmap->pVisual);
+
+ pent = &pmap->red[pdef->pixel];
+
+ if(pdef->flags & DoRed)
+ {
+ if(pent->fShared)
+ {
+ pent->co.shco.red->color = pdef->red;
+ if (pent->co.shco.red->refcnt > 1)
+ ok = FALSE;
+ }
+ else
+ pent->co.local.red = pdef->red;
+ }
+ else
+ {
+ if(pent->fShared)
+ pdef->red = pent->co.shco.red->color;
+ else
+ pdef->red = pent->co.local.red;
+ }
+ if(pdef->flags & DoGreen)
+ {
+ if(pent->fShared)
+ {
+ pent->co.shco.green->color = pdef->green;
+ if (pent->co.shco.green->refcnt > 1)
+ ok = FALSE;
+ }
+ else
+ pent->co.local.green = pdef->green;
+ }
+ else
+ {
+ if(pent->fShared)
+ pdef->green = pent->co.shco.green->color;
+ else
+ pdef->green = pent->co.local.green;
+ }
+ if(pdef->flags & DoBlue)
+ {
+ if(pent->fShared)
+ {
+ pent->co.shco.blue->color = pdef->blue;
+ if (pent->co.shco.blue->refcnt > 1)
+ ok = FALSE;
+ }
+ else
+ pent->co.local.blue = pdef->blue;
+ }
+ else
+ {
+ if(pent->fShared)
+ pdef->blue = pent->co.shco.blue->color;
+ else
+ pdef->blue = pent->co.local.blue;
+ }
+
+ if(!ok)
+ {
+ /* have to run through the colormap and change anybody who
+ * shares this value */
+ pred = pent->co.shco.red;
+ pgreen = pent->co.shco.green;
+ pblue = pent->co.shco.blue;
+ ChgRed = pdef->flags & DoRed;
+ ChgGreen = pdef->flags & DoGreen;
+ ChgBlue = pdef->flags & DoBlue;
+ pentLast = pmap->red + pVisual->ColormapEntries;
+
+ for(pentT = pmap->red; pentT < pentLast; pentT++)
+ {
+ if(pentT->fShared && (pentT != pent))
+ {
+ xColorItem defChg;
+
+ /* There are, alas, devices in this world too dumb
+ * to read their own hardware colormaps. Sick, but
+ * true. So we're going to be really nice and load
+ * the xColorItem with the proper value for all the
+ * fields. We will only set the flags for those
+ * fields that actually change. Smart devices can
+ * arrange to change only those fields. Dumb devices
+ * can rest assured that we have provided for them,
+ * and can change all three fields */
+
+ defChg.flags = 0;
+ if(ChgRed && pentT->co.shco.red == pred)
+ {
+ defChg.flags |= DoRed;
+ }
+ if(ChgGreen && pentT->co.shco.green == pgreen)
+ {
+ defChg.flags |= DoGreen;
+ }
+ if(ChgBlue && pentT->co.shco.blue == pblue)
+ {
+ defChg.flags |= DoBlue;
+ }
+ if(defChg.flags != 0)
+ {
+ defChg.pixel = pentT - pmap->red;
+ defChg.red = pentT->co.shco.red->color;
+ defChg.green = pentT->co.shco.green->color;
+ defChg.blue = pentT->co.shco.blue->color;
+ (*pmap->pScreen->StoreColors) (pmap, 1, &defChg);
+ }
+ }
+ }
+
+ }
+ }
+ }
+ /* Note that we use idef, the count of acceptable entries, and not
+ * count, the count of proposed entries */
+ if (idef != 0)
+ ( *pmap->pScreen->StoreColors) (pmap, idef, defs);
+ return errVal;
+}
+
+int
+IsMapInstalled(Colormap map, WindowPtr pWin)
+{
+ Colormap *pmaps;
+ int imap, nummaps, found;
+
+ pmaps = malloc(pWin->drawable.pScreen->maxInstalledCmaps*sizeof(Colormap));
+ if(!pmaps)
+ return FALSE;
+ nummaps = (*pWin->drawable.pScreen->ListInstalledColormaps)
+ (pWin->drawable.pScreen, pmaps);
+ found = FALSE;
+ for(imap = 0; imap < nummaps; imap++)
+ {
+ if(pmaps[imap] == map)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ free(pmaps);
+ return found;
+}
+
+struct colormap_lookup_data {
+ ScreenPtr pScreen;
+ VisualPtr visuals;
+};
+
+static void _colormap_find_resource(pointer value, XID id,
+ pointer cdata)
+{
+ struct colormap_lookup_data *cmap_data = cdata;
+ VisualPtr visuals = cmap_data->visuals;
+ ScreenPtr pScreen = cmap_data->pScreen;
+ ColormapPtr cmap = value;
+ int j;
+
+ if (pScreen != cmap->pScreen)
+ return;
+
+ j = cmap->pVisual - pScreen->visuals;
+ cmap->pVisual = &visuals[j];
+}
+
+/* something has realloced the visuals, instead of breaking
+ ABI fix it up here - glx and compsite did this wrong */
+Bool
+ResizeVisualArray(ScreenPtr pScreen, int new_visual_count,
+ DepthPtr depth)
+{
+ struct colormap_lookup_data cdata;
+ int numVisuals;
+ VisualPtr visuals;
+ XID *vids, vid;
+ int first_new_vid, first_new_visual, i;
+
+ first_new_vid = depth->numVids;
+ first_new_visual = pScreen->numVisuals;
+
+ vids = realloc(depth->vids, (depth->numVids + new_visual_count) * sizeof(XID));
+ if (!vids)
+ return FALSE;
+
+ /* its realloced now no going back if we fail the next one */
+ depth->vids = vids;
+
+ numVisuals = pScreen->numVisuals + new_visual_count;
+ visuals = realloc(pScreen->visuals, numVisuals * sizeof(VisualRec));
+ if (!visuals) {
+ return FALSE;
+ }
+
+ cdata.visuals = visuals;
+ cdata.pScreen = pScreen;
+ FindClientResourcesByType(serverClient, RT_COLORMAP, _colormap_find_resource, &cdata);
+
+ pScreen->visuals = visuals;
+
+ for (i = 0; i < new_visual_count; i++) {
+ vid = FakeClientID(0);
+ pScreen->visuals[first_new_visual + i].vid = vid;
+ vids[first_new_vid + i] = vid;
+ }
+
+ depth->numVids += new_visual_count;
+ pScreen->numVisuals += new_visual_count;
+
+ return TRUE;
+}
diff --git a/dix/cursor.c b/dix/cursor.c
new file mode 100644
index 0000000..72a7609
--- /dev/null
+++ b/dix/cursor.c
@@ -0,0 +1,515 @@
+/***********************************************************
+
+Copyright 1987, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+******************************************************************/
+
+
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/Xmd.h>
+#include "servermd.h"
+#include "scrnintstr.h"
+#include "dixstruct.h"
+#include "cursorstr.h"
+#include "dixfontstr.h"
+#include "opaque.h"
+#include "inputstr.h"
+#include "xace.h"
+
+typedef struct _GlyphShare {
+ FontPtr font;
+ unsigned short sourceChar;
+ unsigned short maskChar;
+ CursorBitsPtr bits;
+ struct _GlyphShare *next;
+} GlyphShare, *GlyphSharePtr;
+
+static GlyphSharePtr sharedGlyphs = (GlyphSharePtr)NULL;
+
+DevPrivateKeyRec cursorScreenDevPriv[MAXSCREENS];
+
+#ifdef XFIXES
+static CARD32 cursorSerial;
+#endif
+
+static void
+FreeCursorBits(CursorBitsPtr bits)
+{
+ if (--bits->refcnt > 0)
+ return;
+ free(bits->source);
+ free(bits->mask);
+#ifdef ARGB_CURSOR
+ free(bits->argb);
+#endif
+ dixFiniPrivates(bits, PRIVATE_CURSOR_BITS);
+ if (bits->refcnt == 0)
+ {
+ GlyphSharePtr *prev, this;
+
+ for (prev = &sharedGlyphs;
+ (this = *prev) && (this->bits != bits);
+ prev = &this->next)
+ ;
+ if (this)
+ {
+ *prev = this->next;
+ CloseFont(this->font, (Font)0);
+ free(this);
+ }
+ free(bits);
+ }
+}
+
+/**
+ * To be called indirectly by DeleteResource; must use exactly two args.
+ *
+ * \param value must conform to DeleteType
+ */
+int
+FreeCursor(pointer value, XID cid)
+{
+ int nscr;
+ CursorPtr pCurs = (CursorPtr)value;
+
+ ScreenPtr pscr;
+ DeviceIntPtr pDev = NULL; /* unused anyway */
+
+ if ( --pCurs->refcnt != 0)
+ return Success;
+
+ for (nscr = 0; nscr < screenInfo.numScreens; nscr++)
+ {
+ pscr = screenInfo.screens[nscr];
+ (void)( *pscr->UnrealizeCursor)(pDev, pscr, pCurs);
+ }
+ FreeCursorBits(pCurs->bits);
+ dixFiniPrivates(pCurs, PRIVATE_CURSOR);
+ free( pCurs);
+ return Success;
+}
+
+
+/*
+ * We check for empty cursors so that we won't have to display them
+ */
+static void
+CheckForEmptyMask(CursorBitsPtr bits)
+{
+ unsigned char *msk = bits->mask;
+ int n = BitmapBytePad(bits->width) * bits->height;
+
+ bits->emptyMask = FALSE;
+ while(n--)
+ if(*(msk++) != 0) return;
+#ifdef ARGB_CURSOR
+ if (bits->argb)
+ {
+ CARD32 *argb = bits->argb;
+ int n = bits->width * bits->height;
+ while (n--)
+ if (*argb++ & 0xff000000) return;
+ }
+#endif
+ bits->emptyMask = TRUE;
+}
+
+/**
+ * realize the cursor for every screen. Do not change the refcnt, this will be
+ * changed when ChangeToCursor actually changes the sprite.
+ *
+ * @return Success if all cursors realize on all screens, BadAlloc if realize
+ * failed for a device on a given screen.
+ */
+static int
+RealizeCursorAllScreens(CursorPtr pCurs)
+{
+ DeviceIntPtr pDev;
+ ScreenPtr pscr;
+ int nscr;
+
+ for (nscr = 0; nscr < screenInfo.numScreens; nscr++)
+ {
+ pscr = screenInfo.screens[nscr];
+ for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
+ {
+ if (DevHasCursor(pDev))
+ {
+ if (!( *pscr->RealizeCursor)(pDev, pscr, pCurs))
+ {
+ /* Realize failed for device pDev on screen pscr.
+ * We have to assume that for all devices before, realize
+ * worked. We need to rollback all devices so far on the
+ * current screen and then all devices on previous
+ * screens.
+ */
+ DeviceIntPtr pDevIt = inputInfo.devices; /*dev iterator*/
+ while(pDevIt && pDevIt != pDev)
+ {
+ if (DevHasCursor(pDevIt))
+ ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs);
+ pDevIt = pDevIt->next;
+ }
+ while (--nscr >= 0)
+ {
+ pscr = screenInfo.screens[nscr];
+ /* now unrealize all devices on previous screens */
+ pDevIt = inputInfo.devices;
+ while (pDevIt)
+ {
+ if (DevHasCursor(pDevIt))
+ ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs);
+ pDevIt = pDevIt->next;
+ }
+ ( *pscr->UnrealizeCursor)(pDev, pscr, pCurs);
+ }
+ return BadAlloc;
+ }
+ }
+ }
+ }
+
+ return Success;
+}
+
+
+/**
+ * does nothing about the resource table, just creates the data structure.
+ * does not copy the src and mask bits
+ *
+ * \param psrcbits server-defined padding
+ * \param pmaskbits server-defined padding
+ * \param argb no padding
+ */
+int
+AllocARGBCursor(unsigned char *psrcbits, unsigned char *pmaskbits,
+ CARD32 *argb, CursorMetricPtr cm,
+ unsigned foreRed, unsigned foreGreen, unsigned foreBlue,
+ unsigned backRed, unsigned backGreen, unsigned backBlue,
+ CursorPtr *ppCurs, ClientPtr client, XID cid)
+{
+ CursorBitsPtr bits;
+ CursorPtr pCurs;
+ int rc;
+
+ *ppCurs = NULL;
+ pCurs = (CursorPtr)calloc(CURSOR_REC_SIZE + CURSOR_BITS_SIZE, 1);
+ if (!pCurs)
+ {
+ free(psrcbits);
+ free(pmaskbits);
+ return BadAlloc;
+ }
+ bits = (CursorBitsPtr)((char *)pCurs + CURSOR_REC_SIZE);
+ dixInitPrivates(pCurs, pCurs + 1, PRIVATE_CURSOR);
+ dixInitPrivates(bits, bits + 1, PRIVATE_CURSOR_BITS)
+ bits->source = psrcbits;
+ bits->mask = pmaskbits;
+#ifdef ARGB_CURSOR
+ bits->argb = argb;
+#endif
+ bits->width = cm->width;
+ bits->height = cm->height;
+ bits->xhot = cm->xhot;
+ bits->yhot = cm->yhot;
+ pCurs->refcnt = 1;
+ bits->refcnt = -1;
+ CheckForEmptyMask(bits);
+ pCurs->bits = bits;
+#ifdef XFIXES
+ pCurs->serialNumber = ++cursorSerial;
+ pCurs->name = None;
+#endif
+
+ pCurs->foreRed = foreRed;
+ pCurs->foreGreen = foreGreen;
+ pCurs->foreBlue = foreBlue;
+
+ pCurs->backRed = backRed;
+ pCurs->backGreen = backGreen;
+ pCurs->backBlue = backBlue;
+
+ pCurs->id = cid;
+
+ /* security creation/labeling check */
+ rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR,
+ pCurs, RT_NONE, NULL, DixCreateAccess);
+ if (rc != Success)
+ goto error;
+
+ rc = RealizeCursorAllScreens(pCurs);
+ if (rc != Success)
+ goto error;
+
+ *ppCurs = pCurs;
+ return Success;
+
+error:
+ FreeCursorBits(bits);
+ dixFiniPrivates(pCurs, PRIVATE_CURSOR);
+ free(pCurs);
+
+ return rc;
+}
+
+int
+AllocGlyphCursor(Font source, unsigned sourceChar, Font mask, unsigned maskChar,
+ unsigned foreRed, unsigned foreGreen, unsigned foreBlue,
+ unsigned backRed, unsigned backGreen, unsigned backBlue,
+ CursorPtr *ppCurs, ClientPtr client, XID cid)
+{
+ FontPtr sourcefont, maskfont;
+ unsigned char *srcbits;
+ unsigned char *mskbits;
+ CursorMetricRec cm;
+ int rc;
+ CursorBitsPtr bits;
+ CursorPtr pCurs;
+ GlyphSharePtr pShare;
+
+ rc = dixLookupResourceByType((pointer *)&sourcefont, source, RT_FONT, client,
+ DixUseAccess);
+ if (rc != Success)
+ {
+ client->errorValue = source;
+ return rc;
+ }
+ rc = dixLookupResourceByType((pointer *)&maskfont, mask, RT_FONT, client,
+ DixUseAccess);
+ if (rc != Success && mask != None)
+ {
+ client->errorValue = mask;
+ return rc;
+ }
+ if (sourcefont != maskfont)
+ pShare = (GlyphSharePtr)NULL;
+ else
+ {
+ for (pShare = sharedGlyphs;
+ pShare &&
+ ((pShare->font != sourcefont) ||
+ (pShare->sourceChar != sourceChar) ||
+ (pShare->maskChar != maskChar));
+ pShare = pShare->next)
+ ;
+ }
+ if (pShare)
+ {
+ pCurs = (CursorPtr)calloc(CURSOR_REC_SIZE, 1);
+ if (!pCurs)
+ return BadAlloc;
+ dixInitPrivates(pCurs, pCurs + 1, PRIVATE_CURSOR);
+ bits = pShare->bits;
+ bits->refcnt++;
+ }
+ else
+ {
+ if (!CursorMetricsFromGlyph(sourcefont, sourceChar, &cm))
+ {
+ client->errorValue = sourceChar;
+ return BadValue;
+ }
+ if (!maskfont)
+ {
+ long n;
+ unsigned char *mskptr;
+
+ n = BitmapBytePad(cm.width)*(long)cm.height;
+ mskptr = mskbits = malloc(n);
+ if (!mskptr)
+ return BadAlloc;
+ while (--n >= 0)
+ *mskptr++ = ~0;
+ }
+ else
+ {
+ if (!CursorMetricsFromGlyph(maskfont, maskChar, &cm))
+ {
+ client->errorValue = maskChar;
+ return BadValue;
+ }
+ if ((rc = ServerBitsFromGlyph(maskfont, maskChar, &cm, &mskbits)))
+ return rc;
+ }
+ if ((rc = ServerBitsFromGlyph(sourcefont, sourceChar, &cm, &srcbits)))
+ {
+ free(mskbits);
+ return rc;
+ }
+ if (sourcefont != maskfont)
+ {
+ pCurs =
+ (CursorPtr)calloc(CURSOR_REC_SIZE + CURSOR_BITS_SIZE, 1);
+ if (pCurs)
+ bits = (CursorBitsPtr)((char *)pCurs + CURSOR_REC_SIZE);
+ else
+ bits = (CursorBitsPtr)NULL;
+ }
+ else
+ {
+ pCurs = (CursorPtr)calloc(CURSOR_REC_SIZE, 1);
+ if (pCurs)
+ bits = (CursorBitsPtr)calloc(CURSOR_BITS_SIZE, 1);
+ else
+ bits = (CursorBitsPtr)NULL;
+ }
+ if (!bits)
+ {
+ free(pCurs);
+ free(mskbits);
+ free(srcbits);
+ return BadAlloc;
+ }
+ dixInitPrivates(pCurs, pCurs + 1, PRIVATE_CURSOR);
+ dixInitPrivates(bits, bits + 1, PRIVATE_CURSOR_BITS);
+ bits->source = srcbits;
+ bits->mask = mskbits;
+#ifdef ARGB_CURSOR
+ bits->argb = 0;
+#endif
+ bits->width = cm.width;
+ bits->height = cm.height;
+ bits->xhot = cm.xhot;
+ bits->yhot = cm.yhot;
+ if (sourcefont != maskfont)
+ bits->refcnt = -1;
+ else
+ {
+ bits->refcnt = 1;
+ pShare = malloc(sizeof(GlyphShare));
+ if (!pShare)
+ {
+ FreeCursorBits(bits);
+ return BadAlloc;
+ }
+ pShare->font = sourcefont;
+ sourcefont->refcnt++;
+ pShare->sourceChar = sourceChar;
+ pShare->maskChar = maskChar;
+ pShare->bits = bits;
+ pShare->next = sharedGlyphs;
+ sharedGlyphs = pShare;
+ }
+ }
+
+ CheckForEmptyMask(bits);
+ pCurs->bits = bits;
+ pCurs->refcnt = 1;
+#ifdef XFIXES
+ pCurs->serialNumber = ++cursorSerial;
+ pCurs->name = None;
+#endif
+
+ pCurs->foreRed = foreRed;
+ pCurs->foreGreen = foreGreen;
+ pCurs->foreBlue = foreBlue;
+
+ pCurs->backRed = backRed;
+ pCurs->backGreen = backGreen;
+ pCurs->backBlue = backBlue;
+
+ pCurs->id = cid;
+
+ /* security creation/labeling check */
+ rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR,
+ pCurs, RT_NONE, NULL, DixCreateAccess);
+ if (rc != Success)
+ goto error;
+
+ rc = RealizeCursorAllScreens(pCurs);
+ if (rc != Success)
+ goto error;
+
+ *ppCurs = pCurs;
+ return Success;
+
+error:
+ FreeCursorBits(bits);
+ dixFiniPrivates(pCurs, PRIVATE_CURSOR);
+ free(pCurs);
+
+ return rc;
+}
+
+/** CreateRootCursor
+ *
+ * look up the name of a font
+ * open the font
+ * add the font to the resource table
+ * make a cursor from the glyphs
+ * add the cursor to the resource table
+ *************************************************************/
+
+CursorPtr
+CreateRootCursor(char *unused1, unsigned int unused2)
+{
+ CursorPtr curs;
+ FontPtr cursorfont;
+ int err;
+ XID fontID;
+
+ fontID = FakeClientID(0);
+ err = OpenFont(serverClient, fontID, FontLoadAll | FontOpenSync,
+ (unsigned)strlen(defaultCursorFont), defaultCursorFont);
+ if (err != Success)
+ return NullCursor;
+
+ err = dixLookupResourceByType((pointer *)&cursorfont, fontID, RT_FONT,
+ serverClient, DixReadAccess);
+ if (err != Success)
+ return NullCursor;
+ if (AllocGlyphCursor(fontID, 0, fontID, 1, 0, 0, 0, ~0, ~0, ~0,
+ &curs, serverClient, (XID)0) != Success)
+ return NullCursor;
+
+ if (!AddResource(FakeClientID(0), RT_CURSOR, (pointer)curs))
+ return NullCursor;
+
+ return curs;
+}
diff --git a/dix/deprecated.c b/dix/deprecated.c
new file mode 100644
index 0000000..f05588e
--- /dev/null
+++ b/dix/deprecated.c
@@ -0,0 +1,165 @@
+/***********************************************************
+
+Copyright 1987, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+******************************************************************/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "dix.h"
+#include "misc.h"
+#include "dixstruct.h"
+
+/*
+ * These are deprecated compatibility functions and will be marked as such
+ * and removed soon!
+ *
+ * Please use the noted replacements instead.
+ */
+
+/* replaced by dixLookupWindow */
+WindowPtr
+SecurityLookupWindow(XID id, ClientPtr client, Mask access_mode)
+{
+ WindowPtr pWin;
+ static int warn = 1;
+ dixLookupWindow(&pWin, id, client, access_mode);
+ if (warn > 0 && warn--)
+ ErrorF("Warning: LookupWindow()/SecurityLookupWindow() "
+ "are deprecated. Please convert your driver/module "
+ "to use dixLookupWindow().\n");
+ return pWin;
+}
+
+/* replaced by dixLookupWindow */
+WindowPtr
+LookupWindow(XID id, ClientPtr client)
+{
+ return SecurityLookupWindow(id, client, DixUnknownAccess);
+}
+
+/* replaced by dixLookupDrawable */
+pointer
+SecurityLookupDrawable(XID id, ClientPtr client, Mask access_mode)
+{
+ DrawablePtr pDraw;
+ static int warn = 1;
+ dixLookupDrawable(&pDraw, id, client, M_DRAWABLE, access_mode);
+ if (warn > 0 && warn--)
+ ErrorF("Warning: LookupDrawable()/SecurityLookupDrawable() "
+ "are deprecated. Please convert your driver/module "
+ "to use dixLookupDrawable().\n");
+ return pDraw;
+}
+
+/* replaced by dixLookupDrawable */
+pointer
+LookupDrawable(XID id, ClientPtr client)
+{
+ return SecurityLookupDrawable(id, client, DixUnknownAccess);
+}
+
+/* replaced by dixLookupClient */
+ClientPtr
+LookupClient(XID id, ClientPtr client)
+{
+ ClientPtr pClient;
+ static int warn = 1;
+ dixLookupClient(&pClient, id, client, DixUnknownAccess);
+ if (warn > 0 && warn--)
+ ErrorF("Warning: LookupClient() is deprecated. Please convert your "
+ "driver/module to use dixLookupClient().\n");
+ return pClient;
+}
+
+/* replaced by dixLookupResourceByType */
+pointer
+SecurityLookupIDByType(ClientPtr client, XID id, RESTYPE rtype,
+ Mask access_mode)
+{
+ pointer retval;
+ static int warn = 1;
+ dixLookupResourceByType(&retval, id, rtype, client, access_mode);
+ if (warn > 0 && warn--)
+ ErrorF("Warning: LookupIDByType()/SecurityLookupIDByType() "
+ "are deprecated. Please convert your driver/module "
+ "to use dixLookupResourceByType().\n");
+ return retval;
+}
+
+pointer
+SecurityLookupIDByClass(ClientPtr client, XID id, RESTYPE classes,
+ Mask access_mode)
+{
+ pointer retval;
+ static int warn = 1;
+ dixLookupResourceByClass(&retval, id, classes, client, access_mode);
+ if (warn > 0 && warn--)
+ ErrorF("Warning: LookupIDByClass()/SecurityLookupIDByClass() "
+ "are deprecated. Please convert your driver/module "
+ "to use dixLookupResourceByClass().\n");
+ return retval;
+}
+
+/* replaced by dixLookupResourceByType */
+pointer
+LookupIDByType(XID id, RESTYPE rtype)
+{
+ pointer val;
+ dixLookupResourceByType(&val, id, rtype, NullClient, DixUnknownAccess);
+ return val;
+}
+
+/* replaced by dixLookupResourceByClass */
+pointer
+LookupIDByClass(XID id, RESTYPE classes)
+{
+ pointer val;
+ dixLookupResourceByClass(&val, id, classes, NullClient, DixUnknownAccess);
+ return val;
+}
+
+/* end deprecated functions */
diff --git a/dix/devices.c b/dix/devices.c
new file mode 100644
index 0000000..fed05f5
--- /dev/null
+++ b/dix/devices.c
@@ -0,0 +1,2633 @@
+/************************************************************
+
+Copyright 1987, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+********************************************************/
+
+
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include "misc.h"
+#include "resource.h"
+#include <X11/Xproto.h>
+#include <X11/Xatom.h>
+#include "windowstr.h"
+#include "inputstr.h"
+#include "scrnintstr.h"
+#include "cursorstr.h"
+#include "dixstruct.h"
+#include "ptrveloc.h"
+#include "site.h"
+#include "xkbsrv.h"
+#include "privates.h"
+#include "xace.h"
+#include "mi.h"
+
+#include "dispatch.h"
+#include "swaprep.h"
+#include "dixevents.h"
+#include "mipointer.h"
+#include "eventstr.h"
+
+#include <X11/extensions/XI.h>
+#include <X11/extensions/XI2.h>
+#include <X11/extensions/XIproto.h>
+#include <math.h>
+#include <pixman.h>
+#include "exglobals.h"
+#include "exevents.h"
+#include "xiquerydevice.h" /* for SizeDeviceClasses */
+#include "xiproperty.h"
+#include "enterleave.h" /* for EnterWindow() */
+#include "xserver-properties.h"
+#include "xichangehierarchy.h" /* For XISendDeviceHierarchyEvent */
+
+/** @file
+ * This file handles input device-related stuff.
+ */
+
+static void RecalculateMasterButtons(DeviceIntPtr slave);
+
+static void
+DeviceSetTransform(DeviceIntPtr dev, float *transform)
+{
+ struct pixman_f_transform scale;
+ double sx, sy;
+ int x, y;
+
+ /**
+ * calculate combined transformation matrix:
+ *
+ * M = InvScale * Transform * Scale
+ *
+ * So we can later transform points using M * p
+ *
+ * Where:
+ * Scale scales coordinates into 0..1 range
+ * Transform is the user supplied (affine) transform
+ * InvScale scales coordinates back up into their native range
+ */
+ sx = dev->valuator->axes[0].max_value - dev->valuator->axes[0].min_value;
+ sy = dev->valuator->axes[1].max_value - dev->valuator->axes[1].min_value;
+
+ /* invscale */
+ pixman_f_transform_init_scale(&scale, sx, sy);
+ scale.m[0][2] = dev->valuator->axes[0].min_value;
+ scale.m[1][2] = dev->valuator->axes[1].min_value;
+
+ /* transform */
+ for (y=0; y<3; y++)
+ for (x=0; x<3; x++)
+ dev->transform.m[y][x] = *transform++;
+
+ pixman_f_transform_multiply(&dev->transform, &scale, &dev->transform);
+
+ /* scale */
+ pixman_f_transform_init_scale(&scale, 1.0 / sx, 1.0 / sy);
+ scale.m[0][2] = -dev->valuator->axes[0].min_value / sx;
+ scale.m[1][2] = -dev->valuator->axes[1].min_value / sy;
+
+ pixman_f_transform_multiply(&dev->transform, &dev->transform, &scale);
+}
+
+/**
+ * DIX property handler.
+ */
+static int
+DeviceSetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
+ BOOL checkonly)
+{
+ if (property == XIGetKnownProperty(XI_PROP_ENABLED))
+ {
+ if (prop->format != 8 || prop->type != XA_INTEGER || prop->size != 1)
+ return BadValue;
+
+ /* Don't allow disabling of VCP/VCK */
+ if ((dev == inputInfo.pointer || dev == inputInfo.keyboard) &&
+ !(*(CARD8*)prop->data))
+ return BadAccess;
+
+ if (!checkonly)
+ {
+ if ((*((CARD8*)prop->data)) && !dev->enabled)
+ EnableDevice(dev, TRUE);
+ else if (!(*((CARD8*)prop->data)) && dev->enabled)
+ DisableDevice(dev, TRUE);
+ }
+ } else if (property == XIGetKnownProperty(XI_PROP_TRANSFORM))
+ {
+ float *f = (float*)prop->data;
+ int i;
+
+ if (prop->format != 32 || prop->size != 9 ||
+ prop->type != XIGetKnownProperty(XATOM_FLOAT))
+ return BadValue;
+
+ for (i=0; i<9; i++)
+ if (!isfinite(f[i]))
+ return BadValue;
+
+ if (!checkonly)
+ DeviceSetTransform(dev, f);
+ }
+
+ return Success;
+}
+
+/* Pair the keyboard to the pointer device. Keyboard events will follow the
+ * pointer sprite. Only applicable for master devices.
+ * If the client is set, the request to pair comes from some client. In this
+ * case, we need to check for access. If the client is NULL, it's from an
+ * internal automatic pairing, we must always permit this.
+ */
+static int
+PairDevices(ClientPtr client, DeviceIntPtr ptr, DeviceIntPtr kbd)
+{
+ if (!ptr)
+ return BadDevice;
+
+ /* Don't allow pairing for slave devices */
+ if (!IsMaster(ptr) || !IsMaster(kbd))
+ return BadDevice;
+
+ if (ptr->spriteInfo->paired)
+ return BadDevice;
+
+ if (kbd->spriteInfo->spriteOwner)
+ {
+ free(kbd->spriteInfo->sprite);
+ kbd->spriteInfo->sprite = NULL;
+ kbd->spriteInfo->spriteOwner = FALSE;
+ }
+
+ kbd->spriteInfo->sprite = ptr->spriteInfo->sprite;
+ kbd->spriteInfo->paired = ptr;
+ ptr->spriteInfo->paired = kbd;
+ return Success;
+}
+
+
+/**
+ * Find and return the next unpaired MD pointer device.
+ */
+static DeviceIntPtr
+NextFreePointerDevice(void)
+{
+ DeviceIntPtr dev;
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ if (IsMaster(dev) &&
+ dev->spriteInfo->spriteOwner &&
+ !dev->spriteInfo->paired)
+ return dev;
+ return NULL;
+}
+
+/**
+ * Create a new input device and init it to sane values. The device is added
+ * to the server's off_devices list.
+ *
+ * @param deviceProc Callback for device control function (switch dev on/off).
+ * @return The newly created device.
+ */
+DeviceIntPtr
+AddInputDevice(ClientPtr client, DeviceProc deviceProc, Bool autoStart)
+{
+ DeviceIntPtr dev, *prev; /* not a typo */
+ DeviceIntPtr devtmp;
+ int devid;
+ char devind[MAXDEVICES];
+ BOOL enabled;
+ float transform[9];
+
+ /* Find next available id, 0 and 1 are reserved */
+ memset(devind, 0, sizeof(char)*MAXDEVICES);
+ for (devtmp = inputInfo.devices; devtmp; devtmp = devtmp->next)
+ devind[devtmp->id]++;
+ for (devtmp = inputInfo.off_devices; devtmp; devtmp = devtmp->next)
+ devind[devtmp->id]++;
+ for (devid = 2; devid < MAXDEVICES && devind[devid]; devid++)
+ ;
+
+ if (devid >= MAXDEVICES)
+ return (DeviceIntPtr)NULL;
+ dev = _dixAllocateObjectWithPrivates(sizeof(DeviceIntRec) + sizeof(SpriteInfoRec),
+ sizeof(DeviceIntRec) + sizeof(SpriteInfoRec),
+ offsetof(DeviceIntRec, devPrivates), PRIVATE_DEVICE);
+ if (!dev)
+ return (DeviceIntPtr)NULL;
+ dev->id = devid;
+ dev->public.processInputProc = ProcessOtherEvent;
+ dev->public.realInputProc = ProcessOtherEvent;
+ dev->public.enqueueInputProc = EnqueueEvent;
+ dev->deviceProc = deviceProc;
+ dev->startup = autoStart;
+
+ /* device grab defaults */
+ dev->deviceGrab.grabTime = currentTime;
+ dev->deviceGrab.ActivateGrab = ActivateKeyboardGrab;
+ dev->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab;
+
+ XkbSetExtension(dev, ProcessKeyboardEvent);
+
+ dev->coreEvents = TRUE;
+
+ /* sprite defaults */
+ dev->spriteInfo = (SpriteInfoPtr)&dev[1];
+
+ /* security creation/labeling check
+ */
+ if (XaceHook(XACE_DEVICE_ACCESS, client, dev, DixCreateAccess)) {
+ free(dev);
+ return NULL;
+ }
+
+ inputInfo.numDevices++;
+
+ for (prev = &inputInfo.off_devices; *prev; prev = &(*prev)->next)
+ ;
+ *prev = dev;
+ dev->next = NULL;
+
+ enabled = FALSE;
+ XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED),
+ XA_INTEGER, 8, PropModeReplace, 1, &enabled,
+ FALSE);
+ XISetDevicePropertyDeletable(dev, XIGetKnownProperty(XI_PROP_ENABLED), FALSE);
+
+ /* unity matrix */
+ memset(transform, 0, sizeof(transform));
+ transform[0] = transform[4] = transform[8] = 1.0f;
+
+ XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_TRANSFORM),
+ XIGetKnownProperty(XATOM_FLOAT), 32,
+ PropModeReplace, 9, transform, FALSE);
+ XISetDevicePropertyDeletable(dev, XIGetKnownProperty(XI_PROP_TRANSFORM),
+ FALSE);
+
+ XIRegisterPropertyHandler(dev, DeviceSetProperty, NULL, NULL);
+
+ return dev;
+}
+
+void
+SendDevicePresenceEvent(int deviceid, int type)
+{
+ DeviceIntRec dummyDev;
+ devicePresenceNotify ev;
+
+ memset(&dummyDev, 0, sizeof(DeviceIntRec));
+ ev.type = DevicePresenceNotify;
+ ev.time = currentTime.milliseconds;
+ ev.devchange = type;
+ ev.deviceid = deviceid;
+ dummyDev.id = XIAllDevices;
+ SendEventToAllWindows(&dummyDev, DevicePresenceNotifyMask,
+ (xEvent*)&ev, 1);
+}
+
+/**
+ * Enable the device through the driver, add the device to the device list.
+ * Switch device ON through the driver and push it onto the global device
+ * list. Initialize the DIX sprite or pair the device. All clients are
+ * notified about the device being enabled.
+ *
+ * A master pointer device needs to be enabled before a master keyboard
+ * device.
+ *
+ * @param The device to be enabled.
+ * @param sendevent True if an XI2 event should be sent.
+ * @return TRUE on success or FALSE otherwise.
+ */
+Bool
+EnableDevice(DeviceIntPtr dev, BOOL sendevent)
+{
+ DeviceIntPtr *prev;
+ int ret;
+ DeviceIntPtr other;
+ BOOL enabled;
+ int flags[MAXDEVICES] = {0};
+
+ for (prev = &inputInfo.off_devices;
+ *prev && (*prev != dev);
+ prev = &(*prev)->next)
+ ;
+
+ if (!dev->spriteInfo->sprite)
+ {
+ if (IsMaster(dev))
+ {
+ /* Sprites appear on first root window, so we can hardcode it */
+ if (dev->spriteInfo->spriteOwner)
+ {
+ InitializeSprite(dev, screenInfo.screens[0]->root);
+ /* mode doesn't matter */
+ EnterWindow(dev, screenInfo.screens[0]->root, NotifyAncestor);
+ }
+ else if ((other = NextFreePointerDevice()) == NULL)
+ {
+ ErrorF("[dix] cannot find pointer to pair with. "
+ "This is a bug.\n");
+ return FALSE;
+ } else
+ PairDevices(NULL, other, dev);
+ } else
+ {
+ if (dev->coreEvents)
+ other = (IsPointerDevice(dev)) ? inputInfo.pointer :
+ inputInfo.keyboard;
+ else
+ other = NULL; /* auto-float non-core devices */
+ AttachDevice(NULL, dev, other);
+ }
+ }
+
+ if ((*prev != dev) || !dev->inited ||
+ ((ret = (*dev->deviceProc)(dev, DEVICE_ON)) != Success)) {
+ ErrorF("[dix] couldn't enable device %d\n", dev->id);
+ return FALSE;
+ }
+ dev->enabled = TRUE;
+ *prev = dev->next;
+
+ for (prev = &inputInfo.devices; *prev; prev = &(*prev)->next)
+ ;
+ *prev = dev;
+ dev->next = NULL;
+
+ enabled = TRUE;
+ XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED),
+ XA_INTEGER, 8, PropModeReplace, 1, &enabled,
+ TRUE);
+
+ SendDevicePresenceEvent(dev->id, DeviceEnabled);
+ if (sendevent)
+ {
+ flags[dev->id] |= XIDeviceEnabled;
+ XISendDeviceHierarchyEvent(flags);
+ }
+
+ RecalculateMasterButtons(dev);
+
+ return TRUE;
+}
+
+/**
+ * Switch a device off through the driver and push it onto the off_devices
+ * list. A device will not send events while disabled. All clients are
+ * notified about the device being disabled.
+ *
+ * Master keyboard devices have to be disabled before master pointer devices
+ * otherwise things turn bad.
+ *
+ * @param sendevent True if an XI2 event should be sent.
+ * @return TRUE on success or FALSE otherwise.
+ */
+Bool
+DisableDevice(DeviceIntPtr dev, BOOL sendevent)
+{
+ DeviceIntPtr *prev, other;
+ BOOL enabled;
+ int flags[MAXDEVICES] = {0};
+
+ for (prev = &inputInfo.devices;
+ *prev && (*prev != dev);
+ prev = &(*prev)->next)
+ ;
+ if (*prev != dev)
+ return FALSE;
+
+ /* float attached devices */
+ if (IsMaster(dev))
+ {
+ for (other = inputInfo.devices; other; other = other->next)
+ {
+ if (other->u.master == dev)
+ {
+ AttachDevice(NULL, other, NULL);
+ flags[other->id] |= XISlaveDetached;
+ }
+ }
+ }
+ else
+ {
+ for (other = inputInfo.devices; other; other = other->next)
+ {
+ if (IsMaster(other) && other->u.lastSlave == dev)
+ other->u.lastSlave = NULL;
+ }
+ }
+
+ if (IsMaster(dev) && dev->spriteInfo->sprite)
+ {
+ for (other = inputInfo.devices; other; other = other->next)
+ {
+ if (other->spriteInfo->paired == dev)
+ {
+ ErrorF("[dix] cannot disable device, still paired. "
+ "This is a bug. \n");
+ return FALSE;
+ }
+ }
+ }
+
+ (void)(*dev->deviceProc)(dev, DEVICE_OFF);
+ dev->enabled = FALSE;
+
+ /* now that the device is disabled, we can reset the signal handler's
+ * last.slave */
+ OsBlockSignals();
+ for (other = inputInfo.devices; other; other = other->next)
+ {
+ if (other->last.slave == dev)
+ other->last.slave = NULL;
+ }
+ OsReleaseSignals();
+
+ LeaveWindow(dev);
+ SetFocusOut(dev);
+
+ *prev = dev->next;
+ dev->next = inputInfo.off_devices;
+ inputInfo.off_devices = dev;
+
+ enabled = FALSE;
+ XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED),
+ XA_INTEGER, 8, PropModeReplace, 1, &enabled,
+ TRUE);
+
+ SendDevicePresenceEvent(dev->id, DeviceDisabled);
+ if (sendevent)
+ {
+ flags[dev->id] = XIDeviceDisabled;
+ XISendDeviceHierarchyEvent(flags);
+ }
+
+ RecalculateMasterButtons(dev);
+
+ return TRUE;
+}
+
+/**
+ * Initialise a new device through the driver and tell all clients about the
+ * new device.
+ *
+ * Must be called before EnableDevice.
+ * The device will NOT send events until it is enabled!
+ *
+ * @param sendevent True if an XI2 event should be sent.
+ * @return Success or an error code on failure.
+ */
+int
+ActivateDevice(DeviceIntPtr dev, BOOL sendevent)
+{
+ int ret = Success;
+ ScreenPtr pScreen = screenInfo.screens[0];
+
+ if (!dev || !dev->deviceProc)
+ return BadImplementation;
+
+ ret = (*dev->deviceProc) (dev, DEVICE_INIT);
+ dev->inited = (ret == Success);
+ if (!dev->inited)
+ return ret;
+
+ /* Initialize memory for sprites. */
+ if (IsMaster(dev) && dev->spriteInfo->spriteOwner)
+ if (!pScreen->DeviceCursorInitialize(dev, pScreen))
+ ret = BadAlloc;
+
+ SendDevicePresenceEvent(dev->id, DeviceAdded);
+ if (sendevent)
+ {
+ int flags[MAXDEVICES] = {0};
+ flags[dev->id] = XISlaveAdded;
+ XISendDeviceHierarchyEvent(flags);
+ }
+ return ret;
+}
+
+/**
+ * Ring the bell.
+ * The actual task of ringing the bell is the job of the DDX.
+ */
+static void
+CoreKeyboardBell(int volume, DeviceIntPtr pDev, pointer arg, int something)
+{
+ KeybdCtrl *ctrl = arg;
+
+ DDXRingBell(volume, ctrl->bell_pitch, ctrl->bell_duration);
+}
+
+static void
+CoreKeyboardCtl(DeviceIntPtr pDev, KeybdCtrl *ctrl)
+{
+ return;
+}
+
+/**
+ * Device control function for the Virtual Core Keyboard.
+ */
+int
+CoreKeyboardProc(DeviceIntPtr pDev, int what)
+{
+
+ switch (what) {
+ case DEVICE_INIT:
+ if (!InitKeyboardDeviceStruct(pDev, NULL, CoreKeyboardBell,
+ CoreKeyboardCtl))
+ {
+ ErrorF("Keyboard initialization failed. This could be a missing "
+ "or incorrect setup of xkeyboard-config.\n");
+ return BadValue;
+ }
+ return Success;
+
+ case DEVICE_ON:
+ case DEVICE_OFF:
+ return Success;
+
+ case DEVICE_CLOSE:
+ return Success;
+ }
+
+ return BadMatch;
+}
+
+/**
+ * Device control function for the Virtual Core Pointer.
+ */
+int
+CorePointerProc(DeviceIntPtr pDev, int what)
+{
+#define NBUTTONS 10
+#define NAXES 2
+ BYTE map[NBUTTONS + 1];
+ int i = 0;
+ Atom btn_labels[NBUTTONS] = {0};
+ Atom axes_labels[NAXES] = {0};
+
+ switch (what) {
+ case DEVICE_INIT:
+ for (i = 1; i <= NBUTTONS; i++)
+ map[i] = i;
+
+ btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
+ btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
+ btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
+ btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
+ btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
+ btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
+ btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
+ /* don't know about the rest */
+
+ axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
+ axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
+
+ if (!InitPointerDeviceStruct((DevicePtr)pDev, map, NBUTTONS, btn_labels,
+ (PtrCtrlProcPtr)NoopDDA,
+ GetMotionHistorySize(), NAXES, axes_labels))
+ {
+ ErrorF("Could not initialize device '%s'. Out of memory.\n",
+ pDev->name);
+ return BadAlloc; /* IPDS only fails on allocs */
+ }
+ pDev->valuator->axisVal[0] = screenInfo.screens[0]->width / 2;
+ pDev->last.valuators[0] = pDev->valuator->axisVal[0];
+ pDev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2;
+ pDev->last.valuators[1] = pDev->valuator->axisVal[1];
+ break;
+
+ case DEVICE_CLOSE:
+ break;
+
+ default:
+ break;
+ }
+
+ return Success;
+
+#undef NBUTTONS
+#undef NAXES
+}
+
+/**
+ * Initialise the two core devices, VCP and VCK (see events.c).
+ * Both devices are not tied to physical devices, but guarantee that there is
+ * always a keyboard and a pointer present and keep the protocol semantics.
+ *
+ * Note that the server MUST have two core devices at all times, even if there
+ * is no physical device connected.
+ */
+void
+InitCoreDevices(void)
+{
+ if (AllocDevicePair(serverClient, "Virtual core",
+ &inputInfo.pointer, &inputInfo.keyboard,
+ CorePointerProc, CoreKeyboardProc,
+ TRUE) != Success)
+ FatalError("Failed to allocate core devices");
+
+ if (ActivateDevice(inputInfo.pointer, TRUE) != Success ||
+ ActivateDevice(inputInfo.keyboard, TRUE) != Success)
+ FatalError("Failed to activate core devices.");
+ if (!EnableDevice(inputInfo.pointer, TRUE) ||
+ !EnableDevice(inputInfo.keyboard, TRUE))
+ FatalError("Failed to enable core devices.");
+
+ InitXTestDevices();
+}
+
+/**
+ * Activate all switched-off devices and then enable all those devices.
+ *
+ * Will return an error if no core keyboard or core pointer is present.
+ * In theory this should never happen if you call InitCoreDevices() first.
+ *
+ * InitAndStartDevices needs to be called AFTER the windows are initialized.
+ * Devices will start sending events after InitAndStartDevices() has
+ * completed.
+ *
+ * @return Success or error code on failure.
+ */
+int
+InitAndStartDevices(void)
+{
+ DeviceIntPtr dev, next;
+
+ for (dev = inputInfo.off_devices; dev; dev = dev->next) {
+ DebugF("(dix) initialising device %d\n", dev->id);
+ if (!dev->inited)
+ ActivateDevice(dev, TRUE);
+ }
+
+ /* enable real devices */
+ for (dev = inputInfo.off_devices; dev; dev = next)
+ {
+ DebugF("(dix) enabling device %d\n", dev->id);
+ next = dev->next;
+ if (dev->inited && dev->startup)
+ EnableDevice(dev, TRUE);
+ }
+
+ return Success;
+}
+
+/**
+ * Free the given device class and reset the pointer to NULL.
+ */
+static void
+FreeDeviceClass(int type, pointer *class)
+{
+ if (!(*class))
+ return;
+
+ switch(type)
+ {
+ case KeyClass:
+ {
+ KeyClassPtr* k = (KeyClassPtr*)class;
+ if ((*k)->xkbInfo)
+ {
+ XkbFreeInfo((*k)->xkbInfo);
+ (*k)->xkbInfo = NULL;
+ }
+ free((*k));
+ break;
+ }
+ case ButtonClass:
+ {
+ ButtonClassPtr *b = (ButtonClassPtr*)class;
+ free((*b)->xkb_acts);
+ free((*b));
+ break;
+ }
+ case ValuatorClass:
+ {
+ ValuatorClassPtr *v = (ValuatorClassPtr*)class;
+
+ free((*v)->motion);
+ free((*v));
+ break;
+ }
+ case FocusClass:
+ {
+ FocusClassPtr *f = (FocusClassPtr*)class;
+ free((*f)->trace);
+ free((*f));
+ break;
+ }
+ case ProximityClass:
+ {
+ ProximityClassPtr *p = (ProximityClassPtr*)class;
+ free((*p));
+ break;
+ }
+ }
+ *class = NULL;
+}
+
+static void
+FreeFeedbackClass(int type, pointer *class)
+{
+ if (!(*class))
+ return;
+
+ switch(type)
+ {
+ case KbdFeedbackClass:
+ {
+ KbdFeedbackPtr *kbdfeed = (KbdFeedbackPtr*)class;
+ KbdFeedbackPtr k, knext;
+ for (k = (*kbdfeed); k; k = knext) {
+ knext = k->next;
+ if (k->xkb_sli)
+ XkbFreeSrvLedInfo(k->xkb_sli);
+ free(k);
+ }
+ break;
+ }
+ case PtrFeedbackClass:
+ {
+ PtrFeedbackPtr *ptrfeed = (PtrFeedbackPtr*)class;
+ PtrFeedbackPtr p, pnext;
+
+ for (p = (*ptrfeed); p; p = pnext) {
+ pnext = p->next;
+ free(p);
+ }
+ break;
+ }
+ case IntegerFeedbackClass:
+ {
+ IntegerFeedbackPtr *intfeed = (IntegerFeedbackPtr*)class;
+ IntegerFeedbackPtr i, inext;
+
+ for (i = (*intfeed); i; i = inext) {
+ inext = i->next;
+ free(i);
+ }
+ break;
+ }
+ case StringFeedbackClass:
+ {
+ StringFeedbackPtr *stringfeed = (StringFeedbackPtr*)class;
+ StringFeedbackPtr s, snext;
+
+ for (s = (*stringfeed); s; s = snext) {
+ snext = s->next;
+ free(s->ctrl.symbols_supported);
+ free(s->ctrl.symbols_displayed);
+ free(s);
+ }
+ break;
+ }
+ case BellFeedbackClass:
+ {
+ BellFeedbackPtr *bell = (BellFeedbackPtr*)class;
+ BellFeedbackPtr b, bnext;
+
+ for (b = (*bell); b; b = bnext) {
+ bnext = b->next;
+ free(b);
+ }
+ break;
+ }
+ case LedFeedbackClass:
+ {
+ LedFeedbackPtr *leds = (LedFeedbackPtr*)class;
+ LedFeedbackPtr l, lnext;
+
+ for (l = (*leds); l; l = lnext) {
+ lnext = l->next;
+ if (l->xkb_sli)
+ XkbFreeSrvLedInfo(l->xkb_sli);
+ free(l);
+ }
+ break;
+ }
+ }
+ *class = NULL;
+}
+
+static void
+FreeAllDeviceClasses(ClassesPtr classes)
+{
+ if (!classes)
+ return;
+
+ FreeDeviceClass(KeyClass, (pointer)&classes->key);
+ FreeDeviceClass(ValuatorClass, (pointer)&classes->valuator);
+ FreeDeviceClass(ButtonClass, (pointer)&classes->button);
+ FreeDeviceClass(FocusClass, (pointer)&classes->focus);
+ FreeDeviceClass(ProximityClass, (pointer)&classes->proximity);
+
+ FreeFeedbackClass(KbdFeedbackClass, (pointer)&classes->kbdfeed);
+ FreeFeedbackClass(PtrFeedbackClass, (pointer)&classes->ptrfeed);
+ FreeFeedbackClass(IntegerFeedbackClass, (pointer)&classes->intfeed);
+ FreeFeedbackClass(StringFeedbackClass, (pointer)&classes->stringfeed);
+ FreeFeedbackClass(BellFeedbackClass, (pointer)&classes->bell);
+ FreeFeedbackClass(LedFeedbackClass, (pointer)&classes->leds);
+
+}
+
+/**
+ * Close down a device and free all resources.
+ * Once closed down, the driver will probably not expect you that you'll ever
+ * enable it again and free associated structs. If you want the device to just
+ * be disabled, DisableDevice().
+ * Don't call this function directly, use RemoveDevice() instead.
+ */
+static void
+CloseDevice(DeviceIntPtr dev)
+{
+ ScreenPtr screen = screenInfo.screens[0];
+ ClassesPtr classes;
+ int j;
+
+ if (!dev)
+ return;
+
+ XIDeleteAllDeviceProperties(dev);
+
+ if (dev->inited)
+ (void)(*dev->deviceProc)(dev, DEVICE_CLOSE);
+
+ /* free sprite memory */
+ if (IsMaster(dev) && dev->spriteInfo->sprite)
+ screen->DeviceCursorCleanup(dev, screen);
+
+ /* free acceleration info */
+ if(dev->valuator && dev->valuator->accelScheme.AccelCleanupProc)
+ dev->valuator->accelScheme.AccelCleanupProc(dev);
+
+ while (dev->xkb_interest)
+ XkbRemoveResourceClient((DevicePtr)dev,dev->xkb_interest->resource);
+
+ free(dev->name);
+
+ classes = (ClassesPtr)&dev->key;
+ FreeAllDeviceClasses(classes);
+
+ if (IsMaster(dev))
+ {
+ classes = dev->unused_classes;
+ FreeAllDeviceClasses(classes);
+ free(classes);
+ }
+
+ if (DevHasCursor(dev) && dev->spriteInfo->sprite) {
+ if (dev->spriteInfo->sprite->current)
+ FreeCursor(dev->spriteInfo->sprite->current, None);
+ free(dev->spriteInfo->sprite->spriteTrace);
+ free(dev->spriteInfo->sprite);
+ }
+
+ /* a client may have the device set as client pointer */
+ for (j = 0; j < currentMaxClients; j++)
+ {
+ if (clients[j] && clients[j]->clientPtr == dev)
+ {
+ clients[j]->clientPtr = NULL;
+ clients[j]->clientPtr = PickPointer(clients[j]);
+ }
+ }
+
+ free(dev->deviceGrab.sync.event);
+ free(dev->config_info); /* Allocated in xf86ActivateDevice. */
+ dev->config_info = NULL;
+ dixFreeObjectWithPrivates(dev, PRIVATE_DEVICE);
+}
+
+/**
+ * Shut down all devices of one list and free all resources.
+ */
+static
+void
+CloseDeviceList(DeviceIntPtr *listHead)
+{
+ /* Used to mark devices that we tried to free */
+ Bool freedIds[MAXDEVICES];
+ DeviceIntPtr dev;
+ int i;
+
+ if (listHead == NULL)
+ return;
+
+ for (i = 0; i < MAXDEVICES; i++)
+ freedIds[i] = FALSE;
+
+ dev = *listHead;
+ while (dev != NULL)
+ {
+ freedIds[dev->id] = TRUE;
+ DeleteInputDeviceRequest(dev);
+
+ dev = *listHead;
+ while (dev != NULL && freedIds[dev->id])
+ dev = dev->next;
+ }
+}
+
+/**
+ * Shut down all devices, free all resources, etc.
+ * Only useful if you're shutting down the server!
+ */
+void
+CloseDownDevices(void)
+{
+ DeviceIntPtr dev;
+
+ /* Float all SDs before closing them. Note that at this point resources
+ * (e.g. cursors) have been freed already, so we can't just call
+ * AttachDevice(NULL, dev, NULL). Instead, we have to forcibly set master
+ * to NULL and pretend nothing happened.
+ */
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ {
+ if (!IsMaster(dev) && dev->u.master)
+ dev->u.master = NULL;
+ }
+
+ CloseDeviceList(&inputInfo.devices);
+ CloseDeviceList(&inputInfo.off_devices);
+
+ CloseDevice(inputInfo.pointer);
+ CloseDevice(inputInfo.keyboard);
+
+ inputInfo.devices = NULL;
+ inputInfo.off_devices = NULL;
+ inputInfo.keyboard = NULL;
+ inputInfo.pointer = NULL;
+ XkbDeleteRulesDflts();
+}
+
+/**
+ * Remove the cursor sprite for all devices. This needs to be done before any
+ * resources are freed or any device is deleted.
+ */
+void
+UndisplayDevices(void)
+{
+ DeviceIntPtr dev;
+ ScreenPtr screen = screenInfo.screens[0];
+
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ screen->DisplayCursor(dev, screen, NullCursor);
+}
+
+/**
+ * Remove a device from the device list, closes it and thus frees all
+ * resources.
+ * Removes both enabled and disabled devices and notifies all devices about
+ * the removal of the device.
+ *
+ * No PresenceNotify is sent for device that the client never saw. This can
+ * happen if a malloc fails during the addition of master devices. If
+ * dev->init is FALSE it means the client never received a DeviceAdded event,
+ * so let's not send a DeviceRemoved event either.
+ *
+ * @param sendevent True if an XI2 event should be sent.
+ */
+int
+RemoveDevice(DeviceIntPtr dev, BOOL sendevent)
+{
+ DeviceIntPtr prev,tmp,next;
+ int ret = BadMatch;
+ ScreenPtr screen = screenInfo.screens[0];
+ int deviceid;
+ int initialized;
+ int flags[MAXDEVICES] = {0};
+
+ DebugF("(dix) removing device %d\n", dev->id);
+
+ if (!dev || dev == inputInfo.keyboard || dev == inputInfo.pointer)
+ return BadImplementation;
+
+ initialized = dev->inited;
+ deviceid = dev->id;
+
+ if (initialized)
+ {
+ if (DevHasCursor(dev))
+ screen->DisplayCursor(dev, screen, NullCursor);
+
+ DisableDevice(dev, sendevent);
+ flags[dev->id] = XIDeviceDisabled;
+ }
+
+ prev = NULL;
+ for (tmp = inputInfo.devices; tmp; (prev = tmp), (tmp = next)) {
+ next = tmp->next;
+ if (tmp == dev) {
+
+ if (prev==NULL)
+ inputInfo.devices = next;
+ else
+ prev->next = next;
+
+ flags[tmp->id] = IsMaster(tmp) ? XIMasterRemoved : XISlaveRemoved;
+ CloseDevice(tmp);
+ ret = Success;
+ }
+ }
+
+ prev = NULL;
+ for (tmp = inputInfo.off_devices; tmp; (prev = tmp), (tmp = next)) {
+ next = tmp->next;
+ if (tmp == dev) {
+ flags[tmp->id] = IsMaster(tmp) ? XIMasterRemoved : XISlaveRemoved;
+ CloseDevice(tmp);
+
+ if (prev == NULL)
+ inputInfo.off_devices = next;
+ else
+ prev->next = next;
+
+ ret = Success;
+ }
+ }
+
+ if (ret == Success && initialized) {
+ inputInfo.numDevices--;
+ SendDevicePresenceEvent(deviceid, DeviceRemoved);
+ if (sendevent)
+ XISendDeviceHierarchyEvent(flags);
+ }
+
+ return ret;
+}
+
+int
+NumMotionEvents(void)
+{
+ /* only called to fill data in initial connection reply.
+ * VCP is ok here, it is the only fixed device we have. */
+ return inputInfo.pointer->valuator->numMotionEvents;
+}
+
+int
+dixLookupDevice(DeviceIntPtr *pDev, int id, ClientPtr client, Mask access_mode)
+{
+ DeviceIntPtr dev;
+ int rc;
+ *pDev = NULL;
+
+ for (dev=inputInfo.devices; dev; dev=dev->next) {
+ if (dev->id == id)
+ goto found;
+ }
+ for (dev=inputInfo.off_devices; dev; dev=dev->next) {
+ if (dev->id == id)
+ goto found;
+ }
+ return BadDevice;
+
+found:
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode);
+ if (rc == Success)
+ *pDev = dev;
+ return rc;
+}
+
+void
+QueryMinMaxKeyCodes(KeyCode *minCode, KeyCode *maxCode)
+{
+ if (inputInfo.keyboard) {
+ *minCode = inputInfo.keyboard->key->xkbInfo->desc->min_key_code;
+ *maxCode = inputInfo.keyboard->key->xkbInfo->desc->max_key_code;
+ }
+}
+
+/* Notably, this function does not expand the destination's keycode range, or
+ * notify clients. */
+Bool
+SetKeySymsMap(KeySymsPtr dst, KeySymsPtr src)
+{
+ int i, j;
+ KeySym *tmp;
+ int rowDif = src->minKeyCode - dst->minKeyCode;
+
+ /* if keysym map size changes, grow map first */
+ if (src->mapWidth < dst->mapWidth) {
+ for (i = src->minKeyCode; i <= src->maxKeyCode; i++) {
+#define SI(r, c) (((r - src->minKeyCode) * src->mapWidth) + (c))
+#define DI(r, c) (((r - dst->minKeyCode) * dst->mapWidth) + (c))
+ for (j = 0; j < src->mapWidth; j++)
+ dst->map[DI(i, j)] = src->map[SI(i, j)];
+ for (j = src->mapWidth; j < dst->mapWidth; j++)
+ dst->map[DI(i, j)] = NoSymbol;
+#undef SI
+#undef DI
+ }
+ return TRUE;
+ }
+ else if (src->mapWidth > dst->mapWidth) {
+ i = sizeof(KeySym) * src->mapWidth *
+ (dst->maxKeyCode - dst->minKeyCode + 1);
+ tmp = calloc(sizeof(KeySym), i);
+ if (!tmp)
+ return FALSE;
+
+ if (dst->map) {
+ for (i = 0; i <= dst->maxKeyCode-dst->minKeyCode; i++)
+ memmove(&tmp[i * src->mapWidth], &dst->map[i * dst->mapWidth],
+ dst->mapWidth * sizeof(KeySym));
+ free(dst->map);
+ }
+ dst->mapWidth = src->mapWidth;
+ dst->map = tmp;
+ }
+ else if (!dst->map) {
+ i = sizeof(KeySym) * src->mapWidth *
+ (dst->maxKeyCode - dst->minKeyCode + 1);
+ tmp = calloc(sizeof(KeySym), i);
+ if (!tmp)
+ return FALSE;
+
+ dst->map = tmp;
+ dst->mapWidth = src->mapWidth;
+ }
+
+ memmove(&dst->map[rowDif * dst->mapWidth], src->map,
+ (src->maxKeyCode - src->minKeyCode + 1) *
+ dst->mapWidth * sizeof(KeySym));
+
+ return TRUE;
+}
+
+Bool
+InitButtonClassDeviceStruct(DeviceIntPtr dev, int numButtons, Atom* labels,
+ CARD8 *map)
+{
+ ButtonClassPtr butc;
+ int i;
+
+ butc = calloc(1, sizeof(ButtonClassRec));
+ if (!butc)
+ return FALSE;
+ butc->numButtons = numButtons;
+ butc->sourceid = dev->id;
+ for (i = 1; i <= numButtons; i++)
+ butc->map[i] = map[i];
+ for (i = numButtons + 1; i < MAP_LENGTH; i++)
+ butc->map[i] = i;
+ memcpy(butc->labels, labels, numButtons * sizeof(Atom));
+ dev->button = butc;
+ return TRUE;
+}
+
+/**
+ * Allocate a valuator class and set up the pointers for the axis values
+ * appropriately.
+ *
+ * @param src If non-NULL, the memory is reallocated from src. If NULL, the
+ * memory is calloc'd.
+ * @parma numAxes Number of axes to allocate.
+ * @return The allocated valuator struct.
+ */
+ValuatorClassPtr
+AllocValuatorClass(ValuatorClassPtr src, int numAxes)
+{
+ ValuatorClassPtr v;
+ /* force alignment with double */
+ union align_u { ValuatorClassRec valc; double d; } *align;
+ int size;
+
+ size = sizeof(union align_u) + numAxes * (sizeof(double) + sizeof(AxisInfo));
+ align = (union align_u *) realloc(src, size);
+
+ if (!align)
+ return NULL;
+
+ if (!src)
+ memset(align, 0, size);
+
+ v = &align->valc;
+ v->numAxes = numAxes;
+ v->axisVal = (double*)(align + 1);
+ v->axes = (AxisInfoPtr)(v->axisVal + numAxes);
+
+ return v;
+}
+
+Bool
+InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, Atom *labels,
+ int numMotionEvents, int mode)
+{
+ int i;
+ ValuatorClassPtr valc;
+
+ if (!dev)
+ return FALSE;
+
+ if (numAxes > MAX_VALUATORS)
+ {
+ LogMessage(X_WARNING,
+ "Device '%s' has %d axes, only using first %d.\n",
+ dev->name, numAxes, MAX_VALUATORS);
+ numAxes = MAX_VALUATORS;
+ }
+
+ valc = AllocValuatorClass(NULL, numAxes);
+ if (!valc)
+ return FALSE;
+
+ valc->sourceid = dev->id;
+ valc->motion = NULL;
+ valc->first_motion = 0;
+ valc->last_motion = 0;
+
+ valc->numMotionEvents = numMotionEvents;
+ valc->motionHintWindow = NullWindow;
+
+ if (mode & OutOfProximity)
+ InitProximityClassDeviceStruct(dev);
+
+ dev->valuator = valc;
+
+ AllocateMotionHistory(dev);
+
+ for (i=0; i<numAxes; i++) {
+ InitValuatorAxisStruct(dev, i, labels[i], NO_AXIS_LIMITS, NO_AXIS_LIMITS,
+ 0, 0, 0, mode);
+ valc->axisVal[i]=0;
+ }
+
+ dev->last.numValuators = numAxes;
+
+ if (IsMaster(dev) || /* do not accelerate master or xtest devices */
+ IsXTestDevice(dev, NULL))
+ InitPointerAccelerationScheme(dev, PtrAccelNoOp);
+ else
+ InitPointerAccelerationScheme(dev, PtrAccelDefault);
+ return TRUE;
+}
+
+/* global list of acceleration schemes */
+ValuatorAccelerationRec pointerAccelerationScheme[] = {
+ {PtrAccelNoOp, NULL, NULL, NULL},
+ {PtrAccelPredictable, acceleratePointerPredictable, NULL, AccelerationDefaultCleanup},
+ {PtrAccelLightweight, acceleratePointerLightweight, NULL, NULL},
+ {-1, NULL, NULL, NULL} /* terminator */
+};
+
+/**
+ * install an acceleration scheme. returns TRUE on success, and should not
+ * change anything if unsuccessful.
+ */
+Bool
+InitPointerAccelerationScheme(DeviceIntPtr dev,
+ int scheme)
+{
+ int x, i = -1;
+ void* data = NULL;
+ ValuatorClassPtr val;
+
+ val = dev->valuator;
+
+ if(!val)
+ return FALSE;
+
+ if(IsMaster(dev) && scheme != PtrAccelNoOp)
+ return FALSE;
+
+ for(x = 0; pointerAccelerationScheme[x].number >= 0; x++) {
+ if(pointerAccelerationScheme[x].number == scheme){
+ i = x;
+ break;
+ }
+ }
+
+ if(-1 == i)
+ return FALSE;
+
+ if (val->accelScheme.AccelCleanupProc)
+ val->accelScheme.AccelCleanupProc(dev);
+
+ /* init scheme-specific data */
+ switch(scheme){
+ case PtrAccelPredictable:
+ {
+ DeviceVelocityPtr s;
+ s = malloc(sizeof(DeviceVelocityRec));
+ if(!s)
+ return FALSE;
+ InitVelocityData(s);
+ data = s;
+ break;
+ }
+ default:
+ break;
+ }
+
+ val->accelScheme = pointerAccelerationScheme[i];
+ val->accelScheme.accelData = data;
+
+ /* post-init scheme */
+ switch(scheme){
+ case PtrAccelPredictable:
+ InitializePredictableAccelerationProperties(dev);
+ break;
+
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+Bool
+InitAbsoluteClassDeviceStruct(DeviceIntPtr dev)
+{
+ AbsoluteClassPtr abs;
+
+ abs = malloc(sizeof(AbsoluteClassRec));
+ if (!abs)
+ return FALSE;
+
+ /* we don't do anything sensible with these, but should */
+ abs->min_x = NO_AXIS_LIMITS;
+ abs->min_y = NO_AXIS_LIMITS;
+ abs->max_x = NO_AXIS_LIMITS;
+ abs->max_y = NO_AXIS_LIMITS;
+ abs->flip_x = 0;
+ abs->flip_y = 0;
+ abs->rotation = 0;
+ abs->button_threshold = 0;
+
+ abs->offset_x = 0;
+ abs->offset_y = 0;
+ abs->width = NO_AXIS_LIMITS;
+ abs->height = NO_AXIS_LIMITS;
+ abs->following = 0;
+ abs->screen = 0;
+
+ abs->sourceid = dev->id;
+
+ dev->absolute = abs;
+
+ return TRUE;
+}
+
+Bool
+InitFocusClassDeviceStruct(DeviceIntPtr dev)
+{
+ FocusClassPtr focc;
+
+ focc = malloc(sizeof(FocusClassRec));
+ if (!focc)
+ return FALSE;
+ focc->win = PointerRootWin;
+ focc->revert = None;
+ focc->time = currentTime;
+ focc->trace = (WindowPtr *)NULL;
+ focc->traceSize = 0;
+ focc->traceGood = 0;
+ focc->sourceid = dev->id;
+ dev->focus = focc;
+ return TRUE;
+}
+
+Bool
+InitPtrFeedbackClassDeviceStruct(DeviceIntPtr dev, PtrCtrlProcPtr controlProc)
+{
+ PtrFeedbackPtr feedc;
+
+ feedc = malloc(sizeof(PtrFeedbackClassRec));
+ if (!feedc)
+ return FALSE;
+ feedc->CtrlProc = controlProc;
+ feedc->ctrl = defaultPointerControl;
+ feedc->ctrl.id = 0;
+ if ( (feedc->next = dev->ptrfeed) )
+ feedc->ctrl.id = dev->ptrfeed->ctrl.id + 1;
+ dev->ptrfeed = feedc;
+ (*controlProc)(dev, &feedc->ctrl);
+ return TRUE;
+}
+
+
+static LedCtrl defaultLedControl = {
+ DEFAULT_LEDS, DEFAULT_LEDS_MASK, 0};
+
+static BellCtrl defaultBellControl = {
+ DEFAULT_BELL,
+ DEFAULT_BELL_PITCH,
+ DEFAULT_BELL_DURATION,
+ 0};
+
+static IntegerCtrl defaultIntegerControl = {
+ DEFAULT_INT_RESOLUTION,
+ DEFAULT_INT_MIN_VALUE,
+ DEFAULT_INT_MAX_VALUE,
+ DEFAULT_INT_DISPLAYED,
+ 0};
+
+Bool
+InitStringFeedbackClassDeviceStruct (
+ DeviceIntPtr dev, StringCtrlProcPtr controlProc,
+ int max_symbols, int num_symbols_supported, KeySym *symbols)
+{
+ int i;
+ StringFeedbackPtr feedc;
+
+ feedc = malloc(sizeof(StringFeedbackClassRec));
+ if (!feedc)
+ return FALSE;
+ feedc->CtrlProc = controlProc;
+ feedc->ctrl.num_symbols_supported = num_symbols_supported;
+ feedc->ctrl.num_symbols_displayed = 0;
+ feedc->ctrl.max_symbols = max_symbols;
+ feedc->ctrl.symbols_supported = malloc(sizeof (KeySym) * num_symbols_supported);
+ feedc->ctrl.symbols_displayed = malloc(sizeof (KeySym) * max_symbols);
+ if (!feedc->ctrl.symbols_supported || !feedc->ctrl.symbols_displayed)
+ {
+ free(feedc->ctrl.symbols_supported);
+ free(feedc->ctrl.symbols_displayed);
+ free(feedc);
+ return FALSE;
+ }
+ for (i=0; i<num_symbols_supported; i++)
+ *(feedc->ctrl.symbols_supported+i) = *symbols++;
+ for (i=0; i<max_symbols; i++)
+ *(feedc->ctrl.symbols_displayed+i) = (KeySym) 0;
+ feedc->ctrl.id = 0;
+ if ( (feedc->next = dev->stringfeed) )
+ feedc->ctrl.id = dev->stringfeed->ctrl.id + 1;
+ dev->stringfeed = feedc;
+ (*controlProc)(dev, &feedc->ctrl);
+ return TRUE;
+}
+
+Bool
+InitBellFeedbackClassDeviceStruct (DeviceIntPtr dev, BellProcPtr bellProc,
+ BellCtrlProcPtr controlProc)
+{
+ BellFeedbackPtr feedc;
+
+ feedc = malloc(sizeof(BellFeedbackClassRec));
+ if (!feedc)
+ return FALSE;
+ feedc->CtrlProc = controlProc;
+ feedc->BellProc = bellProc;
+ feedc->ctrl = defaultBellControl;
+ feedc->ctrl.id = 0;
+ if ( (feedc->next = dev->bell) )
+ feedc->ctrl.id = dev->bell->ctrl.id + 1;
+ dev->bell = feedc;
+ (*controlProc)(dev, &feedc->ctrl);
+ return TRUE;
+}
+
+Bool
+InitLedFeedbackClassDeviceStruct (DeviceIntPtr dev, LedCtrlProcPtr controlProc)
+{
+ LedFeedbackPtr feedc;
+
+ feedc = malloc(sizeof(LedFeedbackClassRec));
+ if (!feedc)
+ return FALSE;
+ feedc->CtrlProc = controlProc;
+ feedc->ctrl = defaultLedControl;
+ feedc->ctrl.id = 0;
+ if ( (feedc->next = dev->leds) )
+ feedc->ctrl.id = dev->leds->ctrl.id + 1;
+ feedc->xkb_sli= NULL;
+ dev->leds = feedc;
+ (*controlProc)(dev, &feedc->ctrl);
+ return TRUE;
+}
+
+Bool
+InitIntegerFeedbackClassDeviceStruct (DeviceIntPtr dev, IntegerCtrlProcPtr controlProc)
+{
+ IntegerFeedbackPtr feedc;
+
+ feedc = malloc(sizeof(IntegerFeedbackClassRec));
+ if (!feedc)
+ return FALSE;
+ feedc->CtrlProc = controlProc;
+ feedc->ctrl = defaultIntegerControl;
+ feedc->ctrl.id = 0;
+ if ( (feedc->next = dev->intfeed) )
+ feedc->ctrl.id = dev->intfeed->ctrl.id + 1;
+ dev->intfeed = feedc;
+ (*controlProc)(dev, &feedc->ctrl);
+ return TRUE;
+}
+
+Bool
+InitPointerDeviceStruct(DevicePtr device, CARD8 *map, int numButtons, Atom* btn_labels,
+ PtrCtrlProcPtr controlProc, int numMotionEvents,
+ int numAxes, Atom *axes_labels)
+{
+ DeviceIntPtr dev = (DeviceIntPtr)device;
+
+ return(InitButtonClassDeviceStruct(dev, numButtons, btn_labels, map) &&
+ InitValuatorClassDeviceStruct(dev, numAxes, axes_labels,
+ numMotionEvents, Relative) &&
+ InitPtrFeedbackClassDeviceStruct(dev, controlProc));
+}
+
+/*
+ * Check if the given buffer contains elements between low (inclusive) and
+ * high (inclusive) only.
+ *
+ * @return TRUE if the device map is invalid, FALSE otherwise.
+ */
+Bool
+BadDeviceMap(BYTE *buff, int length, unsigned low, unsigned high, XID *errval)
+{
+ int i;
+
+ for (i = 0; i < length; i++)
+ if (buff[i]) /* only check non-zero elements */
+ {
+ if ((low > buff[i]) || (high < buff[i]))
+ {
+ *errval = buff[i];
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+int
+ProcSetModifierMapping(ClientPtr client)
+{
+ xSetModifierMappingReply rep;
+ int rc;
+ REQUEST(xSetModifierMappingReq);
+ REQUEST_AT_LEAST_SIZE(xSetModifierMappingReq);
+
+ if (client->req_len != ((stuff->numKeyPerModifier << 1) +
+ bytes_to_int32(sizeof(xSetModifierMappingReq))))
+ return BadLength;
+
+ rep.type = X_Reply;
+ rep.length = 0;
+ rep.sequenceNumber = client->sequence;
+
+ rc = change_modmap(client, PickKeyboard(client), (KeyCode *)&stuff[1],
+ stuff->numKeyPerModifier);
+ if (rc == MappingFailed || rc == -1)
+ return BadValue;
+ if (rc != Success && rc != MappingSuccess && rc != MappingFailed &&
+ rc != MappingBusy)
+ return rc;
+
+ rep.success = rc;
+
+ WriteReplyToClient(client, sizeof(xSetModifierMappingReply), &rep);
+ return Success;
+}
+
+int
+ProcGetModifierMapping(ClientPtr client)
+{
+ xGetModifierMappingReply rep;
+ int max_keys_per_mod = 0;
+ KeyCode *modkeymap = NULL;
+ REQUEST_SIZE_MATCH(xReq);
+
+ generate_modkeymap(client, PickKeyboard(client), &modkeymap,
+ &max_keys_per_mod);
+
+ memset(&rep, 0, sizeof(xGetModifierMappingReply));
+ rep.type = X_Reply;
+ rep.numKeyPerModifier = max_keys_per_mod;
+ rep.sequenceNumber = client->sequence;
+ /* length counts 4 byte quantities - there are 8 modifiers 1 byte big */
+ rep.length = max_keys_per_mod << 1;
+
+ WriteReplyToClient(client, sizeof(xGetModifierMappingReply), &rep);
+ (void)WriteToClient(client, max_keys_per_mod * 8, (char *) modkeymap);
+
+ free(modkeymap);
+
+ return Success;
+}
+
+int
+ProcChangeKeyboardMapping(ClientPtr client)
+{
+ REQUEST(xChangeKeyboardMappingReq);
+ unsigned len;
+ KeySymsRec keysyms;
+ DeviceIntPtr pDev, tmp;
+ int rc;
+ REQUEST_AT_LEAST_SIZE(xChangeKeyboardMappingReq);
+
+ len = client->req_len - bytes_to_int32(sizeof(xChangeKeyboardMappingReq));
+ if (len != (stuff->keyCodes * stuff->keySymsPerKeyCode))
+ return BadLength;
+
+ pDev = PickKeyboard(client);
+
+ if ((stuff->firstKeyCode < pDev->key->xkbInfo->desc->min_key_code) ||
+ (stuff->firstKeyCode > pDev->key->xkbInfo->desc->max_key_code)) {
+ client->errorValue = stuff->firstKeyCode;
+ return BadValue;
+
+ }
+ if (((unsigned)(stuff->firstKeyCode + stuff->keyCodes - 1) >
+ pDev->key->xkbInfo->desc->max_key_code) ||
+ (stuff->keySymsPerKeyCode == 0)) {
+ client->errorValue = stuff->keySymsPerKeyCode;
+ return BadValue;
+ }
+
+ keysyms.minKeyCode = stuff->firstKeyCode;
+ keysyms.maxKeyCode = stuff->firstKeyCode + stuff->keyCodes - 1;
+ keysyms.mapWidth = stuff->keySymsPerKeyCode;
+ keysyms.map = (KeySym *) &stuff[1];
+
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess);
+ if (rc != Success)
+ return rc;
+
+ XkbApplyMappingChange(pDev, &keysyms, stuff->firstKeyCode,
+ stuff->keyCodes, NULL, client);
+
+ for (tmp = inputInfo.devices; tmp; tmp = tmp->next) {
+ if (IsMaster(tmp) || tmp->u.master != pDev)
+ continue;
+ if (!tmp->key)
+ continue;
+
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess);
+ if (rc != Success)
+ continue;
+
+ XkbApplyMappingChange(tmp, &keysyms, stuff->firstKeyCode,
+ stuff->keyCodes, NULL, client);
+ }
+
+ return Success;
+}
+
+int
+ProcSetPointerMapping(ClientPtr client)
+{
+ BYTE *map;
+ int ret;
+ int i, j;
+ DeviceIntPtr ptr = PickPointer(client);
+ xSetPointerMappingReply rep;
+ REQUEST(xSetPointerMappingReq);
+ REQUEST_AT_LEAST_SIZE(xSetPointerMappingReq);
+
+ if (client->req_len !=
+ bytes_to_int32(sizeof(xSetPointerMappingReq) + stuff->nElts))
+ return BadLength;
+ rep.type = X_Reply;
+ rep.length = 0;
+ rep.sequenceNumber = client->sequence;
+ rep.success = MappingSuccess;
+ map = (BYTE *)&stuff[1];
+
+ /* So we're bounded here by the number of core buttons. This check
+ * probably wants disabling through XFixes. */
+ /* MPX: With ClientPointer, we can return the right number of buttons.
+ * Let's just hope nobody changed ClientPointer between GetPointerMapping
+ * and SetPointerMapping
+ */
+ if (stuff->nElts != ptr->button->numButtons) {
+ client->errorValue = stuff->nElts;
+ return BadValue;
+ }
+
+ /* Core protocol specs don't allow for duplicate mappings; this check
+ * almost certainly wants disabling through XFixes too. */
+ for (i = 0; i < stuff->nElts; i++) {
+ for (j = i + 1; j < stuff->nElts; j++) {
+ if (map[i] && map[i] == map[j]) {
+ client->errorValue = map[i];
+ return BadValue;
+ }
+ }
+ }
+
+ ret = ApplyPointerMapping(ptr, map, stuff->nElts, client);
+ if (ret == MappingBusy)
+ rep.success = ret;
+ else if (ret == -1)
+ return BadValue;
+ else if (ret != Success)
+ return ret;
+
+ WriteReplyToClient(client, sizeof(xSetPointerMappingReply), &rep);
+ return Success;
+}
+
+int
+ProcGetKeyboardMapping(ClientPtr client)
+{
+ xGetKeyboardMappingReply rep;
+ DeviceIntPtr kbd = PickKeyboard(client);
+ XkbDescPtr xkb;
+ KeySymsPtr syms;
+ int rc;
+ REQUEST(xGetKeyboardMappingReq);
+ REQUEST_SIZE_MATCH(xGetKeyboardMappingReq);
+
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ xkb = kbd->key->xkbInfo->desc;
+
+ if ((stuff->firstKeyCode < xkb->min_key_code) ||
+ (stuff->firstKeyCode > xkb->max_key_code)) {
+ client->errorValue = stuff->firstKeyCode;
+ return BadValue;
+ }
+ if (stuff->firstKeyCode + stuff->count > xkb->max_key_code + 1) {
+ client->errorValue = stuff->count;
+ return BadValue;
+ }
+
+ syms = XkbGetCoreMap(kbd);
+ if (!syms)
+ return BadAlloc;
+
+ memset(&rep, 0, sizeof(xGetKeyboardMappingReply));
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ rep.keySymsPerKeyCode = syms->mapWidth;
+ /* length is a count of 4 byte quantities and KeySyms are 4 bytes */
+ rep.length = syms->mapWidth * stuff->count;
+ WriteReplyToClient(client, sizeof(xGetKeyboardMappingReply), &rep);
+ client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write;
+ WriteSwappedDataToClient(client,
+ syms->mapWidth * stuff->count * sizeof(KeySym),
+ &syms->map[syms->mapWidth * (stuff->firstKeyCode -
+ syms->minKeyCode)]);
+ free(syms->map);
+ free(syms);
+
+ return Success;
+}
+
+int
+ProcGetPointerMapping(ClientPtr client)
+{
+ xGetPointerMappingReply rep;
+ /* Apps may get different values each time they call GetPointerMapping as
+ * the ClientPointer could change. */
+ DeviceIntPtr ptr = PickPointer(client);
+ ButtonClassPtr butc = ptr->button;
+ int rc;
+ REQUEST_SIZE_MATCH(xReq);
+
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ rep.nElts = (butc) ? butc->numButtons : 0;
+ rep.length = ((unsigned)rep.nElts + (4-1))/4;
+ WriteReplyToClient(client, sizeof(xGetPointerMappingReply), &rep);
+ if (butc)
+ WriteToClient(client, (int)rep.nElts, (char *)&butc->map[1]);
+ return Success;
+}
+
+void
+NoteLedState(DeviceIntPtr keybd, int led, Bool on)
+{
+ KeybdCtrl *ctrl = &keybd->kbdfeed->ctrl;
+ if (on)
+ ctrl->leds |= ((Leds)1 << (led - 1));
+ else
+ ctrl->leds &= ~((Leds)1 << (led - 1));
+}
+
+int
+Ones(unsigned long mask) /* HACKMEM 169 */
+{
+ unsigned long y;
+
+ y = (mask >> 1) &033333333333;
+ y = mask - y - ((y >>1) & 033333333333);
+ return (((y + (y >> 3)) & 030707070707) % 077);
+}
+
+static int
+DoChangeKeyboardControl (ClientPtr client, DeviceIntPtr keybd, XID *vlist,
+ BITS32 vmask)
+{
+#define DO_ALL (-1)
+ KeybdCtrl ctrl;
+ int t;
+ int led = DO_ALL;
+ int key = DO_ALL;
+ BITS32 index2;
+ int mask = vmask, i;
+ XkbEventCauseRec cause;
+
+ ctrl = keybd->kbdfeed->ctrl;
+ while (vmask) {
+ index2 = (BITS32) lowbit (vmask);
+ vmask &= ~index2;
+ switch (index2) {
+ case KBKeyClickPercent:
+ t = (INT8)*vlist;
+ vlist++;
+ if (t == -1) {
+ t = defaultKeyboardControl.click;
+ }
+ else if (t < 0 || t > 100) {
+ client->errorValue = t;
+ return BadValue;
+ }
+ ctrl.click = t;
+ break;
+ case KBBellPercent:
+ t = (INT8)*vlist;
+ vlist++;
+ if (t == -1) {
+ t = defaultKeyboardControl.bell;
+ }
+ else if (t < 0 || t > 100) {
+ client->errorValue = t;
+ return BadValue;
+ }
+ ctrl.bell = t;
+ break;
+ case KBBellPitch:
+ t = (INT16)*vlist;
+ vlist++;
+ if (t == -1) {
+ t = defaultKeyboardControl.bell_pitch;
+ }
+ else if (t < 0) {
+ client->errorValue = t;
+ return BadValue;
+ }
+ ctrl.bell_pitch = t;
+ break;
+ case KBBellDuration:
+ t = (INT16)*vlist;
+ vlist++;
+ if (t == -1)
+ t = defaultKeyboardControl.bell_duration;
+ else if (t < 0) {
+ client->errorValue = t;
+ return BadValue;
+ }
+ ctrl.bell_duration = t;
+ break;
+ case KBLed:
+ led = (CARD8)*vlist;
+ vlist++;
+ if (led < 1 || led > 32) {
+ client->errorValue = led;
+ return BadValue;
+ }
+ if (!(mask & KBLedMode))
+ return BadMatch;
+ break;
+ case KBLedMode:
+ t = (CARD8)*vlist;
+ vlist++;
+ if (t == LedModeOff) {
+ if (led == DO_ALL)
+ ctrl.leds = 0x0;
+ else
+ ctrl.leds &= ~(((Leds)(1)) << (led - 1));
+ }
+ else if (t == LedModeOn) {
+ if (led == DO_ALL)
+ ctrl.leds = ~0L;
+ else
+ ctrl.leds |= (((Leds)(1)) << (led - 1));
+ }
+ else {
+ client->errorValue = t;
+ return BadValue;
+ }
+
+ XkbSetCauseCoreReq(&cause,X_ChangeKeyboardControl,client);
+ XkbSetIndicators(keybd,((led == DO_ALL) ? ~0L : (1L<<(led-1))),
+ ctrl.leds, &cause);
+ ctrl.leds = keybd->kbdfeed->ctrl.leds;
+
+ break;
+ case KBKey:
+ key = (KeyCode)*vlist;
+ vlist++;
+ if ((KeyCode)key < keybd->key->xkbInfo->desc->min_key_code ||
+ (KeyCode)key > keybd->key->xkbInfo->desc->max_key_code) {
+ client->errorValue = key;
+ return BadValue;
+ }
+ if (!(mask & KBAutoRepeatMode))
+ return BadMatch;
+ break;
+ case KBAutoRepeatMode:
+ i = (key >> 3);
+ mask = (1 << (key & 7));
+ t = (CARD8)*vlist;
+ vlist++;
+ if (key != DO_ALL)
+ XkbDisableComputedAutoRepeats(keybd,key);
+ if (t == AutoRepeatModeOff) {
+ if (key == DO_ALL)
+ ctrl.autoRepeat = FALSE;
+ else
+ ctrl.autoRepeats[i] &= ~mask;
+ }
+ else if (t == AutoRepeatModeOn) {
+ if (key == DO_ALL)
+ ctrl.autoRepeat = TRUE;
+ else
+ ctrl.autoRepeats[i] |= mask;
+ }
+ else if (t == AutoRepeatModeDefault) {
+ if (key == DO_ALL)
+ ctrl.autoRepeat = defaultKeyboardControl.autoRepeat;
+ else
+ ctrl.autoRepeats[i] =
+ (ctrl.autoRepeats[i] & ~mask) |
+ (defaultKeyboardControl.autoRepeats[i] & mask);
+ }
+ else {
+ client->errorValue = t;
+ return BadValue;
+ }
+ break;
+ default:
+ client->errorValue = mask;
+ return BadValue;
+ }
+ }
+ keybd->kbdfeed->ctrl = ctrl;
+
+ /* The XKB RepeatKeys control and core protocol global autorepeat */
+ /* value are linked */
+ XkbSetRepeatKeys(keybd, key, keybd->kbdfeed->ctrl.autoRepeat);
+
+ return Success;
+
+#undef DO_ALL
+}
+
+/**
+ * Changes kbd control on the ClientPointer and all attached SDs.
+ */
+int
+ProcChangeKeyboardControl (ClientPtr client)
+{
+ XID *vlist;
+ BITS32 vmask;
+ int ret = Success, error = Success;
+ DeviceIntPtr pDev = NULL, keyboard;
+ REQUEST(xChangeKeyboardControlReq);
+
+ REQUEST_AT_LEAST_SIZE(xChangeKeyboardControlReq);
+
+ vmask = stuff->mask;
+ vlist = (XID *)&stuff[1];
+
+ if (client->req_len != (sizeof(xChangeKeyboardControlReq)>>2)+Ones(vmask))
+ return BadLength;
+
+ keyboard = PickKeyboard(client);
+
+ for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
+ if ((pDev == keyboard ||
+ (!IsMaster(pDev) && GetMaster(pDev, MASTER_KEYBOARD) == keyboard))
+ && pDev->kbdfeed && pDev->kbdfeed->CtrlProc) {
+ ret = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess);
+ if (ret != Success)
+ return ret;
+ }
+ }
+
+ for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
+ if ((pDev == keyboard ||
+ (!IsMaster(pDev) && GetMaster(pDev, MASTER_KEYBOARD) == keyboard))
+ && pDev->kbdfeed && pDev->kbdfeed->CtrlProc) {
+ ret = DoChangeKeyboardControl(client, pDev, vlist, vmask);
+ if (ret != Success)
+ error = ret;
+ }
+ }
+
+ return error;
+}
+
+int
+ProcGetKeyboardControl (ClientPtr client)
+{
+ int rc, i;
+ DeviceIntPtr kbd = PickKeyboard(client);
+ KeybdCtrl *ctrl = &kbd->kbdfeed->ctrl;
+ xGetKeyboardControlReply rep;
+ REQUEST_SIZE_MATCH(xReq);
+
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ rep.type = X_Reply;
+ rep.length = 5;
+ rep.sequenceNumber = client->sequence;
+ rep.globalAutoRepeat = ctrl->autoRepeat;
+ rep.keyClickPercent = ctrl->click;
+ rep.bellPercent = ctrl->bell;
+ rep.bellPitch = ctrl->bell_pitch;
+ rep.bellDuration = ctrl->bell_duration;
+ rep.ledMask = ctrl->leds;
+ for (i = 0; i < 32; i++)
+ rep.map[i] = ctrl->autoRepeats[i];
+ WriteReplyToClient(client, sizeof(xGetKeyboardControlReply), &rep);
+ return Success;
+}
+
+int
+ProcBell(ClientPtr client)
+{
+ DeviceIntPtr dev, keybd = PickKeyboard(client);
+ int base = keybd->kbdfeed->ctrl.bell;
+ int newpercent;
+ int rc;
+ REQUEST(xBellReq);
+ REQUEST_SIZE_MATCH(xBellReq);
+
+ if (stuff->percent < -100 || stuff->percent > 100) {
+ client->errorValue = stuff->percent;
+ return BadValue;
+ }
+
+ newpercent = (base * stuff->percent) / 100;
+ if (stuff->percent < 0)
+ newpercent = base + newpercent;
+ else
+ newpercent = base - newpercent + stuff->percent;
+
+ for (dev = inputInfo.devices; dev; dev = dev->next) {
+ if ((dev == keybd ||
+ (!IsMaster(dev) && GetMaster(dev, MASTER_KEYBOARD) == keybd)) &&
+ dev->kbdfeed && dev->kbdfeed->BellProc) {
+
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixBellAccess);
+ if (rc != Success)
+ return rc;
+ XkbHandleBell(FALSE, FALSE, dev, newpercent,
+ &dev->kbdfeed->ctrl, 0, None, NULL, client);
+ }
+ }
+
+ return Success;
+}
+
+int
+ProcChangePointerControl(ClientPtr client)
+{
+ DeviceIntPtr dev, mouse = PickPointer(client);
+ PtrCtrl ctrl; /* might get BadValue part way through */
+ int rc;
+ REQUEST(xChangePointerControlReq);
+ REQUEST_SIZE_MATCH(xChangePointerControlReq);
+
+ ctrl = mouse->ptrfeed->ctrl;
+ if ((stuff->doAccel != xTrue) && (stuff->doAccel != xFalse)) {
+ client->errorValue = stuff->doAccel;
+ return BadValue;
+ }
+ if ((stuff->doThresh != xTrue) && (stuff->doThresh != xFalse)) {
+ client->errorValue = stuff->doThresh;
+ return BadValue;
+ }
+ if (stuff->doAccel) {
+ if (stuff->accelNum == -1) {
+ ctrl.num = defaultPointerControl.num;
+ }
+ else if (stuff->accelNum < 0) {
+ client->errorValue = stuff->accelNum;
+ return BadValue;
+ }
+ else {
+ ctrl.num = stuff->accelNum;
+ }
+
+ if (stuff->accelDenum == -1) {
+ ctrl.den = defaultPointerControl.den;
+ }
+ else if (stuff->accelDenum <= 0) {
+ client->errorValue = stuff->accelDenum;
+ return BadValue;
+ }
+ else {
+ ctrl.den = stuff->accelDenum;
+ }
+ }
+ if (stuff->doThresh) {
+ if (stuff->threshold == -1) {
+ ctrl.threshold = defaultPointerControl.threshold;
+ }
+ else if (stuff->threshold < 0) {
+ client->errorValue = stuff->threshold;
+ return BadValue;
+ }
+ else {
+ ctrl.threshold = stuff->threshold;
+ }
+ }
+
+ for (dev = inputInfo.devices; dev; dev = dev->next) {
+ if ((dev == mouse ||
+ (!IsMaster(dev) && GetMaster(dev, MASTER_POINTER) == mouse)) &&
+ dev->ptrfeed) {
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess);
+ if (rc != Success)
+ return rc;
+ }
+ }
+
+ for (dev = inputInfo.devices; dev; dev = dev->next) {
+ if ((dev == mouse ||
+ (!IsMaster(dev) && GetMaster(dev, MASTER_POINTER) == mouse)) &&
+ dev->ptrfeed) {
+ dev->ptrfeed->ctrl = ctrl;
+ }
+ }
+
+ return Success;
+}
+
+int
+ProcGetPointerControl(ClientPtr client)
+{
+ DeviceIntPtr ptr = PickPointer(client);
+ PtrCtrl *ctrl = &ptr->ptrfeed->ctrl;
+ xGetPointerControlReply rep;
+ int rc;
+ REQUEST_SIZE_MATCH(xReq);
+
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ rep.type = X_Reply;
+ rep.length = 0;
+ rep.sequenceNumber = client->sequence;
+ rep.threshold = ctrl->threshold;
+ rep.accelNumerator = ctrl->num;
+ rep.accelDenominator = ctrl->den;
+ WriteReplyToClient(client, sizeof(xGenericReply), &rep);
+ return Success;
+}
+
+void
+MaybeStopHint(DeviceIntPtr dev, ClientPtr client)
+{
+ GrabPtr grab = dev->deviceGrab.grab;
+
+ if ((grab && SameClient(grab, client) &&
+ ((grab->eventMask & PointerMotionHintMask) ||
+ (grab->ownerEvents &&
+ (EventMaskForClient(dev->valuator->motionHintWindow, client) &
+ PointerMotionHintMask)))) ||
+ (!grab &&
+ (EventMaskForClient(dev->valuator->motionHintWindow, client) &
+ PointerMotionHintMask)))
+ dev->valuator->motionHintWindow = NullWindow;
+}
+
+int
+ProcGetMotionEvents(ClientPtr client)
+{
+ WindowPtr pWin;
+ xTimecoord * coords = (xTimecoord *) NULL;
+ xGetMotionEventsReply rep;
+ int i, count, xmin, xmax, ymin, ymax, rc;
+ unsigned long nEvents;
+ DeviceIntPtr mouse = PickPointer(client);
+ TimeStamp start, stop;
+ REQUEST(xGetMotionEventsReq);
+ REQUEST_SIZE_MATCH(xGetMotionEventsReq);
+
+ rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, mouse, DixReadAccess);
+ if (rc != Success)
+ return rc;
+
+ if (mouse->valuator->motionHintWindow)
+ MaybeStopHint(mouse, client);
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ nEvents = 0;
+ start = ClientTimeToServerTime(stuff->start);
+ stop = ClientTimeToServerTime(stuff->stop);
+ if ((CompareTimeStamps(start, stop) != LATER) &&
+ (CompareTimeStamps(start, currentTime) != LATER) &&
+ mouse->valuator->numMotionEvents)
+ {
+ if (CompareTimeStamps(stop, currentTime) == LATER)
+ stop = currentTime;
+ count = GetMotionHistory(mouse, &coords, start.milliseconds,
+ stop.milliseconds, pWin->drawable.pScreen,
+ TRUE);
+ xmin = pWin->drawable.x - wBorderWidth (pWin);
+ xmax = pWin->drawable.x + (int)pWin->drawable.width +
+ wBorderWidth (pWin);
+ ymin = pWin->drawable.y - wBorderWidth (pWin);
+ ymax = pWin->drawable.y + (int)pWin->drawable.height +
+ wBorderWidth (pWin);
+ for (i = 0; i < count; i++)
+ if ((xmin <= coords[i].x) && (coords[i].x < xmax) &&
+ (ymin <= coords[i].y) && (coords[i].y < ymax))
+ {
+ coords[nEvents].time = coords[i].time;
+ coords[nEvents].x = coords[i].x - pWin->drawable.x;
+ coords[nEvents].y = coords[i].y - pWin->drawable.y;
+ nEvents++;
+ }
+ }
+ rep.length = nEvents * bytes_to_int32(sizeof(xTimecoord));
+ rep.nEvents = nEvents;
+ WriteReplyToClient(client, sizeof(xGetMotionEventsReply), &rep);
+ if (nEvents)
+ {
+ client->pSwapReplyFunc = (ReplySwapPtr) SwapTimeCoordWrite;
+ WriteSwappedDataToClient(client, nEvents * sizeof(xTimecoord),
+ (char *)coords);
+ }
+ free(coords);
+ return Success;
+}
+
+int
+ProcQueryKeymap(ClientPtr client)
+{
+ xQueryKeymapReply rep;
+ int rc, i;
+ DeviceIntPtr keybd = PickKeyboard(client);
+ CARD8 *down = keybd->key->down;
+
+ REQUEST_SIZE_MATCH(xReq);
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ rep.length = 2;
+
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, keybd, DixReadAccess);
+ if (rc != Success && rc != BadAccess)
+ return rc;
+
+ for (i = 0; i<32; i++)
+ rep.map[i] = down[i];
+
+ if (rc == BadAccess)
+ memset(rep.map, 0, 32);
+
+ WriteReplyToClient(client, sizeof(xQueryKeymapReply), &rep);
+
+ return Success;
+}
+
+
+/**
+ * Recalculate the number of buttons for the master device. The number of
+ * buttons on the master device is equal to the number of buttons on the
+ * slave device with the highest number of buttons.
+ */
+static void
+RecalculateMasterButtons(DeviceIntPtr slave)
+{
+ DeviceIntPtr dev, master;
+ int maxbuttons = 0;
+
+ if (!slave->button || IsMaster(slave))
+ return;
+
+ master = GetMaster(slave, MASTER_POINTER);
+ if (!master)
+ return;
+
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ {
+ if (IsMaster(dev) ||
+ dev->u.master != master ||
+ !dev->button)
+ continue;
+
+ maxbuttons = max(maxbuttons, dev->button->numButtons);
+ }
+
+ if (master->button && master->button->numButtons != maxbuttons)
+ {
+ int i;
+ DeviceChangedEvent event;
+
+ memset(&event, 0, sizeof(event));
+
+ master->button->numButtons = maxbuttons;
+
+ event.header = ET_Internal;
+ event.type = ET_DeviceChanged;
+ event.time = GetTimeInMillis();
+ event.deviceid = master->id;
+ event.flags = DEVCHANGE_POINTER_EVENT | DEVCHANGE_DEVICE_CHANGE;
+ event.buttons.num_buttons = maxbuttons;
+ memcpy(&event.buttons.names, master->button->labels, maxbuttons *
+ sizeof(Atom));
+
+ if (master->valuator)
+ {
+ event.num_valuators = master->valuator->numAxes;
+ for (i = 0; i < event.num_valuators; i++)
+ {
+ event.valuators[i].min = master->valuator->axes[i].min_value;
+ event.valuators[i].max = master->valuator->axes[i].max_value;
+ event.valuators[i].resolution = master->valuator->axes[i].resolution;
+ event.valuators[i].mode = master->valuator->axes[i].mode;
+ event.valuators[i].name = master->valuator->axes[i].label;
+ }
+ }
+
+ if (master->key)
+ {
+ event.keys.min_keycode = master->key->xkbInfo->desc->min_key_code;
+ event.keys.max_keycode = master->key->xkbInfo->desc->max_key_code;
+ }
+
+ XISendDeviceChangedEvent(master, master, &event);
+ }
+}
+
+/**
+ * Attach device 'dev' to device 'master'.
+ * Client is set to the client that issued the request, or NULL if it comes
+ * from some internal automatic pairing.
+ *
+ * Master may be NULL to set the device floating.
+ *
+ * We don't allow multi-layer hierarchies right now. You can't attach a slave
+ * to another slave.
+ */
+int
+AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master)
+{
+ ScreenPtr screen;
+ DeviceIntPtr oldmaster;
+ if (!dev || IsMaster(dev))
+ return BadDevice;
+
+ if (master && !IsMaster(master)) /* can't attach to slaves */
+ return BadDevice;
+
+ /* set from floating to floating? */
+ if (!dev->u.master && !master && dev->enabled)
+ return Success;
+
+ /* free the existing sprite. */
+ if (!dev->u.master && dev->spriteInfo->paired == dev)
+ {
+ screen = miPointerGetScreen(dev);
+ screen->DeviceCursorCleanup(dev, screen);
+ free(dev->spriteInfo->sprite);
+ }
+
+ oldmaster = dev->u.master;
+ dev->u.master = master;
+
+ /* If device is set to floating, we need to create a sprite for it,
+ * otherwise things go bad. However, we don't want to render the cursor,
+ * so we reset spriteOwner.
+ * Sprite has to be forced to NULL first, otherwise InitializeSprite won't
+ * alloc new memory but overwrite the previous one.
+ */
+ if (!master)
+ {
+ WindowPtr currentRoot;
+
+ if (dev->spriteInfo->sprite)
+ currentRoot = GetCurrentRootWindow(dev);
+ else /* new device auto-set to floating */
+ currentRoot = screenInfo.screens[0]->root;
+
+ /* we need to init a fake sprite */
+ screen = currentRoot->drawable.pScreen;
+ screen->DeviceCursorInitialize(dev, screen);
+ dev->spriteInfo->sprite = NULL;
+ InitializeSprite(dev, currentRoot);
+ dev->spriteInfo->spriteOwner = FALSE;
+ dev->spriteInfo->paired = dev;
+ } else
+ {
+ dev->spriteInfo->sprite = master->spriteInfo->sprite;
+ dev->spriteInfo->paired = master;
+ dev->spriteInfo->spriteOwner = FALSE;
+
+ RecalculateMasterButtons(master);
+ }
+
+ /* XXX: in theory, the MD should change back to its old, original
+ * classes when the last SD is detached. Thanks to the XTEST devices,
+ * we'll always have an SD attached until the MD is removed.
+ * So let's not worry about that.
+ */
+
+ return Success;
+}
+
+/**
+ * Return the device paired with the given device or NULL.
+ * Returns the device paired with the parent master if the given device is a
+ * slave device.
+ */
+DeviceIntPtr
+GetPairedDevice(DeviceIntPtr dev)
+{
+ if (!IsMaster(dev) && dev->u.master)
+ dev = dev->u.master;
+
+ return dev->spriteInfo->paired;
+}
+
+
+/**
+ * Returns the right master for the type of event needed. If the event is a
+ * keyboard event.
+ * This function may be called with a master device as argument. If so, the
+ * returned master is either the device itself or the paired master device.
+ * If dev is a floating slave device, NULL is returned.
+ *
+ * @type ::MASTER_KEYBOARD or ::MASTER_POINTER
+ */
+DeviceIntPtr
+GetMaster(DeviceIntPtr dev, int which)
+{
+ DeviceIntPtr master;
+
+ if (IsMaster(dev))
+ master = dev;
+ else
+ master = dev->u.master;
+
+ if (master)
+ {
+ if (which == MASTER_KEYBOARD)
+ {
+ if (master->type != MASTER_KEYBOARD)
+ master = GetPairedDevice(master);
+ } else
+ {
+ if (master->type != MASTER_POINTER)
+ master = GetPairedDevice(master);
+ }
+ }
+
+ return master;
+}
+
+/**
+ * Create a new device pair (== one pointer, one keyboard device).
+ * Only allocates the devices, you will need to call ActivateDevice() and
+ * EnableDevice() manually.
+ * Either a master or a slave device can be created depending on
+ * the value for master.
+ */
+int
+AllocDevicePair (ClientPtr client, char* name,
+ DeviceIntPtr* ptr,
+ DeviceIntPtr* keybd,
+ DeviceProc ptr_proc,
+ DeviceProc keybd_proc,
+ Bool master)
+{
+ DeviceIntPtr pointer;
+ DeviceIntPtr keyboard;
+ *ptr = *keybd = NULL;
+
+ pointer = AddInputDevice(client, ptr_proc, TRUE);
+ if (!pointer)
+ return BadAlloc;
+
+ if (asprintf(&pointer->name, "%s pointer", name) == -1) {
+ pointer->name = NULL;
+ RemoveDevice(pointer, FALSE);
+ return BadAlloc;
+ }
+
+ pointer->public.processInputProc = ProcessOtherEvent;
+ pointer->public.realInputProc = ProcessOtherEvent;
+ XkbSetExtension(pointer, ProcessPointerEvent);
+ pointer->deviceGrab.ActivateGrab = ActivatePointerGrab;
+ pointer->deviceGrab.DeactivateGrab = DeactivatePointerGrab;
+ pointer->coreEvents = TRUE;
+ pointer->spriteInfo->spriteOwner = TRUE;
+
+ pointer->u.lastSlave = NULL;
+ pointer->last.slave = NULL;
+ pointer->type = (master) ? MASTER_POINTER : SLAVE;
+
+ keyboard = AddInputDevice(client, keybd_proc, TRUE);
+ if (!keyboard)
+ {
+ RemoveDevice(pointer, FALSE);
+ return BadAlloc;
+ }
+
+ if (asprintf(&keyboard->name, "%s keyboard", name) == -1) {
+ keyboard->name = NULL;
+ RemoveDevice(keyboard, FALSE);
+ RemoveDevice(pointer, FALSE);
+ return BadAlloc;
+ }
+
+ keyboard->public.processInputProc = ProcessOtherEvent;
+ keyboard->public.realInputProc = ProcessOtherEvent;
+ XkbSetExtension(keyboard, ProcessKeyboardEvent);
+ keyboard->deviceGrab.ActivateGrab = ActivateKeyboardGrab;
+ keyboard->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab;
+ keyboard->coreEvents = TRUE;
+ keyboard->spriteInfo->spriteOwner = FALSE;
+
+ keyboard->u.lastSlave = NULL;
+ keyboard->last.slave = NULL;
+ keyboard->type = (master) ? MASTER_KEYBOARD : SLAVE;
+
+ /* The ClassesRec stores the device classes currently not used. */
+ pointer->unused_classes = calloc(1, sizeof(ClassesRec));
+ keyboard->unused_classes = calloc(1, sizeof(ClassesRec));
+
+ *ptr = pointer;
+ *keybd = keyboard;
+
+ return Success;
+}
+
+/**
+ * Return Relative or Absolute for the device.
+ */
+int valuator_get_mode(DeviceIntPtr dev, int axis)
+{
+ return (dev->valuator->axes[axis].mode & DeviceMode);
+}
+
+/**
+ * Set the given mode for the axis. If axis is VALUATOR_MODE_ALL_AXES, then
+ * set the mode for all axes.
+ */
+void valuator_set_mode(DeviceIntPtr dev, int axis, int mode)
+{
+ if (axis != VALUATOR_MODE_ALL_AXES)
+ dev->valuator->axes[axis].mode = mode;
+ else {
+ int i;
+ for (i = 0; i < dev->valuator->numAxes; i++)
+ dev->valuator->axes[i].mode = mode;
+ }
+}
diff --git a/dix/dispatch.c b/dix/dispatch.c
new file mode 100644
index 0000000..7b2132d
--- /dev/null
+++ b/dix/dispatch.c
@@ -0,0 +1,3901 @@
+/************************************************************
+
+Copyright 1987, 1989, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+********************************************************/
+
+/* The panoramix components contained the following notice */
+/*****************************************************************
+
+Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
+BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of Digital Equipment Corporation
+shall not be used in advertising or otherwise to promote the sale, use or other
+dealings in this Software without prior written authorization from Digital
+Equipment Corporation.
+
+******************************************************************/
+
+/* XSERVER_DTRACE additions:
+ * Copyright (c) 2005-2006, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#include <version-config.h>
+#endif
+
+#ifdef PANORAMIX_DEBUG
+#include <stdio.h>
+int ProcInitialConnection();
+#endif
+
+#include "windowstr.h"
+#include <X11/fonts/fontstruct.h>
+#include "dixfontstr.h"
+#include "gcstruct.h"
+#include "selection.h"
+#include "colormapst.h"
+#include "cursorstr.h"
+#include "scrnintstr.h"
+#include "opaque.h"
+#include "input.h"
+#include "servermd.h"
+#include "extnsionst.h"
+#include "dixfont.h"
+#include "dispatch.h"
+#include "swaprep.h"
+#include "swapreq.h"
+#include "privates.h"
+#include "xace.h"
+#include "inputstr.h"
+#include "xkbsrv.h"
+#include "site.h"
+
+#ifdef XSERVER_DTRACE
+#include "registry.h"
+#include <sys/types.h>
+typedef const char *string;
+#include "Xserver-dtrace.h"
+#endif
+
+#define mskcnt ((MAXCLIENTS + 31) / 32)
+#define BITMASK(i) (1U << ((i) & 31))
+#define MASKIDX(i) ((i) >> 5)
+#define MASKWORD(buf, i) buf[MASKIDX(i)]
+#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i)
+#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i)
+#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i))
+
+xConnSetupPrefix connSetupPrefix;
+
+PaddingInfo PixmapWidthPaddingInfo[33];
+
+static ClientPtr grabClient;
+#define GrabNone 0
+#define GrabActive 1
+#define GrabKickout 2
+static int grabState = GrabNone;
+static long grabWaiters[mskcnt];
+CallbackListPtr ServerGrabCallback = NULL;
+HWEventQueuePtr checkForInput[2];
+int connBlockScreenStart;
+
+static void KillAllClients(void);
+
+static int nextFreeClientID; /* always MIN free client ID */
+
+static int nClients; /* number of authorized clients */
+
+CallbackListPtr ClientStateCallback;
+
+/* dispatchException & isItTimeToYield must be declared volatile since they
+ * are modified by signal handlers - otherwise optimizer may assume it doesn't
+ * need to actually check value in memory when used and may miss changes from
+ * signal handlers.
+ */
+volatile char dispatchException = 0;
+volatile char isItTimeToYield;
+
+#define SAME_SCREENS(a, b) (\
+ (a.pScreen == b.pScreen))
+
+void
+SetInputCheck(HWEventQueuePtr c0, HWEventQueuePtr c1)
+{
+ checkForInput[0] = c0;
+ checkForInput[1] = c1;
+}
+
+void
+UpdateCurrentTime(void)
+{
+ TimeStamp systime;
+
+ /* To avoid time running backwards, we must call GetTimeInMillis before
+ * calling ProcessInputEvents.
+ */
+ systime.months = currentTime.months;
+ systime.milliseconds = GetTimeInMillis();
+ if (systime.milliseconds < currentTime.milliseconds)
+ systime.months++;
+ if (*checkForInput[0] != *checkForInput[1])
+ ProcessInputEvents();
+ if (CompareTimeStamps(systime, currentTime) == LATER)
+ currentTime = systime;
+}
+
+/* Like UpdateCurrentTime, but can't call ProcessInputEvents */
+void
+UpdateCurrentTimeIf(void)
+{
+ TimeStamp systime;
+
+ systime.months = currentTime.months;
+ systime.milliseconds = GetTimeInMillis();
+ if (systime.milliseconds < currentTime.milliseconds)
+ systime.months++;
+ if (*checkForInput[0] == *checkForInput[1])
+ currentTime = systime;
+}
+
+
+#undef SMART_DEBUG
+
+#define SMART_SCHEDULE_DEFAULT_INTERVAL 20 /* ms */
+#define SMART_SCHEDULE_MAX_SLICE 200 /* ms */
+
+Bool SmartScheduleDisable = FALSE;
+long SmartScheduleSlice = SMART_SCHEDULE_DEFAULT_INTERVAL;
+long SmartScheduleInterval = SMART_SCHEDULE_DEFAULT_INTERVAL;
+long SmartScheduleMaxSlice = SMART_SCHEDULE_MAX_SLICE;
+long SmartScheduleTime;
+int SmartScheduleLatencyLimited = 0;
+static ClientPtr SmartLastClient;
+static int SmartLastIndex[SMART_MAX_PRIORITY-SMART_MIN_PRIORITY+1];
+
+#ifdef SMART_DEBUG
+long SmartLastPrint;
+#endif
+
+void Dispatch(void);
+
+static int
+SmartScheduleClient (int *clientReady, int nready)
+{
+ ClientPtr pClient;
+ int i;
+ int client;
+ int bestPrio, best = 0;
+ int bestRobin, robin;
+ long now = SmartScheduleTime;
+ long idle;
+
+ bestPrio = -0x7fffffff;
+ bestRobin = 0;
+ idle = 2 * SmartScheduleSlice;
+ for (i = 0; i < nready; i++)
+ {
+ client = clientReady[i];
+ pClient = clients[client];
+ /* Praise clients which are idle */
+ if ((now - pClient->smart_check_tick) >= idle)
+ {
+ if (pClient->smart_priority < 0)
+ pClient->smart_priority++;
+ }
+ pClient->smart_check_tick = now;
+
+ /* check priority to select best client */
+ robin = (pClient->index - SmartLastIndex[pClient->smart_priority-SMART_MIN_PRIORITY]) & 0xff;
+ if (pClient->smart_priority > bestPrio ||
+ (pClient->smart_priority == bestPrio && robin > bestRobin))
+ {
+ bestPrio = pClient->smart_priority;
+ bestRobin = robin;
+ best = client;
+ }
+#ifdef SMART_DEBUG
+ if ((now - SmartLastPrint) >= 5000)
+ fprintf (stderr, " %2d: %3d", client, pClient->smart_priority);
+#endif
+ }
+#ifdef SMART_DEBUG
+ if ((now - SmartLastPrint) >= 5000)
+ {
+ fprintf (stderr, " use %2d\n", best);
+ SmartLastPrint = now;
+ }
+#endif
+ pClient = clients[best];
+ SmartLastIndex[bestPrio-SMART_MIN_PRIORITY] = pClient->index;
+ /*
+ * Set current client pointer
+ */
+ if (SmartLastClient != pClient)
+ {
+ pClient->smart_start_tick = now;
+ SmartLastClient = pClient;
+ }
+ /*
+ * Adjust slice
+ */
+ if (nready == 1 && SmartScheduleLatencyLimited == 0)
+ {
+ /*
+ * If it's been a long time since another client
+ * has run, bump the slice up to get maximal
+ * performance from a single client
+ */
+ if ((now - pClient->smart_start_tick) > 1000 &&
+ SmartScheduleSlice < SmartScheduleMaxSlice)
+ {
+ SmartScheduleSlice += SmartScheduleInterval;
+ }
+ }
+ else
+ {
+ SmartScheduleSlice = SmartScheduleInterval;
+ }
+ return best;
+}
+
+void
+EnableLimitedSchedulingLatency(void)
+{
+ ++SmartScheduleLatencyLimited;
+ SmartScheduleSlice = SmartScheduleInterval;
+}
+
+void
+DisableLimitedSchedulingLatency(void)
+{
+ --SmartScheduleLatencyLimited;
+
+ /* protect against bugs */
+ if (SmartScheduleLatencyLimited < 0)
+ SmartScheduleLatencyLimited = 0;
+}
+
+#define MAJOROP ((xReq *)client->requestBuffer)->reqType
+
+void
+Dispatch(void)
+{
+ int *clientReady; /* array of request ready clients */
+ int result;
+ ClientPtr client;
+ int nready;
+ HWEventQueuePtr* icheck = checkForInput;
+ long start_tick;
+
+ nextFreeClientID = 1;
+ nClients = 0;
+
+ clientReady = malloc(sizeof(int) * MaxClients);
+ if (!clientReady)
+ return;
+
+ SmartScheduleSlice = SmartScheduleInterval;
+ while (!dispatchException)
+ {
+ if (*icheck[0] != *icheck[1])
+ {
+ ProcessInputEvents();
+ FlushIfCriticalOutputPending();
+ }
+
+ nready = WaitForSomething(clientReady);
+
+ if (nready && !SmartScheduleDisable)
+ {
+ clientReady[0] = SmartScheduleClient (clientReady, nready);
+ nready = 1;
+ }
+ /*****************
+ * Handle events in round robin fashion, doing input between
+ * each round
+ *****************/
+
+ while (!dispatchException && (--nready >= 0))
+ {
+ client = clients[clientReady[nready]];
+ if (! client)
+ {
+ /* KillClient can cause this to happen */
+ continue;
+ }
+ /* GrabServer activation can cause this to be true */
+ if (grabState == GrabKickout)
+ {
+ grabState = GrabActive;
+ break;
+ }
+ isItTimeToYield = FALSE;
+
+ start_tick = SmartScheduleTime;
+ while (!isItTimeToYield)
+ {
+ if (*icheck[0] != *icheck[1])
+ ProcessInputEvents();
+
+ FlushIfCriticalOutputPending();
+ if (!SmartScheduleDisable &&
+ (SmartScheduleTime - start_tick) >= SmartScheduleSlice)
+ {
+ /* Penalize clients which consume ticks */
+ if (client->smart_priority > SMART_MIN_PRIORITY)
+ client->smart_priority--;
+ break;
+ }
+ /* now, finally, deal with client requests */
+
+ result = ReadRequestFromClient(client);
+ if (result <= 0)
+ {
+ if (result < 0)
+ CloseDownClient(client);
+ break;
+ }
+
+ client->sequence++;
+#ifdef XSERVER_DTRACE
+ XSERVER_REQUEST_START(LookupMajorName(MAJOROP), MAJOROP,
+ ((xReq *)client->requestBuffer)->length,
+ client->index, client->requestBuffer);
+#endif
+ if (result > (maxBigRequestSize << 2))
+ result = BadLength;
+ else {
+ result = XaceHookDispatch(client, MAJOROP);
+ if (result == Success)
+ result = (* client->requestVector[MAJOROP])(client);
+ XaceHookAuditEnd(client, result);
+ }
+#ifdef XSERVER_DTRACE
+ XSERVER_REQUEST_DONE(LookupMajorName(MAJOROP), MAJOROP,
+ client->sequence, client->index, result);
+#endif
+
+ if (client->noClientException != Success)
+ {
+ CloseDownClient(client);
+ break;
+ }
+ else if (result != Success)
+ {
+ SendErrorToClient(client, MAJOROP,
+ MinorOpcodeOfRequest(client),
+ client->errorValue, result);
+ break;
+ }
+ }
+ FlushAllOutput();
+ client = clients[clientReady[nready]];
+ if (client)
+ client->smart_stop_tick = SmartScheduleTime;
+ }
+ dispatchException &= ~DE_PRIORITYCHANGE;
+ }
+#if defined(DDXBEFORERESET)
+ ddxBeforeReset ();
+#endif
+ KillAllClients();
+ free(clientReady);
+ dispatchException &= ~DE_RESET;
+ SmartScheduleLatencyLimited = 0;
+}
+
+#undef MAJOROP
+
+static int VendorRelease = VENDOR_RELEASE;
+static char *VendorString = VENDOR_NAME;
+
+static const int padlength[4] = {0, 3, 2, 1};
+
+void
+SetVendorRelease(int release)
+{
+ VendorRelease = release;
+}
+
+void
+SetVendorString(char *string)
+{
+ VendorString = string;
+}
+
+Bool
+CreateConnectionBlock(void)
+{
+ xConnSetup setup;
+ xWindowRoot root;
+ xDepth depth;
+ xVisualType visual;
+ xPixmapFormat format;
+ unsigned long vid;
+ int i, j, k,
+ lenofblock,
+ sizesofar = 0;
+ char *pBuf;
+
+
+ memset(&setup, 0, sizeof(xConnSetup));
+ /* Leave off the ridBase and ridMask, these must be sent with
+ connection */
+
+ setup.release = VendorRelease;
+ /*
+ * per-server image and bitmap parameters are defined in Xmd.h
+ */
+ setup.imageByteOrder = screenInfo.imageByteOrder;
+
+ setup.bitmapScanlineUnit = screenInfo.bitmapScanlineUnit;
+ setup.bitmapScanlinePad = screenInfo.bitmapScanlinePad;
+
+ setup.bitmapBitOrder = screenInfo.bitmapBitOrder;
+ setup.motionBufferSize = NumMotionEvents();
+ setup.numRoots = screenInfo.numScreens;
+ setup.nbytesVendor = strlen(VendorString);
+ setup.numFormats = screenInfo.numPixmapFormats;
+ setup.maxRequestSize = MAX_REQUEST_SIZE;
+ QueryMinMaxKeyCodes(&setup.minKeyCode, &setup.maxKeyCode);
+
+ lenofblock = sizeof(xConnSetup) +
+ pad_to_int32(setup.nbytesVendor) +
+ (setup.numFormats * sizeof(xPixmapFormat)) +
+ (setup.numRoots * sizeof(xWindowRoot));
+ ConnectionInfo = malloc(lenofblock);
+ if (!ConnectionInfo)
+ return FALSE;
+
+ memmove(ConnectionInfo, (char *)&setup, sizeof(xConnSetup));
+ sizesofar = sizeof(xConnSetup);
+ pBuf = ConnectionInfo + sizeof(xConnSetup);
+
+ memmove(pBuf, VendorString, (int)setup.nbytesVendor);
+ sizesofar += setup.nbytesVendor;
+ pBuf += setup.nbytesVendor;
+ i = padlength[setup.nbytesVendor & 3];
+ sizesofar += i;
+ while (--i >= 0)
+ *pBuf++ = 0;
+
+ memset(&format, 0, sizeof(xPixmapFormat));
+ for (i=0; i<screenInfo.numPixmapFormats; i++)
+ {
+ format.depth = screenInfo.formats[i].depth;
+ format.bitsPerPixel = screenInfo.formats[i].bitsPerPixel;
+ format.scanLinePad = screenInfo.formats[i].scanlinePad;
+ memmove(pBuf, (char *)&format, sizeof(xPixmapFormat));
+ pBuf += sizeof(xPixmapFormat);
+ sizesofar += sizeof(xPixmapFormat);
+ }
+
+ connBlockScreenStart = sizesofar;
+ memset(&depth, 0, sizeof(xDepth));
+ memset(&visual, 0, sizeof(xVisualType));
+ for (i=0; i<screenInfo.numScreens; i++)
+ {
+ ScreenPtr pScreen;
+ DepthPtr pDepth;
+ VisualPtr pVisual;
+
+ pScreen = screenInfo.screens[i];
+ root.windowId = pScreen->root->drawable.id;
+ root.defaultColormap = pScreen->defColormap;
+ root.whitePixel = pScreen->whitePixel;
+ root.blackPixel = pScreen->blackPixel;
+ root.currentInputMask = 0; /* filled in when sent */
+ root.pixWidth = pScreen->width;
+ root.pixHeight = pScreen->height;
+ root.mmWidth = pScreen->mmWidth;
+ root.mmHeight = pScreen->mmHeight;
+ root.minInstalledMaps = pScreen->minInstalledCmaps;
+ root.maxInstalledMaps = pScreen->maxInstalledCmaps;
+ root.rootVisualID = pScreen->rootVisual;
+ root.backingStore = pScreen->backingStoreSupport;
+ root.saveUnders = FALSE;
+ root.rootDepth = pScreen->rootDepth;
+ root.nDepths = pScreen->numDepths;
+ memmove(pBuf, (char *)&root, sizeof(xWindowRoot));
+ sizesofar += sizeof(xWindowRoot);
+ pBuf += sizeof(xWindowRoot);
+
+ pDepth = pScreen->allowedDepths;
+ for(j = 0; j < pScreen->numDepths; j++, pDepth++)
+ {
+ lenofblock += sizeof(xDepth) +
+ (pDepth->numVids * sizeof(xVisualType));
+ pBuf = (char *)realloc(ConnectionInfo, lenofblock);
+ if (!pBuf)
+ {
+ free(ConnectionInfo);
+ return FALSE;
+ }
+ ConnectionInfo = pBuf;
+ pBuf += sizesofar;
+ depth.depth = pDepth->depth;
+ depth.nVisuals = pDepth->numVids;
+ memmove(pBuf, (char *)&depth, sizeof(xDepth));
+ pBuf += sizeof(xDepth);
+ sizesofar += sizeof(xDepth);
+ for(k = 0; k < pDepth->numVids; k++)
+ {
+ vid = pDepth->vids[k];
+ for (pVisual = pScreen->visuals;
+ pVisual->vid != vid;
+ pVisual++)
+ ;
+ visual.visualID = vid;
+ visual.class = pVisual->class;
+ visual.bitsPerRGB = pVisual->bitsPerRGBValue;
+ visual.colormapEntries = pVisual->ColormapEntries;
+ visual.redMask = pVisual->redMask;
+ visual.greenMask = pVisual->greenMask;
+ visual.blueMask = pVisual->blueMask;
+ memmove(pBuf, (char *)&visual, sizeof(xVisualType));
+ pBuf += sizeof(xVisualType);
+ sizesofar += sizeof(xVisualType);
+ }
+ }
+ }
+ connSetupPrefix.success = xTrue;
+ connSetupPrefix.length = lenofblock/4;
+ connSetupPrefix.majorVersion = X_PROTOCOL;
+ connSetupPrefix.minorVersion = X_PROTOCOL_REVISION;
+ return TRUE;
+}
+
+
+int
+ProcBadRequest(ClientPtr client)
+{
+ return BadRequest;
+}
+
+int
+ProcCreateWindow(ClientPtr client)
+{
+ WindowPtr pParent, pWin;
+ REQUEST(xCreateWindowReq);
+ int len, rc;
+
+ REQUEST_AT_LEAST_SIZE(xCreateWindowReq);
+
+ LEGAL_NEW_RESOURCE(stuff->wid, client);
+ rc = dixLookupWindow(&pParent, stuff->parent, client, DixAddAccess);
+ if (rc != Success)
+ return rc;
+ len = client->req_len - bytes_to_int32(sizeof(xCreateWindowReq));
+ if (Ones(stuff->mask) != len)
+ return BadLength;
+ if (!stuff->width || !stuff->height)
+ {
+ client->errorValue = 0;
+ return BadValue;
+ }
+ pWin = CreateWindow(stuff->wid, pParent, stuff->x,
+ stuff->y, stuff->width, stuff->height,
+ stuff->borderWidth, stuff->class,
+ stuff->mask, (XID *) &stuff[1],
+ (int)stuff->depth,
+ client, stuff->visual, &rc);
+ if (pWin)
+ {
+ Mask mask = pWin->eventMask;
+
+ pWin->eventMask = 0; /* subterfuge in case AddResource fails */
+ if (!AddResource(stuff->wid, RT_WINDOW, (pointer)pWin))
+ return BadAlloc;
+ pWin->eventMask = mask;
+ }
+ return rc;
+}
+
+int
+ProcChangeWindowAttributes(ClientPtr client)
+{
+ WindowPtr pWin;
+ REQUEST(xChangeWindowAttributesReq);
+ int len, rc;
+ Mask access_mode = 0;
+
+ REQUEST_AT_LEAST_SIZE(xChangeWindowAttributesReq);
+ access_mode |= (stuff->valueMask & CWEventMask) ? DixReceiveAccess : 0;
+ access_mode |= (stuff->valueMask & ~CWEventMask) ? DixSetAttrAccess : 0;
+ rc = dixLookupWindow(&pWin, stuff->window, client, access_mode);
+ if (rc != Success)
+ return rc;
+ len = client->req_len - bytes_to_int32(sizeof(xChangeWindowAttributesReq));
+ if (len != Ones(stuff->valueMask))
+ return BadLength;
+ return ChangeWindowAttributes(pWin,
+ stuff->valueMask,
+ (XID *) &stuff[1],
+ client);
+}
+
+int
+ProcGetWindowAttributes(ClientPtr client)
+{
+ WindowPtr pWin;
+ REQUEST(xResourceReq);
+ xGetWindowAttributesReply wa;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xResourceReq);
+ rc = dixLookupWindow(&pWin, stuff->id, client, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+ memset(&wa, 0, sizeof(xGetWindowAttributesReply));
+ GetWindowAttributes(pWin, client, &wa);
+ WriteReplyToClient(client, sizeof(xGetWindowAttributesReply), &wa);
+ return Success;
+}
+
+int
+ProcDestroyWindow(ClientPtr client)
+{
+ WindowPtr pWin;
+ REQUEST(xResourceReq);
+ int rc;
+
+ REQUEST_SIZE_MATCH(xResourceReq);
+ rc = dixLookupWindow(&pWin, stuff->id, client, DixDestroyAccess);
+ if (rc != Success)
+ return rc;
+ if (pWin->parent) {
+ rc = dixLookupWindow(&pWin, pWin->parent->drawable.id, client,
+ DixRemoveAccess);
+ if (rc != Success)
+ return rc;
+ FreeResource(stuff->id, RT_NONE);
+ }
+ return Success;
+}
+
+int
+ProcDestroySubwindows(ClientPtr client)
+{
+ WindowPtr pWin;
+ REQUEST(xResourceReq);
+ int rc;
+
+ REQUEST_SIZE_MATCH(xResourceReq);
+ rc = dixLookupWindow(&pWin, stuff->id, client, DixRemoveAccess);
+ if (rc != Success)
+ return rc;
+ DestroySubwindows(pWin, client);
+ return Success;
+}
+
+int
+ProcChangeSaveSet(ClientPtr client)
+{
+ WindowPtr pWin;
+ REQUEST(xChangeSaveSetReq);
+ int rc;
+
+ REQUEST_SIZE_MATCH(xChangeSaveSetReq);
+ rc = dixLookupWindow(&pWin, stuff->window, client, DixManageAccess);
+ if (rc != Success)
+ return rc;
+ if (client->clientAsMask == (CLIENT_BITS(pWin->drawable.id)))
+ return BadMatch;
+ if ((stuff->mode == SetModeInsert) || (stuff->mode == SetModeDelete))
+ return AlterSaveSetForClient(client, pWin, stuff->mode, FALSE, TRUE);
+ client->errorValue = stuff->mode;
+ return BadValue;
+}
+
+int
+ProcReparentWindow(ClientPtr client)
+{
+ WindowPtr pWin, pParent;
+ REQUEST(xReparentWindowReq);
+ int rc;
+
+ REQUEST_SIZE_MATCH(xReparentWindowReq);
+ rc = dixLookupWindow(&pWin, stuff->window, client, DixManageAccess);
+ if (rc != Success)
+ return rc;
+ rc = dixLookupWindow(&pParent, stuff->parent, client, DixAddAccess);
+ if (rc != Success)
+ return rc;
+ if (!SAME_SCREENS(pWin->drawable, pParent->drawable))
+ return BadMatch;
+ if ((pWin->backgroundState == ParentRelative) &&
+ (pParent->drawable.depth != pWin->drawable.depth))
+ return BadMatch;
+ if ((pWin->drawable.class != InputOnly) &&
+ (pParent->drawable.class == InputOnly))
+ return BadMatch;
+ return ReparentWindow(pWin, pParent,
+ (short)stuff->x, (short)stuff->y, client);
+}
+
+int
+ProcMapWindow(ClientPtr client)
+{
+ WindowPtr pWin;
+ REQUEST(xResourceReq);
+ int rc;
+
+ REQUEST_SIZE_MATCH(xResourceReq);
+ rc = dixLookupWindow(&pWin, stuff->id, client, DixShowAccess);
+ if (rc != Success)
+ return rc;
+ MapWindow(pWin, client);
+ /* update cache to say it is mapped */
+ return Success;
+}
+
+int
+ProcMapSubwindows(ClientPtr client)
+{
+ WindowPtr pWin;
+ REQUEST(xResourceReq);
+ int rc;
+
+ REQUEST_SIZE_MATCH(xResourceReq);
+ rc = dixLookupWindow(&pWin, stuff->id, client, DixListAccess);
+ if (rc != Success)
+ return rc;
+ MapSubwindows(pWin, client);
+ /* update cache to say it is mapped */
+ return Success;
+}
+
+int
+ProcUnmapWindow(ClientPtr client)
+{
+ WindowPtr pWin;
+ REQUEST(xResourceReq);
+ int rc;
+
+ REQUEST_SIZE_MATCH(xResourceReq);
+ rc = dixLookupWindow(&pWin, stuff->id, client, DixHideAccess);
+ if (rc != Success)
+ return rc;
+ UnmapWindow(pWin, FALSE);
+ /* update cache to say it is mapped */
+ return Success;
+}
+
+int
+ProcUnmapSubwindows(ClientPtr client)
+{
+ WindowPtr pWin;
+ REQUEST(xResourceReq);
+ int rc;
+
+ REQUEST_SIZE_MATCH(xResourceReq);
+ rc = dixLookupWindow(&pWin, stuff->id, client, DixListAccess);
+ if (rc != Success)
+ return rc;
+ UnmapSubwindows(pWin);
+ return Success;
+}
+
+int
+ProcConfigureWindow(ClientPtr client)
+{
+ WindowPtr pWin;
+ REQUEST(xConfigureWindowReq);
+ int len, rc;
+
+ REQUEST_AT_LEAST_SIZE(xConfigureWindowReq);
+ rc = dixLookupWindow(&pWin, stuff->window, client,
+ DixManageAccess|DixSetAttrAccess);
+ if (rc != Success)
+ return rc;
+ len = client->req_len - bytes_to_int32(sizeof(xConfigureWindowReq));
+ if (Ones((Mask)stuff->mask) != len)
+ return BadLength;
+ return ConfigureWindow(pWin, (Mask)stuff->mask, (XID *) &stuff[1], client);
+}
+
+int
+ProcCirculateWindow(ClientPtr client)
+{
+ WindowPtr pWin;
+ REQUEST(xCirculateWindowReq);
+ int rc;
+
+ REQUEST_SIZE_MATCH(xCirculateWindowReq);
+ if ((stuff->direction != RaiseLowest) &&
+ (stuff->direction != LowerHighest))
+ {
+ client->errorValue = stuff->direction;
+ return BadValue;
+ }
+ rc = dixLookupWindow(&pWin, stuff->window, client, DixManageAccess);
+ if (rc != Success)
+ return rc;
+ CirculateWindow(pWin, (int)stuff->direction, client);
+ return Success;
+}
+
+static int
+GetGeometry(ClientPtr client, xGetGeometryReply *rep)
+{
+ DrawablePtr pDraw;
+ int rc;
+ REQUEST(xResourceReq);
+ REQUEST_SIZE_MATCH(xResourceReq);
+
+ rc = dixLookupDrawable(&pDraw, stuff->id, client, M_ANY, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ rep->type = X_Reply;
+ rep->length = 0;
+ rep->sequenceNumber = client->sequence;
+ rep->root = pDraw->pScreen->root->drawable.id;
+ rep->depth = pDraw->depth;
+ rep->width = pDraw->width;
+ rep->height = pDraw->height;
+
+ if (WindowDrawable(pDraw->type))
+ {
+ WindowPtr pWin = (WindowPtr)pDraw;
+ rep->x = pWin->origin.x - wBorderWidth (pWin);
+ rep->y = pWin->origin.y - wBorderWidth (pWin);
+ rep->borderWidth = pWin->borderWidth;
+ }
+ else /* DRAWABLE_PIXMAP */
+ {
+ rep->x = rep->y = rep->borderWidth = 0;
+ }
+
+ return Success;
+}
+
+
+int
+ProcGetGeometry(ClientPtr client)
+{
+ xGetGeometryReply rep;
+ int status;
+
+ memset(&rep, 0, sizeof(xGetGeometryReply));
+ if ((status = GetGeometry(client, &rep)) != Success)
+ return status;
+
+ WriteReplyToClient(client, sizeof(xGetGeometryReply), &rep);
+ return Success;
+}
+
+
+int
+ProcQueryTree(ClientPtr client)
+{
+ xQueryTreeReply reply;
+ int rc, numChildren = 0;
+ WindowPtr pChild, pWin, pHead;
+ Window *childIDs = (Window *)NULL;
+ REQUEST(xResourceReq);
+
+ REQUEST_SIZE_MATCH(xResourceReq);
+ rc = dixLookupWindow(&pWin, stuff->id, client, DixListAccess);
+ if (rc != Success)
+ return rc;
+ memset(&reply, 0, sizeof(xQueryTreeReply));
+ reply.type = X_Reply;
+ reply.root = pWin->drawable.pScreen->root->drawable.id;
+ reply.sequenceNumber = client->sequence;
+ if (pWin->parent)
+ reply.parent = pWin->parent->drawable.id;
+ else
+ reply.parent = (Window)None;
+ pHead = RealChildHead(pWin);
+ for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib)
+ numChildren++;
+ if (numChildren)
+ {
+ int curChild = 0;
+
+ childIDs = malloc(numChildren * sizeof(Window));
+ if (!childIDs)
+ return BadAlloc;
+ for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib)
+ childIDs[curChild++] = pChild->drawable.id;
+ }
+
+ reply.nChildren = numChildren;
+ reply.length = bytes_to_int32(numChildren * sizeof(Window));
+
+ WriteReplyToClient(client, sizeof(xQueryTreeReply), &reply);
+ if (numChildren)
+ {
+ client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
+ WriteSwappedDataToClient(client, numChildren * sizeof(Window), childIDs);
+ free(childIDs);
+ }
+
+ return Success;
+}
+
+int
+ProcInternAtom(ClientPtr client)
+{
+ Atom atom;
+ char *tchar;
+ REQUEST(xInternAtomReq);
+
+ REQUEST_FIXED_SIZE(xInternAtomReq, stuff->nbytes);
+ if ((stuff->onlyIfExists != xTrue) && (stuff->onlyIfExists != xFalse))
+ {
+ client->errorValue = stuff->onlyIfExists;
+ return BadValue;
+ }
+ tchar = (char *) &stuff[1];
+ atom = MakeAtom(tchar, stuff->nbytes, !stuff->onlyIfExists);
+ if (atom != BAD_RESOURCE)
+ {
+ xInternAtomReply reply;
+ memset(&reply, 0, sizeof(xInternAtomReply));
+ reply.type = X_Reply;
+ reply.length = 0;
+ reply.sequenceNumber = client->sequence;
+ reply.atom = atom;
+ WriteReplyToClient(client, sizeof(xInternAtomReply), &reply);
+ return Success;
+ }
+ else
+ return BadAlloc;
+}
+
+int
+ProcGetAtomName(ClientPtr client)
+{
+ const char *str;
+ xGetAtomNameReply reply;
+ int len;
+ REQUEST(xResourceReq);
+
+ REQUEST_SIZE_MATCH(xResourceReq);
+ if ( (str = NameForAtom(stuff->id)) )
+ {
+ len = strlen(str);
+ memset(&reply, 0, sizeof(xGetAtomNameReply));
+ reply.type = X_Reply;
+ reply.length = bytes_to_int32(len);
+ reply.sequenceNumber = client->sequence;
+ reply.nameLength = len;
+ WriteReplyToClient(client, sizeof(xGetAtomNameReply), &reply);
+ (void)WriteToClient(client, len, str);
+ return Success;
+ }
+ else
+ {
+ client->errorValue = stuff->id;
+ return BadAtom;
+ }
+}
+
+int
+ProcGrabServer(ClientPtr client)
+{
+ int rc;
+ REQUEST_SIZE_MATCH(xReq);
+ if (grabState != GrabNone && client != grabClient)
+ {
+ ResetCurrentRequest(client);
+ client->sequence--;
+ BITSET(grabWaiters, client->index);
+ IgnoreClient(client);
+ return Success;
+ }
+ rc = OnlyListenToOneClient(client);
+ if (rc != Success)
+ return rc;
+ grabState = GrabKickout;
+ grabClient = client;
+
+ if (ServerGrabCallback)
+ {
+ ServerGrabInfoRec grabinfo;
+ grabinfo.client = client;
+ grabinfo.grabstate = SERVER_GRABBED;
+ CallCallbacks(&ServerGrabCallback, (pointer)&grabinfo);
+ }
+
+ return Success;
+}
+
+static void
+UngrabServer(ClientPtr client)
+{
+ int i;
+
+ grabState = GrabNone;
+ ListenToAllClients();
+ for (i = mskcnt; --i >= 0 && !grabWaiters[i]; )
+ ;
+ if (i >= 0)
+ {
+ i <<= 5;
+ while (!GETBIT(grabWaiters, i))
+ i++;
+ BITCLEAR(grabWaiters, i);
+ AttendClient(clients[i]);
+ }
+
+ if (ServerGrabCallback)
+ {
+ ServerGrabInfoRec grabinfo;
+ grabinfo.client = client;
+ grabinfo.grabstate = SERVER_UNGRABBED;
+ CallCallbacks(&ServerGrabCallback, (pointer)&grabinfo);
+ }
+}
+
+int
+ProcUngrabServer(ClientPtr client)
+{
+ REQUEST_SIZE_MATCH(xReq);
+ UngrabServer(client);
+ return Success;
+}
+
+int
+ProcTranslateCoords(ClientPtr client)
+{
+ REQUEST(xTranslateCoordsReq);
+
+ WindowPtr pWin, pDst;
+ xTranslateCoordsReply rep;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xTranslateCoordsReq);
+ rc = dixLookupWindow(&pWin, stuff->srcWid, client, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+ rc = dixLookupWindow(&pDst, stuff->dstWid, client, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+ memset(&rep, 0, sizeof(xTranslateCoordsReply));
+ rep.type = X_Reply;
+ rep.length = 0;
+ rep.sequenceNumber = client->sequence;
+ if (!SAME_SCREENS(pWin->drawable, pDst->drawable))
+ {
+ rep.sameScreen = xFalse;
+ rep.child = None;
+ rep.dstX = rep.dstY = 0;
+ }
+ else
+ {
+ INT16 x, y;
+ rep.sameScreen = xTrue;
+ rep.child = None;
+ /* computing absolute coordinates -- adjust to destination later */
+ x = pWin->drawable.x + stuff->srcX;
+ y = pWin->drawable.y + stuff->srcY;
+ pWin = pDst->firstChild;
+ while (pWin)
+ {
+ BoxRec box;
+ if ((pWin->mapped) &&
+ (x >= pWin->drawable.x - wBorderWidth (pWin)) &&
+ (x < pWin->drawable.x + (int)pWin->drawable.width +
+ wBorderWidth (pWin)) &&
+ (y >= pWin->drawable.y - wBorderWidth (pWin)) &&
+ (y < pWin->drawable.y + (int)pWin->drawable.height +
+ wBorderWidth (pWin))
+ /* When a window is shaped, a further check
+ * is made to see if the point is inside
+ * borderSize
+ */
+ && (!wBoundingShape(pWin) ||
+ RegionContainsPoint(&pWin->borderSize, x, y, &box))
+
+ && (!wInputShape(pWin) ||
+ RegionContainsPoint(wInputShape(pWin),
+ x - pWin->drawable.x,
+ y - pWin->drawable.y, &box))
+ )
+ {
+ rep.child = pWin->drawable.id;
+ pWin = (WindowPtr) NULL;
+ }
+ else
+ pWin = pWin->nextSib;
+ }
+ /* adjust to destination coordinates */
+ rep.dstX = x - pDst->drawable.x;
+ rep.dstY = y - pDst->drawable.y;
+ }
+ WriteReplyToClient(client, sizeof(xTranslateCoordsReply), &rep);
+ return Success;
+}
+
+int
+ProcOpenFont(ClientPtr client)
+{
+ int err;
+ REQUEST(xOpenFontReq);
+
+ REQUEST_FIXED_SIZE(xOpenFontReq, stuff->nbytes);
+ client->errorValue = stuff->fid;
+ LEGAL_NEW_RESOURCE(stuff->fid, client);
+ err = OpenFont(client, stuff->fid, (Mask) 0,
+ stuff->nbytes, (char *)&stuff[1]);
+ if (err == Success)
+ {
+ return Success;
+ }
+ else
+ return err;
+}
+
+int
+ProcCloseFont(ClientPtr client)
+{
+ FontPtr pFont;
+ int rc;
+ REQUEST(xResourceReq);
+
+ REQUEST_SIZE_MATCH(xResourceReq);
+ rc = dixLookupResourceByType((pointer *)&pFont, stuff->id, RT_FONT,
+ client, DixDestroyAccess);
+ if (rc == Success)
+ {
+ FreeResource(stuff->id, RT_NONE);
+ return Success;
+ }
+ else
+ {
+ client->errorValue = stuff->id;
+ return rc;
+ }
+}
+
+int
+ProcQueryFont(ClientPtr client)
+{
+ xQueryFontReply *reply;
+ FontPtr pFont;
+ int rc;
+ REQUEST(xResourceReq);
+ REQUEST_SIZE_MATCH(xResourceReq);
+
+ rc = dixLookupFontable(&pFont, stuff->id, client, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ {
+ xCharInfo *pmax = FONTINKMAX(pFont);
+ xCharInfo *pmin = FONTINKMIN(pFont);
+ int nprotoxcistructs;
+ int rlength;
+
+ nprotoxcistructs = (
+ pmax->rightSideBearing == pmin->rightSideBearing &&
+ pmax->leftSideBearing == pmin->leftSideBearing &&
+ pmax->descent == pmin->descent &&
+ pmax->ascent == pmin->ascent &&
+ pmax->characterWidth == pmin->characterWidth) ?
+ 0 : N2dChars(pFont);
+
+ rlength = sizeof(xQueryFontReply) +
+ FONTINFONPROPS(FONTCHARSET(pFont)) * sizeof(xFontProp) +
+ nprotoxcistructs * sizeof(xCharInfo);
+ reply = calloc(1, rlength);
+ if(!reply)
+ {
+ return BadAlloc;
+ }
+
+ reply->type = X_Reply;
+ reply->length = bytes_to_int32(rlength - sizeof(xGenericReply));
+ reply->sequenceNumber = client->sequence;
+ QueryFont( pFont, reply, nprotoxcistructs);
+
+ WriteReplyToClient(client, rlength, reply);
+ free(reply);
+ return Success;
+ }
+}
+
+int
+ProcQueryTextExtents(ClientPtr client)
+{
+ xQueryTextExtentsReply reply;
+ FontPtr pFont;
+ ExtentInfoRec info;
+ unsigned long length;
+ int rc;
+ REQUEST(xQueryTextExtentsReq);
+ REQUEST_AT_LEAST_SIZE(xQueryTextExtentsReq);
+
+ rc = dixLookupFontable(&pFont, stuff->fid, client, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ length = client->req_len - bytes_to_int32(sizeof(xQueryTextExtentsReq));
+ length = length << 1;
+ if (stuff->oddLength)
+ {
+ if (length == 0)
+ return BadLength;
+ length--;
+ }
+ if (!QueryTextExtents(pFont, length, (unsigned char *)&stuff[1], &info))
+ return BadAlloc;
+ reply.type = X_Reply;
+ reply.length = 0;
+ reply.sequenceNumber = client->sequence;
+ reply.drawDirection = info.drawDirection;
+ reply.fontAscent = info.fontAscent;
+ reply.fontDescent = info.fontDescent;
+ reply.overallAscent = info.overallAscent;
+ reply.overallDescent = info.overallDescent;
+ reply.overallWidth = info.overallWidth;
+ reply.overallLeft = info.overallLeft;
+ reply.overallRight = info.overallRight;
+ WriteReplyToClient(client, sizeof(xQueryTextExtentsReply), &reply);
+ return Success;
+}
+
+int
+ProcListFonts(ClientPtr client)
+{
+ REQUEST(xListFontsReq);
+
+ REQUEST_FIXED_SIZE(xListFontsReq, stuff->nbytes);
+
+ return ListFonts(client, (unsigned char *) &stuff[1], stuff->nbytes,
+ stuff->maxNames);
+}
+
+int
+ProcListFontsWithInfo(ClientPtr client)
+{
+ REQUEST(xListFontsWithInfoReq);
+
+ REQUEST_FIXED_SIZE(xListFontsWithInfoReq, stuff->nbytes);
+
+ return StartListFontsWithInfo(client, stuff->nbytes,
+ (unsigned char *) &stuff[1], stuff->maxNames);
+}
+
+/**
+ *
+ * \param value must conform to DeleteType
+ */
+int
+dixDestroyPixmap(pointer value, XID pid)
+{
+ PixmapPtr pPixmap = (PixmapPtr)value;
+ return (*pPixmap->drawable.pScreen->DestroyPixmap)(pPixmap);
+}
+
+int
+ProcCreatePixmap(ClientPtr client)
+{
+ PixmapPtr pMap;
+ DrawablePtr pDraw;
+ REQUEST(xCreatePixmapReq);
+ DepthPtr pDepth;
+ int i, rc;
+
+ REQUEST_SIZE_MATCH(xCreatePixmapReq);
+ client->errorValue = stuff->pid;
+ LEGAL_NEW_RESOURCE(stuff->pid, client);
+
+ rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
+ DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ if (!stuff->width || !stuff->height)
+ {
+ client->errorValue = 0;
+ return BadValue;
+ }
+ if (stuff->width > 32767 || stuff->height > 32767)
+ {
+ /* It is allowed to try and allocate a pixmap which is larger than
+ * 32767 in either dimension. However, all of the framebuffer code
+ * is buggy and does not reliably draw to such big pixmaps, basically
+ * because the Region data structure operates with signed shorts
+ * for the rectangles in it.
+ *
+ * Furthermore, several places in the X server computes the
+ * size in bytes of the pixmap and tries to store it in an
+ * integer. This integer can overflow and cause the allocated size
+ * to be much smaller.
+ *
+ * So, such big pixmaps are rejected here with a BadAlloc
+ */
+ return BadAlloc;
+ }
+ if (stuff->depth != 1)
+ {
+ pDepth = pDraw->pScreen->allowedDepths;
+ for (i=0; i<pDraw->pScreen->numDepths; i++, pDepth++)
+ if (pDepth->depth == stuff->depth)
+ goto CreatePmap;
+ client->errorValue = stuff->depth;
+ return BadValue;
+ }
+CreatePmap:
+ pMap = (PixmapPtr)(*pDraw->pScreen->CreatePixmap)
+ (pDraw->pScreen, stuff->width,
+ stuff->height, stuff->depth, 0);
+ if (pMap)
+ {
+ pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ pMap->drawable.id = stuff->pid;
+ /* security creation/labeling check */
+ rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid, RT_PIXMAP,
+ pMap, RT_NONE, NULL, DixCreateAccess);
+ if (rc != Success) {
+ (*pDraw->pScreen->DestroyPixmap)(pMap);
+ return rc;
+ }
+ if (AddResource(stuff->pid, RT_PIXMAP, (pointer)pMap))
+ return Success;
+ (*pDraw->pScreen->DestroyPixmap)(pMap);
+ }
+ return BadAlloc;
+}
+
+int
+ProcFreePixmap(ClientPtr client)
+{
+ PixmapPtr pMap;
+ int rc;
+ REQUEST(xResourceReq);
+ REQUEST_SIZE_MATCH(xResourceReq);
+
+ rc = dixLookupResourceByType((pointer *)&pMap, stuff->id, RT_PIXMAP, client,
+ DixDestroyAccess);
+ if (rc == Success)
+ {
+ FreeResource(stuff->id, RT_NONE);
+ return Success;
+ }
+ else
+ {
+ client->errorValue = stuff->id;
+ return rc;
+ }
+}
+
+int
+ProcCreateGC(ClientPtr client)
+{
+ int error, rc;
+ GC *pGC;
+ DrawablePtr pDraw;
+ unsigned len;
+ REQUEST(xCreateGCReq);
+
+ REQUEST_AT_LEAST_SIZE(xCreateGCReq);
+ client->errorValue = stuff->gc;
+ LEGAL_NEW_RESOURCE(stuff->gc, client);
+ rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0,
+ DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ len = client->req_len - bytes_to_int32(sizeof(xCreateGCReq));
+ if (len != Ones(stuff->mask))
+ return BadLength;
+ pGC = (GC *)CreateGC(pDraw, stuff->mask, (XID *) &stuff[1], &error,
+ stuff->gc, client);
+ if (error != Success)
+ return error;
+ if (!AddResource(stuff->gc, RT_GC, (pointer)pGC))
+ return BadAlloc;
+ return Success;
+}
+
+int
+ProcChangeGC(ClientPtr client)
+{
+ GC *pGC;
+ int result;
+ unsigned len;
+ REQUEST(xChangeGCReq);
+ REQUEST_AT_LEAST_SIZE(xChangeGCReq);
+
+ result = dixLookupGC(&pGC, stuff->gc, client, DixSetAttrAccess);
+ if (result != Success)
+ return result;
+
+ len = client->req_len - bytes_to_int32(sizeof(xChangeGCReq));
+ if (len != Ones(stuff->mask))
+ return BadLength;
+
+ return ChangeGCXIDs(client, pGC, stuff->mask, (CARD32 *) &stuff[1]);
+}
+
+int
+ProcCopyGC(ClientPtr client)
+{
+ GC *dstGC;
+ GC *pGC;
+ int result;
+ REQUEST(xCopyGCReq);
+ REQUEST_SIZE_MATCH(xCopyGCReq);
+
+ result = dixLookupGC(&pGC, stuff->srcGC, client, DixGetAttrAccess);
+ if (result != Success)
+ return result;
+ result = dixLookupGC(&dstGC, stuff->dstGC, client, DixSetAttrAccess);
+ if (result != Success)
+ return result;
+ if ((dstGC->pScreen != pGC->pScreen) || (dstGC->depth != pGC->depth))
+ return BadMatch;
+ if (stuff->mask & ~GCAllBits)
+ {
+ client->errorValue = stuff->mask;
+ return BadValue;
+ }
+ return CopyGC(pGC, dstGC, stuff->mask);
+}
+
+int
+ProcSetDashes(ClientPtr client)
+{
+ GC *pGC;
+ int result;
+ REQUEST(xSetDashesReq);
+
+ REQUEST_FIXED_SIZE(xSetDashesReq, stuff->nDashes);
+ if (stuff->nDashes == 0)
+ {
+ client->errorValue = 0;
+ return BadValue;
+ }
+
+ result = dixLookupGC(&pGC,stuff->gc, client, DixSetAttrAccess);
+ if (result != Success)
+ return result;
+
+ /* If there's an error, either there's no sensible errorValue,
+ * or there was a dash segment of 0. */
+ client->errorValue = 0;
+ return SetDashes(pGC, stuff->dashOffset, stuff->nDashes,
+ (unsigned char *)&stuff[1]);
+}
+
+int
+ProcSetClipRectangles(ClientPtr client)
+{
+ int nr, result;
+ GC *pGC;
+ REQUEST(xSetClipRectanglesReq);
+
+ REQUEST_AT_LEAST_SIZE(xSetClipRectanglesReq);
+ if ((stuff->ordering != Unsorted) && (stuff->ordering != YSorted) &&
+ (stuff->ordering != YXSorted) && (stuff->ordering != YXBanded))
+ {
+ client->errorValue = stuff->ordering;
+ return BadValue;
+ }
+ result = dixLookupGC(&pGC,stuff->gc, client, DixSetAttrAccess);
+ if (result != Success)
+ return result;
+
+ nr = (client->req_len << 2) - sizeof(xSetClipRectanglesReq);
+ if (nr & 4)
+ return BadLength;
+ nr >>= 3;
+ return SetClipRects(pGC, stuff->xOrigin, stuff->yOrigin,
+ nr, (xRectangle *)&stuff[1], (int)stuff->ordering);
+}
+
+int
+ProcFreeGC(ClientPtr client)
+{
+ GC *pGC;
+ int rc;
+ REQUEST(xResourceReq);
+ REQUEST_SIZE_MATCH(xResourceReq);
+
+ rc = dixLookupGC(&pGC, stuff->id, client, DixDestroyAccess);
+ if (rc != Success)
+ return rc;
+
+ FreeResource(stuff->id, RT_NONE);
+ return Success;
+}
+
+int
+ProcClearToBackground(ClientPtr client)
+{
+ REQUEST(xClearAreaReq);
+ WindowPtr pWin;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xClearAreaReq);
+ rc = dixLookupWindow(&pWin, stuff->window, client, DixWriteAccess);
+ if (rc != Success)
+ return rc;
+ if (pWin->drawable.class == InputOnly)
+ {
+ client->errorValue = stuff->window;
+ return BadMatch;
+ }
+ if ((stuff->exposures != xTrue) && (stuff->exposures != xFalse))
+ {
+ client->errorValue = stuff->exposures;
+ return BadValue;
+ }
+ (*pWin->drawable.pScreen->ClearToBackground)(pWin, stuff->x, stuff->y,
+ stuff->width, stuff->height,
+ (Bool)stuff->exposures);
+ return Success;
+}
+
+int
+ProcCopyArea(ClientPtr client)
+{
+ DrawablePtr pDst;
+ DrawablePtr pSrc;
+ GC *pGC;
+ REQUEST(xCopyAreaReq);
+ RegionPtr pRgn;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xCopyAreaReq);
+
+ VALIDATE_DRAWABLE_AND_GC(stuff->dstDrawable, pDst, DixWriteAccess);
+ if (stuff->dstDrawable != stuff->srcDrawable)
+ {
+ rc = dixLookupDrawable(&pSrc, stuff->srcDrawable, client, 0,
+ DixReadAccess);
+ if (rc != Success)
+ return rc;
+ if ((pDst->pScreen != pSrc->pScreen) || (pDst->depth != pSrc->depth))
+ {
+ client->errorValue = stuff->dstDrawable;
+ return BadMatch;
+ }
+ }
+ else
+ pSrc = pDst;
+
+ pRgn = (*pGC->ops->CopyArea)(pSrc, pDst, pGC, stuff->srcX, stuff->srcY,
+ stuff->width, stuff->height,
+ stuff->dstX, stuff->dstY);
+ if (pGC->graphicsExposures)
+ {
+ (*pDst->pScreen->SendGraphicsExpose)
+ (client, pRgn, stuff->dstDrawable, X_CopyArea, 0);
+ if (pRgn)
+ RegionDestroy(pRgn);
+ }
+
+ return Success;
+}
+
+int
+ProcCopyPlane(ClientPtr client)
+{
+ DrawablePtr psrcDraw, pdstDraw;
+ GC *pGC;
+ REQUEST(xCopyPlaneReq);
+ RegionPtr pRgn;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xCopyPlaneReq);
+
+ VALIDATE_DRAWABLE_AND_GC(stuff->dstDrawable, pdstDraw, DixWriteAccess);
+ if (stuff->dstDrawable != stuff->srcDrawable)
+ {
+ rc = dixLookupDrawable(&psrcDraw, stuff->srcDrawable, client, 0,
+ DixReadAccess);
+ if (rc != Success)
+ return rc;
+
+ if (pdstDraw->pScreen != psrcDraw->pScreen)
+ {
+ client->errorValue = stuff->dstDrawable;
+ return BadMatch;
+ }
+ }
+ else
+ psrcDraw = pdstDraw;
+
+ /* Check to see if stuff->bitPlane has exactly ONE good bit set */
+ if(stuff->bitPlane == 0 || (stuff->bitPlane & (stuff->bitPlane - 1)) ||
+ (stuff->bitPlane > (1L << (psrcDraw->depth - 1))))
+ {
+ client->errorValue = stuff->bitPlane;
+ return BadValue;
+ }
+
+ pRgn = (*pGC->ops->CopyPlane)(psrcDraw, pdstDraw, pGC, stuff->srcX, stuff->srcY,
+ stuff->width, stuff->height,
+ stuff->dstX, stuff->dstY, stuff->bitPlane);
+ if (pGC->graphicsExposures)
+ {
+ (*pdstDraw->pScreen->SendGraphicsExpose)
+ (client, pRgn, stuff->dstDrawable, X_CopyPlane, 0);
+ if (pRgn)
+ RegionDestroy(pRgn);
+ }
+ return Success;
+}
+
+int
+ProcPolyPoint(ClientPtr client)
+{
+ int npoint;
+ GC *pGC;
+ DrawablePtr pDraw;
+ REQUEST(xPolyPointReq);
+
+ REQUEST_AT_LEAST_SIZE(xPolyPointReq);
+ if ((stuff->coordMode != CoordModeOrigin) &&
+ (stuff->coordMode != CoordModePrevious))
+ {
+ client->errorValue = stuff->coordMode;
+ return BadValue;
+ }
+ VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
+ npoint = bytes_to_int32((client->req_len << 2) - sizeof(xPolyPointReq));
+ if (npoint)
+ (*pGC->ops->PolyPoint)(pDraw, pGC, stuff->coordMode, npoint,
+ (xPoint *) &stuff[1]);
+ return Success;
+}
+
+int
+ProcPolyLine(ClientPtr client)
+{
+ int npoint;
+ GC *pGC;
+ DrawablePtr pDraw;
+ REQUEST(xPolyLineReq);
+
+ REQUEST_AT_LEAST_SIZE(xPolyLineReq);
+ if ((stuff->coordMode != CoordModeOrigin) &&
+ (stuff->coordMode != CoordModePrevious))
+ {
+ client->errorValue = stuff->coordMode;
+ return BadValue;
+ }
+ VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
+ npoint = bytes_to_int32((client->req_len << 2) - sizeof(xPolyLineReq));
+ if (npoint > 1)
+ (*pGC->ops->Polylines)(pDraw, pGC, stuff->coordMode, npoint,
+ (DDXPointPtr) &stuff[1]);
+ return Success;
+}
+
+int
+ProcPolySegment(ClientPtr client)
+{
+ int nsegs;
+ GC *pGC;
+ DrawablePtr pDraw;
+ REQUEST(xPolySegmentReq);
+
+ REQUEST_AT_LEAST_SIZE(xPolySegmentReq);
+ VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
+ nsegs = (client->req_len << 2) - sizeof(xPolySegmentReq);
+ if (nsegs & 4)
+ return BadLength;
+ nsegs >>= 3;
+ if (nsegs)
+ (*pGC->ops->PolySegment)(pDraw, pGC, nsegs, (xSegment *) &stuff[1]);
+ return Success;
+}
+
+int
+ProcPolyRectangle (ClientPtr client)
+{
+ int nrects;
+ GC *pGC;
+ DrawablePtr pDraw;
+ REQUEST(xPolyRectangleReq);
+
+ REQUEST_AT_LEAST_SIZE(xPolyRectangleReq);
+ VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
+ nrects = (client->req_len << 2) - sizeof(xPolyRectangleReq);
+ if (nrects & 4)
+ return BadLength;
+ nrects >>= 3;
+ if (nrects)
+ (*pGC->ops->PolyRectangle)(pDraw, pGC,
+ nrects, (xRectangle *) &stuff[1]);
+ return Success;
+}
+
+int
+ProcPolyArc(ClientPtr client)
+{
+ int narcs;
+ GC *pGC;
+ DrawablePtr pDraw;
+ REQUEST(xPolyArcReq);
+
+ REQUEST_AT_LEAST_SIZE(xPolyArcReq);
+ VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
+ narcs = (client->req_len << 2) - sizeof(xPolyArcReq);
+ if (narcs % sizeof(xArc))
+ return BadLength;
+ narcs /= sizeof(xArc);
+ if (narcs)
+ (*pGC->ops->PolyArc)(pDraw, pGC, narcs, (xArc *) &stuff[1]);
+ return Success;
+}
+
+int
+ProcFillPoly(ClientPtr client)
+{
+ int things;
+ GC *pGC;
+ DrawablePtr pDraw;
+ REQUEST(xFillPolyReq);
+
+ REQUEST_AT_LEAST_SIZE(xFillPolyReq);
+ if ((stuff->shape != Complex) && (stuff->shape != Nonconvex) &&
+ (stuff->shape != Convex))
+ {
+ client->errorValue = stuff->shape;
+ return BadValue;
+ }
+ if ((stuff->coordMode != CoordModeOrigin) &&
+ (stuff->coordMode != CoordModePrevious))
+ {
+ client->errorValue = stuff->coordMode;
+ return BadValue;
+ }
+
+ VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
+ things = bytes_to_int32((client->req_len << 2) - sizeof(xFillPolyReq));
+ if (things)
+ (*pGC->ops->FillPolygon) (pDraw, pGC, stuff->shape,
+ stuff->coordMode, things,
+ (DDXPointPtr) &stuff[1]);
+ return Success;
+}
+
+int
+ProcPolyFillRectangle(ClientPtr client)
+{
+ int things;
+ GC *pGC;
+ DrawablePtr pDraw;
+ REQUEST(xPolyFillRectangleReq);
+
+ REQUEST_AT_LEAST_SIZE(xPolyFillRectangleReq);
+ VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
+ things = (client->req_len << 2) - sizeof(xPolyFillRectangleReq);
+ if (things & 4)
+ return BadLength;
+ things >>= 3;
+
+ if (things)
+ (*pGC->ops->PolyFillRect) (pDraw, pGC, things,
+ (xRectangle *) &stuff[1]);
+ return Success;
+}
+
+int
+ProcPolyFillArc(ClientPtr client)
+{
+ int narcs;
+ GC *pGC;
+ DrawablePtr pDraw;
+ REQUEST(xPolyFillArcReq);
+
+ REQUEST_AT_LEAST_SIZE(xPolyFillArcReq);
+ VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
+ narcs = (client->req_len << 2) - sizeof(xPolyFillArcReq);
+ if (narcs % sizeof(xArc))
+ return BadLength;
+ narcs /= sizeof(xArc);
+ if (narcs)
+ (*pGC->ops->PolyFillArc) (pDraw, pGC, narcs, (xArc *) &stuff[1]);
+ return Success;
+}
+
+#ifdef MATCH_CLIENT_ENDIAN
+
+int
+ServerOrder (void)
+{
+ int whichbyte = 1;
+
+ if (*((char *) &whichbyte))
+ return LSBFirst;
+ return MSBFirst;
+}
+
+#define ClientOrder(client) ((client)->swapped ? !ServerOrder() : ServerOrder())
+
+void
+ReformatImage (char *base, int nbytes, int bpp, int order)
+{
+ switch (bpp) {
+ case 1: /* yuck */
+ if (BITMAP_BIT_ORDER != order)
+ BitOrderInvert ((unsigned char *) base, nbytes);
+#if IMAGE_BYTE_ORDER != BITMAP_BIT_ORDER && BITMAP_SCANLINE_UNIT != 8
+ ReformatImage (base, nbytes, BITMAP_SCANLINE_UNIT, order);
+#endif
+ break;
+ case 4:
+ break; /* yuck */
+ case 8:
+ break;
+ case 16:
+ if (IMAGE_BYTE_ORDER != order)
+ TwoByteSwap ((unsigned char *) base, nbytes);
+ break;
+ case 32:
+ if (IMAGE_BYTE_ORDER != order)
+ FourByteSwap ((unsigned char *) base, nbytes);
+ break;
+ }
+}
+#else
+#define ReformatImage(b,n,bpp,o)
+#endif
+
+/* 64-bit server notes: the protocol restricts padding of images to
+ * 8-, 16-, or 32-bits. We would like to have 64-bits for the server
+ * to use internally. Removes need for internal alignment checking.
+ * All of the PutImage functions could be changed individually, but
+ * as currently written, they call other routines which require things
+ * to be 64-bit padded on scanlines, so we changed things here.
+ * If an image would be padded differently for 64- versus 32-, then
+ * copy each scanline to a 64-bit padded scanline.
+ * Also, we need to make sure that the image is aligned on a 64-bit
+ * boundary, even if the scanlines are padded to our satisfaction.
+ */
+int
+ProcPutImage(ClientPtr client)
+{
+ GC *pGC;
+ DrawablePtr pDraw;
+ long length; /* length of scanline server padded */
+ long lengthProto; /* length of scanline protocol padded */
+ char *tmpImage;
+ REQUEST(xPutImageReq);
+
+ REQUEST_AT_LEAST_SIZE(xPutImageReq);
+ VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
+ if (stuff->format == XYBitmap)
+ {
+ if ((stuff->depth != 1) ||
+ (stuff->leftPad >= (unsigned int)screenInfo.bitmapScanlinePad))
+ return BadMatch;
+ length = BitmapBytePad(stuff->width + stuff->leftPad);
+ }
+ else if (stuff->format == XYPixmap)
+ {
+ if ((pDraw->depth != stuff->depth) ||
+ (stuff->leftPad >= (unsigned int)screenInfo.bitmapScanlinePad))
+ return BadMatch;
+ length = BitmapBytePad(stuff->width + stuff->leftPad);
+ length *= stuff->depth;
+ }
+ else if (stuff->format == ZPixmap)
+ {
+ if ((pDraw->depth != stuff->depth) || (stuff->leftPad != 0))
+ return BadMatch;
+ length = PixmapBytePad(stuff->width, stuff->depth);
+ }
+ else
+ {
+ client->errorValue = stuff->format;
+ return BadValue;
+ }
+
+ tmpImage = (char *)&stuff[1];
+ lengthProto = length;
+
+ if ((bytes_to_int32(lengthProto * stuff->height) +
+ bytes_to_int32(sizeof(xPutImageReq))) != client->req_len)
+ return BadLength;
+
+ ReformatImage (tmpImage, lengthProto * stuff->height,
+ stuff->format == ZPixmap ? BitsPerPixel (stuff->depth) : 1,
+ ClientOrder(client));
+
+ (*pGC->ops->PutImage) (pDraw, pGC, stuff->depth, stuff->dstX, stuff->dstY,
+ stuff->width, stuff->height,
+ stuff->leftPad, stuff->format, tmpImage);
+
+ return Success;
+}
+
+static int
+DoGetImage(ClientPtr client, int format, Drawable drawable,
+ int x, int y, int width, int height,
+ Mask planemask, xGetImageReply **im_return)
+{
+ DrawablePtr pDraw, pBoundingDraw;
+ int nlines, linesPerBuf, rc;
+ int linesDone;
+ /* coordinates relative to the bounding drawable */
+ int relx, rely;
+ long widthBytesLine, length;
+ Mask plane = 0;
+ char *pBuf;
+ xGetImageReply xgi;
+ RegionPtr pVisibleRegion = NULL;
+
+ if ((format != XYPixmap) && (format != ZPixmap))
+ {
+ client->errorValue = format;
+ return BadValue;
+ }
+ rc = dixLookupDrawable(&pDraw, drawable, client, 0, DixReadAccess);
+ if (rc != Success)
+ return rc;
+
+ memset(&xgi, 0, sizeof(xGetImageReply));
+
+ relx = x;
+ rely = y;
+
+ if(pDraw->type == DRAWABLE_WINDOW)
+ {
+ WindowPtr pWin = (WindowPtr)pDraw;
+
+ /* "If the drawable is a window, the window must be viewable ... or a
+ * BadMatch error results" */
+ if (!pWin->viewable)
+ return BadMatch;
+
+ relx += pDraw->x;
+ rely += pDraw->y;
+
+ if (pDraw->pScreen->GetWindowPixmap) {
+ PixmapPtr pPix = (*pDraw->pScreen->GetWindowPixmap) (pWin);
+
+ pBoundingDraw = &pPix->drawable;
+#ifdef COMPOSITE
+ relx -= pPix->screen_x;
+ rely -= pPix->screen_y;
+#endif
+ }
+ else
+ {
+ pBoundingDraw = (DrawablePtr)pDraw->pScreen->root;
+ }
+
+ xgi.visual = wVisual (pWin);
+ }
+ else
+ {
+ pBoundingDraw = pDraw;
+ xgi.visual = None;
+ }
+
+ /* "If the drawable is a pixmap, the given rectangle must be wholly
+ * contained within the pixmap, or a BadMatch error results. If the
+ * drawable is a window [...] it must be the case that if there were no
+ * inferiors or overlapping windows, the specified rectangle of the window
+ * would be fully visible on the screen and wholly contained within the
+ * outside edges of the window, or a BadMatch error results."
+ *
+ * We relax the window case slightly to mean that the rectangle must exist
+ * within the bounds of the window's backing pixmap. In particular, this
+ * means that a GetImage request may succeed or fail with BadMatch depending
+ * on whether any of its ancestor windows are redirected. */
+ if(relx < 0 || relx + width > (int)pBoundingDraw->width ||
+ rely < 0 || rely + height > (int)pBoundingDraw->height)
+ return BadMatch;
+
+ xgi.type = X_Reply;
+ xgi.sequenceNumber = client->sequence;
+ xgi.depth = pDraw->depth;
+ if(format == ZPixmap)
+ {
+ widthBytesLine = PixmapBytePad(width, pDraw->depth);
+ length = widthBytesLine * height;
+
+ }
+ else
+ {
+ widthBytesLine = BitmapBytePad(width);
+ plane = ((Mask)1) << (pDraw->depth - 1);
+ /* only planes asked for */
+ length = widthBytesLine * height *
+ Ones(planemask & (plane | (plane - 1)));
+
+ }
+
+ xgi.length = length;
+
+ if (im_return) {
+ pBuf = calloc(1, sz_xGetImageReply + length);
+ if (!pBuf)
+ return BadAlloc;
+ if (widthBytesLine == 0)
+ linesPerBuf = 0;
+ else
+ linesPerBuf = height;
+ *im_return = (xGetImageReply *)pBuf;
+ *(xGetImageReply *)pBuf = xgi;
+ pBuf += sz_xGetImageReply;
+ } else {
+ xgi.length = bytes_to_int32(xgi.length);
+ if (widthBytesLine == 0 || height == 0)
+ linesPerBuf = 0;
+ else if (widthBytesLine >= IMAGE_BUFSIZE)
+ linesPerBuf = 1;
+ else
+ {
+ linesPerBuf = IMAGE_BUFSIZE / widthBytesLine;
+ if (linesPerBuf > height)
+ linesPerBuf = height;
+ }
+ length = linesPerBuf * widthBytesLine;
+ if (linesPerBuf < height)
+ {
+ /* we have to make sure intermediate buffers don't need padding */
+ while ((linesPerBuf > 1) &&
+ (length & ((1L << LOG2_BYTES_PER_SCANLINE_PAD)-1)))
+ {
+ linesPerBuf--;
+ length -= widthBytesLine;
+ }
+ while (length & ((1L << LOG2_BYTES_PER_SCANLINE_PAD)-1))
+ {
+ linesPerBuf++;
+ length += widthBytesLine;
+ }
+ }
+ if(!(pBuf = calloc(1, length)))
+ return BadAlloc;
+ WriteReplyToClient(client, sizeof (xGetImageReply), &xgi);
+ }
+
+ if (pDraw->type == DRAWABLE_WINDOW)
+ {
+ pVisibleRegion = NotClippedByChildren((WindowPtr)pDraw);
+ if (pVisibleRegion)
+ {
+ RegionTranslate(pVisibleRegion, -pDraw->x, -pDraw->y);
+ }
+ }
+
+ if (linesPerBuf == 0)
+ {
+ /* nothing to do */
+ }
+ else if (format == ZPixmap)
+ {
+ linesDone = 0;
+ while (height - linesDone > 0)
+ {
+ nlines = min(linesPerBuf, height - linesDone);
+ (*pDraw->pScreen->GetImage) (pDraw,
+ x,
+ y + linesDone,
+ width,
+ nlines,
+ format,
+ planemask,
+ (pointer) pBuf);
+ if (pVisibleRegion)
+ XaceCensorImage(client, pVisibleRegion, widthBytesLine,
+ pDraw, x, y + linesDone, width,
+ nlines, format, pBuf);
+
+ /* Note that this is NOT a call to WriteSwappedDataToClient,
+ as we do NOT byte swap */
+ if (!im_return)
+ {
+ ReformatImage (pBuf, (int)(nlines * widthBytesLine),
+ BitsPerPixel (pDraw->depth),
+ ClientOrder(client));
+
+/* Don't split me, gcc pukes when you do */
+ (void)WriteToClient(client,
+ (int)(nlines * widthBytesLine),
+ pBuf);
+ }
+ linesDone += nlines;
+ }
+ }
+ else /* XYPixmap */
+ {
+ for (; plane; plane >>= 1)
+ {
+ if (planemask & plane)
+ {
+ linesDone = 0;
+ while (height - linesDone > 0)
+ {
+ nlines = min(linesPerBuf, height - linesDone);
+ (*pDraw->pScreen->GetImage) (pDraw,
+ x,
+ y + linesDone,
+ width,
+ nlines,
+ format,
+ plane,
+ (pointer)pBuf);
+ if (pVisibleRegion)
+ XaceCensorImage(client, pVisibleRegion,
+ widthBytesLine,
+ pDraw, x, y + linesDone, width,
+ nlines, format, pBuf);
+
+ /* Note: NOT a call to WriteSwappedDataToClient,
+ as we do NOT byte swap */
+ if (im_return) {
+ pBuf += nlines * widthBytesLine;
+ } else {
+ ReformatImage (pBuf,
+ (int)(nlines * widthBytesLine),
+ 1,
+ ClientOrder (client));
+
+/* Don't split me, gcc pukes when you do */
+ (void)WriteToClient(client,
+ (int)(nlines * widthBytesLine),
+ pBuf);
+ }
+ linesDone += nlines;
+ }
+ }
+ }
+ }
+ if (pVisibleRegion)
+ RegionDestroy(pVisibleRegion);
+ if (!im_return)
+ free(pBuf);
+ return Success;
+}
+
+int
+ProcGetImage(ClientPtr client)
+{
+ REQUEST(xGetImageReq);
+
+ REQUEST_SIZE_MATCH(xGetImageReq);
+
+ return DoGetImage(client, stuff->format, stuff->drawable,
+ stuff->x, stuff->y,
+ (int)stuff->width, (int)stuff->height,
+ stuff->planeMask, (xGetImageReply **)NULL);
+}
+
+int
+ProcPolyText(ClientPtr client)
+{
+ int err;
+ REQUEST(xPolyTextReq);
+ DrawablePtr pDraw;
+ GC *pGC;
+
+ REQUEST_AT_LEAST_SIZE(xPolyTextReq);
+ VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
+
+ err = PolyText(client,
+ pDraw,
+ pGC,
+ (unsigned char *)&stuff[1],
+ ((unsigned char *) stuff) + (client->req_len << 2),
+ stuff->x,
+ stuff->y,
+ stuff->reqType,
+ stuff->drawable);
+
+ if (err == Success)
+ {
+ return Success;
+ }
+ else
+ return err;
+}
+
+int
+ProcImageText8(ClientPtr client)
+{
+ int err;
+ DrawablePtr pDraw;
+ GC *pGC;
+
+ REQUEST(xImageTextReq);
+
+ REQUEST_FIXED_SIZE(xImageTextReq, stuff->nChars);
+ VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
+
+ err = ImageText(client,
+ pDraw,
+ pGC,
+ stuff->nChars,
+ (unsigned char *)&stuff[1],
+ stuff->x,
+ stuff->y,
+ stuff->reqType,
+ stuff->drawable);
+
+ if (err == Success)
+ {
+ return Success;
+ }
+ else
+ return err;
+}
+
+int
+ProcImageText16(ClientPtr client)
+{
+ int err;
+ DrawablePtr pDraw;
+ GC *pGC;
+
+ REQUEST(xImageTextReq);
+
+ REQUEST_FIXED_SIZE(xImageTextReq, stuff->nChars << 1);
+ VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
+
+ err = ImageText(client,
+ pDraw,
+ pGC,
+ stuff->nChars,
+ (unsigned char *)&stuff[1],
+ stuff->x,
+ stuff->y,
+ stuff->reqType,
+ stuff->drawable);
+
+ if (err == Success)
+ {
+ return Success;
+ }
+ else
+ return err;
+}
+
+
+int
+ProcCreateColormap(ClientPtr client)
+{
+ VisualPtr pVisual;
+ ColormapPtr pmap;
+ Colormap mid;
+ WindowPtr pWin;
+ ScreenPtr pScreen;
+ REQUEST(xCreateColormapReq);
+ int i, result;
+
+ REQUEST_SIZE_MATCH(xCreateColormapReq);
+
+ if ((stuff->alloc != AllocNone) && (stuff->alloc != AllocAll))
+ {
+ client->errorValue = stuff->alloc;
+ return BadValue;
+ }
+ mid = stuff->mid;
+ LEGAL_NEW_RESOURCE(mid, client);
+ result = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
+ if (result != Success)
+ return result;
+
+ pScreen = pWin->drawable.pScreen;
+ for (i = 0, pVisual = pScreen->visuals;
+ i < pScreen->numVisuals;
+ i++, pVisual++)
+ {
+ if (pVisual->vid != stuff->visual)
+ continue;
+ return CreateColormap(mid, pScreen, pVisual, &pmap,
+ (int)stuff->alloc, client->index);
+ }
+ client->errorValue = stuff->visual;
+ return BadMatch;
+}
+
+int
+ProcFreeColormap(ClientPtr client)
+{
+ ColormapPtr pmap;
+ int rc;
+ REQUEST(xResourceReq);
+
+ REQUEST_SIZE_MATCH(xResourceReq);
+ rc = dixLookupResourceByType((pointer *)&pmap, stuff->id, RT_COLORMAP, client,
+ DixDestroyAccess);
+ if (rc == Success)
+ {
+ /* Freeing a default colormap is a no-op */
+ if (!(pmap->flags & IsDefault))
+ FreeResource(stuff->id, RT_NONE);
+ return Success;
+ }
+ else
+ {
+ client->errorValue = stuff->id;
+ return rc;
+ }
+}
+
+
+int
+ProcCopyColormapAndFree(ClientPtr client)
+{
+ Colormap mid;
+ ColormapPtr pSrcMap;
+ REQUEST(xCopyColormapAndFreeReq);
+ int rc;
+
+ REQUEST_SIZE_MATCH(xCopyColormapAndFreeReq);
+ mid = stuff->mid;
+ LEGAL_NEW_RESOURCE(mid, client);
+ rc = dixLookupResourceByType((pointer *)&pSrcMap, stuff->srcCmap, RT_COLORMAP,
+ client, DixReadAccess|DixRemoveAccess);
+ if (rc == Success)
+ return CopyColormapAndFree(mid, pSrcMap, client->index);
+ client->errorValue = stuff->srcCmap;
+ return rc;
+}
+
+int
+ProcInstallColormap(ClientPtr client)
+{
+ ColormapPtr pcmp;
+ int rc;
+ REQUEST(xResourceReq);
+ REQUEST_SIZE_MATCH(xResourceReq);
+
+ rc = dixLookupResourceByType((pointer *)&pcmp, stuff->id, RT_COLORMAP, client,
+ DixInstallAccess);
+ if (rc != Success)
+ goto out;
+
+ rc = XaceHook(XACE_SCREEN_ACCESS, client, pcmp->pScreen, DixSetAttrAccess);
+ if (rc != Success) {
+ if (rc == BadValue)
+ rc = BadColor;
+ goto out;
+ }
+
+ (*(pcmp->pScreen->InstallColormap)) (pcmp);
+ return Success;
+
+out:
+ client->errorValue = stuff->id;
+ return rc;
+}
+
+int
+ProcUninstallColormap(ClientPtr client)
+{
+ ColormapPtr pcmp;
+ int rc;
+ REQUEST(xResourceReq);
+ REQUEST_SIZE_MATCH(xResourceReq);
+
+ rc = dixLookupResourceByType((pointer *)&pcmp, stuff->id, RT_COLORMAP, client,
+ DixUninstallAccess);
+ if (rc != Success)
+ goto out;
+
+ rc = XaceHook(XACE_SCREEN_ACCESS, client, pcmp->pScreen, DixSetAttrAccess);
+ if (rc != Success) {
+ if (rc == BadValue)
+ rc = BadColor;
+ goto out;
+ }
+
+ if(pcmp->mid != pcmp->pScreen->defColormap)
+ (*(pcmp->pScreen->UninstallColormap)) (pcmp);
+ return Success;
+
+out:
+ client->errorValue = stuff->id;
+ return rc;
+}
+
+int
+ProcListInstalledColormaps(ClientPtr client)
+{
+ xListInstalledColormapsReply *preply;
+ int nummaps, rc;
+ WindowPtr pWin;
+ REQUEST(xResourceReq);
+ REQUEST_SIZE_MATCH(xResourceReq);
+
+ rc = dixLookupWindow(&pWin, stuff->id, client, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ rc = XaceHook(XACE_SCREEN_ACCESS, client, pWin->drawable.pScreen,
+ DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ preply = malloc(sizeof(xListInstalledColormapsReply) +
+ pWin->drawable.pScreen->maxInstalledCmaps *
+ sizeof(Colormap));
+ if(!preply)
+ return BadAlloc;
+
+ preply->type = X_Reply;
+ preply->sequenceNumber = client->sequence;
+ nummaps = (*pWin->drawable.pScreen->ListInstalledColormaps)
+ (pWin->drawable.pScreen, (Colormap *)&preply[1]);
+ preply->nColormaps = nummaps;
+ preply->length = nummaps;
+ WriteReplyToClient(client, sizeof (xListInstalledColormapsReply), preply);
+ client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
+ WriteSwappedDataToClient(client, nummaps * sizeof(Colormap), &preply[1]);
+ free(preply);
+ return Success;
+}
+
+int
+ProcAllocColor (ClientPtr client)
+{
+ ColormapPtr pmap;
+ int rc;
+ xAllocColorReply acr;
+ REQUEST(xAllocColorReq);
+
+ REQUEST_SIZE_MATCH(xAllocColorReq);
+ rc = dixLookupResourceByType((pointer *)&pmap, stuff->cmap, RT_COLORMAP, client,
+ DixAddAccess);
+ if (rc == Success)
+ {
+ acr.type = X_Reply;
+ acr.length = 0;
+ acr.sequenceNumber = client->sequence;
+ acr.red = stuff->red;
+ acr.green = stuff->green;
+ acr.blue = stuff->blue;
+ acr.pixel = 0;
+ if( (rc = AllocColor(pmap, &acr.red, &acr.green, &acr.blue,
+ &acr.pixel, client->index)) )
+ return rc;
+#ifdef PANORAMIX
+ if (noPanoramiXExtension || !pmap->pScreen->myNum)
+#endif
+ WriteReplyToClient(client, sizeof(xAllocColorReply), &acr);
+ return Success;
+
+ }
+ else
+ {
+ client->errorValue = stuff->cmap;
+ return rc;
+ }
+}
+
+int
+ProcAllocNamedColor (ClientPtr client)
+{
+ ColormapPtr pcmp;
+ int rc;
+ REQUEST(xAllocNamedColorReq);
+
+ REQUEST_FIXED_SIZE(xAllocNamedColorReq, stuff->nbytes);
+ rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client,
+ DixAddAccess);
+ if (rc == Success)
+ {
+ xAllocNamedColorReply ancr;
+
+ ancr.type = X_Reply;
+ ancr.length = 0;
+ ancr.sequenceNumber = client->sequence;
+
+ if(OsLookupColor(pcmp->pScreen->myNum, (char *)&stuff[1], stuff->nbytes,
+ &ancr.exactRed, &ancr.exactGreen, &ancr.exactBlue))
+ {
+ ancr.screenRed = ancr.exactRed;
+ ancr.screenGreen = ancr.exactGreen;
+ ancr.screenBlue = ancr.exactBlue;
+ ancr.pixel = 0;
+ if( (rc = AllocColor(pcmp,
+ &ancr.screenRed, &ancr.screenGreen, &ancr.screenBlue,
+ &ancr.pixel, client->index)) )
+ return rc;
+#ifdef PANORAMIX
+ if (noPanoramiXExtension || !pcmp->pScreen->myNum)
+#endif
+ WriteReplyToClient(client, sizeof (xAllocNamedColorReply), &ancr);
+ return Success;
+ }
+ else
+ return BadName;
+
+ }
+ else
+ {
+ client->errorValue = stuff->cmap;
+ return rc;
+ }
+}
+
+int
+ProcAllocColorCells (ClientPtr client)
+{
+ ColormapPtr pcmp;
+ int rc;
+ REQUEST(xAllocColorCellsReq);
+
+ REQUEST_SIZE_MATCH(xAllocColorCellsReq);
+ rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client,
+ DixAddAccess);
+ if (rc == Success)
+ {
+ xAllocColorCellsReply accr;
+ int npixels, nmasks;
+ long length;
+ Pixel *ppixels, *pmasks;
+
+ npixels = stuff->colors;
+ if (!npixels)
+ {
+ client->errorValue = npixels;
+ return BadValue;
+ }
+ if (stuff->contiguous != xTrue && stuff->contiguous != xFalse)
+ {
+ client->errorValue = stuff->contiguous;
+ return BadValue;
+ }
+ nmasks = stuff->planes;
+ length = ((long)npixels + (long)nmasks) * sizeof(Pixel);
+ ppixels = malloc(length);
+ if(!ppixels)
+ return BadAlloc;
+ pmasks = ppixels + npixels;
+
+ if( (rc = AllocColorCells(client->index, pcmp, npixels, nmasks,
+ (Bool)stuff->contiguous, ppixels, pmasks)) )
+ {
+ free(ppixels);
+ return rc;
+ }
+#ifdef PANORAMIX
+ if (noPanoramiXExtension || !pcmp->pScreen->myNum)
+#endif
+ {
+ accr.type = X_Reply;
+ accr.length = bytes_to_int32(length);
+ accr.sequenceNumber = client->sequence;
+ accr.nPixels = npixels;
+ accr.nMasks = nmasks;
+ WriteReplyToClient(client, sizeof (xAllocColorCellsReply), &accr);
+ client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
+ WriteSwappedDataToClient(client, length, ppixels);
+ }
+ free(ppixels);
+ return Success;
+ }
+ else
+ {
+ client->errorValue = stuff->cmap;
+ return rc;
+ }
+}
+
+int
+ProcAllocColorPlanes(ClientPtr client)
+{
+ ColormapPtr pcmp;
+ int rc;
+ REQUEST(xAllocColorPlanesReq);
+
+ REQUEST_SIZE_MATCH(xAllocColorPlanesReq);
+ rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client,
+ DixAddAccess);
+ if (rc == Success)
+ {
+ xAllocColorPlanesReply acpr;
+ int npixels;
+ long length;
+ Pixel *ppixels;
+
+ npixels = stuff->colors;
+ if (!npixels)
+ {
+ client->errorValue = npixels;
+ return BadValue;
+ }
+ if (stuff->contiguous != xTrue && stuff->contiguous != xFalse)
+ {
+ client->errorValue = stuff->contiguous;
+ return BadValue;
+ }
+ acpr.type = X_Reply;
+ acpr.sequenceNumber = client->sequence;
+ acpr.nPixels = npixels;
+ length = (long)npixels * sizeof(Pixel);
+ ppixels = malloc(length);
+ if(!ppixels)
+ return BadAlloc;
+ if( (rc = AllocColorPlanes(client->index, pcmp, npixels,
+ (int)stuff->red, (int)stuff->green, (int)stuff->blue,
+ (Bool)stuff->contiguous, ppixels,
+ &acpr.redMask, &acpr.greenMask, &acpr.blueMask)) )
+ {
+ free(ppixels);
+ return rc;
+ }
+ acpr.length = bytes_to_int32(length);
+#ifdef PANORAMIX
+ if (noPanoramiXExtension || !pcmp->pScreen->myNum)
+#endif
+ {
+ WriteReplyToClient(client, sizeof(xAllocColorPlanesReply), &acpr);
+ client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
+ WriteSwappedDataToClient(client, length, ppixels);
+ }
+ free(ppixels);
+ return Success;
+ }
+ else
+ {
+ client->errorValue = stuff->cmap;
+ return rc;
+ }
+}
+
+int
+ProcFreeColors(ClientPtr client)
+{
+ ColormapPtr pcmp;
+ int rc;
+ REQUEST(xFreeColorsReq);
+
+ REQUEST_AT_LEAST_SIZE(xFreeColorsReq);
+ rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client,
+ DixRemoveAccess);
+ if (rc == Success)
+ {
+ int count;
+
+ if(pcmp->flags & AllAllocated)
+ return BadAccess;
+ count = bytes_to_int32((client->req_len << 2) - sizeof(xFreeColorsReq));
+ return FreeColors(pcmp, client->index, count,
+ (Pixel *)&stuff[1], (Pixel)stuff->planeMask);
+ }
+ else
+ {
+ client->errorValue = stuff->cmap;
+ return rc;
+ }
+}
+
+int
+ProcStoreColors (ClientPtr client)
+{
+ ColormapPtr pcmp;
+ int rc;
+ REQUEST(xStoreColorsReq);
+
+ REQUEST_AT_LEAST_SIZE(xStoreColorsReq);
+ rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client,
+ DixWriteAccess);
+ if (rc == Success)
+ {
+ int count;
+
+ count = (client->req_len << 2) - sizeof(xStoreColorsReq);
+ if (count % sizeof(xColorItem))
+ return BadLength;
+ count /= sizeof(xColorItem);
+ return StoreColors(pcmp, count, (xColorItem *)&stuff[1], client);
+ }
+ else
+ {
+ client->errorValue = stuff->cmap;
+ return rc;
+ }
+}
+
+int
+ProcStoreNamedColor (ClientPtr client)
+{
+ ColormapPtr pcmp;
+ int rc;
+ REQUEST(xStoreNamedColorReq);
+
+ REQUEST_FIXED_SIZE(xStoreNamedColorReq, stuff->nbytes);
+ rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client,
+ DixWriteAccess);
+ if (rc == Success)
+ {
+ xColorItem def;
+
+ if(OsLookupColor(pcmp->pScreen->myNum, (char *)&stuff[1],
+ stuff->nbytes, &def.red, &def.green, &def.blue))
+ {
+ def.flags = stuff->flags;
+ def.pixel = stuff->pixel;
+ return StoreColors(pcmp, 1, &def, client);
+ }
+ return BadName;
+ }
+ else
+ {
+ client->errorValue = stuff->cmap;
+ return rc;
+ }
+}
+
+int
+ProcQueryColors(ClientPtr client)
+{
+ ColormapPtr pcmp;
+ int rc;
+ REQUEST(xQueryColorsReq);
+
+ REQUEST_AT_LEAST_SIZE(xQueryColorsReq);
+ rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client,
+ DixReadAccess);
+ if (rc == Success)
+ {
+ int count;
+ xrgb *prgbs;
+ xQueryColorsReply qcr;
+
+ count = bytes_to_int32((client->req_len << 2) - sizeof(xQueryColorsReq));
+ prgbs = calloc(1, count * sizeof(xrgb));
+ if(!prgbs && count)
+ return BadAlloc;
+ if( (rc = QueryColors(pcmp, count, (Pixel *)&stuff[1], prgbs, client)) )
+ {
+ free(prgbs);
+ return rc;
+ }
+ memset(&qcr, 0, sizeof(xQueryColorsReply));
+ qcr.type = X_Reply;
+ qcr.length = bytes_to_int32(count * sizeof(xrgb));
+ qcr.sequenceNumber = client->sequence;
+ qcr.nColors = count;
+ WriteReplyToClient(client, sizeof(xQueryColorsReply), &qcr);
+ if (count)
+ {
+ client->pSwapReplyFunc = (ReplySwapPtr) SQColorsExtend;
+ WriteSwappedDataToClient(client, count * sizeof(xrgb), prgbs);
+ }
+ free(prgbs);
+ return Success;
+
+ }
+ else
+ {
+ client->errorValue = stuff->cmap;
+ return rc;
+ }
+}
+
+int
+ProcLookupColor(ClientPtr client)
+{
+ ColormapPtr pcmp;
+ int rc;
+ REQUEST(xLookupColorReq);
+
+ REQUEST_FIXED_SIZE(xLookupColorReq, stuff->nbytes);
+ rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client,
+ DixReadAccess);
+ if (rc == Success)
+ {
+ xLookupColorReply lcr;
+
+ if(OsLookupColor(pcmp->pScreen->myNum, (char *)&stuff[1], stuff->nbytes,
+ &lcr.exactRed, &lcr.exactGreen, &lcr.exactBlue))
+ {
+ lcr.type = X_Reply;
+ lcr.length = 0;
+ lcr.sequenceNumber = client->sequence;
+ lcr.screenRed = lcr.exactRed;
+ lcr.screenGreen = lcr.exactGreen;
+ lcr.screenBlue = lcr.exactBlue;
+ (*pcmp->pScreen->ResolveColor)(&lcr.screenRed,
+ &lcr.screenGreen,
+ &lcr.screenBlue,
+ pcmp->pVisual);
+ WriteReplyToClient(client, sizeof(xLookupColorReply), &lcr);
+ return Success;
+ }
+ return BadName;
+ }
+ else
+ {
+ client->errorValue = stuff->cmap;
+ return rc;
+ }
+}
+
+int
+ProcCreateCursor (ClientPtr client)
+{
+ CursorPtr pCursor;
+ PixmapPtr src;
+ PixmapPtr msk;
+ unsigned char * srcbits;
+ unsigned char * mskbits;
+ unsigned short width, height;
+ long n;
+ CursorMetricRec cm;
+ int rc;
+
+ REQUEST(xCreateCursorReq);
+
+ REQUEST_SIZE_MATCH(xCreateCursorReq);
+ LEGAL_NEW_RESOURCE(stuff->cid, client);
+
+ rc = dixLookupResourceByType((pointer *)&src, stuff->source, RT_PIXMAP, client,
+ DixReadAccess);
+ if (rc != Success) {
+ client->errorValue = stuff->source;
+ return rc;
+ }
+
+ rc = dixLookupResourceByType((pointer *)&msk, stuff->mask, RT_PIXMAP, client,
+ DixReadAccess);
+ if (rc != Success)
+ {
+ if (stuff->mask != None)
+ {
+ client->errorValue = stuff->mask;
+ return rc;
+ }
+ }
+ else if ( src->drawable.width != msk->drawable.width
+ || src->drawable.height != msk->drawable.height
+ || src->drawable.depth != 1
+ || msk->drawable.depth != 1)
+ return BadMatch;
+
+ width = src->drawable.width;
+ height = src->drawable.height;
+
+ if ( stuff->x > width
+ || stuff->y > height )
+ return BadMatch;
+
+ n = BitmapBytePad(width)*height;
+ srcbits = calloc(1, n);
+ if (!srcbits)
+ return BadAlloc;
+ mskbits = malloc(n);
+ if (!mskbits)
+ {
+ free(srcbits);
+ return BadAlloc;
+ }
+
+ (* src->drawable.pScreen->GetImage)( (DrawablePtr)src, 0, 0, width, height,
+ XYPixmap, 1, (pointer)srcbits);
+ if ( msk == (PixmapPtr)NULL)
+ {
+ unsigned char *bits = mskbits;
+ while (--n >= 0)
+ *bits++ = ~0;
+ }
+ else
+ {
+ /* zeroing the (pad) bits helps some ddx cursor handling */
+ memset((char *)mskbits, 0, n);
+ (* msk->drawable.pScreen->GetImage)( (DrawablePtr)msk, 0, 0, width,
+ height, XYPixmap, 1, (pointer)mskbits);
+ }
+ cm.width = width;
+ cm.height = height;
+ cm.xhot = stuff->x;
+ cm.yhot = stuff->y;
+ rc = AllocARGBCursor(srcbits, mskbits, NULL, &cm,
+ stuff->foreRed, stuff->foreGreen, stuff->foreBlue,
+ stuff->backRed, stuff->backGreen, stuff->backBlue,
+ &pCursor, client, stuff->cid);
+
+ if (rc != Success)
+ return rc;
+ if (!AddResource(stuff->cid, RT_CURSOR, (pointer)pCursor))
+ return BadAlloc;
+
+ return Success;
+}
+
+int
+ProcCreateGlyphCursor (ClientPtr client)
+{
+ CursorPtr pCursor;
+ int res;
+
+ REQUEST(xCreateGlyphCursorReq);
+
+ REQUEST_SIZE_MATCH(xCreateGlyphCursorReq);
+ LEGAL_NEW_RESOURCE(stuff->cid, client);
+
+ res = AllocGlyphCursor(stuff->source, stuff->sourceChar,
+ stuff->mask, stuff->maskChar,
+ stuff->foreRed, stuff->foreGreen, stuff->foreBlue,
+ stuff->backRed, stuff->backGreen, stuff->backBlue,
+ &pCursor, client, stuff->cid);
+ if (res != Success)
+ return res;
+ if (AddResource(stuff->cid, RT_CURSOR, (pointer)pCursor))
+ return Success;
+ return BadAlloc;
+}
+
+
+int
+ProcFreeCursor (ClientPtr client)
+{
+ CursorPtr pCursor;
+ int rc;
+ REQUEST(xResourceReq);
+
+ REQUEST_SIZE_MATCH(xResourceReq);
+ rc = dixLookupResourceByType((pointer *)&pCursor, stuff->id, RT_CURSOR, client,
+ DixDestroyAccess);
+ if (rc == Success)
+ {
+ FreeResource(stuff->id, RT_NONE);
+ return Success;
+ }
+ else
+ {
+ client->errorValue = stuff->id;
+ return rc;
+ }
+}
+
+int
+ProcQueryBestSize (ClientPtr client)
+{
+ xQueryBestSizeReply reply;
+ DrawablePtr pDraw;
+ ScreenPtr pScreen;
+ int rc;
+ REQUEST(xQueryBestSizeReq);
+ REQUEST_SIZE_MATCH(xQueryBestSizeReq);
+
+ if ((stuff->class != CursorShape) &&
+ (stuff->class != TileShape) &&
+ (stuff->class != StippleShape))
+ {
+ client->errorValue = stuff->class;
+ return BadValue;
+ }
+
+ rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
+ DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+ if (stuff->class != CursorShape && pDraw->type == UNDRAWABLE_WINDOW)
+ return BadMatch;
+ pScreen = pDraw->pScreen;
+ rc = XaceHook(XACE_SCREEN_ACCESS, client, pScreen, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+ (* pScreen->QueryBestSize)(stuff->class, &stuff->width,
+ &stuff->height, pScreen);
+ memset(&reply, 0, sizeof(xQueryBestSizeReply));
+ reply.type = X_Reply;
+ reply.length = 0;
+ reply.sequenceNumber = client->sequence;
+ reply.width = stuff->width;
+ reply.height = stuff->height;
+ WriteReplyToClient(client, sizeof(xQueryBestSizeReply), &reply);
+ return Success;
+}
+
+
+int
+ProcSetScreenSaver (ClientPtr client)
+{
+ int rc, i, blankingOption, exposureOption;
+ REQUEST(xSetScreenSaverReq);
+ REQUEST_SIZE_MATCH(xSetScreenSaverReq);
+
+ for (i = 0; i < screenInfo.numScreens; i++) {
+ rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, screenInfo.screens[i],
+ DixSetAttrAccess);
+ if (rc != Success)
+ return rc;
+ }
+
+ blankingOption = stuff->preferBlank;
+ if ((blankingOption != DontPreferBlanking) &&
+ (blankingOption != PreferBlanking) &&
+ (blankingOption != DefaultBlanking))
+ {
+ client->errorValue = blankingOption;
+ return BadValue;
+ }
+ exposureOption = stuff->allowExpose;
+ if ((exposureOption != DontAllowExposures) &&
+ (exposureOption != AllowExposures) &&
+ (exposureOption != DefaultExposures))
+ {
+ client->errorValue = exposureOption;
+ return BadValue;
+ }
+ if (stuff->timeout < -1)
+ {
+ client->errorValue = stuff->timeout;
+ return BadValue;
+ }
+ if (stuff->interval < -1)
+ {
+ client->errorValue = stuff->interval;
+ return BadValue;
+ }
+
+ if (blankingOption == DefaultBlanking)
+ ScreenSaverBlanking = defaultScreenSaverBlanking;
+ else
+ ScreenSaverBlanking = blankingOption;
+ if (exposureOption == DefaultExposures)
+ ScreenSaverAllowExposures = defaultScreenSaverAllowExposures;
+ else
+ ScreenSaverAllowExposures = exposureOption;
+
+ if (stuff->timeout >= 0)
+ ScreenSaverTime = stuff->timeout * MILLI_PER_SECOND;
+ else
+ ScreenSaverTime = defaultScreenSaverTime;
+ if (stuff->interval >= 0)
+ ScreenSaverInterval = stuff->interval * MILLI_PER_SECOND;
+ else
+ ScreenSaverInterval = defaultScreenSaverInterval;
+
+ SetScreenSaverTimer();
+ return Success;
+}
+
+int
+ProcGetScreenSaver(ClientPtr client)
+{
+ xGetScreenSaverReply rep;
+ int rc, i;
+ REQUEST_SIZE_MATCH(xReq);
+
+ for (i = 0; i < screenInfo.numScreens; i++) {
+ rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, screenInfo.screens[i],
+ DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+ }
+
+ rep.type = X_Reply;
+ rep.length = 0;
+ rep.sequenceNumber = client->sequence;
+ rep.timeout = ScreenSaverTime / MILLI_PER_SECOND;
+ rep.interval = ScreenSaverInterval / MILLI_PER_SECOND;
+ rep.preferBlanking = ScreenSaverBlanking;
+ rep.allowExposures = ScreenSaverAllowExposures;
+ WriteReplyToClient(client, sizeof(xGetScreenSaverReply), &rep);
+ return Success;
+}
+
+int
+ProcChangeHosts(ClientPtr client)
+{
+ REQUEST(xChangeHostsReq);
+
+ REQUEST_FIXED_SIZE(xChangeHostsReq, stuff->hostLength);
+
+ if(stuff->mode == HostInsert)
+ return AddHost(client, (int)stuff->hostFamily,
+ stuff->hostLength, (pointer)&stuff[1]);
+ if (stuff->mode == HostDelete)
+ return RemoveHost(client, (int)stuff->hostFamily,
+ stuff->hostLength, (pointer)&stuff[1]);
+ client->errorValue = stuff->mode;
+ return BadValue;
+}
+
+int
+ProcListHosts(ClientPtr client)
+{
+ xListHostsReply reply;
+ int len, nHosts, result;
+ pointer pdata;
+ /* REQUEST(xListHostsReq); */
+
+ REQUEST_SIZE_MATCH(xListHostsReq);
+
+ /* untrusted clients can't list hosts */
+ result = XaceHook(XACE_SERVER_ACCESS, client, DixReadAccess);
+ if (result != Success)
+ return result;
+
+ result = GetHosts(&pdata, &nHosts, &len, &reply.enabled);
+ if (result != Success)
+ return result;
+ reply.type = X_Reply;
+ reply.sequenceNumber = client->sequence;
+ reply.nHosts = nHosts;
+ reply.length = bytes_to_int32(len);
+ WriteReplyToClient(client, sizeof(xListHostsReply), &reply);
+ if (nHosts)
+ {
+ client->pSwapReplyFunc = (ReplySwapPtr) SLHostsExtend;
+ WriteSwappedDataToClient(client, len, pdata);
+ }
+ free(pdata);
+ return Success;
+}
+
+int
+ProcChangeAccessControl(ClientPtr client)
+{
+ REQUEST(xSetAccessControlReq);
+
+ REQUEST_SIZE_MATCH(xSetAccessControlReq);
+ if ((stuff->mode != EnableAccess) && (stuff->mode != DisableAccess))
+ {
+ client->errorValue = stuff->mode;
+ return BadValue;
+ }
+ return ChangeAccessControl(client, stuff->mode == EnableAccess);
+}
+
+/*********************
+ * CloseDownRetainedResources
+ *
+ * Find all clients that are gone and have terminated in RetainTemporary
+ * and destroy their resources.
+ *********************/
+
+static void
+CloseDownRetainedResources(void)
+{
+ int i;
+ ClientPtr client;
+
+ for (i=1; i<currentMaxClients; i++)
+ {
+ client = clients[i];
+ if (client && (client->closeDownMode == RetainTemporary)
+ && (client->clientGone))
+ CloseDownClient(client);
+ }
+}
+
+int
+ProcKillClient(ClientPtr client)
+{
+ REQUEST(xResourceReq);
+ ClientPtr killclient;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xResourceReq);
+ if (stuff->id == AllTemporary)
+ {
+ CloseDownRetainedResources();
+ return Success;
+ }
+
+ rc = dixLookupClient(&killclient, stuff->id, client, DixDestroyAccess);
+ if (rc == Success) {
+ CloseDownClient(killclient);
+ /* if an LBX proxy gets killed, isItTimeToYield will be set */
+ if (isItTimeToYield || (client == killclient))
+ {
+ /* force yield and return Success, so that Dispatch()
+ * doesn't try to touch client
+ */
+ isItTimeToYield = TRUE;
+ return Success;
+ }
+ return Success;
+ }
+ else
+ return rc;
+}
+
+int
+ProcSetFontPath(ClientPtr client)
+{
+ unsigned char *ptr;
+ unsigned long nbytes, total;
+ long nfonts;
+ int n;
+ REQUEST(xSetFontPathReq);
+
+ REQUEST_AT_LEAST_SIZE(xSetFontPathReq);
+
+ nbytes = (client->req_len << 2) - sizeof(xSetFontPathReq);
+ total = nbytes;
+ ptr = (unsigned char *)&stuff[1];
+ nfonts = stuff->nFonts;
+ while (--nfonts >= 0)
+ {
+ if ((total == 0) || (total < (n = (*ptr + 1))))
+ return BadLength;
+ total -= n;
+ ptr += n;
+ }
+ if (total >= 4)
+ return BadLength;
+ return SetFontPath(client, stuff->nFonts, (unsigned char *)&stuff[1]);
+}
+
+int
+ProcGetFontPath(ClientPtr client)
+{
+ xGetFontPathReply reply;
+ int rc, stringLens, numpaths;
+ unsigned char *bufferStart;
+ /* REQUEST (xReq); */
+
+ REQUEST_SIZE_MATCH(xReq);
+ rc = GetFontPath(client, &numpaths, &stringLens, &bufferStart);
+ if (rc != Success)
+ return rc;
+
+ reply.type = X_Reply;
+ reply.sequenceNumber = client->sequence;
+ reply.length = bytes_to_int32(stringLens + numpaths);
+ reply.nPaths = numpaths;
+
+ WriteReplyToClient(client, sizeof(xGetFontPathReply), &reply);
+ if (stringLens || numpaths)
+ (void)WriteToClient(client, stringLens + numpaths, (char *)bufferStart);
+ return Success;
+}
+
+int
+ProcChangeCloseDownMode(ClientPtr client)
+{
+ int rc;
+ REQUEST(xSetCloseDownModeReq);
+ REQUEST_SIZE_MATCH(xSetCloseDownModeReq);
+
+ rc = XaceHook(XACE_CLIENT_ACCESS, client, client, DixManageAccess);
+ if (rc != Success)
+ return rc;
+
+ if ((stuff->mode == AllTemporary) ||
+ (stuff->mode == RetainPermanent) ||
+ (stuff->mode == RetainTemporary))
+ {
+ client->closeDownMode = stuff->mode;
+ return Success;
+ }
+ else
+ {
+ client->errorValue = stuff->mode;
+ return BadValue;
+ }
+}
+
+int ProcForceScreenSaver(ClientPtr client)
+{
+ int rc;
+ REQUEST(xForceScreenSaverReq);
+
+ REQUEST_SIZE_MATCH(xForceScreenSaverReq);
+
+ if ((stuff->mode != ScreenSaverReset) &&
+ (stuff->mode != ScreenSaverActive))
+ {
+ client->errorValue = stuff->mode;
+ return BadValue;
+ }
+ rc = dixSaveScreens(client, SCREEN_SAVER_FORCER, (int)stuff->mode);
+ if (rc != Success)
+ return rc;
+ return Success;
+}
+
+int ProcNoOperation(ClientPtr client)
+{
+ REQUEST_AT_LEAST_SIZE(xReq);
+
+ /* noop -- don't do anything */
+ return Success;
+}
+
+/**********************
+ * CloseDownClient
+ *
+ * Client can either mark his resources destroy or retain. If retained and
+ * then killed again, the client is really destroyed.
+ *********************/
+
+char dispatchExceptionAtReset = DE_RESET;
+
+void
+CloseDownClient(ClientPtr client)
+{
+ Bool really_close_down = client->clientGone ||
+ client->closeDownMode == DestroyAll;
+
+ if (!client->clientGone)
+ {
+ /* ungrab server if grabbing client dies */
+ if (grabState != GrabNone && grabClient == client)
+ {
+ UngrabServer(client);
+ }
+ BITCLEAR(grabWaiters, client->index);
+ DeleteClientFromAnySelections(client);
+ ReleaseActiveGrabs(client);
+ DeleteClientFontStuff(client);
+ if (!really_close_down)
+ {
+ /* This frees resources that should never be retained
+ * no matter what the close down mode is. Actually we
+ * could do this unconditionally, but it's probably
+ * better not to traverse all the client's resources
+ * twice (once here, once a few lines down in
+ * FreeClientResources) in the common case of
+ * really_close_down == TRUE.
+ */
+ FreeClientNeverRetainResources(client);
+ client->clientState = ClientStateRetained;
+ if (ClientStateCallback)
+ {
+ NewClientInfoRec clientinfo;
+
+ clientinfo.client = client;
+ clientinfo.prefix = (xConnSetupPrefix *)NULL;
+ clientinfo.setup = (xConnSetup *) NULL;
+ CallCallbacks((&ClientStateCallback), (pointer)&clientinfo);
+ }
+ }
+ client->clientGone = TRUE; /* so events aren't sent to client */
+ if (ClientIsAsleep(client))
+ ClientSignal (client);
+ ProcessWorkQueueZombies();
+ CloseDownConnection(client);
+
+ /* If the client made it to the Running stage, nClients has
+ * been incremented on its behalf, so we need to decrement it
+ * now. If it hasn't gotten to Running, nClients has *not*
+ * been incremented, so *don't* decrement it.
+ */
+ if (client->clientState != ClientStateInitial &&
+ client->clientState != ClientStateAuthenticating )
+ {
+ --nClients;
+ }
+ }
+
+ if (really_close_down)
+ {
+ if (client->clientState == ClientStateRunning && nClients == 0)
+ dispatchException |= dispatchExceptionAtReset;
+
+ client->clientState = ClientStateGone;
+ if (ClientStateCallback)
+ {
+ NewClientInfoRec clientinfo;
+
+ clientinfo.client = client;
+ clientinfo.prefix = (xConnSetupPrefix *)NULL;
+ clientinfo.setup = (xConnSetup *) NULL;
+ CallCallbacks((&ClientStateCallback), (pointer)&clientinfo);
+ }
+ FreeClientResources(client);
+#ifdef XSERVER_DTRACE
+ XSERVER_CLIENT_DISCONNECT(client->index);
+#endif
+ if (client->index < nextFreeClientID)
+ nextFreeClientID = client->index;
+ clients[client->index] = NullClient;
+ SmartLastClient = NullClient;
+ dixFreeObjectWithPrivates(client, PRIVATE_CLIENT);
+
+ while (!clients[currentMaxClients-1])
+ currentMaxClients--;
+ }
+}
+
+static void
+KillAllClients(void)
+{
+ int i;
+ for (i=1; i<currentMaxClients; i++)
+ if (clients[i]) {
+ /* Make sure Retained clients are released. */
+ clients[i]->closeDownMode = DestroyAll;
+ CloseDownClient(clients[i]);
+ }
+}
+
+void InitClient(ClientPtr client, int i, pointer ospriv)
+{
+ client->index = i;
+ client->clientAsMask = ((Mask)i) << CLIENTOFFSET;
+ client->closeDownMode = i ? DestroyAll : RetainPermanent;
+ client->requestVector = InitialVector;
+ client->osPrivate = ospriv;
+ QueryMinMaxKeyCodes(&client->minKC,&client->maxKC);
+ client->smart_start_tick = SmartScheduleTime;
+ client->smart_stop_tick = SmartScheduleTime;
+ client->smart_check_tick = SmartScheduleTime;
+}
+
+/************************
+ * int NextAvailableClient(ospriv)
+ *
+ * OS dependent portion can't assign client id's because of CloseDownModes.
+ * Returns NULL if there are no free clients.
+ *************************/
+
+ClientPtr NextAvailableClient(pointer ospriv)
+{
+ int i;
+ ClientPtr client;
+ xReq data;
+
+ i = nextFreeClientID;
+ if (i == MAXCLIENTS)
+ return (ClientPtr)NULL;
+ clients[i] = client = dixAllocateObjectWithPrivates(ClientRec, PRIVATE_CLIENT);
+ if (!client)
+ return (ClientPtr)NULL;
+ InitClient(client, i, ospriv);
+ if (!InitClientResources(client))
+ {
+ dixFreeObjectWithPrivates(client, PRIVATE_CLIENT);
+ return (ClientPtr)NULL;
+ }
+ data.reqType = 1;
+ data.length = bytes_to_int32(sz_xReq + sz_xConnClientPrefix);
+ if (!InsertFakeRequest(client, (char *)&data, sz_xReq))
+ {
+ FreeClientResources(client);
+ dixFreeObjectWithPrivates(client, PRIVATE_CLIENT);
+ return (ClientPtr)NULL;
+ }
+ if (i == currentMaxClients)
+ currentMaxClients++;
+ while ((nextFreeClientID < MAXCLIENTS) && clients[nextFreeClientID])
+ nextFreeClientID++;
+ if (ClientStateCallback)
+ {
+ NewClientInfoRec clientinfo;
+
+ clientinfo.client = client;
+ clientinfo.prefix = (xConnSetupPrefix *)NULL;
+ clientinfo.setup = (xConnSetup *) NULL;
+ CallCallbacks((&ClientStateCallback), (pointer)&clientinfo);
+ }
+ return client;
+}
+
+int
+ProcInitialConnection(ClientPtr client)
+{
+ REQUEST(xReq);
+ xConnClientPrefix *prefix;
+ int whichbyte = 1;
+
+ prefix = (xConnClientPrefix *)((char *)stuff + sz_xReq);
+ if ((prefix->byteOrder != 'l') && (prefix->byteOrder != 'B'))
+ return client->noClientException = -1;
+ if (((*(char *) &whichbyte) && (prefix->byteOrder == 'B')) ||
+ (!(*(char *) &whichbyte) && (prefix->byteOrder == 'l')))
+ {
+ client->swapped = TRUE;
+ SwapConnClientPrefix(prefix);
+ }
+ stuff->reqType = 2;
+ stuff->length += bytes_to_int32(prefix->nbytesAuthProto) +
+ bytes_to_int32(prefix->nbytesAuthString);
+ if (client->swapped)
+ {
+ swaps(&stuff->length, whichbyte);
+ }
+ ResetCurrentRequest(client);
+ return Success;
+}
+
+static int
+SendConnSetup(ClientPtr client, char *reason)
+{
+ xWindowRoot *root;
+ int i;
+ int numScreens;
+ char* lConnectionInfo;
+ xConnSetupPrefix* lconnSetupPrefix;
+
+ if (reason)
+ {
+ xConnSetupPrefix csp;
+
+ csp.success = xFalse;
+ csp.lengthReason = strlen(reason);
+ csp.length = bytes_to_int32(csp.lengthReason);
+ csp.majorVersion = X_PROTOCOL;
+ csp.minorVersion = X_PROTOCOL_REVISION;
+ if (client->swapped)
+ WriteSConnSetupPrefix(client, &csp);
+ else
+ (void)WriteToClient(client, sz_xConnSetupPrefix, (char *) &csp);
+ (void)WriteToClient(client, (int)csp.lengthReason, reason);
+ return client->noClientException = -1;
+ }
+
+ numScreens = screenInfo.numScreens;
+ lConnectionInfo = ConnectionInfo;
+ lconnSetupPrefix = &connSetupPrefix;
+
+ /* We're about to start speaking X protocol back to the client by
+ * sending the connection setup info. This means the authorization
+ * step is complete, and we can count the client as an
+ * authorized one.
+ */
+ nClients++;
+
+ client->requestVector = client->swapped ? SwappedProcVector : ProcVector;
+ client->sequence = 0;
+ ((xConnSetup *)lConnectionInfo)->ridBase = client->clientAsMask;
+ ((xConnSetup *)lConnectionInfo)->ridMask = RESOURCE_ID_MASK;
+#ifdef MATCH_CLIENT_ENDIAN
+ ((xConnSetup *)lConnectionInfo)->imageByteOrder = ClientOrder (client);
+ ((xConnSetup *)lConnectionInfo)->bitmapBitOrder = ClientOrder (client);
+#endif
+ /* fill in the "currentInputMask" */
+ root = (xWindowRoot *)(lConnectionInfo + connBlockScreenStart);
+#ifdef PANORAMIX
+ if (noPanoramiXExtension)
+ numScreens = screenInfo.numScreens;
+ else
+ numScreens = ((xConnSetup *)ConnectionInfo)->numRoots;
+#endif
+
+ for (i=0; i<numScreens; i++)
+ {
+ unsigned int j;
+ xDepth *pDepth;
+ WindowPtr pRoot = screenInfo.screens[i]->root;
+
+ root->currentInputMask = pRoot->eventMask | wOtherEventMasks(pRoot);
+ pDepth = (xDepth *)(root + 1);
+ for (j = 0; j < root->nDepths; j++)
+ {
+ pDepth = (xDepth *)(((char *)(pDepth + 1)) +
+ pDepth->nVisuals * sizeof(xVisualType));
+ }
+ root = (xWindowRoot *)pDepth;
+ }
+
+ if (client->swapped)
+ {
+ WriteSConnSetupPrefix(client, lconnSetupPrefix);
+ WriteSConnectionInfo(client,
+ (unsigned long)(lconnSetupPrefix->length << 2),
+ lConnectionInfo);
+ }
+ else
+ {
+ (void)WriteToClient(client, sizeof(xConnSetupPrefix),
+ (char *) lconnSetupPrefix);
+ (void)WriteToClient(client, (int)(lconnSetupPrefix->length << 2),
+ lConnectionInfo);
+ }
+ client->clientState = ClientStateRunning;
+ if (ClientStateCallback)
+ {
+ NewClientInfoRec clientinfo;
+
+ clientinfo.client = client;
+ clientinfo.prefix = lconnSetupPrefix;
+ clientinfo.setup = (xConnSetup *)lConnectionInfo;
+ CallCallbacks((&ClientStateCallback), (pointer)&clientinfo);
+ }
+ return Success;
+}
+
+int
+ProcEstablishConnection(ClientPtr client)
+{
+ char *reason, *auth_proto, *auth_string;
+ xConnClientPrefix *prefix;
+ REQUEST(xReq);
+
+ prefix = (xConnClientPrefix *)((char *)stuff + sz_xReq);
+ auth_proto = (char *)prefix + sz_xConnClientPrefix;
+ auth_string = auth_proto + pad_to_int32(prefix->nbytesAuthProto);
+ if ((prefix->majorVersion != X_PROTOCOL) ||
+ (prefix->minorVersion != X_PROTOCOL_REVISION))
+ reason = "Protocol version mismatch";
+ else
+ reason = ClientAuthorized(client,
+ (unsigned short)prefix->nbytesAuthProto,
+ auth_proto,
+ (unsigned short)prefix->nbytesAuthString,
+ auth_string);
+ /*
+ * If Kerberos is being used for this client, the clientState
+ * will be set to ClientStateAuthenticating at this point.
+ * More messages need to be exchanged among the X server, Kerberos
+ * server, and client to figure out if everyone is authorized.
+ * So we don't want to send the connection setup info yet, since
+ * the auth step isn't really done.
+ */
+ if (client->clientState == ClientStateCheckingSecurity)
+ client->clientState = ClientStateCheckedSecurity;
+ else if (client->clientState != ClientStateAuthenticating)
+ return(SendConnSetup(client, reason));
+ return Success;
+}
+
+void
+SendErrorToClient(ClientPtr client, unsigned majorCode, unsigned minorCode,
+ XID resId, int errorCode)
+{
+ xError rep;
+
+ memset(&rep, 0, sizeof(xError));
+ rep.type = X_Error;
+ rep.errorCode = errorCode;
+ rep.majorCode = majorCode;
+ rep.minorCode = minorCode;
+ rep.resourceID = resId;
+
+ WriteEventsToClient (client, 1, (xEvent *)&rep);
+}
+
+void
+MarkClientException(ClientPtr client)
+{
+ client->noClientException = -1;
+}
+
+/*
+ * This array encodes the answer to the question "what is the log base 2
+ * of the number of pixels that fit in a scanline pad unit?"
+ * Note that ~0 is an invalid entry (mostly for the benefit of the reader).
+ */
+static int answer[6][4] = {
+ /* pad pad pad pad*/
+ /* 8 16 32 64 */
+
+ { 3, 4, 5 , 6 }, /* 1 bit per pixel */
+ { 1, 2, 3 , 4 }, /* 4 bits per pixel */
+ { 0, 1, 2 , 3 }, /* 8 bits per pixel */
+ { ~0, 0, 1 , 2 }, /* 16 bits per pixel */
+ { ~0, ~0, 0 , 1 }, /* 24 bits per pixel */
+ { ~0, ~0, 0 , 1 } /* 32 bits per pixel */
+};
+
+/*
+ * This array gives the answer to the question "what is the first index for
+ * the answer array above given the number of bits per pixel?"
+ * Note that ~0 is an invalid entry (mostly for the benefit of the reader).
+ */
+static int indexForBitsPerPixel[ 33 ] = {
+ ~0, 0, ~0, ~0, /* 1 bit per pixel */
+ 1, ~0, ~0, ~0, /* 4 bits per pixel */
+ 2, ~0, ~0, ~0, /* 8 bits per pixel */
+ ~0,~0, ~0, ~0,
+ 3, ~0, ~0, ~0, /* 16 bits per pixel */
+ ~0,~0, ~0, ~0,
+ 4, ~0, ~0, ~0, /* 24 bits per pixel */
+ ~0,~0, ~0, ~0,
+ 5 /* 32 bits per pixel */
+};
+
+/*
+ * This array gives the bytesperPixel value for cases where the number
+ * of bits per pixel is a multiple of 8 but not a power of 2.
+ */
+static int answerBytesPerPixel[ 33 ] = {
+ ~0, 0, ~0, ~0, /* 1 bit per pixel */
+ 0, ~0, ~0, ~0, /* 4 bits per pixel */
+ 0, ~0, ~0, ~0, /* 8 bits per pixel */
+ ~0,~0, ~0, ~0,
+ 0, ~0, ~0, ~0, /* 16 bits per pixel */
+ ~0,~0, ~0, ~0,
+ 3, ~0, ~0, ~0, /* 24 bits per pixel */
+ ~0,~0, ~0, ~0,
+ 0 /* 32 bits per pixel */
+};
+
+/*
+ * This array gives the answer to the question "what is the second index for
+ * the answer array above given the number of bits per scanline pad unit?"
+ * Note that ~0 is an invalid entry (mostly for the benefit of the reader).
+ */
+static int indexForScanlinePad[ 65 ] = {
+ ~0, ~0, ~0, ~0,
+ ~0, ~0, ~0, ~0,
+ 0, ~0, ~0, ~0, /* 8 bits per scanline pad unit */
+ ~0, ~0, ~0, ~0,
+ 1, ~0, ~0, ~0, /* 16 bits per scanline pad unit */
+ ~0, ~0, ~0, ~0,
+ ~0, ~0, ~0, ~0,
+ ~0, ~0, ~0, ~0,
+ 2, ~0, ~0, ~0, /* 32 bits per scanline pad unit */
+ ~0, ~0, ~0, ~0,
+ ~0, ~0, ~0, ~0,
+ ~0, ~0, ~0, ~0,
+ ~0, ~0, ~0, ~0,
+ ~0, ~0, ~0, ~0,
+ ~0, ~0, ~0, ~0,
+ ~0, ~0, ~0, ~0,
+ 3 /* 64 bits per scanline pad unit */
+};
+
+/*
+ grow the array of screenRecs if necessary.
+ call the device-supplied initialization procedure
+with its screen number, a pointer to its ScreenRec, argc, and argv.
+ return the number of successfully installed screens.
+
+*/
+
+int
+AddScreen(
+ Bool (* pfnInit)(
+ int /*index*/,
+ ScreenPtr /*pScreen*/,
+ int /*argc*/,
+ char ** /*argv*/
+ ),
+ int argc,
+ char **argv)
+{
+
+ int i;
+ int scanlinepad, format, depth, bitsPerPixel, j, k;
+ ScreenPtr pScreen;
+
+ i = screenInfo.numScreens;
+ if (i == MAXSCREENS)
+ return -1;
+
+ pScreen = (ScreenPtr) calloc(1, sizeof(ScreenRec));
+ if (!pScreen)
+ return -1;
+
+ if (!dixAllocatePrivates(&pScreen->devPrivates, PRIVATE_SCREEN)) {
+ free (pScreen);
+ return -1;
+ }
+ pScreen->myNum = i;
+ pScreen->totalPixmapSize = 0; /* computed in CreateScratchPixmapForScreen */
+ pScreen->ClipNotify = 0; /* for R4 ddx compatibility */
+ pScreen->CreateScreenResources = 0;
+
+ /*
+ * This loop gets run once for every Screen that gets added,
+ * but thats ok. If the ddx layer initializes the formats
+ * one at a time calling AddScreen() after each, then each
+ * iteration will make it a little more accurate. Worst case
+ * we do this loop N * numPixmapFormats where N is # of screens.
+ * Anyway, this must be called after InitOutput and before the
+ * screen init routine is called.
+ */
+ for (format=0; format<screenInfo.numPixmapFormats; format++)
+ {
+ depth = screenInfo.formats[format].depth;
+ bitsPerPixel = screenInfo.formats[format].bitsPerPixel;
+ scanlinepad = screenInfo.formats[format].scanlinePad;
+ j = indexForBitsPerPixel[ bitsPerPixel ];
+ k = indexForScanlinePad[ scanlinepad ];
+ PixmapWidthPaddingInfo[ depth ].padPixelsLog2 = answer[j][k];
+ PixmapWidthPaddingInfo[ depth ].padRoundUp =
+ (scanlinepad/bitsPerPixel) - 1;
+ j = indexForBitsPerPixel[ 8 ]; /* bits per byte */
+ PixmapWidthPaddingInfo[ depth ].padBytesLog2 = answer[j][k];
+ PixmapWidthPaddingInfo[ depth ].bitsPerPixel = bitsPerPixel;
+ if (answerBytesPerPixel[bitsPerPixel])
+ {
+ PixmapWidthPaddingInfo[ depth ].notPower2 = 1;
+ PixmapWidthPaddingInfo[ depth ].bytesPerPixel =
+ answerBytesPerPixel[bitsPerPixel];
+ }
+ else
+ {
+ PixmapWidthPaddingInfo[ depth ].notPower2 = 0;
+ }
+ }
+
+ /* This is where screen specific stuff gets initialized. Load the
+ screen structure, call the hardware, whatever.
+ This is also where the default colormap should be allocated and
+ also pixel values for blackPixel, whitePixel, and the cursor
+ Note that InitScreen is NOT allowed to modify argc, argv, or
+ any of the strings pointed to by argv. They may be passed to
+ multiple screens.
+ */
+ screenInfo.screens[i] = pScreen;
+ screenInfo.numScreens++;
+ if (!(*pfnInit)(i, pScreen, argc, argv))
+ {
+ dixFreePrivates(pScreen->devPrivates, PRIVATE_SCREEN);
+ free(pScreen);
+ screenInfo.numScreens--;
+ return -1;
+ }
+
+ dixRegisterPrivateKey(&cursorScreenDevPriv[i], PRIVATE_CURSOR, 0);
+
+ return i;
+}
diff --git a/dix/dispatch.h b/dix/dispatch.h
new file mode 100644
index 0000000..758b83d
--- /dev/null
+++ b/dix/dispatch.h
@@ -0,0 +1,145 @@
+/************************************************************
+
+Copyright 1996 by Thomas E. Dickey <dickey@clark.net>
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 the above listed
+copyright holder(s) not be used in advertising or publicity pertaining
+to distribution of the software without specific, written prior
+permission.
+
+THE ABOVE LISTED COPYRIGHT HOLDER(S) DISCLAIM ALL WARRANTIES WITH REGARD
+TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS, IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) 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.
+
+********************************************************/
+
+/*
+ * This prototypes the dispatch.c module (except for functions declared in
+ * global headers), plus related dispatch procedures from devices.c, events.c,
+ * extension.c, property.c.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#ifndef DISPATCH_H
+#define DISPATCH_H 1
+
+int ProcAllocColor(ClientPtr /* client */);
+int ProcAllocColorCells(ClientPtr /* client */);
+int ProcAllocColorPlanes(ClientPtr /* client */);
+int ProcAllocNamedColor(ClientPtr /* client */);
+int ProcBell(ClientPtr /* client */);
+int ProcChangeAccessControl(ClientPtr /* client */);
+int ProcChangeCloseDownMode(ClientPtr /* client */);
+int ProcChangeGC(ClientPtr /* client */);
+int ProcChangeHosts(ClientPtr /* client */);
+int ProcChangeKeyboardControl(ClientPtr /* client */);
+int ProcChangeKeyboardMapping(ClientPtr /* client */);
+int ProcChangePointerControl(ClientPtr /* client */);
+int ProcChangeProperty(ClientPtr /* client */);
+int ProcChangeSaveSet(ClientPtr /* client */);
+int ProcChangeWindowAttributes(ClientPtr /* client */);
+int ProcCirculateWindow(ClientPtr /* client */);
+int ProcClearToBackground(ClientPtr /* client */);
+int ProcCloseFont(ClientPtr /* client */);
+int ProcConfigureWindow(ClientPtr /* client */);
+int ProcConvertSelection(ClientPtr /* client */);
+int ProcCopyArea(ClientPtr /* client */);
+int ProcCopyColormapAndFree(ClientPtr /* client */);
+int ProcCopyGC(ClientPtr /* client */);
+int ProcCopyPlane(ClientPtr /* client */);
+int ProcCreateColormap(ClientPtr /* client */);
+int ProcCreateCursor(ClientPtr /* client */);
+int ProcCreateGC(ClientPtr /* client */);
+int ProcCreateGlyphCursor(ClientPtr /* client */);
+int ProcCreatePixmap(ClientPtr /* client */);
+int ProcCreateWindow(ClientPtr /* client */);
+int ProcDeleteProperty(ClientPtr /* client */);
+int ProcDestroySubwindows(ClientPtr /* client */);
+int ProcDestroyWindow(ClientPtr /* client */);
+int ProcEstablishConnection(ClientPtr /* client */);
+int ProcFillPoly(ClientPtr /* client */);
+int ProcForceScreenSaver(ClientPtr /* client */);
+int ProcFreeColormap(ClientPtr /* client */);
+int ProcFreeColors(ClientPtr /* client */);
+int ProcFreeCursor(ClientPtr /* client */);
+int ProcFreeGC(ClientPtr /* client */);
+int ProcFreePixmap(ClientPtr /* client */);
+int ProcGetAtomName(ClientPtr /* client */);
+int ProcGetFontPath(ClientPtr /* client */);
+int ProcGetGeometry(ClientPtr /* client */);
+int ProcGetImage(ClientPtr /* client */);
+int ProcGetKeyboardControl(ClientPtr /* client */);
+int ProcGetKeyboardMapping(ClientPtr /* client */);
+int ProcGetModifierMapping(ClientPtr /* client */);
+int ProcGetMotionEvents(ClientPtr /* client */);
+int ProcGetPointerControl(ClientPtr /* client */);
+int ProcGetPointerMapping(ClientPtr /* client */);
+int ProcGetProperty(ClientPtr /* client */);
+int ProcGetScreenSaver(ClientPtr /* client */);
+int ProcGetSelectionOwner(ClientPtr /* client */);
+int ProcGetWindowAttributes(ClientPtr /* client */);
+int ProcGrabServer(ClientPtr /* client */);
+int ProcImageText16(ClientPtr /* client */);
+int ProcImageText8(ClientPtr /* client */);
+int ProcInitialConnection(ClientPtr /* client */);
+int ProcInstallColormap(ClientPtr /* client */);
+int ProcInternAtom(ClientPtr /* client */);
+int ProcKillClient(ClientPtr /* client */);
+int ProcListExtensions(ClientPtr /* client */);
+int ProcListFonts(ClientPtr /* client */);
+int ProcListFontsWithInfo(ClientPtr /* client */);
+int ProcListHosts(ClientPtr /* client */);
+int ProcListInstalledColormaps(ClientPtr /* client */);
+int ProcListProperties(ClientPtr /* client */);
+int ProcLookupColor(ClientPtr /* client */);
+int ProcMapSubwindows(ClientPtr /* client */);
+int ProcMapWindow(ClientPtr /* client */);
+int ProcNoOperation(ClientPtr /* client */);
+int ProcOpenFont(ClientPtr /* client */);
+int ProcPolyArc(ClientPtr /* client */);
+int ProcPolyFillArc(ClientPtr /* client */);
+int ProcPolyFillRectangle(ClientPtr /* client */);
+int ProcPolyLine(ClientPtr /* client */);
+int ProcPolyPoint(ClientPtr /* client */);
+int ProcPolyRectangle(ClientPtr /* client */);
+int ProcPolySegment(ClientPtr /* client */);
+int ProcPolyText(ClientPtr /* client */);
+int ProcPutImage(ClientPtr /* client */);
+int ProcQueryBestSize(ClientPtr /* client */);
+int ProcQueryColors(ClientPtr /* client */);
+int ProcQueryExtension(ClientPtr /* client */);
+int ProcQueryFont(ClientPtr /* client */);
+int ProcQueryKeymap(ClientPtr /* client */);
+int ProcQueryTextExtents(ClientPtr /* client */);
+int ProcQueryTree(ClientPtr /* client */);
+int ProcReparentWindow(ClientPtr /* client */);
+int ProcRotateProperties(ClientPtr /* client */);
+int ProcSetClipRectangles(ClientPtr /* client */);
+int ProcSetDashes(ClientPtr /* client */);
+int ProcSetFontPath(ClientPtr /* client */);
+int ProcSetModifierMapping(ClientPtr /* client */);
+int ProcSetPointerMapping(ClientPtr /* client */);
+int ProcSetScreenSaver(ClientPtr /* client */);
+int ProcSetSelectionOwner(ClientPtr /* client */);
+int ProcStoreColors(ClientPtr /* client */);
+int ProcStoreNamedColor(ClientPtr /* client */);
+int ProcTranslateCoords(ClientPtr /* client */);
+int ProcUngrabServer(ClientPtr /* client */);
+int ProcUninstallColormap(ClientPtr /* client */);
+int ProcUnmapSubwindows(ClientPtr /* client */);
+int ProcUnmapWindow(ClientPtr /* client */);
+
+#endif /* DISPATCH_H */
diff --git a/dix/dix.c b/dix/dix.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dix/dix.c
diff --git a/dix/dixfonts.c b/dix/dixfonts.c
new file mode 100644
index 0000000..fbac124
--- /dev/null
+++ b/dix/dixfonts.c
@@ -0,0 +1,2072 @@
+/************************************************************************
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+************************************************************************/
+/* The panoramix components contained the following notice */
+/*
+Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
+BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of Digital Equipment Corporation
+shall not be used in advertising or otherwise to promote the sale, use or other
+dealings in this Software without prior written authorization from Digital
+Equipment Corporation.
+
+******************************************************************/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/Xmd.h>
+#include <X11/Xproto.h>
+#include "scrnintstr.h"
+#include "resource.h"
+#include "dixstruct.h"
+#include "cursorstr.h"
+#include "misc.h"
+#include "opaque.h"
+#include "dixfontstr.h"
+#include "closestr.h"
+#include "dixfont.h"
+#include "xace.h"
+
+#ifdef XF86BIGFONT
+#include "xf86bigfontsrv.h"
+#endif
+
+extern pointer fosNaturalParams;
+extern FontPtr defaultFont;
+
+static FontPathElementPtr *font_path_elements = (FontPathElementPtr *) 0;
+static int num_fpes = 0;
+static FPEFunctions *fpe_functions = (FPEFunctions *) 0;
+static int num_fpe_types = 0;
+
+static unsigned char *font_path_string;
+
+static int num_slept_fpes = 0;
+static int size_slept_fpes = 0;
+static FontPathElementPtr *slept_fpes = (FontPathElementPtr *) 0;
+static FontPatternCachePtr patternCache;
+
+static int
+FontToXError(int err)
+{
+ switch (err) {
+ case Successful:
+ return Success;
+ case AllocError:
+ return BadAlloc;
+ case BadFontName:
+ return BadName;
+ case BadFontPath:
+ case BadFontFormat: /* is there something better? */
+ case BadCharRange:
+ return BadValue;
+ default:
+ return err;
+ }
+}
+
+static int
+LoadGlyphs(ClientPtr client, FontPtr pfont, unsigned nchars, int item_size,
+ unsigned char *data)
+{
+ if (fpe_functions[pfont->fpe->type].load_glyphs)
+ return (*fpe_functions[pfont->fpe->type].load_glyphs)
+ (client, pfont, 0, nchars, item_size, data);
+ else
+ return Successful;
+}
+
+/*
+ * adding RT_FONT prevents conflict with default cursor font
+ */
+Bool
+SetDefaultFont(char *defaultfontname)
+{
+ int err;
+ FontPtr pf;
+ XID fid;
+
+ fid = FakeClientID(0);
+ err = OpenFont(serverClient, fid, FontLoadAll | FontOpenSync,
+ (unsigned) strlen(defaultfontname), defaultfontname);
+ if (err != Success)
+ return FALSE;
+ err = dixLookupResourceByType((pointer *)&pf, fid, RT_FONT, serverClient,
+ DixReadAccess);
+ if (err != Success)
+ return FALSE;
+ defaultFont = pf;
+ return TRUE;
+}
+
+/*
+ * note that the font wakeup queue is not refcounted. this is because
+ * an fpe needs to be added when it's inited, and removed when it's finally
+ * freed, in order to handle any data that isn't requested, like FS events.
+ *
+ * since the only thing that should call these routines is the renderer's
+ * init_fpe() and free_fpe(), there shouldn't be any problem in using
+ * freed data.
+ */
+void
+QueueFontWakeup(FontPathElementPtr fpe)
+{
+ int i;
+ FontPathElementPtr *new;
+
+ for (i = 0; i < num_slept_fpes; i++) {
+ if (slept_fpes[i] == fpe) {
+ return;
+ }
+ }
+ if (num_slept_fpes == size_slept_fpes) {
+ new = (FontPathElementPtr *)
+ realloc(slept_fpes,
+ sizeof(FontPathElementPtr) * (size_slept_fpes + 4));
+ if (!new)
+ return;
+ slept_fpes = new;
+ size_slept_fpes += 4;
+ }
+ slept_fpes[num_slept_fpes] = fpe;
+ num_slept_fpes++;
+}
+
+void
+RemoveFontWakeup(FontPathElementPtr fpe)
+{
+ int i,
+ j;
+
+ for (i = 0; i < num_slept_fpes; i++) {
+ if (slept_fpes[i] == fpe) {
+ for (j = i; j < num_slept_fpes; j++) {
+ slept_fpes[j] = slept_fpes[j + 1];
+ }
+ num_slept_fpes--;
+ return;
+ }
+ }
+}
+
+void
+FontWakeup(pointer data, int count, pointer LastSelectMask)
+{
+ int i;
+ FontPathElementPtr fpe;
+
+ if (count < 0)
+ return;
+ /* wake up any fpe's that may be waiting for information */
+ for (i = 0; i < num_slept_fpes; i++) {
+ fpe = slept_fpes[i];
+ (void) (*fpe_functions[fpe->type].wakeup_fpe) (fpe, LastSelectMask);
+ }
+}
+
+/* XXX -- these two funcs may want to be broken into macros */
+static void
+UseFPE(FontPathElementPtr fpe)
+{
+ fpe->refcount++;
+}
+
+static void
+FreeFPE (FontPathElementPtr fpe)
+{
+ fpe->refcount--;
+ if (fpe->refcount == 0) {
+ (*fpe_functions[fpe->type].free_fpe) (fpe);
+ free(fpe->name);
+ free(fpe);
+ }
+}
+
+static Bool
+doOpenFont(ClientPtr client, OFclosurePtr c)
+{
+ FontPtr pfont = NullFont;
+ FontPathElementPtr fpe = NULL;
+ ScreenPtr pScr;
+ int err = Successful;
+ int i;
+ char *alias,
+ *newname;
+ int newlen;
+ int aliascount = 20;
+ /*
+ * Decide at runtime what FontFormat to use.
+ */
+ Mask FontFormat =
+
+ ((screenInfo.imageByteOrder == LSBFirst) ?
+ BitmapFormatByteOrderLSB : BitmapFormatByteOrderMSB) |
+
+ ((screenInfo.bitmapBitOrder == LSBFirst) ?
+ BitmapFormatBitOrderLSB : BitmapFormatBitOrderMSB) |
+
+ BitmapFormatImageRectMin |
+
+#if GLYPHPADBYTES == 1
+ BitmapFormatScanlinePad8 |
+#endif
+
+#if GLYPHPADBYTES == 2
+ BitmapFormatScanlinePad16 |
+#endif
+
+#if GLYPHPADBYTES == 4
+ BitmapFormatScanlinePad32 |
+#endif
+
+#if GLYPHPADBYTES == 8
+ BitmapFormatScanlinePad64 |
+#endif
+
+ BitmapFormatScanlineUnit8;
+
+ if (client->clientGone)
+ {
+ if (c->current_fpe < c->num_fpes)
+ {
+ fpe = c->fpe_list[c->current_fpe];
+ (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
+ }
+ err = Successful;
+ goto bail;
+ }
+ while (c->current_fpe < c->num_fpes) {
+ fpe = c->fpe_list[c->current_fpe];
+ err = (*fpe_functions[fpe->type].open_font)
+ ((pointer) client, fpe, c->flags,
+ c->fontname, c->fnamelen, FontFormat,
+ BitmapFormatMaskByte |
+ BitmapFormatMaskBit |
+ BitmapFormatMaskImageRectangle |
+ BitmapFormatMaskScanLinePad |
+ BitmapFormatMaskScanLineUnit,
+ c->fontid, &pfont, &alias,
+ c->non_cachable_font && c->non_cachable_font->fpe == fpe ?
+ c->non_cachable_font :
+ (FontPtr)0);
+
+ if (err == FontNameAlias && alias) {
+ newlen = strlen(alias);
+ newname = (char *) realloc(c->fontname, newlen);
+ if (!newname) {
+ err = AllocError;
+ break;
+ }
+ memmove(newname, alias, newlen);
+ c->fontname = newname;
+ c->fnamelen = newlen;
+ c->current_fpe = 0;
+ if (--aliascount <= 0) {
+ /* We've tried resolving this alias 20 times, we're
+ * probably stuck in an infinite loop of aliases pointing
+ * to each other - time to take emergency exit!
+ */
+ err = BadImplementation;
+ break;
+ }
+ continue;
+ }
+ if (err == BadFontName) {
+ c->current_fpe++;
+ continue;
+ }
+ if (err == Suspended) {
+ if (!ClientIsAsleep(client))
+ ClientSleep(client, (ClientSleepProcPtr)doOpenFont, c);
+ else
+ goto xinerama_sleep;
+ return TRUE;
+ }
+ break;
+ }
+
+ if (err != Successful)
+ goto bail;
+ if (!pfont) {
+ err = BadFontName;
+ goto bail;
+ }
+ /* check values for firstCol, lastCol, firstRow, and lastRow */
+ if (pfont->info.firstCol > pfont->info.lastCol ||
+ pfont->info.firstRow > pfont->info.lastRow ||
+ pfont->info.lastCol - pfont->info.firstCol > 255) {
+ err = AllocError;
+ goto bail;
+ }
+ if (!pfont->fpe)
+ pfont->fpe = fpe;
+ pfont->refcnt++;
+ if (pfont->refcnt == 1) {
+ UseFPE(pfont->fpe);
+ for (i = 0; i < screenInfo.numScreens; i++) {
+ pScr = screenInfo.screens[i];
+ if (pScr->RealizeFont)
+ {
+ if (!(*pScr->RealizeFont) (pScr, pfont))
+ {
+ CloseFont (pfont, (Font) 0);
+ err = AllocError;
+ goto bail;
+ }
+ }
+ }
+ }
+ if (!AddResource(c->fontid, RT_FONT, (pointer) pfont)) {
+ err = AllocError;
+ goto bail;
+ }
+ if (patternCache && pfont != c->non_cachable_font)
+ CacheFontPattern(patternCache, c->origFontName, c->origFontNameLen,
+ pfont);
+bail:
+ if (err != Successful && c->client != serverClient) {
+ SendErrorToClient(c->client, X_OpenFont, 0,
+ c->fontid, FontToXError(err));
+ }
+ ClientWakeup(c->client);
+xinerama_sleep:
+ for (i = 0; i < c->num_fpes; i++) {
+ FreeFPE(c->fpe_list[i]);
+ }
+ free(c->fpe_list);
+ free(c->fontname);
+ free(c);
+ return TRUE;
+}
+
+int
+OpenFont(ClientPtr client, XID fid, Mask flags, unsigned lenfname, char *pfontname)
+{
+ OFclosurePtr c;
+ int i;
+ FontPtr cached = (FontPtr)0;
+
+ if (!lenfname || lenfname > XLFDMAXFONTNAMELEN)
+ return BadName;
+ if (patternCache)
+ {
+
+ /*
+ ** Check name cache. If we find a cached version of this font that
+ ** is cachable, immediately satisfy the request with it. If we find
+ ** a cached version of this font that is non-cachable, we do not
+ ** satisfy the request with it. Instead, we pass the FontPtr to the
+ ** FPE's open_font code (the fontfile FPE in turn passes the
+ ** information to the rasterizer; the fserve FPE ignores it).
+ **
+ ** Presumably, the font is marked non-cachable because the FPE has
+ ** put some licensing restrictions on it. If the FPE, using
+ ** whatever logic it relies on, determines that it is willing to
+ ** share this existing font with the client, then it has the option
+ ** to return the FontPtr we passed it as the newly-opened font.
+ ** This allows the FPE to exercise its licensing logic without
+ ** having to create another instance of a font that already exists.
+ */
+
+ cached = FindCachedFontPattern(patternCache, pfontname, lenfname);
+ if (cached && cached->info.cachable)
+ {
+ if (!AddResource(fid, RT_FONT, (pointer) cached))
+ return BadAlloc;
+ cached->refcnt++;
+ return Success;
+ }
+ }
+ c = malloc(sizeof(OFclosureRec));
+ if (!c)
+ return BadAlloc;
+ c->fontname = malloc(lenfname);
+ c->origFontName = pfontname;
+ c->origFontNameLen = lenfname;
+ if (!c->fontname) {
+ free(c);
+ return BadAlloc;
+ }
+ /*
+ * copy the current FPE list, so that if it gets changed by another client
+ * while we're blocking, the request still appears atomic
+ */
+ c->fpe_list = malloc(sizeof(FontPathElementPtr) * num_fpes);
+ if (!c->fpe_list) {
+ free(c->fontname);
+ free(c);
+ return BadAlloc;
+ }
+ memmove(c->fontname, pfontname, lenfname);
+ for (i = 0; i < num_fpes; i++) {
+ c->fpe_list[i] = font_path_elements[i];
+ UseFPE(c->fpe_list[i]);
+ }
+ c->client = client;
+ c->fontid = fid;
+ c->current_fpe = 0;
+ c->num_fpes = num_fpes;
+ c->fnamelen = lenfname;
+ c->flags = flags;
+ c->non_cachable_font = cached;
+
+ (void) doOpenFont(client, c);
+ return Success;
+}
+
+/**
+ * Decrement font's ref count, and free storage if ref count equals zero
+ *
+ * \param value must conform to DeleteType
+ */
+int
+CloseFont(pointer value, XID fid)
+{
+ int nscr;
+ ScreenPtr pscr;
+ FontPathElementPtr fpe;
+ FontPtr pfont = (FontPtr)value;
+
+ if (pfont == NullFont)
+ return Success;
+ if (--pfont->refcnt == 0) {
+ if (patternCache)
+ RemoveCachedFontPattern (patternCache, pfont);
+ /*
+ * since the last reference is gone, ask each screen to free any
+ * storage it may have allocated locally for it.
+ */
+ for (nscr = 0; nscr < screenInfo.numScreens; nscr++) {
+ pscr = screenInfo.screens[nscr];
+ if (pscr->UnrealizeFont)
+ (*pscr->UnrealizeFont) (pscr, pfont);
+ }
+ if (pfont == defaultFont)
+ defaultFont = NULL;
+#ifdef XF86BIGFONT
+ XF86BigfontFreeFontShm(pfont);
+#endif
+ fpe = pfont->fpe;
+ (*fpe_functions[fpe->type].close_font) (fpe, pfont);
+ FreeFPE(fpe);
+ }
+ return Success;
+}
+
+
+/***====================================================================***/
+
+/**
+ * Sets up pReply as the correct QueryFontReply for pFont with the first
+ * nProtoCCIStructs char infos.
+ *
+ * \param pReply caller must allocate this storage
+ */
+void
+QueryFont(FontPtr pFont, xQueryFontReply *pReply, int nProtoCCIStructs)
+{
+ FontPropPtr pFP;
+ int r,
+ c,
+ i;
+ xFontProp *prFP;
+ xCharInfo *prCI;
+ xCharInfo *charInfos[256];
+ unsigned char chars[512];
+ int ninfos;
+ unsigned long ncols;
+ unsigned long count;
+
+ /* pr->length set in dispatch */
+ pReply->minCharOrByte2 = pFont->info.firstCol;
+ pReply->defaultChar = pFont->info.defaultCh;
+ pReply->maxCharOrByte2 = pFont->info.lastCol;
+ pReply->drawDirection = pFont->info.drawDirection;
+ pReply->allCharsExist = pFont->info.allExist;
+ pReply->minByte1 = pFont->info.firstRow;
+ pReply->maxByte1 = pFont->info.lastRow;
+ pReply->fontAscent = pFont->info.fontAscent;
+ pReply->fontDescent = pFont->info.fontDescent;
+
+ pReply->minBounds = pFont->info.ink_minbounds;
+ pReply->maxBounds = pFont->info.ink_maxbounds;
+
+ pReply->nFontProps = pFont->info.nprops;
+ pReply->nCharInfos = nProtoCCIStructs;
+
+ for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) (&pReply[1]);
+ i < pFont->info.nprops;
+ i++, pFP++, prFP++) {
+ prFP->name = pFP->name;
+ prFP->value = pFP->value;
+ }
+
+ ninfos = 0;
+ ncols = (unsigned long) (pFont->info.lastCol - pFont->info.firstCol + 1);
+ prCI = (xCharInfo *) (prFP);
+ for (r = pFont->info.firstRow;
+ ninfos < nProtoCCIStructs && r <= (int)pFont->info.lastRow;
+ r++) {
+ i = 0;
+ for (c = pFont->info.firstCol; c <= (int)pFont->info.lastCol; c++) {
+ chars[i++] = r;
+ chars[i++] = c;
+ }
+ (*pFont->get_metrics) (pFont, ncols, chars,
+ TwoD16Bit, &count, charInfos);
+ i = 0;
+ for (i = 0; i < (int) count && ninfos < nProtoCCIStructs; i++) {
+ *prCI = *charInfos[i];
+ prCI++;
+ ninfos++;
+ }
+ }
+ return;
+}
+
+static Bool
+doListFontsAndAliases(ClientPtr client, LFclosurePtr c)
+{
+ FontPathElementPtr fpe;
+ int err = Successful;
+ FontNamesPtr names = NULL;
+ char *name, *resolved=NULL;
+ int namelen, resolvedlen;
+ int nnames;
+ int stringLens;
+ int i;
+ xListFontsReply reply;
+ char *bufptr;
+ char *bufferStart;
+ int aliascount = 0;
+
+ if (client->clientGone)
+ {
+ if (c->current.current_fpe < c->num_fpes)
+ {
+ fpe = c->fpe_list[c->current.current_fpe];
+ (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
+ }
+ err = Successful;
+ goto bail;
+ }
+
+ if (!c->current.patlen)
+ goto finish;
+
+ while (c->current.current_fpe < c->num_fpes) {
+ fpe = c->fpe_list[c->current.current_fpe];
+ err = Successful;
+
+ if (!fpe_functions[fpe->type].start_list_fonts_and_aliases)
+ {
+ /* This FPE doesn't support/require list_fonts_and_aliases */
+
+ err = (*fpe_functions[fpe->type].list_fonts)
+ ((pointer) c->client, fpe, c->current.pattern,
+ c->current.patlen, c->current.max_names - c->names->nnames,
+ c->names);
+
+ if (err == Suspended) {
+ if (!ClientIsAsleep(client))
+ ClientSleep(client,
+ (ClientSleepProcPtr)doListFontsAndAliases,
+ c);
+ else
+ goto xinerama_sleep;
+ return TRUE;
+ }
+
+ err = BadFontName;
+ }
+ else
+ {
+ /* Start of list_fonts_and_aliases functionality. Modeled
+ after list_fonts_with_info in that it resolves aliases,
+ except that the information collected from FPEs is just
+ names, not font info. Each list_next_font_or_alias()
+ returns either a name into name/namelen or an alias into
+ name/namelen and its target name into resolved/resolvedlen.
+ The code at this level then resolves the alias by polling
+ the FPEs. */
+
+ if (!c->current.list_started) {
+ err = (*fpe_functions[fpe->type].start_list_fonts_and_aliases)
+ ((pointer) c->client, fpe, c->current.pattern,
+ c->current.patlen, c->current.max_names - c->names->nnames,
+ &c->current.private);
+ if (err == Suspended) {
+ if (!ClientIsAsleep(client))
+ ClientSleep(client,
+ (ClientSleepProcPtr)doListFontsAndAliases,
+ c);
+ else
+ goto xinerama_sleep;
+ return TRUE;
+ }
+ if (err == Successful)
+ c->current.list_started = TRUE;
+ }
+ if (err == Successful) {
+ char *tmpname;
+ name = 0;
+ err = (*fpe_functions[fpe->type].list_next_font_or_alias)
+ ((pointer) c->client, fpe, &name, &namelen, &tmpname,
+ &resolvedlen, c->current.private);
+ if (err == Suspended) {
+ if (!ClientIsAsleep(client))
+ ClientSleep(client,
+ (ClientSleepProcPtr)doListFontsAndAliases,
+ c);
+ else
+ goto xinerama_sleep;
+ return TRUE;
+ }
+ if (err == FontNameAlias) {
+ free(resolved);
+ resolved = malloc(resolvedlen + 1);
+ if (resolved)
+ memmove(resolved, tmpname, resolvedlen + 1);
+ }
+ }
+
+ if (err == Successful)
+ {
+ if (c->haveSaved)
+ {
+ if (c->savedName)
+ (void)AddFontNamesName(c->names, c->savedName,
+ c->savedNameLen);
+ }
+ else
+ (void)AddFontNamesName(c->names, name, namelen);
+ }
+
+ /*
+ * When we get an alias back, save our state and reset back to
+ * the start of the FPE looking for the specified name. As
+ * soon as a real font is found for the alias, pop back to the
+ * old state
+ */
+ else if (err == FontNameAlias) {
+ char tmp_pattern[XLFDMAXFONTNAMELEN];
+ /*
+ * when an alias recurses, we need to give
+ * the last FPE a chance to clean up; so we call
+ * it again, and assume that the error returned
+ * is BadFontName, indicating the alias resolution
+ * is complete.
+ */
+ memmove(tmp_pattern, resolved, resolvedlen);
+ if (c->haveSaved)
+ {
+ char *tmpname;
+ int tmpnamelen;
+
+ tmpname = 0;
+ (void) (*fpe_functions[fpe->type].list_next_font_or_alias)
+ ((pointer) c->client, fpe, &tmpname, &tmpnamelen,
+ &tmpname, &tmpnamelen, c->current.private);
+ if (--aliascount <= 0)
+ {
+ err = BadFontName;
+ goto ContBadFontName;
+ }
+ }
+ else
+ {
+ c->saved = c->current;
+ c->haveSaved = TRUE;
+ free(c->savedName);
+ c->savedName = malloc(namelen + 1);
+ if (c->savedName)
+ memmove(c->savedName, name, namelen + 1);
+ c->savedNameLen = namelen;
+ aliascount = 20;
+ }
+ memmove(c->current.pattern, tmp_pattern, resolvedlen);
+ c->current.patlen = resolvedlen;
+ c->current.max_names = c->names->nnames + 1;
+ c->current.current_fpe = -1;
+ c->current.private = 0;
+ err = BadFontName;
+ }
+ }
+ /*
+ * At the end of this FPE, step to the next. If we've finished
+ * processing an alias, pop state back. If we've collected enough
+ * font names, quit.
+ */
+ if (err == BadFontName) {
+ ContBadFontName: ;
+ c->current.list_started = FALSE;
+ c->current.current_fpe++;
+ err = Successful;
+ if (c->haveSaved)
+ {
+ if (c->names->nnames == c->current.max_names ||
+ c->current.current_fpe == c->num_fpes) {
+ c->haveSaved = FALSE;
+ c->current = c->saved;
+ /* Give the saved namelist a chance to clean itself up */
+ continue;
+ }
+ }
+ if (c->names->nnames == c->current.max_names)
+ break;
+ }
+ }
+
+ /*
+ * send the reply
+ */
+ if (err != Successful) {
+ SendErrorToClient(client, X_ListFonts, 0, 0, FontToXError(err));
+ goto bail;
+ }
+
+finish:
+
+ names = c->names;
+ nnames = names->nnames;
+ client = c->client;
+ stringLens = 0;
+ for (i = 0; i < nnames; i++)
+ stringLens += (names->length[i] <= 255) ? names->length[i] : 0;
+
+ memset(&reply, 0, sizeof(xListFontsReply));
+ reply.type = X_Reply;
+ reply.length = bytes_to_int32(stringLens + nnames);
+ reply.nFonts = nnames;
+ reply.sequenceNumber = client->sequence;
+
+ bufptr = bufferStart = malloc(reply.length << 2);
+
+ if (!bufptr && reply.length) {
+ SendErrorToClient(client, X_ListFonts, 0, 0, BadAlloc);
+ goto bail;
+ }
+ /*
+ * since WriteToClient long word aligns things, copy to temp buffer and
+ * write all at once
+ */
+ for (i = 0; i < nnames; i++) {
+ if (names->length[i] > 255)
+ reply.nFonts--;
+ else
+ {
+ *bufptr++ = names->length[i];
+ memmove( bufptr, names->names[i], names->length[i]);
+ bufptr += names->length[i];
+ }
+ }
+ nnames = reply.nFonts;
+ reply.length = bytes_to_int32(stringLens + nnames);
+ client->pSwapReplyFunc = ReplySwapVector[X_ListFonts];
+ WriteSwappedDataToClient(client, sizeof(xListFontsReply), &reply);
+ (void) WriteToClient(client, stringLens + nnames, bufferStart);
+ free(bufferStart);
+
+bail:
+ ClientWakeup(client);
+xinerama_sleep:
+ for (i = 0; i < c->num_fpes; i++)
+ FreeFPE(c->fpe_list[i]);
+ free(c->fpe_list);
+ free(c->savedName);
+ FreeFontNames(names);
+ free(c);
+ free(resolved);
+ return TRUE;
+}
+
+int
+ListFonts(ClientPtr client, unsigned char *pattern, unsigned length,
+ unsigned max_names)
+{
+ int i;
+ LFclosurePtr c;
+
+ /*
+ * The right error to return here would be BadName, however the
+ * specification does not allow for a Name error on this request.
+ * Perhaps a better solution would be to return a nil list, i.e.
+ * a list containing zero fontnames.
+ */
+ if (length > XLFDMAXFONTNAMELEN)
+ return BadAlloc;
+
+ i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess);
+ if (i != Success)
+ return i;
+
+ if (!(c = malloc(sizeof *c)))
+ return BadAlloc;
+ c->fpe_list = malloc(sizeof(FontPathElementPtr) * num_fpes);
+ if (!c->fpe_list) {
+ free(c);
+ return BadAlloc;
+ }
+ c->names = MakeFontNamesRecord(max_names < 100 ? max_names : 100);
+ if (!c->names)
+ {
+ free(c->fpe_list);
+ free(c);
+ return BadAlloc;
+ }
+ memmove( c->current.pattern, pattern, length);
+ for (i = 0; i < num_fpes; i++) {
+ c->fpe_list[i] = font_path_elements[i];
+ UseFPE(c->fpe_list[i]);
+ }
+ c->client = client;
+ c->num_fpes = num_fpes;
+ c->current.patlen = length;
+ c->current.current_fpe = 0;
+ c->current.max_names = max_names;
+ c->current.list_started = FALSE;
+ c->current.private = 0;
+ c->haveSaved = FALSE;
+ c->savedName = 0;
+ doListFontsAndAliases(client, c);
+ return Success;
+}
+
+int
+doListFontsWithInfo(ClientPtr client, LFWIclosurePtr c)
+{
+ FontPathElementPtr fpe;
+ int err = Successful;
+ char *name;
+ int namelen;
+ int numFonts;
+ FontInfoRec fontInfo,
+ *pFontInfo;
+ xListFontsWithInfoReply *reply;
+ int length;
+ xFontProp *pFP;
+ int i;
+ int aliascount = 0;
+ xListFontsWithInfoReply finalReply;
+
+ if (client->clientGone)
+ {
+ if (c->current.current_fpe < c->num_fpes)
+ {
+ fpe = c->fpe_list[c->current.current_fpe];
+ (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
+ }
+ err = Successful;
+ goto bail;
+ }
+ client->pSwapReplyFunc = ReplySwapVector[X_ListFontsWithInfo];
+ if (!c->current.patlen)
+ goto finish;
+ while (c->current.current_fpe < c->num_fpes)
+ {
+ fpe = c->fpe_list[c->current.current_fpe];
+ err = Successful;
+ if (!c->current.list_started)
+ {
+ err = (*fpe_functions[fpe->type].start_list_fonts_with_info)
+ (client, fpe, c->current.pattern, c->current.patlen,
+ c->current.max_names, &c->current.private);
+ if (err == Suspended)
+ {
+ if (!ClientIsAsleep(client))
+ ClientSleep(client,
+ (ClientSleepProcPtr)doListFontsWithInfo, c);
+ else
+ goto xinerama_sleep;
+ return TRUE;
+ }
+ if (err == Successful)
+ c->current.list_started = TRUE;
+ }
+ if (err == Successful)
+ {
+ name = 0;
+ pFontInfo = &fontInfo;
+ err = (*fpe_functions[fpe->type].list_next_font_with_info)
+ (client, fpe, &name, &namelen, &pFontInfo,
+ &numFonts, c->current.private);
+ if (err == Suspended)
+ {
+ if (!ClientIsAsleep(client))
+ ClientSleep(client,
+ (ClientSleepProcPtr)doListFontsWithInfo, c);
+ else
+ goto xinerama_sleep;
+ return TRUE;
+ }
+ }
+ /*
+ * When we get an alias back, save our state and reset back to the
+ * start of the FPE looking for the specified name. As soon as a real
+ * font is found for the alias, pop back to the old state
+ */
+ if (err == FontNameAlias)
+ {
+ /*
+ * when an alias recurses, we need to give
+ * the last FPE a chance to clean up; so we call
+ * it again, and assume that the error returned
+ * is BadFontName, indicating the alias resolution
+ * is complete.
+ */
+ if (c->haveSaved)
+ {
+ char *tmpname;
+ int tmpnamelen;
+ FontInfoPtr tmpFontInfo;
+
+ tmpname = 0;
+ tmpFontInfo = &fontInfo;
+ (void) (*fpe_functions[fpe->type].list_next_font_with_info)
+ (client, fpe, &tmpname, &tmpnamelen, &tmpFontInfo,
+ &numFonts, c->current.private);
+ if (--aliascount <= 0)
+ {
+ err = BadFontName;
+ goto ContBadFontName;
+ }
+ }
+ else
+ {
+ c->saved = c->current;
+ c->haveSaved = TRUE;
+ c->savedNumFonts = numFonts;
+ free(c->savedName);
+ c->savedName = malloc(namelen + 1);
+ if (c->savedName)
+ memmove(c->savedName, name, namelen + 1);
+ aliascount = 20;
+ }
+ memmove(c->current.pattern, name, namelen);
+ c->current.patlen = namelen;
+ c->current.max_names = 1;
+ c->current.current_fpe = 0;
+ c->current.private = 0;
+ c->current.list_started = FALSE;
+ }
+ /*
+ * At the end of this FPE, step to the next. If we've finished
+ * processing an alias, pop state back. If we've sent enough font
+ * names, quit. Always wait for BadFontName to let the FPE
+ * have a chance to clean up.
+ */
+ else if (err == BadFontName)
+ {
+ ContBadFontName: ;
+ c->current.list_started = FALSE;
+ c->current.current_fpe++;
+ err = Successful;
+ if (c->haveSaved)
+ {
+ if (c->current.max_names == 0 ||
+ c->current.current_fpe == c->num_fpes)
+ {
+ c->haveSaved = FALSE;
+ c->saved.max_names -= (1 - c->current.max_names);
+ c->current = c->saved;
+ }
+ }
+ else if (c->current.max_names == 0)
+ break;
+ }
+ else if (err == Successful)
+ {
+ length = sizeof(*reply) + pFontInfo->nprops * sizeof(xFontProp);
+ reply = c->reply;
+ if (c->length < length)
+ {
+ reply = (xListFontsWithInfoReply *) realloc(c->reply, length);
+ if (!reply)
+ {
+ err = AllocError;
+ break;
+ }
+ memset((char*)reply + c->length, 0, length - c->length);
+ c->reply = reply;
+ c->length = length;
+ }
+ if (c->haveSaved)
+ {
+ numFonts = c->savedNumFonts;
+ name = c->savedName;
+ namelen = strlen(name);
+ }
+ reply->type = X_Reply;
+ reply->length = bytes_to_int32(sizeof *reply - sizeof(xGenericReply) +
+ pFontInfo->nprops * sizeof(xFontProp) +
+ namelen);
+ reply->sequenceNumber = client->sequence;
+ reply->nameLength = namelen;
+ reply->minBounds = pFontInfo->ink_minbounds;
+ reply->maxBounds = pFontInfo->ink_maxbounds;
+ reply->minCharOrByte2 = pFontInfo->firstCol;
+ reply->maxCharOrByte2 = pFontInfo->lastCol;
+ reply->defaultChar = pFontInfo->defaultCh;
+ reply->nFontProps = pFontInfo->nprops;
+ reply->drawDirection = pFontInfo->drawDirection;
+ reply->minByte1 = pFontInfo->firstRow;
+ reply->maxByte1 = pFontInfo->lastRow;
+ reply->allCharsExist = pFontInfo->allExist;
+ reply->fontAscent = pFontInfo->fontAscent;
+ reply->fontDescent = pFontInfo->fontDescent;
+ reply->nReplies = numFonts;
+ pFP = (xFontProp *) (reply + 1);
+ for (i = 0; i < pFontInfo->nprops; i++)
+ {
+ pFP->name = pFontInfo->props[i].name;
+ pFP->value = pFontInfo->props[i].value;
+ pFP++;
+ }
+ WriteSwappedDataToClient(client, length, reply);
+ (void) WriteToClient(client, namelen, name);
+ if (pFontInfo == &fontInfo)
+ {
+ free(fontInfo.props);
+ free(fontInfo.isStringProp);
+ }
+ --c->current.max_names;
+ }
+ }
+finish:
+ length = sizeof(xListFontsWithInfoReply);
+ memset((char *) &finalReply, 0, sizeof(xListFontsWithInfoReply));
+ finalReply.type = X_Reply;
+ finalReply.sequenceNumber = client->sequence;
+ finalReply.length = bytes_to_int32(sizeof(xListFontsWithInfoReply)
+ - sizeof(xGenericReply));
+ WriteSwappedDataToClient(client, length, &finalReply);
+bail:
+ ClientWakeup(client);
+xinerama_sleep:
+ for (i = 0; i < c->num_fpes; i++)
+ FreeFPE(c->fpe_list[i]);
+ free(c->reply);
+ free(c->fpe_list);
+ free(c->savedName);
+ free(c);
+ return TRUE;
+}
+
+int
+StartListFontsWithInfo(ClientPtr client, int length, unsigned char *pattern,
+ int max_names)
+{
+ int i;
+ LFWIclosurePtr c;
+
+ /*
+ * The right error to return here would be BadName, however the
+ * specification does not allow for a Name error on this request.
+ * Perhaps a better solution would be to return a nil list, i.e.
+ * a list containing zero fontnames.
+ */
+ if (length > XLFDMAXFONTNAMELEN)
+ return BadAlloc;
+
+ i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess);
+ if (i != Success)
+ return i;
+
+ if (!(c = malloc(sizeof *c)))
+ goto badAlloc;
+ c->fpe_list = malloc(sizeof(FontPathElementPtr) * num_fpes);
+ if (!c->fpe_list)
+ {
+ free(c);
+ goto badAlloc;
+ }
+ memmove(c->current.pattern, pattern, length);
+ for (i = 0; i < num_fpes; i++)
+ {
+ c->fpe_list[i] = font_path_elements[i];
+ UseFPE(c->fpe_list[i]);
+ }
+ c->client = client;
+ c->num_fpes = num_fpes;
+ c->reply = 0;
+ c->length = 0;
+ c->current.patlen = length;
+ c->current.current_fpe = 0;
+ c->current.max_names = max_names;
+ c->current.list_started = FALSE;
+ c->current.private = 0;
+ c->savedNumFonts = 0;
+ c->haveSaved = FALSE;
+ c->savedName = 0;
+ doListFontsWithInfo(client, c);
+ return Success;
+badAlloc:
+ return BadAlloc;
+}
+
+#define TextEltHeader 2
+#define FontShiftSize 5
+static ChangeGCVal clearGC[] = { { .ptr = NullPixmap } };
+#define clearGCmask (GCClipMask)
+
+int
+doPolyText(ClientPtr client, PTclosurePtr c)
+{
+ FontPtr pFont = c->pGC->font, oldpFont;
+ int err = Success, lgerr; /* err is in X error, not font error, space */
+ enum { NEVER_SLEPT, START_SLEEP, SLEEPING } client_state = NEVER_SLEPT;
+ FontPathElementPtr fpe;
+ GC *origGC = NULL;
+ int itemSize = c->reqType == X_PolyText8 ? 1 : 2;
+
+ if (client->clientGone)
+ {
+ fpe = c->pGC->font->fpe;
+ (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
+
+ if (ClientIsAsleep(client))
+ {
+ /* Client has died, but we cannot bail out right now. We
+ need to clean up after the work we did when going to
+ sleep. Setting the drawable pointer to 0 makes this
+ happen without any attempts to render or perform other
+ unnecessary activities. */
+ c->pDraw = (DrawablePtr)0;
+ }
+ else
+ {
+ err = Success;
+ goto bail;
+ }
+ }
+
+ /* Make sure our drawable hasn't disappeared while we slept. */
+ if (ClientIsAsleep(client) && c->pDraw)
+ {
+ DrawablePtr pDraw;
+ dixLookupDrawable(&pDraw, c->did, client, 0, DixWriteAccess);
+ if (c->pDraw != pDraw) {
+ /* Our drawable has disappeared. Treat like client died... ask
+ the FPE code to clean up after client and avoid further
+ rendering while we clean up after ourself. */
+ fpe = c->pGC->font->fpe;
+ (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
+ c->pDraw = (DrawablePtr)0;
+ }
+ }
+
+ client_state = ClientIsAsleep(client) ? SLEEPING : NEVER_SLEPT;
+
+ while (c->endReq - c->pElt > TextEltHeader)
+ {
+ if (*c->pElt == FontChange)
+ {
+ Font fid;
+ if (c->endReq - c->pElt < FontShiftSize)
+ {
+ err = BadLength;
+ goto bail;
+ }
+
+ oldpFont = pFont;
+
+ fid = ((Font)*(c->pElt+4)) /* big-endian */
+ | ((Font)*(c->pElt+3)) << 8
+ | ((Font)*(c->pElt+2)) << 16
+ | ((Font)*(c->pElt+1)) << 24;
+ err = dixLookupResourceByType((pointer *)&pFont, fid, RT_FONT,
+ client, DixUseAccess);
+ if (err != Success)
+ {
+ /* restore pFont for step 4 (described below) */
+ pFont = oldpFont;
+
+ /* If we're in START_SLEEP mode, the following step
+ shortens the request... in the unlikely event that
+ the fid somehow becomes valid before we come through
+ again to actually execute the polytext, which would
+ then mess up our refcounting scheme badly. */
+ c->err = err;
+ c->endReq = c->pElt;
+
+ goto bail;
+ }
+
+ /* Step 3 (described below) on our new font */
+ if (client_state == START_SLEEP)
+ pFont->refcnt++;
+ else
+ {
+ if (pFont != c->pGC->font && c->pDraw)
+ {
+ ChangeGCVal val;
+ val.ptr = pFont;
+ ChangeGC(NullClient, c->pGC, GCFont, &val);
+ ValidateGC(c->pDraw, c->pGC);
+ }
+
+ /* Undo the refcnt++ we performed when going to sleep */
+ if (client_state == SLEEPING)
+ (void)CloseFont(c->pGC->font, (Font)0);
+ }
+ c->pElt += FontShiftSize;
+ }
+ else /* print a string */
+ {
+ unsigned char *pNextElt;
+ pNextElt = c->pElt + TextEltHeader + (*c->pElt) * itemSize;
+ if ( pNextElt > c->endReq)
+ {
+ err = BadLength;
+ goto bail;
+ }
+ if (client_state == START_SLEEP)
+ {
+ c->pElt = pNextElt;
+ continue;
+ }
+ if (c->pDraw)
+ {
+ lgerr = LoadGlyphs(client, c->pGC->font, *c->pElt, itemSize,
+ c->pElt + TextEltHeader);
+ }
+ else lgerr = Successful;
+
+ if (lgerr == Suspended)
+ {
+ if (!ClientIsAsleep(client)) {
+ int len;
+ GC *pGC;
+ PTclosurePtr new_closure;
+
+ /* We're putting the client to sleep. We need to do a few things
+ to ensure successful and atomic-appearing execution of the
+ remainder of the request. First, copy the remainder of the
+ request into a safe malloc'd area. Second, create a scratch GC
+ to use for the remainder of the request. Third, mark all fonts
+ referenced in the remainder of the request to prevent their
+ deallocation. Fourth, make the original GC look like the
+ request has completed... set its font to the final font value
+ from this request. These GC manipulations are for the unlikely
+ (but possible) event that some other client is using the GC.
+ Steps 3 and 4 are performed by running this procedure through
+ the remainder of the request in a special no-render mode
+ indicated by client_state = START_SLEEP. */
+
+ /* Step 1 */
+ /* Allocate a malloc'd closure structure to replace
+ the local one we were passed */
+ new_closure = malloc(sizeof(PTclosureRec));
+ if (!new_closure)
+ {
+ err = BadAlloc;
+ goto bail;
+ }
+ *new_closure = *c;
+ c = new_closure;
+
+ len = c->endReq - c->pElt;
+ c->data = malloc(len);
+ if (!c->data)
+ {
+ free(c);
+ err = BadAlloc;
+ goto bail;
+ }
+ memmove(c->data, c->pElt, len);
+ c->pElt = c->data;
+ c->endReq = c->pElt + len;
+
+ /* Step 2 */
+
+ pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen);
+ if (!pGC)
+ {
+ free(c->data);
+ free(c);
+ err = BadAlloc;
+ goto bail;
+ }
+ if ((err = CopyGC(c->pGC, pGC, GCFunction |
+ GCPlaneMask | GCForeground |
+ GCBackground | GCFillStyle |
+ GCTile | GCStipple |
+ GCTileStipXOrigin |
+ GCTileStipYOrigin | GCFont |
+ GCSubwindowMode | GCClipXOrigin |
+ GCClipYOrigin | GCClipMask)) !=
+ Success)
+ {
+ FreeScratchGC(pGC);
+ free(c->data);
+ free(c);
+ err = BadAlloc;
+ goto bail;
+ }
+ origGC = c->pGC;
+ c->pGC = pGC;
+ ValidateGC(c->pDraw, c->pGC);
+
+ ClientSleep(client, (ClientSleepProcPtr)doPolyText, c);
+
+ /* Set up to perform steps 3 and 4 */
+ client_state = START_SLEEP;
+ continue; /* on to steps 3 and 4 */
+ }
+ else
+ goto xinerama_sleep;
+ return TRUE;
+ }
+ else if (lgerr != Successful)
+ {
+ err = FontToXError(lgerr);
+ goto bail;
+ }
+ if (c->pDraw)
+ {
+ c->xorg += *((INT8 *)(c->pElt + 1)); /* must be signed */
+ if (c->reqType == X_PolyText8)
+ c->xorg = (* c->pGC->ops->PolyText8)(c->pDraw, c->pGC, c->xorg, c->yorg,
+ *c->pElt, (char *) (c->pElt + TextEltHeader));
+ else
+ c->xorg = (* c->pGC->ops->PolyText16)(c->pDraw, c->pGC, c->xorg, c->yorg,
+ *c->pElt, (unsigned short *) (c->pElt + TextEltHeader));
+ }
+ c->pElt = pNextElt;
+ }
+ }
+
+bail:
+
+ if (client_state == START_SLEEP)
+ {
+ /* Step 4 */
+ if (pFont != origGC->font)
+ {
+ ChangeGCVal val;
+ val.ptr = pFont;
+ ChangeGC(NullClient, origGC, GCFont, &val);
+ ValidateGC(c->pDraw, origGC);
+ }
+
+ /* restore pElt pointer for execution of remainder of the request */
+ c->pElt = c->data;
+ return TRUE;
+ }
+
+ if (c->err != Success) err = c->err;
+ if (err != Success && c->client != serverClient) {
+#ifdef PANORAMIX
+ if (noPanoramiXExtension || !c->pGC->pScreen->myNum)
+#endif
+ SendErrorToClient(c->client, c->reqType, 0, 0, err);
+ }
+ if (ClientIsAsleep(client))
+ {
+ ClientWakeup(c->client);
+xinerama_sleep:
+ ChangeGC(NullClient, c->pGC, clearGCmask, clearGC);
+
+ /* Unreference the font from the scratch GC */
+ CloseFont(c->pGC->font, (Font)0);
+ c->pGC->font = NullFont;
+
+ FreeScratchGC(c->pGC);
+ free(c->data);
+ free(c);
+ }
+ return TRUE;
+}
+
+int
+PolyText(ClientPtr client, DrawablePtr pDraw, GC *pGC, unsigned char *pElt,
+ unsigned char *endReq, int xorg, int yorg, int reqType, XID did)
+{
+ PTclosureRec local_closure;
+
+ local_closure.pElt = pElt;
+ local_closure.endReq = endReq;
+ local_closure.client = client;
+ local_closure.pDraw = pDraw;
+ local_closure.xorg = xorg;
+ local_closure.yorg = yorg;
+ local_closure.reqType = reqType;
+ local_closure.pGC = pGC;
+ local_closure.did = did;
+ local_closure.err = Success;
+
+ (void) doPolyText(client, &local_closure);
+ return Success;
+}
+
+
+#undef TextEltHeader
+#undef FontShiftSize
+
+int
+doImageText(ClientPtr client, ITclosurePtr c)
+{
+ int err = Success, lgerr; /* err is in X error, not font error, space */
+ FontPathElementPtr fpe;
+ int itemSize = c->reqType == X_ImageText8 ? 1 : 2;
+
+ if (client->clientGone)
+ {
+ fpe = c->pGC->font->fpe;
+ (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
+ err = Success;
+ goto bail;
+ }
+
+ /* Make sure our drawable hasn't disappeared while we slept. */
+ if (ClientIsAsleep(client) && c->pDraw)
+ {
+ DrawablePtr pDraw;
+ dixLookupDrawable(&pDraw, c->did, client, 0, DixWriteAccess);
+ if (c->pDraw != pDraw) {
+ /* Our drawable has disappeared. Treat like client died... ask
+ the FPE code to clean up after client. */
+ fpe = c->pGC->font->fpe;
+ (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
+ err = Success;
+ goto bail;
+ }
+ }
+
+ lgerr = LoadGlyphs(client, c->pGC->font, c->nChars, itemSize, c->data);
+ if (lgerr == Suspended)
+ {
+ if (!ClientIsAsleep(client)) {
+ GC *pGC;
+ unsigned char *data;
+ ITclosurePtr new_closure;
+
+ /* We're putting the client to sleep. We need to
+ save some state. Similar problem to that handled
+ in doPolyText, but much simpler because the
+ request structure is much simpler. */
+
+ new_closure = malloc(sizeof(ITclosureRec));
+ if (!new_closure)
+ {
+ err = BadAlloc;
+ goto bail;
+ }
+ *new_closure = *c;
+ c = new_closure;
+
+ data = malloc(c->nChars * itemSize);
+ if (!data)
+ {
+ free(c);
+ err = BadAlloc;
+ goto bail;
+ }
+ memmove(data, c->data, c->nChars * itemSize);
+ c->data = data;
+
+ pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen);
+ if (!pGC)
+ {
+ free(c->data);
+ free(c);
+ err = BadAlloc;
+ goto bail;
+ }
+ if ((err = CopyGC(c->pGC, pGC, GCFunction | GCPlaneMask |
+ GCForeground | GCBackground | GCFillStyle |
+ GCTile | GCStipple | GCTileStipXOrigin |
+ GCTileStipYOrigin | GCFont |
+ GCSubwindowMode | GCClipXOrigin |
+ GCClipYOrigin | GCClipMask)) != Success)
+ {
+ FreeScratchGC(pGC);
+ free(c->data);
+ free(c);
+ err = BadAlloc;
+ goto bail;
+ }
+ c->pGC = pGC;
+ ValidateGC(c->pDraw, c->pGC);
+
+ ClientSleep(client, (ClientSleepProcPtr)doImageText, c);
+ }
+ else
+ goto xinerama_sleep;
+ return TRUE;
+ }
+ else if (lgerr != Successful)
+ {
+ err = FontToXError(lgerr);
+ goto bail;
+ }
+ if (c->pDraw)
+ {
+ if (c->reqType == X_ImageText8)
+ (* c->pGC->ops->ImageText8)(c->pDraw, c->pGC, c->xorg, c->yorg,
+ c->nChars, (char *) c->data);
+ else
+ (* c->pGC->ops->ImageText16)(c->pDraw, c->pGC, c->xorg, c->yorg,
+ c->nChars, (unsigned short *) c->data);
+ }
+
+bail:
+
+ if (err != Success && c->client != serverClient) {
+ SendErrorToClient(c->client, c->reqType, 0, 0, err);
+ }
+ if (ClientIsAsleep(client))
+ {
+ ClientWakeup(c->client);
+xinerama_sleep:
+ ChangeGC(NullClient, c->pGC, clearGCmask, clearGC);
+
+ /* Unreference the font from the scratch GC */
+ CloseFont(c->pGC->font, (Font)0);
+ c->pGC->font = NullFont;
+
+ FreeScratchGC(c->pGC);
+ free(c->data);
+ free(c);
+ }
+ return TRUE;
+}
+
+int
+ImageText(ClientPtr client, DrawablePtr pDraw, GC *pGC, int nChars,
+ unsigned char *data, int xorg, int yorg, int reqType, XID did)
+{
+ ITclosureRec local_closure;
+
+ local_closure.client = client;
+ local_closure.pDraw = pDraw;
+ local_closure.pGC = pGC;
+ local_closure.nChars = nChars;
+ local_closure.data = data;
+ local_closure.xorg = xorg;
+ local_closure.yorg = yorg;
+ local_closure.reqType = reqType;
+ local_closure.did = did;
+
+ (void) doImageText(client, &local_closure);
+ return Success;
+}
+
+
+/* does the necessary magic to figure out the fpe type */
+static int
+DetermineFPEType(char *pathname)
+{
+ int i;
+
+ for (i = 0; i < num_fpe_types; i++) {
+ if ((*fpe_functions[i].name_check) (pathname))
+ return i;
+ }
+ return -1;
+}
+
+
+static void
+FreeFontPath(FontPathElementPtr *list, int n, Bool force)
+{
+ int i;
+
+ for (i = 0; i < n; i++) {
+ if (force) {
+ /* Sanity check that all refcounts will be 0 by the time
+ we get to the end of the list. */
+ int found = 1; /* the first reference is us */
+ int j;
+ for (j = i+1; j < n; j++) {
+ if (list[j] == list[i])
+ found++;
+ }
+ if (list[i]->refcount != found) {
+ list[i]->refcount = found; /* ensure it will get freed */
+ }
+ }
+ FreeFPE(list[i]);
+ }
+ free(list);
+}
+
+static FontPathElementPtr
+find_existing_fpe(FontPathElementPtr *list, int num, unsigned char *name, int len)
+{
+ FontPathElementPtr fpe;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ fpe = list[i];
+ if (fpe->name_length == len && memcmp(name, fpe->name, len) == 0)
+ return fpe;
+ }
+ return (FontPathElementPtr) 0;
+}
+
+
+static int
+SetFontPathElements(int npaths, unsigned char *paths, int *bad, Bool persist)
+{
+ int i, err = 0;
+ int valid_paths = 0;
+ unsigned int len;
+ unsigned char *cp = paths;
+ FontPathElementPtr fpe = NULL, *fplist;
+
+ fplist = malloc(sizeof(FontPathElementPtr) * npaths);
+ if (!fplist) {
+ *bad = 0;
+ return BadAlloc;
+ }
+ for (i = 0; i < num_fpe_types; i++) {
+ if (fpe_functions[i].set_path_hook)
+ (*fpe_functions[i].set_path_hook) ();
+ }
+ for (i = 0; i < npaths; i++)
+ {
+ len = (unsigned int) (*cp++);
+
+ if (len == 0)
+ {
+ if (persist)
+ ErrorF("[dix] Removing empty element from the valid list of fontpaths\n");
+ err = BadValue;
+ }
+ else
+ {
+ /* if it's already in our active list, just reset it */
+ /*
+ * note that this can miss FPE's in limbo -- may be worth catching
+ * them, though it'd muck up refcounting
+ */
+ fpe = find_existing_fpe(font_path_elements, num_fpes, cp, len);
+ if (fpe)
+ {
+ err = (*fpe_functions[fpe->type].reset_fpe) (fpe);
+ if (err == Successful)
+ {
+ UseFPE(fpe);/* since it'll be decref'd later when freed
+ * from the old list */
+ }
+ else
+ fpe = 0;
+ }
+ /* if error or can't do it, act like it's a new one */
+ if (!fpe)
+ {
+ fpe = malloc(sizeof(FontPathElementRec));
+ if (!fpe)
+ {
+ err = BadAlloc;
+ goto bail;
+ }
+ fpe->name = malloc(len + 1);
+ if (!fpe->name)
+ {
+ free(fpe);
+ err = BadAlloc;
+ goto bail;
+ }
+ fpe->refcount = 1;
+
+ strncpy(fpe->name, (char *) cp, (int) len);
+ fpe->name[len] = '\0';
+ fpe->name_length = len;
+ fpe->type = DetermineFPEType(fpe->name);
+ if (fpe->type == -1)
+ err = BadValue;
+ else
+ err = (*fpe_functions[fpe->type].init_fpe) (fpe);
+ if (err != Successful)
+ {
+ if (persist)
+ {
+ ErrorF("[dix] Could not init font path element %s, removing from list!\n",
+ fpe->name);
+ }
+ free(fpe->name);
+ free(fpe);
+ }
+ }
+ }
+ if (err != Successful)
+ {
+ if (!persist)
+ goto bail;
+ }
+ else
+ {
+ fplist[valid_paths++] = fpe;
+ }
+ cp += len;
+ }
+
+ FreeFontPath(font_path_elements, num_fpes, FALSE);
+ font_path_elements = fplist;
+ if (patternCache)
+ EmptyFontPatternCache(patternCache);
+ num_fpes = valid_paths;
+
+ return Success;
+bail:
+ *bad = i;
+ while (--valid_paths >= 0)
+ FreeFPE(fplist[valid_paths]);
+ free(fplist);
+ return FontToXError(err);
+}
+
+int
+SetFontPath(ClientPtr client, int npaths, unsigned char *paths)
+{
+ int err = XaceHook(XACE_SERVER_ACCESS, client, DixManageAccess);
+ if (err != Success)
+ return err;
+
+ if (npaths == 0) {
+ if (SetDefaultFontPath(defaultFontPath) != Success)
+ return BadValue;
+ } else {
+ int bad;
+ err = SetFontPathElements(npaths, paths, &bad, FALSE);
+ client->errorValue = bad;
+ }
+ return err;
+}
+
+int
+SetDefaultFontPath(char *path)
+{
+ char *temp_path,
+ *start,
+ *end;
+ unsigned char *cp,
+ *pp,
+ *nump,
+ *newpath;
+ int num = 1,
+ len,
+ err,
+ size = 0,
+ bad;
+
+ /* ensure temp_path contains "built-ins" */
+ start = path;
+ while (1) {
+ start = strstr(start, "built-ins");
+ if (start == NULL)
+ break;
+ end = start + strlen("built-ins");
+ if ((start == path || start[-1] == ',') && (!*end || *end == ','))
+ break;
+ start = end;
+ }
+ if (!start) {
+ if (asprintf(&temp_path, "%s%sbuilt-ins", path, *path ? "," : "")
+ == -1)
+ temp_path = NULL;
+ } else {
+ temp_path = strdup(path);
+ }
+ if (!temp_path)
+ return BadAlloc;
+
+ /* get enough for string, plus values -- use up commas */
+ len = strlen(temp_path) + 1;
+ nump = cp = newpath = malloc(len);
+ if (!newpath) {
+ free(temp_path);
+ return BadAlloc;
+ }
+ pp = (unsigned char *) temp_path;
+ cp++;
+ while (*pp) {
+ if (*pp == ',') {
+ *nump = (unsigned char) size;
+ nump = cp++;
+ pp++;
+ num++;
+ size = 0;
+ } else {
+ *cp++ = *pp++;
+ size++;
+ }
+ }
+ *nump = (unsigned char) size;
+
+ err = SetFontPathElements(num, newpath, &bad, TRUE);
+
+ free(newpath);
+ free(temp_path);
+
+ return err;
+}
+
+int
+GetFontPath(ClientPtr client, int *count, int *length, unsigned char **result)
+{
+ int i;
+ unsigned char *c;
+ int len;
+ FontPathElementPtr fpe;
+
+ i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess);
+ if (i != Success)
+ return i;
+
+ len = 0;
+ for (i = 0; i < num_fpes; i++) {
+ fpe = font_path_elements[i];
+ len += fpe->name_length + 1;
+ }
+ font_path_string = (unsigned char *) realloc(font_path_string, len);
+ if (!font_path_string)
+ return BadAlloc;
+
+ c = font_path_string;
+ *length = 0;
+ for (i = 0; i < num_fpes; i++) {
+ fpe = font_path_elements[i];
+ *c = fpe->name_length;
+ *length += *c++;
+ memmove(c, fpe->name, fpe->name_length);
+ c += fpe->name_length;
+ }
+ *count = num_fpes;
+ *result = font_path_string;
+ return Success;
+}
+
+void
+DeleteClientFontStuff(ClientPtr client)
+{
+ int i;
+ FontPathElementPtr fpe;
+
+ for (i = 0; i < num_fpes; i++)
+ {
+ fpe = font_path_elements[i];
+ if (fpe_functions[fpe->type].client_died)
+ (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
+ }
+}
+
+void
+InitFonts (void)
+{
+ patternCache = MakeFontPatternCache();
+
+ register_fpe_functions();
+}
+
+int
+GetDefaultPointSize (void)
+{
+ return 120;
+}
+
+
+FontResolutionPtr
+GetClientResolutions (int *num)
+{
+ static struct _FontResolution res;
+ ScreenPtr pScreen;
+
+ pScreen = screenInfo.screens[0];
+ res.x_resolution = (pScreen->width * 25.4) / pScreen->mmWidth;
+ /*
+ * XXX - we'll want this as long as bitmap instances are prevalent
+ so that we can match them from scalable fonts
+ */
+ if (res.x_resolution < 88)
+ res.x_resolution = 75;
+ else
+ res.x_resolution = 100;
+ res.y_resolution = (pScreen->height * 25.4) / pScreen->mmHeight;
+ if (res.y_resolution < 88)
+ res.y_resolution = 75;
+ else
+ res.y_resolution = 100;
+ res.point_size = 120;
+ *num = 1;
+ return &res;
+}
+
+/*
+ * returns the type index of the new fpe
+ *
+ * should be called (only once!) by each type of fpe when initialized
+ */
+
+int
+RegisterFPEFunctions(NameCheckFunc name_func,
+ InitFpeFunc init_func,
+ FreeFpeFunc free_func,
+ ResetFpeFunc reset_func,
+ OpenFontFunc open_func,
+ CloseFontFunc close_func,
+ ListFontsFunc list_func,
+ StartLfwiFunc start_lfwi_func,
+ NextLfwiFunc next_lfwi_func,
+ WakeupFpeFunc wakeup_func,
+ ClientDiedFunc client_died,
+ LoadGlyphsFunc load_glyphs,
+ StartLaFunc start_list_alias_func,
+ NextLaFunc next_list_alias_func,
+ SetPathFunc set_path_func)
+{
+ FPEFunctions *new;
+
+ /* grow the list */
+ new = (FPEFunctions *) realloc(fpe_functions,
+ (num_fpe_types + 1) * sizeof(FPEFunctions));
+ if (!new)
+ return -1;
+ fpe_functions = new;
+
+ fpe_functions[num_fpe_types].name_check = name_func;
+ fpe_functions[num_fpe_types].open_font = open_func;
+ fpe_functions[num_fpe_types].close_font = close_func;
+ fpe_functions[num_fpe_types].wakeup_fpe = wakeup_func;
+ fpe_functions[num_fpe_types].list_fonts = list_func;
+ fpe_functions[num_fpe_types].start_list_fonts_with_info =
+ start_lfwi_func;
+ fpe_functions[num_fpe_types].list_next_font_with_info =
+ next_lfwi_func;
+ fpe_functions[num_fpe_types].init_fpe = init_func;
+ fpe_functions[num_fpe_types].free_fpe = free_func;
+ fpe_functions[num_fpe_types].reset_fpe = reset_func;
+ fpe_functions[num_fpe_types].client_died = client_died;
+ fpe_functions[num_fpe_types].load_glyphs = load_glyphs;
+ fpe_functions[num_fpe_types].start_list_fonts_and_aliases =
+ start_list_alias_func;
+ fpe_functions[num_fpe_types].list_next_font_or_alias =
+ next_list_alias_func;
+ fpe_functions[num_fpe_types].set_path_hook = set_path_func;
+
+ return num_fpe_types++;
+}
+
+void
+FreeFonts(void)
+{
+ if (patternCache) {
+ FreeFontPatternCache(patternCache);
+ patternCache = 0;
+ }
+ FreeFontPath(font_path_elements, num_fpes, TRUE);
+ font_path_elements = 0;
+ num_fpes = 0;
+ free(fpe_functions);
+ num_fpe_types = 0;
+ fpe_functions = (FPEFunctions *) 0;
+}
+
+/* convenience functions for FS interface */
+
+FontPtr
+find_old_font(XID id)
+{
+ pointer pFont;
+ dixLookupResourceByType(&pFont, id, RT_NONE, serverClient, DixReadAccess);
+ return (FontPtr)pFont;
+}
+
+Font
+GetNewFontClientID(void)
+{
+ return FakeClientID(0);
+}
+
+int
+StoreFontClientFont(FontPtr pfont, Font id)
+{
+ return AddResource(id, RT_NONE, (pointer) pfont);
+}
+
+void
+DeleteFontClientID(Font id)
+{
+ FreeResource(id, RT_NONE);
+}
+
+int
+client_auth_generation(ClientPtr client)
+{
+ return 0;
+}
+
+static int fs_handlers_installed = 0;
+static unsigned int last_server_gen;
+
+int
+init_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler)
+{
+ /* if server has reset, make sure the b&w handlers are reinstalled */
+ if (last_server_gen < serverGeneration) {
+ last_server_gen = serverGeneration;
+ fs_handlers_installed = 0;
+ }
+ if (fs_handlers_installed == 0) {
+ if (!RegisterBlockAndWakeupHandlers(block_handler,
+ FontWakeup, (pointer) 0))
+ return AllocError;
+ fs_handlers_installed++;
+ }
+ QueueFontWakeup(fpe);
+ return Successful;
+}
+
+void
+remove_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler, Bool all)
+{
+ if (all) {
+ /* remove the handlers if no one else is using them */
+ if (--fs_handlers_installed == 0) {
+ RemoveBlockAndWakeupHandlers(block_handler, FontWakeup,
+ (pointer) 0);
+ }
+ }
+ RemoveFontWakeup(fpe);
+}
diff --git a/dix/dixutils.c b/dix/dixutils.c
new file mode 100644
index 0000000..104363b
--- /dev/null
+++ b/dix/dixutils.c
@@ -0,0 +1,893 @@
+/***********************************************************
+
+Copyright 1987, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+******************************************************************/
+
+/*
+
+(c)Copyright 1988,1991 Adobe Systems Incorporated. All rights reserved.
+
+Permission to use, copy, modify, distribute, and sublicense this software and its
+documentation for any purpose and without fee is hereby granted, provided that
+the above copyright notices appear in all copies and that both those copyright
+notices and this permission notice appear in supporting documentation and that
+the name of Adobe Systems Incorporated not be used in advertising or publicity
+pertaining to distribution of the software without specific, written prior
+permission. No trademark license to use the Adobe trademarks is hereby
+granted. If the Adobe trademark "Display PostScript"(tm) is used to describe
+this software, its functionality or for any other purpose, such use shall be
+limited to a statement that this software works in conjunction with the Display
+PostScript system. Proper trademark attribution to reflect Adobe's ownership
+of the trademark shall be given whenever any such reference to the Display
+PostScript system is made.
+
+ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR ANY
+PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. ADOBE
+DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-
+INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE TO YOU
+OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,NEGLIGENCE, STRICT
+LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT PROVIDE ANY TRAINING OR OTHER
+SUPPORT FOR THE SOFTWARE.
+
+Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems
+Incorporated which may be registered in certain jurisdictions.
+
+Author: Adobe Systems Incorporated
+
+*/
+
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/Xmd.h>
+#include "misc.h"
+#include "windowstr.h"
+#include "dixstruct.h"
+#include "pixmapstr.h"
+#include "gcstruct.h"
+#include "scrnintstr.h"
+#define XK_LATIN1
+#include <X11/keysymdef.h>
+#include "xace.h"
+
+/*
+ * CompareTimeStamps returns -1, 0, or +1 depending on if the first
+ * argument is less than, equal to or greater than the second argument.
+ */
+
+int
+CompareTimeStamps(TimeStamp a, TimeStamp b)
+{
+ if (a.months < b.months)
+ return EARLIER;
+ if (a.months > b.months)
+ return LATER;
+ if (a.milliseconds < b.milliseconds)
+ return EARLIER;
+ if (a.milliseconds > b.milliseconds)
+ return LATER;
+ return SAMETIME;
+}
+
+/*
+ * convert client times to server TimeStamps
+ */
+
+#define HALFMONTH ((unsigned long) 1<<31)
+TimeStamp
+ClientTimeToServerTime(CARD32 c)
+{
+ TimeStamp ts;
+ if (c == CurrentTime)
+ return currentTime;
+ ts.months = currentTime.months;
+ ts.milliseconds = c;
+ if (c > currentTime.milliseconds)
+ {
+ if (((unsigned long) c - currentTime.milliseconds) > HALFMONTH)
+ ts.months -= 1;
+ }
+ else if (c < currentTime.milliseconds)
+ {
+ if (((unsigned long)currentTime.milliseconds - c) > HALFMONTH)
+ ts.months += 1;
+ }
+ return ts;
+}
+
+/*
+ * ISO Latin-1 case conversion routine
+ *
+ * this routine always null-terminates the result, so
+ * beware of too-small buffers
+ */
+
+static unsigned char
+ISOLatin1ToLower (unsigned char source)
+{
+ unsigned char dest;
+ if ((source >= XK_A) && (source <= XK_Z))
+ dest = source + (XK_a - XK_A);
+ else if ((source >= XK_Agrave) && (source <= XK_Odiaeresis))
+ dest = source + (XK_agrave - XK_Agrave);
+ else if ((source >= XK_Ooblique) && (source <= XK_Thorn))
+ dest = source + (XK_oslash - XK_Ooblique);
+ else
+ dest = source;
+ return dest;
+}
+
+
+int
+CompareISOLatin1Lowered(unsigned char *s1, int s1len,
+ unsigned char *s2, int s2len)
+{
+ unsigned char c1, c2;
+
+ for (;;)
+ {
+ /* note -- compare against zero so that -1 ignores len */
+ c1 = s1len-- ? *s1++ : '\0';
+ c2 = s2len-- ? *s2++ : '\0';
+ if (!c1 ||
+ (c1 != c2 &&
+ (c1 = ISOLatin1ToLower (c1)) != (c2 = ISOLatin1ToLower (c2))))
+ break;
+ }
+ return (int) c1 - (int) c2;
+}
+
+/*
+ * dixLookupWindow and dixLookupDrawable:
+ * Look up the window/drawable taking into account the client doing the
+ * lookup, the type of drawable desired, and the type of access desired.
+ * Return Success with *pDraw set if the window/drawable exists and the client
+ * is allowed access, else return an error code with *pDraw set to NULL. The
+ * access mask values are defined in resource.h. The type mask values are
+ * defined in pixmap.h, with zero equivalent to M_DRAWABLE.
+ */
+int
+dixLookupDrawable(DrawablePtr *pDraw, XID id, ClientPtr client,
+ Mask type, Mask access)
+{
+ DrawablePtr pTmp;
+ int rc;
+
+ *pDraw = NULL;
+ client->errorValue = id;
+
+ if (id == INVALID)
+ return BadDrawable;
+
+ rc = dixLookupResourceByClass((pointer *)&pTmp, id, RC_DRAWABLE, client, access);
+
+ if (rc == BadValue)
+ return BadDrawable;
+ if (rc != Success)
+ return rc;
+ if (!((1 << pTmp->type) & (type ? type : M_DRAWABLE)))
+ return BadMatch;
+
+ *pDraw = pTmp;
+ return Success;
+}
+
+int
+dixLookupWindow(WindowPtr *pWin, XID id, ClientPtr client, Mask access)
+{
+ int rc;
+ rc = dixLookupDrawable((DrawablePtr*)pWin, id, client, M_WINDOW, access);
+ return (rc == BadDrawable) ? BadWindow : rc;
+}
+
+int
+dixLookupGC(GCPtr *pGC, XID id, ClientPtr client, Mask access)
+{
+ return dixLookupResourceByType((pointer *)pGC, id, RT_GC, client, access);
+}
+
+int
+dixLookupFontable(FontPtr *pFont, XID id, ClientPtr client, Mask access)
+{
+ int rc;
+ GC *pGC;
+ client->errorValue = id; /* EITHER font or gc */
+ rc = dixLookupResourceByType((pointer *) pFont, id, RT_FONT, client, access);
+ if (rc != BadFont)
+ return rc;
+ rc = dixLookupResourceByType((pointer *) &pGC, id, RT_GC, client, access);
+ if (rc == BadGC)
+ return BadFont;
+ if (rc == Success)
+ *pFont = pGC->font;
+ return rc;
+}
+
+int
+dixLookupClient(ClientPtr *pClient, XID rid, ClientPtr client, Mask access)
+{
+ pointer pRes;
+ int rc = BadValue, clientIndex = CLIENT_ID(rid);
+
+ if (!clientIndex || !clients[clientIndex] || (rid & SERVER_BIT))
+ goto bad;
+
+ rc = dixLookupResourceByClass(&pRes, rid, RC_ANY, client, DixGetAttrAccess);
+ if (rc != Success)
+ goto bad;
+
+ rc = XaceHook(XACE_CLIENT_ACCESS, client, clients[clientIndex], access);
+ if (rc != Success)
+ goto bad;
+
+ *pClient = clients[clientIndex];
+ return Success;
+bad:
+ if(client)
+ client->errorValue = rid;
+ *pClient = NULL;
+ return rc;
+}
+
+int
+AlterSaveSetForClient(ClientPtr client, WindowPtr pWin, unsigned mode,
+ Bool toRoot, Bool map)
+{
+ int numnow;
+ SaveSetElt *pTmp = NULL;
+ int j;
+
+ numnow = client->numSaved;
+ j = 0;
+ if (numnow)
+ {
+ pTmp = client->saveSet;
+ while ((j < numnow) && (SaveSetWindow(pTmp[j]) != (pointer)pWin))
+ j++;
+ }
+ if (mode == SetModeInsert)
+ {
+ if (j < numnow) /* duplicate */
+ return Success;
+ numnow++;
+ pTmp = (SaveSetElt *)realloc(client->saveSet, sizeof(*pTmp) * numnow);
+ if (!pTmp)
+ return BadAlloc;
+ client->saveSet = pTmp;
+ client->numSaved = numnow;
+ SaveSetAssignWindow(client->saveSet[numnow - 1], pWin);
+ SaveSetAssignToRoot(client->saveSet[numnow - 1], toRoot);
+ SaveSetAssignMap(client->saveSet[numnow - 1], map);
+ return Success;
+ }
+ else if ((mode == SetModeDelete) && (j < numnow))
+ {
+ while (j < numnow-1)
+ {
+ pTmp[j] = pTmp[j+1];
+ j++;
+ }
+ numnow--;
+ if (numnow)
+ {
+ pTmp = (SaveSetElt *)realloc(client->saveSet, sizeof(*pTmp) * numnow);
+ if (pTmp)
+ client->saveSet = pTmp;
+ }
+ else
+ {
+ free(client->saveSet);
+ client->saveSet = (SaveSetElt *)NULL;
+ }
+ client->numSaved = numnow;
+ return Success;
+ }
+ return Success;
+}
+
+void
+DeleteWindowFromAnySaveSet(WindowPtr pWin)
+{
+ int i;
+ ClientPtr client;
+
+ for (i = 0; i< currentMaxClients; i++)
+ {
+ client = clients[i];
+ if (client && client->numSaved)
+ (void)AlterSaveSetForClient(client, pWin, SetModeDelete, FALSE, TRUE);
+ }
+}
+
+/* No-op Don't Do Anything : sometimes we need to be able to call a procedure
+ * that doesn't do anything. For example, on screen with only static
+ * colormaps, if someone calls install colormap, it's easier to have a dummy
+ * procedure to call than to check if there's a procedure
+ */
+void
+NoopDDA(void)
+{
+}
+
+typedef struct _BlockHandler {
+ BlockHandlerProcPtr BlockHandler;
+ WakeupHandlerProcPtr WakeupHandler;
+ pointer blockData;
+ Bool deleted;
+} BlockHandlerRec, *BlockHandlerPtr;
+
+static BlockHandlerPtr handlers;
+static int numHandlers;
+static int sizeHandlers;
+static Bool inHandler;
+static Bool handlerDeleted;
+
+/**
+ *
+ * \param pTimeout DIX doesn't want to know how OS represents time
+ * \param pReadMask nor how it represents the det of descriptors
+ */
+void
+BlockHandler(pointer pTimeout, pointer pReadmask)
+{
+ int i, j;
+
+ ++inHandler;
+ for (i = 0; i < screenInfo.numScreens; i++)
+ (* screenInfo.screens[i]->BlockHandler)(i,
+ screenInfo.screens[i]->blockData,
+ pTimeout, pReadmask);
+ for (i = 0; i < numHandlers; i++)
+ (*handlers[i].BlockHandler) (handlers[i].blockData,
+ pTimeout, pReadmask);
+ if (handlerDeleted)
+ {
+ for (i = 0; i < numHandlers;)
+ if (handlers[i].deleted)
+ {
+ for (j = i; j < numHandlers - 1; j++)
+ handlers[j] = handlers[j+1];
+ numHandlers--;
+ }
+ else
+ i++;
+ handlerDeleted = FALSE;
+ }
+ --inHandler;
+}
+
+/**
+ *
+ * \param result 32 bits of undefined result from the wait
+ * \param pReadmask the resulting descriptor mask
+ */
+void
+WakeupHandler(int result, pointer pReadmask)
+{
+ int i, j;
+
+ ++inHandler;
+ for (i = numHandlers - 1; i >= 0; i--)
+ (*handlers[i].WakeupHandler) (handlers[i].blockData,
+ result, pReadmask);
+ for (i = 0; i < screenInfo.numScreens; i++)
+ (* screenInfo.screens[i]->WakeupHandler)(i,
+ screenInfo.screens[i]->wakeupData,
+ result, pReadmask);
+ if (handlerDeleted)
+ {
+ for (i = 0; i < numHandlers;)
+ if (handlers[i].deleted)
+ {
+ for (j = i; j < numHandlers - 1; j++)
+ handlers[j] = handlers[j+1];
+ numHandlers--;
+ }
+ else
+ i++;
+ handlerDeleted = FALSE;
+ }
+ --inHandler;
+}
+
+/**
+ * Reentrant with BlockHandler and WakeupHandler, except wakeup won't
+ * get called until next time
+ */
+Bool
+RegisterBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler,
+ WakeupHandlerProcPtr wakeupHandler,
+ pointer blockData)
+{
+ BlockHandlerPtr new;
+
+ if (numHandlers >= sizeHandlers)
+ {
+ new = (BlockHandlerPtr) realloc(handlers, (numHandlers + 1) *
+ sizeof (BlockHandlerRec));
+ if (!new)
+ return FALSE;
+ handlers = new;
+ sizeHandlers = numHandlers + 1;
+ }
+ handlers[numHandlers].BlockHandler = blockHandler;
+ handlers[numHandlers].WakeupHandler = wakeupHandler;
+ handlers[numHandlers].blockData = blockData;
+ handlers[numHandlers].deleted = FALSE;
+ numHandlers = numHandlers + 1;
+ return TRUE;
+}
+
+void
+RemoveBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler,
+ WakeupHandlerProcPtr wakeupHandler,
+ pointer blockData)
+{
+ int i;
+
+ for (i = 0; i < numHandlers; i++)
+ if (handlers[i].BlockHandler == blockHandler &&
+ handlers[i].WakeupHandler == wakeupHandler &&
+ handlers[i].blockData == blockData)
+ {
+ if (inHandler)
+ {
+ handlerDeleted = TRUE;
+ handlers[i].deleted = TRUE;
+ }
+ else
+ {
+ for (; i < numHandlers - 1; i++)
+ handlers[i] = handlers[i+1];
+ numHandlers--;
+ }
+ break;
+ }
+}
+
+void
+InitBlockAndWakeupHandlers (void)
+{
+ free(handlers);
+ handlers = (BlockHandlerPtr) 0;
+ numHandlers = 0;
+ sizeHandlers = 0;
+}
+
+/*
+ * A general work queue. Perform some task before the server
+ * sleeps for input.
+ */
+
+WorkQueuePtr workQueue;
+static WorkQueuePtr *workQueueLast = &workQueue;
+
+void
+ProcessWorkQueue(void)
+{
+ WorkQueuePtr q, *p;
+
+ p = &workQueue;
+ /*
+ * Scan the work queue once, calling each function. Those
+ * which return TRUE are removed from the queue, otherwise
+ * they will be called again. This must be reentrant with
+ * QueueWorkProc.
+ */
+ while ((q = *p))
+ {
+ if ((*q->function) (q->client, q->closure))
+ {
+ /* remove q from the list */
+ *p = q->next; /* don't fetch until after func called */
+ free(q);
+ }
+ else
+ {
+ p = &q->next; /* don't fetch until after func called */
+ }
+ }
+ workQueueLast = p;
+}
+
+void
+ProcessWorkQueueZombies(void)
+{
+ WorkQueuePtr q, *p;
+
+ p = &workQueue;
+ while ((q = *p))
+ {
+ if (q->client && q->client->clientGone)
+ {
+ (void) (*q->function) (q->client, q->closure);
+ /* remove q from the list */
+ *p = q->next; /* don't fetch until after func called */
+ free(q);
+ }
+ else
+ {
+ p = &q->next; /* don't fetch until after func called */
+ }
+ }
+ workQueueLast = p;
+}
+
+Bool
+QueueWorkProc (
+ Bool (*function)(ClientPtr /* pClient */, pointer /* closure */),
+ ClientPtr client, pointer closure)
+{
+ WorkQueuePtr q;
+
+ q = malloc(sizeof *q);
+ if (!q)
+ return FALSE;
+ q->function = function;
+ q->client = client;
+ q->closure = closure;
+ q->next = NULL;
+ *workQueueLast = q;
+ workQueueLast = &q->next;
+ return TRUE;
+}
+
+/*
+ * Manage a queue of sleeping clients, awakening them
+ * when requested, by using the OS functions IgnoreClient
+ * and AttendClient. Note that this *ignores* the troubles
+ * with request data interleaving itself with events, but
+ * we'll leave that until a later time.
+ */
+
+typedef struct _SleepQueue {
+ struct _SleepQueue *next;
+ ClientPtr client;
+ ClientSleepProcPtr function;
+ pointer closure;
+} SleepQueueRec, *SleepQueuePtr;
+
+static SleepQueuePtr sleepQueue = NULL;
+
+Bool
+ClientSleep (ClientPtr client, ClientSleepProcPtr function, pointer closure)
+{
+ SleepQueuePtr q;
+
+ q = malloc(sizeof *q);
+ if (!q)
+ return FALSE;
+
+ IgnoreClient (client);
+ q->next = sleepQueue;
+ q->client = client;
+ q->function = function;
+ q->closure = closure;
+ sleepQueue = q;
+ return TRUE;
+}
+
+Bool
+ClientSignal (ClientPtr client)
+{
+ SleepQueuePtr q;
+
+ for (q = sleepQueue; q; q = q->next)
+ if (q->client == client)
+ {
+ return QueueWorkProc (q->function, q->client, q->closure);
+ }
+ return FALSE;
+}
+
+void
+ClientWakeup (ClientPtr client)
+{
+ SleepQueuePtr q, *prev;
+
+ prev = &sleepQueue;
+ while ( (q = *prev) )
+ {
+ if (q->client == client)
+ {
+ *prev = q->next;
+ free(q);
+ if (client->clientGone)
+ /* Oops -- new zombie cleanup code ensures this only
+ * happens from inside CloseDownClient; don't want to
+ * recurse here...
+ */
+ /* CloseDownClient(client) */;
+ else
+ AttendClient (client);
+ break;
+ }
+ prev = &q->next;
+ }
+}
+
+Bool
+ClientIsAsleep (ClientPtr client)
+{
+ SleepQueuePtr q;
+
+ for (q = sleepQueue; q; q = q->next)
+ if (q->client == client)
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * Generic Callback Manager
+ */
+
+/* ===== Private Procedures ===== */
+
+static int numCallbackListsToCleanup = 0;
+static CallbackListPtr **listsToCleanup = NULL;
+
+static Bool
+_AddCallback(
+ CallbackListPtr *pcbl,
+ CallbackProcPtr callback,
+ pointer data)
+{
+ CallbackPtr cbr;
+
+ cbr = malloc(sizeof(CallbackRec));
+ if (!cbr)
+ return FALSE;
+ cbr->proc = callback;
+ cbr->data = data;
+ cbr->next = (*pcbl)->list;
+ cbr->deleted = FALSE;
+ (*pcbl)->list = cbr;
+ return TRUE;
+}
+
+static Bool
+_DeleteCallback(
+ CallbackListPtr *pcbl,
+ CallbackProcPtr callback,
+ pointer data)
+{
+ CallbackListPtr cbl = *pcbl;
+ CallbackPtr cbr, pcbr;
+
+ for (pcbr = NULL, cbr = cbl->list;
+ cbr != NULL;
+ pcbr = cbr, cbr = cbr->next)
+ {
+ if ((cbr->proc == callback) && (cbr->data == data))
+ break;
+ }
+ if (cbr != NULL)
+ {
+ if (cbl->inCallback)
+ {
+ ++(cbl->numDeleted);
+ cbr->deleted = TRUE;
+ }
+ else
+ {
+ if (pcbr == NULL)
+ cbl->list = cbr->next;
+ else
+ pcbr->next = cbr->next;
+ free(cbr);
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void
+_CallCallbacks(
+ CallbackListPtr *pcbl,
+ pointer call_data)
+{
+ CallbackListPtr cbl = *pcbl;
+ CallbackPtr cbr, pcbr;
+
+ ++(cbl->inCallback);
+ for (cbr = cbl->list; cbr != NULL; cbr = cbr->next)
+ {
+ (*(cbr->proc)) (pcbl, cbr->data, call_data);
+ }
+ --(cbl->inCallback);
+
+ if (cbl->inCallback) return;
+
+ /* Was the entire list marked for deletion? */
+
+ if (cbl->deleted)
+ {
+ DeleteCallbackList(pcbl);
+ return;
+ }
+
+ /* Were some individual callbacks on the list marked for deletion?
+ * If so, do the deletions.
+ */
+
+ if (cbl->numDeleted)
+ {
+ for (pcbr = NULL, cbr = cbl->list; (cbr != NULL) && cbl->numDeleted; )
+ {
+ if (cbr->deleted)
+ {
+ if (pcbr)
+ {
+ cbr = cbr->next;
+ free(pcbr->next);
+ pcbr->next = cbr;
+ } else
+ {
+ cbr = cbr->next;
+ free(cbl->list);
+ cbl->list = cbr;
+ }
+ cbl->numDeleted--;
+ }
+ else /* this one wasn't deleted */
+ {
+ pcbr = cbr;
+ cbr = cbr->next;
+ }
+ }
+ }
+}
+
+static void
+_DeleteCallbackList(
+ CallbackListPtr *pcbl)
+{
+ CallbackListPtr cbl = *pcbl;
+ CallbackPtr cbr, nextcbr;
+ int i;
+
+ if (cbl->inCallback)
+ {
+ cbl->deleted = TRUE;
+ return;
+ }
+
+ for (i = 0; i < numCallbackListsToCleanup; i++)
+ {
+ if (listsToCleanup[i] == pcbl)
+ {
+ listsToCleanup[i] = NULL;
+ break;
+ }
+ }
+
+ for (cbr = cbl->list; cbr != NULL; cbr = nextcbr)
+ {
+ nextcbr = cbr->next;
+ free(cbr);
+ }
+ free(cbl);
+ *pcbl = NULL;
+}
+
+static Bool
+CreateCallbackList(CallbackListPtr *pcbl)
+{
+ CallbackListPtr cbl;
+ int i;
+
+ if (!pcbl) return FALSE;
+ cbl = malloc(sizeof(CallbackListRec));
+ if (!cbl) return FALSE;
+ cbl->inCallback = 0;
+ cbl->deleted = FALSE;
+ cbl->numDeleted = 0;
+ cbl->list = NULL;
+ *pcbl = cbl;
+
+ for (i = 0; i < numCallbackListsToCleanup; i++)
+ {
+ if (!listsToCleanup[i])
+ {
+ listsToCleanup[i] = pcbl;
+ return TRUE;
+ }
+ }
+
+ listsToCleanup = (CallbackListPtr **)xnfrealloc(listsToCleanup,
+ sizeof(CallbackListPtr *) * (numCallbackListsToCleanup+1));
+ listsToCleanup[numCallbackListsToCleanup] = pcbl;
+ numCallbackListsToCleanup++;
+ return TRUE;
+}
+
+/* ===== Public Procedures ===== */
+
+Bool
+AddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data)
+{
+ if (!pcbl) return FALSE;
+ if (!*pcbl)
+ { /* list hasn't been created yet; go create it */
+ if (!CreateCallbackList(pcbl))
+ return FALSE;
+ }
+ return _AddCallback(pcbl, callback, data);
+}
+
+Bool
+DeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data)
+{
+ if (!pcbl || !*pcbl) return FALSE;
+ return _DeleteCallback(pcbl, callback, data);
+}
+
+void
+DeleteCallbackList(CallbackListPtr *pcbl)
+{
+ if (!pcbl || !*pcbl) return;
+ _DeleteCallbackList(pcbl);
+}
+
+void
+InitCallbackManager(void)
+{
+ int i;
+
+ for (i = 0; i < numCallbackListsToCleanup; i++)
+ {
+ DeleteCallbackList(listsToCleanup[i]);
+ }
+ free(listsToCleanup);
+
+ numCallbackListsToCleanup = 0;
+ listsToCleanup = NULL;
+}
diff --git a/dix/enterleave.c b/dix/enterleave.c
new file mode 100644
index 0000000..b1ee3fb
--- /dev/null
+++ b/dix/enterleave.c
@@ -0,0 +1,1389 @@
+/*
+ * Copyright © 2008 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Peter Hutterer
+ *
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/extensions/XI2.h>
+#include "inputstr.h"
+#include "windowstr.h"
+#include "scrnintstr.h"
+#include "exglobals.h"
+#include "enterleave.h"
+
+/**
+ * @file
+ * This file describes the model for sending core enter/leave events and
+ * focus in/out in the case of multiple pointers/keyboard foci.
+ *
+ * Since we can't send more than one Enter or Leave/Focus in or out event per
+ * window to a core client without confusing it, this is a rather complicated
+ * approach.
+ *
+ * For a full description of the enter/leave model from a window's
+ * perspective, see
+ * http://lists.freedesktop.org/archives/xorg/2008-August/037606.html
+ *
+ * For a full description of the focus in/out model from a window's
+ * perspective, see
+ * http://lists.freedesktop.org/archives/xorg/2008-December/041740.html
+ *
+ * Additional notes:
+ * - The core protocol spec says that "In a LeaveNotify event, if a child of the
+ * event window contains the initial position of the pointer, then the child
+ * component is set to that child. Otherwise, it is None. For an EnterNotify
+ * event, if a child of the event window contains the final pointer position,
+ * then the child component is set to that child. Otherwise, it is None."
+ *
+ * By inference, this means that only NotifyVirtual or NotifyNonlinearVirtual
+ * events may have a subwindow set to other than None.
+ *
+ * - NotifyPointer events may be sent if the focus changes from window A to
+ * B. The assumption used in this model is that NotifyPointer events are only
+ * sent for the pointer paired with the keyboard that is involved in the focus
+ * events. For example, if F(W) changes because of keyboard 2, then
+ * NotifyPointer events are only sent for pointer 2.
+ */
+
+static WindowPtr PointerWindows[MAXDEVICES];
+static WindowPtr FocusWindows[MAXDEVICES];
+
+/**
+ * Return TRUE if 'win' has a pointer within its boundaries, excluding child
+ * window.
+ */
+static BOOL
+HasPointer(DeviceIntPtr dev, WindowPtr win)
+{
+ int i;
+
+ /* FIXME: The enter/leave model does not cater for grabbed devices. For
+ * now, a quickfix: if the device about to send an enter/leave event to
+ * a window is grabbed, assume there is no pointer in that window.
+ * Fixes fdo 27804.
+ * There isn't enough beer in my fridge to fix this properly.
+ */
+ if (dev->deviceGrab.grab)
+ return FALSE;
+
+ for (i = 0; i < MAXDEVICES; i++)
+ if (PointerWindows[i] == win)
+ return TRUE;
+
+ return FALSE;
+}
+
+/**
+ * Return TRUE if at least one keyboard focus is set to 'win' (excluding
+ * descendants of win).
+ */
+static BOOL
+HasFocus(WindowPtr win)
+{
+ int i;
+ for (i = 0; i < MAXDEVICES; i++)
+ if (FocusWindows[i] == win)
+ return TRUE;
+
+ return FALSE;
+}
+
+/**
+ * Return the window the device dev is currently on.
+ */
+static WindowPtr
+PointerWin(DeviceIntPtr dev)
+{
+ return PointerWindows[dev->id];
+}
+
+/**
+ * Search for the first window below 'win' that has a pointer directly within
+ * it's boundaries (excluding boundaries of its own descendants).
+ *
+ * @return The child window that has the pointer within its boundaries or
+ * NULL.
+ */
+static WindowPtr
+FirstPointerChild(WindowPtr win)
+{
+ int i;
+ for (i = 0; i < MAXDEVICES; i++)
+ {
+ if (PointerWindows[i] && IsParent(win, PointerWindows[i]))
+ return PointerWindows[i];
+ }
+
+ return NULL;
+}
+
+/**
+ * Search for the first window below 'win' that has a focus directly within
+ * it's boundaries (excluding boundaries of its own descendants).
+ *
+ * @return The child window that has the pointer within its boundaries or
+ * NULL.
+ */
+static WindowPtr
+FirstFocusChild(WindowPtr win)
+{
+ int i;
+ for (i = 0; i < MAXDEVICES; i++)
+ {
+ if (FocusWindows[i] && FocusWindows[i] != PointerRootWin &&
+ IsParent(win, FocusWindows[i]))
+ return FocusWindows[i];
+ }
+
+ return NULL;
+}
+
+/**
+ * Set the presence flag for dev to mark that it is now in 'win'.
+ */
+void
+EnterWindow(DeviceIntPtr dev, WindowPtr win, int mode)
+{
+ PointerWindows[dev->id] = win;
+}
+
+/**
+ * Unset the presence flag for dev to mark that it is not in 'win' anymore.
+ */
+void
+LeaveWindow(DeviceIntPtr dev)
+{
+ PointerWindows[dev->id] = NULL;
+}
+
+/**
+ * Set the presence flag for dev to mark that it is now in 'win'.
+ */
+void
+SetFocusIn(DeviceIntPtr dev, WindowPtr win)
+{
+ FocusWindows[dev->id] = win;
+}
+
+/**
+ * Unset the presence flag for dev to mark that it is not in 'win' anymore.
+ */
+void
+SetFocusOut(DeviceIntPtr dev)
+{
+ FocusWindows[dev->id] = NULL;
+}
+
+
+
+
+/**
+ * Return the common ancestor of 'a' and 'b' (if one exists).
+ * @param a A window with the same ancestor as b.
+ * @param b A window with the same ancestor as a.
+ * @return The window that is the first ancestor of both 'a' and 'b', or the
+ * NullWindow if they do not have a common ancestor.
+ */
+WindowPtr
+CommonAncestor(
+ WindowPtr a,
+ WindowPtr b)
+{
+ for (b = b->parent; b; b = b->parent)
+ if (IsParent(b, a)) return b;
+ return NullWindow;
+}
+
+
+/**
+ * Send enter notifies to all windows between 'ancestor' and 'child' (excluding
+ * both). Events are sent running up the window hierarchy. This function
+ * recurses.
+ */
+static void
+DeviceEnterNotifies(DeviceIntPtr dev,
+ int sourceid,
+ WindowPtr ancestor,
+ WindowPtr child,
+ int mode,
+ int detail)
+{
+ WindowPtr parent = child->parent;
+
+ if (ancestor == parent)
+ return;
+ DeviceEnterNotifies(dev, sourceid, ancestor, parent, mode, detail);
+ DeviceEnterLeaveEvent(dev, sourceid, XI_Enter, mode, detail, parent,
+ child->drawable.id);
+}
+
+/**
+ * Send enter notifies to all windows between 'ancestor' and 'child' (excluding
+ * both). Events are sent running down the window hierarchy. This function
+ * recurses.
+ */
+static void
+CoreEnterNotifies(DeviceIntPtr dev,
+ WindowPtr ancestor,
+ WindowPtr child,
+ int mode,
+ int detail)
+{
+ WindowPtr parent = child->parent;
+ if (ancestor == parent)
+ return;
+ CoreEnterNotifies(dev, ancestor, parent, mode, detail);
+
+
+ /* Case 3:
+ A is above W, B is a descendant
+
+ Classically: The move generates an EnterNotify on W with a detail of
+ Virtual or NonlinearVirtual
+
+ MPX:
+ Case 3A: There is at least one other pointer on W itself
+ P(W) doesn't change, so the event should be suppressed
+ Case 3B: Otherwise, if there is at least one other pointer in a
+ descendant
+ P(W) stays on the same descendant, or changes to a different
+ descendant. The event should be suppressed.
+ Case 3C: Otherwise:
+ P(W) moves from a window above W to a descendant. The subwindow
+ field is set to the child containing the descendant. The detail
+ may need to be changed from Virtual to NonlinearVirtual depending
+ on the previous P(W). */
+
+ if (!HasPointer(dev, parent) && !FirstPointerChild(parent))
+ CoreEnterLeaveEvent(dev, EnterNotify, mode, detail, parent,
+ child->drawable.id);
+}
+
+static void
+CoreLeaveNotifies(DeviceIntPtr dev,
+ WindowPtr child,
+ WindowPtr ancestor,
+ int mode,
+ int detail)
+{
+ WindowPtr win;
+
+ if (ancestor == child)
+ return;
+
+ for (win = child->parent; win != ancestor; win = win->parent)
+ {
+ /*Case 7:
+ A is a descendant of W, B is above W
+
+ Classically: A LeaveNotify is generated on W with a detail of Virtual
+ or NonlinearVirtual.
+
+ MPX:
+ Case 3A: There is at least one other pointer on W itself
+ P(W) doesn't change, the event should be suppressed.
+ Case 3B: Otherwise, if there is at least one other pointer in a
+ descendant
+ P(W) stays on the same descendant, or changes to a different
+ descendant. The event should be suppressed.
+ Case 3C: Otherwise:
+ P(W) changes from the descendant of W to a window above W.
+ The detail may need to be changed from Virtual to NonlinearVirtual
+ or vice-versa depending on the new P(W).*/
+
+ /* If one window has a pointer or a child with a pointer, skip some
+ * work and exit. */
+ if (HasPointer(dev, win) || FirstPointerChild(win))
+ return;
+
+ CoreEnterLeaveEvent(dev, LeaveNotify, mode, detail, win, child->drawable.id);
+
+ child = win;
+ }
+}
+
+/**
+ * Send leave notifies to all windows between 'child' and 'ancestor'.
+ * Events are sent running up the hierarchy.
+ */
+static void
+DeviceLeaveNotifies(DeviceIntPtr dev,
+ int sourceid,
+ WindowPtr child,
+ WindowPtr ancestor,
+ int mode,
+ int detail)
+{
+ WindowPtr win;
+
+ if (ancestor == child)
+ return;
+ for (win = child->parent; win != ancestor; win = win->parent)
+ {
+ DeviceEnterLeaveEvent(dev, sourceid, XI_Leave, mode, detail, win,
+ child->drawable.id);
+ child = win;
+ }
+}
+
+/**
+ * Pointer dev moves from A to B and A neither a descendant of B nor is
+ * B a descendant of A.
+ */
+static void
+CoreEnterLeaveNonLinear(DeviceIntPtr dev,
+ WindowPtr A,
+ WindowPtr B,
+ int mode)
+{
+ WindowPtr X = CommonAncestor(A, B);
+ /* Case 4:
+ A is W, B is above W
+
+ Classically: The move generates a LeaveNotify on W with a detail of
+ Ancestor or Nonlinear
+
+ MPX:
+ Case 3A: There is at least one other pointer on W itself
+ P(W) doesn't change, the event should be suppressed
+ Case 3B: Otherwise, if there is at least one other pointer in a
+ descendant of W
+ P(W) changes from W to a descendant of W. The subwindow field
+ is set to the child containing the new P(W), the detail field
+ is set to Inferior
+ Case 3C: Otherwise:
+ The pointer window moves from W to a window above W.
+ The detail may need to be changed from Ancestor to Nonlinear or
+ vice versa depending on the the new P(W)
+ */
+
+ if (!HasPointer(dev, A))
+ {
+ WindowPtr child = FirstPointerChild(A);
+ if (child)
+ CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyInferior, A, None);
+ else
+ CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyNonlinear, A, None);
+ }
+
+
+ CoreLeaveNotifies(dev, A, X, mode, NotifyNonlinearVirtual);
+
+ /*
+ Case 9:
+ A is a descendant of W, B is a descendant of W
+
+ Classically: No events are generated on W
+ MPX: The pointer window stays the same or moves to a different
+ descendant of W. No events should be generated on W.
+
+
+ Therefore, no event to X.
+ */
+
+ CoreEnterNotifies(dev, X, B, mode, NotifyNonlinearVirtual);
+
+ /* Case 2:
+ A is above W, B=W
+
+ Classically: The move generates an EnterNotify on W with a detail of
+ Ancestor or Nonlinear
+
+ MPX:
+ Case 2A: There is at least one other pointer on W itself
+ P(W) doesn't change, so the event should be suppressed
+ Case 2B: Otherwise, if there is at least one other pointer in a
+ descendant
+ P(W) moves from a descendant to W. detail is changed to Inferior,
+ subwindow is set to the child containing the previous P(W)
+ Case 2C: Otherwise:
+ P(W) changes from a window above W to W itself.
+ The detail may need to be changed from Ancestor to Nonlinear
+ or vice-versa depending on the previous P(W). */
+
+ if (!HasPointer(dev, B))
+ {
+ WindowPtr child = FirstPointerChild(B);
+ if (child)
+ CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyInferior, B, None);
+ else
+ CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyNonlinear, B, None);
+ }
+}
+
+/**
+ * Pointer dev moves from A to B and A is a descendant of B.
+ */
+static void
+CoreEnterLeaveToAncestor(DeviceIntPtr dev,
+ WindowPtr A,
+ WindowPtr B,
+ int mode)
+{
+ /* Case 4:
+ A is W, B is above W
+
+ Classically: The move generates a LeaveNotify on W with a detail of
+ Ancestor or Nonlinear
+
+ MPX:
+ Case 3A: There is at least one other pointer on W itself
+ P(W) doesn't change, the event should be suppressed
+ Case 3B: Otherwise, if there is at least one other pointer in a
+ descendant of W
+ P(W) changes from W to a descendant of W. The subwindow field
+ is set to the child containing the new P(W), the detail field
+ is set to Inferior
+ Case 3C: Otherwise:
+ The pointer window moves from W to a window above W.
+ The detail may need to be changed from Ancestor to Nonlinear or
+ vice versa depending on the the new P(W)
+ */
+ if (!HasPointer(dev, A))
+ {
+ WindowPtr child = FirstPointerChild(A);
+ if (child)
+ CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyInferior, A, None);
+ else
+ CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyAncestor, A, None);
+ }
+
+ CoreLeaveNotifies(dev, A, B, mode, NotifyVirtual);
+
+ /* Case 8:
+ A is a descendant of W, B is W
+
+ Classically: A EnterNotify is generated on W with a detail of
+ NotifyInferior
+
+ MPX:
+ Case 3A: There is at least one other pointer on W itself
+ P(W) doesn't change, the event should be suppressed
+ Case 3B: Otherwise:
+ P(W) changes from a descendant to W itself. The subwindow
+ field should be set to the child containing the old P(W) <<< WRONG */
+
+ if (!HasPointer(dev, B))
+ CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyInferior, B, None);
+
+}
+
+
+/**
+ * Pointer dev moves from A to B and B is a descendant of A.
+ */
+static void
+CoreEnterLeaveToDescendant(DeviceIntPtr dev,
+ WindowPtr A,
+ WindowPtr B,
+ int mode)
+{
+ /* Case 6:
+ A is W, B is a descendant of W
+
+ Classically: A LeaveNotify is generated on W with a detail of
+ NotifyInferior
+
+ MPX:
+ Case 3A: There is at least one other pointer on W itself
+ P(W) doesn't change, the event should be suppressed
+ Case 3B: Otherwise:
+ P(W) changes from W to a descendant of W. The subwindow field
+ is set to the child containing the new P(W) <<< THIS IS WRONG */
+
+ if (!HasPointer(dev, A))
+ CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyInferior, A, None);
+
+
+ CoreEnterNotifies(dev, A, B, mode, NotifyVirtual);
+
+ /* Case 2:
+ A is above W, B=W
+
+ Classically: The move generates an EnterNotify on W with a detail of
+ Ancestor or Nonlinear
+
+ MPX:
+ Case 2A: There is at least one other pointer on W itself
+ P(W) doesn't change, so the event should be suppressed
+ Case 2B: Otherwise, if there is at least one other pointer in a
+ descendant
+ P(W) moves from a descendant to W. detail is changed to Inferior,
+ subwindow is set to the child containing the previous P(W)
+ Case 2C: Otherwise:
+ P(W) changes from a window above W to W itself.
+ The detail may need to be changed from Ancestor to Nonlinear
+ or vice-versa depending on the previous P(W). */
+
+ if (!HasPointer(dev, B))
+ {
+ WindowPtr child = FirstPointerChild(B);
+ if (child)
+ CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyInferior, B, None);
+ else
+ CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyAncestor, B, None);
+ }
+}
+
+static void
+CoreEnterLeaveEvents(DeviceIntPtr dev,
+ WindowPtr from,
+ WindowPtr to,
+ int mode)
+{
+ if (!IsMaster(dev))
+ return;
+
+ LeaveWindow(dev);
+
+ if (IsParent(from, to))
+ CoreEnterLeaveToDescendant(dev, from, to, mode);
+ else if (IsParent(to, from))
+ CoreEnterLeaveToAncestor(dev, from, to, mode);
+ else
+ CoreEnterLeaveNonLinear(dev, from, to, mode);
+
+ EnterWindow(dev, to, mode);
+}
+
+static void
+DeviceEnterLeaveEvents(DeviceIntPtr dev,
+ int sourceid,
+ WindowPtr from,
+ WindowPtr to,
+ int mode)
+{
+ if (IsParent(from, to))
+ {
+ DeviceEnterLeaveEvent(dev, sourceid, XI_Leave, mode, NotifyInferior, from, None);
+ DeviceEnterNotifies(dev, sourceid, from, to, mode, NotifyVirtual);
+ DeviceEnterLeaveEvent(dev, sourceid, XI_Enter, mode, NotifyAncestor, to, None);
+ }
+ else if (IsParent(to, from))
+ {
+ DeviceEnterLeaveEvent(dev, sourceid, XI_Leave, mode, NotifyAncestor, from, None);
+ DeviceLeaveNotifies(dev, sourceid, from, to, mode, NotifyVirtual);
+ DeviceEnterLeaveEvent(dev, sourceid, XI_Enter, mode, NotifyInferior, to, None);
+ }
+ else
+ { /* neither from nor to is descendent of the other */
+ WindowPtr common = CommonAncestor(to, from);
+ /* common == NullWindow ==> different screens */
+ DeviceEnterLeaveEvent(dev, sourceid, XI_Leave, mode, NotifyNonlinear, from, None);
+ DeviceLeaveNotifies(dev, sourceid, from, common, mode, NotifyNonlinearVirtual);
+ DeviceEnterNotifies(dev, sourceid, common, to, mode, NotifyNonlinearVirtual);
+ DeviceEnterLeaveEvent(dev, sourceid, XI_Enter, mode, NotifyNonlinear, to, None);
+ }
+}
+
+/**
+ * Figure out if enter/leave events are necessary and send them to the
+ * appropriate windows.
+ *
+ * @param fromWin Window the sprite moved out of.
+ * @param toWin Window the sprite moved into.
+ */
+void
+DoEnterLeaveEvents(DeviceIntPtr pDev,
+ int sourceid,
+ WindowPtr fromWin,
+ WindowPtr toWin,
+ int mode)
+{
+ if (!IsPointerDevice(pDev))
+ return;
+
+ if (fromWin == toWin)
+ return;
+
+ if (mode != XINotifyPassiveGrab && mode != XINotifyPassiveUngrab)
+ CoreEnterLeaveEvents(pDev, fromWin, toWin, mode);
+ DeviceEnterLeaveEvents(pDev, sourceid, fromWin, toWin, mode);
+}
+
+/**
+ * Send focus out events to all windows between 'child' and 'ancestor'.
+ * Events are sent running up the hierarchy.
+ */
+static void
+DeviceFocusOutEvents(DeviceIntPtr dev,
+ WindowPtr child,
+ WindowPtr ancestor,
+ int mode,
+ int detail)
+{
+ WindowPtr win;
+
+ if (ancestor == child)
+ return;
+ for (win = child->parent; win != ancestor; win = win->parent)
+ DeviceFocusEvent(dev, XI_FocusOut, mode, detail, win);
+}
+
+
+/**
+ * Send enter notifies to all windows between 'ancestor' and 'child' (excluding
+ * both). Events are sent running up the window hierarchy. This function
+ * recurses.
+ */
+static void
+DeviceFocusInEvents(DeviceIntPtr dev,
+ WindowPtr ancestor,
+ WindowPtr child,
+ int mode,
+ int detail)
+{
+ WindowPtr parent = child->parent;
+
+ if (ancestor == parent || !parent)
+ return;
+ DeviceFocusInEvents(dev, ancestor, parent, mode, detail);
+ DeviceFocusEvent(dev, XI_FocusIn, mode, detail, parent);
+}
+
+/**
+ * Send FocusIn events to all windows between 'ancestor' and 'child' (excluding
+ * both). Events are sent running down the window hierarchy. This function
+ * recurses.
+ */
+static void
+CoreFocusInEvents(DeviceIntPtr dev,
+ WindowPtr ancestor,
+ WindowPtr child,
+ int mode,
+ int detail)
+{
+ WindowPtr parent = child->parent;
+ if (ancestor == parent)
+ return;
+ CoreFocusInEvents(dev, ancestor, parent, mode, detail);
+
+
+ /* Case 3:
+ A is above W, B is a descendant
+
+ Classically: The move generates an FocusIn on W with a detail of
+ Virtual or NonlinearVirtual
+
+ MPX:
+ Case 3A: There is at least one other focus on W itself
+ F(W) doesn't change, so the event should be suppressed
+ Case 3B: Otherwise, if there is at least one other focus in a
+ descendant
+ F(W) stays on the same descendant, or changes to a different
+ descendant. The event should be suppressed.
+ Case 3C: Otherwise:
+ F(W) moves from a window above W to a descendant. The detail may
+ need to be changed from Virtual to NonlinearVirtual depending
+ on the previous F(W). */
+
+ if (!HasFocus(parent) && !FirstFocusChild(parent))
+ CoreFocusEvent(dev, FocusIn, mode, detail, parent);
+}
+
+static void
+CoreFocusOutEvents(DeviceIntPtr dev,
+ WindowPtr child,
+ WindowPtr ancestor,
+ int mode,
+ int detail)
+{
+ WindowPtr win;
+
+ if (ancestor == child)
+ return;
+
+ for (win = child->parent; win != ancestor; win = win->parent)
+ {
+ /*Case 7:
+ A is a descendant of W, B is above W
+
+ Classically: A FocusOut is generated on W with a detail of Virtual
+ or NonlinearVirtual.
+
+ MPX:
+ Case 3A: There is at least one other focus on W itself
+ F(W) doesn't change, the event should be suppressed.
+ Case 3B: Otherwise, if there is at least one other focus in a
+ descendant
+ F(W) stays on the same descendant, or changes to a different
+ descendant. The event should be suppressed.
+ Case 3C: Otherwise:
+ F(W) changes from the descendant of W to a window above W.
+ The detail may need to be changed from Virtual to NonlinearVirtual
+ or vice-versa depending on the new P(W).*/
+
+ /* If one window has a focus or a child with a focuspointer, skip some
+ * work and exit. */
+ if (HasFocus(win) || FirstFocusChild(win))
+ return;
+
+ CoreFocusEvent(dev, FocusOut, mode, detail, win);
+ }
+}
+
+/**
+ * Send FocusOut(NotifyPointer) events from the current pointer window (which
+ * is a descendant of pwin_parent) up to (excluding) pwin_parent.
+ *
+ * NotifyPointer events are only sent for the device paired with dev.
+ *
+ * If the current pointer window is a descendant of 'exclude' or an ancestor of
+ * 'exclude', no events are sent. If the current pointer IS 'exclude', events
+ * are sent!
+ */
+static void
+CoreFocusOutNotifyPointerEvents(DeviceIntPtr dev,
+ WindowPtr pwin_parent,
+ WindowPtr exclude,
+ int mode,
+ int inclusive)
+{
+ WindowPtr P, stopAt;
+
+ P = PointerWin(GetPairedDevice(dev));
+
+ if (!P)
+ return;
+ if (!IsParent(pwin_parent, P))
+ if (!(pwin_parent == P && inclusive))
+ return;
+
+ if (exclude != None && exclude != PointerRootWin &&
+ (IsParent(exclude, P) || IsParent(P, exclude)))
+ return;
+
+ stopAt = (inclusive) ? pwin_parent->parent : pwin_parent;
+
+ for (; P && P != stopAt; P = P->parent)
+ CoreFocusEvent(dev, FocusOut, mode, NotifyPointer, P);
+}
+
+/**
+ * DO NOT CALL DIRECTLY.
+ * Recursion helper for CoreFocusInNotifyPointerEvents.
+ */
+static void
+CoreFocusInRecurse(DeviceIntPtr dev,
+ WindowPtr win,
+ WindowPtr stopAt,
+ int mode,
+ int inclusive)
+{
+ if ((!inclusive && win == stopAt) || !win)
+ return;
+
+ CoreFocusInRecurse(dev, win->parent, stopAt, mode, inclusive);
+ CoreFocusEvent(dev, FocusIn, mode, NotifyPointer, win);
+}
+
+
+/**
+ * Send FocusIn(NotifyPointer) events from pwin_parent down to
+ * including the current pointer window (which is a descendant of pwin_parent).
+ *
+ * @param pwin The pointer window.
+ * @param exclude If the pointer window is a child of 'exclude', no events are
+ * sent.
+ * @param inclusive If TRUE, pwin_parent will receive the event too.
+ */
+static void
+CoreFocusInNotifyPointerEvents(DeviceIntPtr dev,
+ WindowPtr pwin_parent,
+ WindowPtr exclude,
+ int mode,
+ int inclusive)
+{
+ WindowPtr P;
+
+ P = PointerWin(GetPairedDevice(dev));
+
+ if (!P || P == exclude || (pwin_parent != P && !IsParent(pwin_parent, P)))
+ return;
+
+ if (exclude != None && (IsParent(exclude, P) || IsParent(P, exclude)))
+ return;
+
+ CoreFocusInRecurse(dev, P, pwin_parent, mode, inclusive);
+}
+
+
+/**
+ * Focus of dev moves from A to B and A neither a descendant of B nor is
+ * B a descendant of A.
+ */
+static void
+CoreFocusNonLinear(DeviceIntPtr dev,
+ WindowPtr A,
+ WindowPtr B,
+ int mode)
+{
+ WindowPtr X = CommonAncestor(A, B);
+
+ /* Case 4:
+ A is W, B is above W
+
+ Classically: The change generates a FocusOut on W with a detail of
+ Ancestor or Nonlinear
+
+ MPX:
+ Case 3A: There is at least one other focus on W itself
+ F(W) doesn't change, the event should be suppressed
+ Case 3B: Otherwise, if there is at least one other focus in a
+ descendant of W
+ F(W) changes from W to a descendant of W. The detail field
+ is set to Inferior
+ Case 3C: Otherwise:
+ The focus window moves from W to a window above W.
+ The detail may need to be changed from Ancestor to Nonlinear or
+ vice versa depending on the the new F(W)
+ */
+
+ if (!HasFocus(A))
+ {
+ WindowPtr child = FirstFocusChild(A);
+ if (child)
+ {
+ /* NotifyPointer P-A unless P is child or below*/
+ CoreFocusOutNotifyPointerEvents(dev, A, child, mode, FALSE);
+ CoreFocusEvent(dev, FocusOut, mode, NotifyInferior, A);
+ } else
+ {
+ /* NotifyPointer P-A */
+ CoreFocusOutNotifyPointerEvents(dev, A, None, mode, FALSE);
+ CoreFocusEvent(dev, FocusOut, mode, NotifyNonlinear, A);
+ }
+ }
+
+
+ CoreFocusOutEvents(dev, A, X, mode, NotifyNonlinearVirtual);
+
+ /*
+ Case 9:
+ A is a descendant of W, B is a descendant of W
+
+ Classically: No events are generated on W
+ MPX: The focus window stays the same or moves to a different
+ descendant of W. No events should be generated on W.
+
+
+ Therefore, no event to X.
+ */
+
+ CoreFocusInEvents(dev, X, B, mode, NotifyNonlinearVirtual);
+
+ /* Case 2:
+ A is above W, B=W
+
+ Classically: The move generates an EnterNotify on W with a detail of
+ Ancestor or Nonlinear
+
+ MPX:
+ Case 2A: There is at least one other focus on W itself
+ F(W) doesn't change, so the event should be suppressed
+ Case 2B: Otherwise, if there is at least one other focus in a
+ descendant
+ F(W) moves from a descendant to W. detail is changed to Inferior.
+ Case 2C: Otherwise:
+ F(W) changes from a window above W to W itself.
+ The detail may need to be changed from Ancestor to Nonlinear
+ or vice-versa depending on the previous F(W). */
+
+ if (!HasFocus(B))
+ {
+ WindowPtr child = FirstFocusChild(B);
+ if (child)
+ {
+ CoreFocusEvent(dev, FocusIn, mode, NotifyInferior, B);
+ /* NotifyPointer B-P unless P is child or below. */
+ CoreFocusInNotifyPointerEvents(dev, B, child, mode, FALSE);
+ } else {
+ CoreFocusEvent(dev, FocusIn, mode, NotifyNonlinear, B);
+ /* NotifyPointer B-P unless P is child or below. */
+ CoreFocusInNotifyPointerEvents(dev, B, None, mode, FALSE);
+ }
+ }
+}
+
+
+/**
+ * Focus of dev moves from A to B and A is a descendant of B.
+ */
+static void
+CoreFocusToAncestor(DeviceIntPtr dev,
+ WindowPtr A,
+ WindowPtr B,
+ int mode)
+{
+ /* Case 4:
+ A is W, B is above W
+
+ Classically: The change generates a FocusOut on W with a detail of
+ Ancestor or Nonlinear
+
+ MPX:
+ Case 3A: There is at least one other focus on W itself
+ F(W) doesn't change, the event should be suppressed
+ Case 3B: Otherwise, if there is at least one other focus in a
+ descendant of W
+ F(W) changes from W to a descendant of W. The detail field
+ is set to Inferior
+ Case 3C: Otherwise:
+ The focus window moves from W to a window above W.
+ The detail may need to be changed from Ancestor to Nonlinear or
+ vice versa depending on the the new F(W)
+ */
+ if (!HasFocus(A))
+ {
+ WindowPtr child = FirstFocusChild(A);
+ if (child)
+ {
+ /* NotifyPointer P-A unless P is child or below*/
+ CoreFocusOutNotifyPointerEvents(dev, A, child, mode, FALSE);
+ CoreFocusEvent(dev, FocusOut, mode, NotifyInferior, A);
+ } else
+ CoreFocusEvent(dev, FocusOut, mode, NotifyAncestor, A);
+ }
+
+ CoreFocusOutEvents(dev, A, B, mode, NotifyVirtual);
+
+ /* Case 8:
+ A is a descendant of W, B is W
+
+ Classically: A FocusOut is generated on W with a detail of
+ NotifyInferior
+
+ MPX:
+ Case 3A: There is at least one other focus on W itself
+ F(W) doesn't change, the event should be suppressed
+ Case 3B: Otherwise:
+ F(W) changes from a descendant to W itself. */
+
+ if (!HasFocus(B))
+ {
+ CoreFocusEvent(dev, FocusIn, mode, NotifyInferior, B);
+ /* NotifyPointer B-P unless P is A or below. */
+ CoreFocusInNotifyPointerEvents(dev, B, A, mode, FALSE);
+ }
+}
+
+/**
+ * Focus of dev moves from A to B and B is a descendant of A.
+ */
+static void
+CoreFocusToDescendant(DeviceIntPtr dev,
+ WindowPtr A,
+ WindowPtr B,
+ int mode)
+{
+ /* Case 6:
+ A is W, B is a descendant of W
+
+ Classically: A FocusOut is generated on W with a detail of
+ NotifyInferior
+
+ MPX:
+ Case 3A: There is at least one other focus on W itself
+ F(W) doesn't change, the event should be suppressed
+ Case 3B: Otherwise:
+ F(W) changes from W to a descendant of W. */
+
+ if (!HasFocus(A))
+ {
+ /* NotifyPointer P-A unless P is B or below*/
+ CoreFocusOutNotifyPointerEvents(dev, A, B, mode, FALSE);
+ CoreFocusEvent(dev, FocusOut, mode, NotifyInferior, A);
+ }
+
+
+ CoreFocusInEvents(dev, A, B, mode, NotifyVirtual);
+
+ /* Case 2:
+ A is above W, B=W
+
+ Classically: The move generates an FocusIn on W with a detail of
+ Ancestor or Nonlinear
+
+ MPX:
+ Case 2A: There is at least one other focus on W itself
+ F(W) doesn't change, so the event should be suppressed
+ Case 2B: Otherwise, if there is at least one other focus in a
+ descendant
+ F(W) moves from a descendant to W. detail is changed to Inferior.
+ Case 2C: Otherwise:
+ F(W) changes from a window above W to W itself.
+ The detail may need to be changed from Ancestor to Nonlinear
+ or vice-versa depending on the previous F(W). */
+
+ if (!HasFocus(B))
+ {
+ WindowPtr child = FirstFocusChild(B);
+ if (child)
+ {
+ CoreFocusEvent(dev, FocusIn, mode, NotifyInferior, B);
+ /* NotifyPointer B-P unless P is child or below. */
+ CoreFocusInNotifyPointerEvents(dev, B, child, mode, FALSE);
+ } else
+ CoreFocusEvent(dev, FocusIn, mode, NotifyAncestor, B);
+ }
+}
+
+static BOOL
+HasOtherPointer(WindowPtr win, DeviceIntPtr exclude)
+{
+ int i;
+
+ for (i = 0; i < MAXDEVICES; i++)
+ if (i != exclude->id && PointerWindows[i] == win)
+ return TRUE;
+
+ return FALSE;
+}
+
+/**
+ * Focus moves from PointerRoot to None or from None to PointerRoot.
+ * Assumption: Neither A nor B are valid windows.
+ */
+static void
+CoreFocusPointerRootNoneSwitch(DeviceIntPtr dev,
+ WindowPtr A, /* PointerRootWin or NoneWin */
+ WindowPtr B, /* NoneWin or PointerRootWin */
+ int mode)
+{
+ WindowPtr root;
+ int i;
+ int nscreens = screenInfo.numScreens;
+
+#ifdef PANORAMIX
+ if (!noPanoramiXExtension)
+ nscreens = 1;
+#endif
+
+ for (i = 0; i < nscreens; i++)
+ {
+ root = screenInfo.screens[i]->root;
+ if (!HasOtherPointer(root, GetPairedDevice(dev)) && !FirstFocusChild(root))
+ {
+ /* If pointer was on PointerRootWin and changes to NoneWin, and
+ * the pointer paired with dev is below the current root window,
+ * do a NotifyPointer run. */
+ if (dev->focus && dev->focus->win == PointerRootWin &&
+ B != PointerRootWin)
+ {
+ WindowPtr ptrwin = PointerWin(GetPairedDevice(dev));
+ if (ptrwin && IsParent(root, ptrwin))
+ CoreFocusOutNotifyPointerEvents(dev, root, None, mode, TRUE);
+ }
+ CoreFocusEvent(dev, FocusOut, mode, A ? NotifyPointerRoot : NotifyDetailNone, root);
+ CoreFocusEvent(dev, FocusIn, mode, B ? NotifyPointerRoot : NotifyDetailNone, root);
+ if (B == PointerRootWin)
+ CoreFocusInNotifyPointerEvents(dev, root, None, mode, TRUE);
+ }
+
+ }
+}
+
+/**
+ * Focus moves from window A to PointerRoot or to None.
+ * Assumption: A is a valid window and not PointerRoot or None.
+ */
+static void
+CoreFocusToPointerRootOrNone(DeviceIntPtr dev,
+ WindowPtr A,
+ WindowPtr B, /* PointerRootWin or NoneWin */
+ int mode)
+{
+ WindowPtr root;
+ int i;
+ int nscreens = screenInfo.numScreens;
+
+#ifdef PANORAMIX
+ if (!noPanoramiXExtension)
+ nscreens = 1;
+#endif
+
+ if (!HasFocus(A))
+ {
+ WindowPtr child = FirstFocusChild(A);
+ if (child)
+ {
+ /* NotifyPointer P-A unless P is B or below*/
+ CoreFocusOutNotifyPointerEvents(dev, A, B, mode, FALSE);
+ CoreFocusEvent(dev, FocusOut, mode, NotifyInferior, A);
+ } else {
+ /* NotifyPointer P-A */
+ CoreFocusOutNotifyPointerEvents(dev, A, None, mode, FALSE);
+ CoreFocusEvent(dev, FocusOut, mode, NotifyNonlinear, A);
+ }
+ }
+
+ /* NullWindow means we include the root window */
+ CoreFocusOutEvents(dev, A, NullWindow, mode, NotifyNonlinearVirtual);
+
+ for (i = 0; i < nscreens; i++)
+ {
+ root = screenInfo.screens[i]->root;
+ if (!HasFocus(root) && !FirstFocusChild(root))
+ {
+ CoreFocusEvent(dev, FocusIn, mode, B ? NotifyPointerRoot : NotifyDetailNone, root);
+ if (B == PointerRootWin)
+ CoreFocusInNotifyPointerEvents(dev, root, None, mode, TRUE);
+ }
+ }
+}
+
+/**
+ * Focus moves from PointerRoot or None to a window B.
+ * Assumption: B is a valid window and not PointerRoot or None.
+ */
+static void
+CoreFocusFromPointerRootOrNone(DeviceIntPtr dev,
+ WindowPtr A, /* PointerRootWin or NoneWin */
+ WindowPtr B,
+ int mode)
+{
+ WindowPtr root;
+ int i;
+ int nscreens = screenInfo.numScreens;
+
+#ifdef PANORAMIX
+ if (!noPanoramiXExtension)
+ nscreens = 1;
+#endif
+
+ for (i = 0; i < nscreens; i++)
+ {
+ root = screenInfo.screens[i]->root;
+ if (!HasFocus(root) && !FirstFocusChild(root))
+ {
+ /* If pointer was on PointerRootWin and changes to NoneWin, and
+ * the pointer paired with dev is below the current root window,
+ * do a NotifyPointer run. */
+ if (dev->focus && dev->focus->win == PointerRootWin &&
+ B != PointerRootWin)
+ {
+ WindowPtr ptrwin = PointerWin(GetPairedDevice(dev));
+ if (ptrwin)
+ CoreFocusOutNotifyPointerEvents(dev, root, None, mode, TRUE);
+ }
+ CoreFocusEvent(dev, FocusOut, mode, A ? NotifyPointerRoot : NotifyDetailNone, root);
+ }
+ }
+
+ root = B; /* get B's root window */
+ while(root->parent)
+ root = root->parent;
+
+ if (B != root)
+ {
+ CoreFocusEvent(dev, FocusIn, mode, NotifyNonlinearVirtual, root);
+ CoreFocusInEvents(dev, root, B, mode, NotifyNonlinearVirtual);
+ }
+
+
+ if (!HasFocus(B))
+ {
+ WindowPtr child = FirstFocusChild(B);
+ if (child)
+ {
+ CoreFocusEvent(dev, FocusIn, mode, NotifyInferior, B);
+ /* NotifyPointer B-P unless P is child or below. */
+ CoreFocusInNotifyPointerEvents(dev, B, child, mode, FALSE);
+ } else {
+ CoreFocusEvent(dev, FocusIn, mode, NotifyNonlinear, B);
+ /* NotifyPointer B-P unless P is child or below. */
+ CoreFocusInNotifyPointerEvents(dev, B, None, mode, FALSE);
+ }
+ }
+
+}
+
+static void
+CoreFocusEvents(DeviceIntPtr dev,
+ WindowPtr from,
+ WindowPtr to,
+ int mode)
+{
+ if (!IsMaster(dev))
+ return;
+
+ SetFocusOut(dev);
+
+ if (((to == NullWindow) || (to == PointerRootWin)) &&
+ ((from == NullWindow) || (from == PointerRootWin)))
+ CoreFocusPointerRootNoneSwitch(dev, from, to, mode);
+ else if ((to == NullWindow) || (to == PointerRootWin))
+ CoreFocusToPointerRootOrNone(dev, from, to, mode);
+ else if ((from == NullWindow) || (from == PointerRootWin))
+ CoreFocusFromPointerRootOrNone(dev, from, to, mode);
+ else if (IsParent(from, to))
+ CoreFocusToDescendant(dev, from, to, mode);
+ else if (IsParent(to, from))
+ CoreFocusToAncestor(dev, from, to, mode);
+ else
+ CoreFocusNonLinear(dev, from, to, mode);
+
+ SetFocusIn(dev, to);
+}
+
+static void
+DeviceFocusEvents(DeviceIntPtr dev,
+ WindowPtr from,
+ WindowPtr to,
+ int mode)
+{
+ int out, in; /* for holding details for to/from
+ PointerRoot/None */
+ int i;
+ int nscreens = screenInfo.numScreens;
+ SpritePtr sprite = dev->spriteInfo->sprite;
+
+ if (from == to)
+ return;
+ out = (from == NoneWin) ? NotifyDetailNone : NotifyPointerRoot;
+ in = (to == NoneWin) ? NotifyDetailNone : NotifyPointerRoot;
+ /* wrong values if neither, but then not referenced */
+
+#ifdef PANORAMIX
+ if (!noPanoramiXExtension)
+ nscreens = 1;
+#endif
+
+ if ((to == NullWindow) || (to == PointerRootWin))
+ {
+ if ((from == NullWindow) || (from == PointerRootWin))
+ {
+ if (from == PointerRootWin)
+ DeviceFocusOutEvents(dev, sprite->win, GetCurrentRootWindow(dev), mode,
+ NotifyPointer);
+ /* Notify all the roots */
+ for (i = 0; i < nscreens; i++)
+ DeviceFocusEvent(dev, XI_FocusOut, mode, out, screenInfo.screens[i]->root);
+ }
+ else
+ {
+ if (IsParent(from, sprite->win))
+ DeviceFocusOutEvents(dev, sprite->win, from, mode,
+ NotifyPointer);
+ DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyNonlinear, from);
+ /* next call catches the root too, if the screen changed */
+ DeviceFocusOutEvents(dev, from->parent, NullWindow, mode,
+ NotifyNonlinearVirtual);
+ }
+ /* Notify all the roots */
+ for (i = 0; i < nscreens; i++)
+ DeviceFocusEvent(dev, XI_FocusIn, mode, in, screenInfo.screens[i]->root);
+ if (to == PointerRootWin)
+ DeviceFocusInEvents(dev, GetCurrentRootWindow(dev), sprite->win, mode, NotifyPointer);
+ }
+ else
+ {
+ if ((from == NullWindow) || (from == PointerRootWin))
+ {
+ if (from == PointerRootWin)
+ DeviceFocusOutEvents(dev, sprite->win, GetCurrentRootWindow(dev), mode,
+ NotifyPointer);
+ for (i = 0; i < nscreens; i++)
+ DeviceFocusEvent(dev, XI_FocusOut, mode, out, screenInfo.screens[i]->root);
+ if (to->parent != NullWindow)
+ DeviceFocusInEvents(dev, GetCurrentRootWindow(dev), to, mode, NotifyNonlinearVirtual);
+ DeviceFocusEvent(dev, XI_FocusIn, mode, NotifyNonlinear, to);
+ if (IsParent(to, sprite->win))
+ DeviceFocusInEvents(dev, to, sprite->win, mode, NotifyPointer);
+ }
+ else
+ {
+ if (IsParent(to, from))
+ {
+ DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyAncestor, from);
+ DeviceFocusOutEvents(dev, from->parent, to, mode,
+ NotifyVirtual);
+ DeviceFocusEvent(dev, XI_FocusIn, mode, NotifyInferior, to);
+ if ((IsParent(to, sprite->win)) &&
+ (sprite->win != from) &&
+ (!IsParent(from, sprite->win)) &&
+ (!IsParent(sprite->win, from)))
+ DeviceFocusInEvents(dev, to, sprite->win, mode, NotifyPointer);
+ }
+ else
+ if (IsParent(from, to))
+ {
+ if ((IsParent(from, sprite->win)) &&
+ (sprite->win != from) &&
+ (!IsParent(to, sprite->win)) &&
+ (!IsParent(sprite->win, to)))
+ DeviceFocusOutEvents(dev, sprite->win, from, mode,
+ NotifyPointer);
+ DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyInferior, from);
+ DeviceFocusInEvents(dev, from, to, mode, NotifyVirtual);
+ DeviceFocusEvent(dev, XI_FocusIn, mode, NotifyAncestor, to);
+ }
+ else
+ {
+ /* neither from or to is child of other */
+ WindowPtr common = CommonAncestor(to, from);
+ /* common == NullWindow ==> different screens */
+ if (IsParent(from, sprite->win))
+ DeviceFocusOutEvents(dev, sprite->win, from, mode,
+ NotifyPointer);
+ DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyNonlinear, from);
+ if (from->parent != NullWindow)
+ DeviceFocusOutEvents(dev, from->parent, common, mode,
+ NotifyNonlinearVirtual);
+ if (to->parent != NullWindow)
+ DeviceFocusInEvents(dev, common, to, mode, NotifyNonlinearVirtual);
+ DeviceFocusEvent(dev, XI_FocusIn, mode, NotifyNonlinear, to);
+ if (IsParent(to, sprite->win))
+ DeviceFocusInEvents(dev, to, sprite->win, mode, NotifyPointer);
+ }
+ }
+ }
+}
+
+/**
+ * Figure out if focus events are necessary and send them to the
+ * appropriate windows.
+ *
+ * @param from Window the focus moved out of.
+ * @param to Window the focus moved into.
+ */
+void
+DoFocusEvents(DeviceIntPtr pDev,
+ WindowPtr from,
+ WindowPtr to,
+ int mode)
+{
+ if (!IsKeyboardDevice(pDev))
+ return;
+
+ if (from == to)
+ return;
+
+ CoreFocusEvents(pDev, from, to, mode);
+ DeviceFocusEvents(pDev, from, to, mode);
+}
diff --git a/dix/enterleave.h b/dix/enterleave.h
new file mode 100644
index 0000000..471f4ef
--- /dev/null
+++ b/dix/enterleave.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright © 2008 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Peter Hutterer
+ *
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#ifndef ENTERLEAVE_H
+#define ENTERLEAVE_H
+
+extern void DoEnterLeaveEvents(
+ DeviceIntPtr pDev,
+ int sourceid,
+ WindowPtr fromWin,
+ WindowPtr toWin,
+ int mode
+);
+
+extern void DoFocusEvents(
+ DeviceIntPtr pDev,
+ WindowPtr fromWin,
+ WindowPtr toWin,
+ int mode
+);
+
+extern void EnterLeaveEvent(
+ DeviceIntPtr mouse,
+ int type,
+ int mode,
+ int detail,
+ WindowPtr pWin,
+ Window child);
+
+extern WindowPtr CommonAncestor(
+ WindowPtr a,
+ WindowPtr b);
+
+extern void CoreEnterLeaveEvent(DeviceIntPtr mouse,
+ int type,
+ int mode,
+ int detail,
+ WindowPtr pWin,
+ Window child);
+extern void DeviceEnterLeaveEvent(DeviceIntPtr mouse,
+ int sourceid,
+ int type,
+ int mode,
+ int detail,
+ WindowPtr pWin,
+ Window child);
+
+extern void EnterWindow(DeviceIntPtr dev,
+ WindowPtr win,
+ int mode);
+
+extern void LeaveWindow(DeviceIntPtr dev);
+
+extern void CoreFocusEvent(DeviceIntPtr kbd,
+ int type,
+ int mode,
+ int detail,
+ WindowPtr pWin);
+
+extern void DeviceFocusEvent(DeviceIntPtr kbd,
+ int type,
+ int mode,
+ int detail,
+ WindowPtr pWin);
+
+extern void SetFocusIn(DeviceIntPtr kbd,
+ WindowPtr win);
+
+extern void SetFocusOut(DeviceIntPtr dev);
+#endif /* _ENTERLEAVE_H_ */
diff --git a/dix/eventconvert.c b/dix/eventconvert.c
new file mode 100644
index 0000000..a73c671
--- /dev/null
+++ b/dix/eventconvert.c
@@ -0,0 +1,739 @@
+/*
+ * Copyright © 2009 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/**
+ * @file eventconvert.c
+ * This file contains event conversion routines from InternalEvent to the
+ * matching protocol events.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stdint.h>
+#include <X11/X.h>
+#include <X11/extensions/XIproto.h>
+#include <X11/extensions/XI2proto.h>
+#include <X11/extensions/XI.h>
+#include <X11/extensions/XI2.h>
+
+#include "dix.h"
+#include "inputstr.h"
+#include "misc.h"
+#include "eventstr.h"
+#include "exglobals.h"
+#include "eventconvert.h"
+#include "xiquerydevice.h"
+#include "xkbsrv.h"
+
+
+static int countValuators(DeviceEvent *ev, int *first);
+static int getValuatorEvents(DeviceEvent *ev, deviceValuator *xv);
+static int eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count);
+static int eventToDeviceChanged(DeviceChangedEvent *ev, xEvent **dcce);
+static int eventToDeviceEvent(DeviceEvent *ev, xEvent **xi);
+static int eventToRawEvent(RawDeviceEvent *ev, xEvent **xi);
+
+/* Do not use, read comments below */
+BOOL EventIsKeyRepeat(xEvent *event);
+
+/**
+ * Hack to allow detectable autorepeat for core and XI1 events.
+ * The sequence number is unused until we send to the client and can be
+ * misused to store data. More or less, anyway.
+ *
+ * Do not use this. It may change any time without warning, eat your babies
+ * and piss on your cat.
+ */
+static void
+EventSetKeyRepeatFlag(xEvent *event, BOOL on)
+{
+ event->u.u.sequenceNumber = on;
+}
+
+/**
+ * Check if the event was marked as a repeat event before.
+ * NOTE: This is a nasty hack and should NOT be used by anyone else but
+ * TryClientEvents.
+ */
+BOOL
+EventIsKeyRepeat(xEvent *event)
+{
+ return !!event->u.u.sequenceNumber;
+}
+
+/**
+ * Convert the given event to the respective core event.
+ *
+ * Return values:
+ * Success ... core contains the matching core event.
+ * BadValue .. One or more values in the internal event are invalid.
+ * BadMatch .. The event has no core equivalent.
+ *
+ * @param[in] event The event to convert into a core event.
+ * @param[in] core The memory location to store the core event at.
+ * @return Success or the matching error code.
+ */
+int
+EventToCore(InternalEvent *event, xEvent *core)
+{
+ switch(event->any.type)
+ {
+ case ET_Motion:
+ {
+ DeviceEvent *e = &event->device_event;
+ /* Don't create core motion event if neither x nor y are
+ * present */
+ if (!BitIsOn(e->valuators.mask, 0) &&
+ !BitIsOn(e->valuators.mask, 1))
+ return BadMatch;
+ }
+ /* fallthrough */
+ case ET_ButtonPress:
+ case ET_ButtonRelease:
+ case ET_KeyPress:
+ case ET_KeyRelease:
+ {
+ DeviceEvent *e = &event->device_event;
+
+ if (e->detail.key > 0xFF)
+ return BadMatch;
+
+ memset(core, 0, sizeof(xEvent));
+ core->u.u.type = e->type - ET_KeyPress + KeyPress;
+ core->u.u.detail = e->detail.key & 0xFF;
+ core->u.keyButtonPointer.time = e->time;
+ core->u.keyButtonPointer.rootX = e->root_x;
+ core->u.keyButtonPointer.rootY = e->root_y;
+ core->u.keyButtonPointer.state = e->corestate;
+ core->u.keyButtonPointer.root = e->root;
+ EventSetKeyRepeatFlag(core, (e->type == ET_KeyPress && e->key_repeat));
+ }
+ break;
+ case ET_ProximityIn:
+ case ET_ProximityOut:
+ case ET_RawKeyPress:
+ case ET_RawKeyRelease:
+ case ET_RawButtonPress:
+ case ET_RawButtonRelease:
+ case ET_RawMotion:
+ return BadMatch;
+ default:
+ /* XXX: */
+ ErrorF("[dix] EventToCore: Not implemented yet \n");
+ return BadImplementation;
+ }
+ return Success;
+}
+
+/**
+ * Convert the given event to the respective XI 1.x event and store it in
+ * xi. xi is allocated on demand and must be freed by the caller.
+ * count returns the number of events in xi. If count is 1, and the type of
+ * xi is GenericEvent, then xi may be larger than 32 bytes.
+ *
+ * Return values:
+ * Success ... core contains the matching core event.
+ * BadValue .. One or more values in the internal event are invalid.
+ * BadMatch .. The event has no XI equivalent.
+ *
+ * @param[in] ev The event to convert into an XI 1 event.
+ * @param[out] xi Future memory location for the XI event.
+ * @param[out] count Number of elements in xi.
+ *
+ * @return Success or the error code.
+ */
+int
+EventToXI(InternalEvent *ev, xEvent **xi, int *count)
+{
+ switch (ev->any.type)
+ {
+ case ET_Motion:
+ case ET_ButtonPress:
+ case ET_ButtonRelease:
+ case ET_KeyPress:
+ case ET_KeyRelease:
+ case ET_ProximityIn:
+ case ET_ProximityOut:
+ return eventToKeyButtonPointer(&ev->device_event, xi, count);
+ case ET_DeviceChanged:
+ case ET_RawKeyPress:
+ case ET_RawKeyRelease:
+ case ET_RawButtonPress:
+ case ET_RawButtonRelease:
+ case ET_RawMotion:
+ *count = 0;
+ *xi = NULL;
+ return BadMatch;
+ default:
+ break;
+ }
+
+ ErrorF("[dix] EventToXI: Not implemented for %d \n", ev->any.type);
+ return BadImplementation;
+}
+
+/**
+ * Convert the given event to the respective XI 2.x event and store it in xi.
+ * xi is allocated on demand and must be freed by the caller.
+ *
+ * Return values:
+ * Success ... core contains the matching core event.
+ * BadValue .. One or more values in the internal event are invalid.
+ * BadMatch .. The event has no XI2 equivalent.
+ *
+ * @param[in] ev The event to convert into an XI2 event
+ * @param[out] xi Future memory location for the XI2 event.
+ *
+ * @return Success or the error code.
+ */
+int
+EventToXI2(InternalEvent *ev, xEvent **xi)
+{
+ switch (ev->any.type)
+ {
+ /* Enter/FocusIn are for grabs. We don't need an actual event, since
+ * the real events delivered are triggered elsewhere */
+ case ET_Enter:
+ case ET_FocusIn:
+ *xi = NULL;
+ return Success;
+ case ET_Motion:
+ case ET_ButtonPress:
+ case ET_ButtonRelease:
+ case ET_KeyPress:
+ case ET_KeyRelease:
+ return eventToDeviceEvent(&ev->device_event, xi);
+ case ET_ProximityIn:
+ case ET_ProximityOut:
+ *xi = NULL;
+ return BadMatch;
+ case ET_DeviceChanged:
+ return eventToDeviceChanged(&ev->changed_event, xi);
+ case ET_RawKeyPress:
+ case ET_RawKeyRelease:
+ case ET_RawButtonPress:
+ case ET_RawButtonRelease:
+ case ET_RawMotion:
+ return eventToRawEvent(&ev->raw_event, xi);
+ default:
+ break;
+ }
+
+ ErrorF("[dix] EventToXI2: Not implemented for %d \n", ev->any.type);
+ return BadImplementation;
+}
+
+static int
+eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count)
+{
+ int num_events;
+ int first; /* dummy */
+ deviceKeyButtonPointer *kbp;
+
+ /* Sorry, XI 1.x protocol restrictions. */
+ if (ev->detail.button > 0xFF || ev->deviceid >= 0x80)
+ {
+ *count = 0;
+ return Success;
+ }
+
+ num_events = (countValuators(ev, &first) + 5)/6; /* valuator ev */
+ if (num_events <= 0)
+ {
+ switch (ev->type)
+ {
+ case ET_KeyPress:
+ case ET_KeyRelease:
+ case ET_ButtonPress:
+ case ET_ButtonRelease:
+ /* no axes is ok */
+ break;
+ case ET_Motion:
+ case ET_ProximityIn:
+ case ET_ProximityOut:
+ *count = 0;
+ return BadMatch;
+ }
+ }
+
+ num_events++; /* the actual event event */
+
+ *xi = calloc(num_events, sizeof(xEvent));
+ if (!(*xi))
+ {
+ return BadAlloc;
+ }
+
+ kbp = (deviceKeyButtonPointer*)(*xi);
+ kbp->detail = ev->detail.button;
+ kbp->time = ev->time;
+ kbp->root = ev->root;
+ kbp->root_x = ev->root_x;
+ kbp->root_y = ev->root_y;
+ kbp->deviceid = ev->deviceid;
+ kbp->state = ev->corestate;
+ EventSetKeyRepeatFlag((xEvent*)kbp,
+ (ev->type == ET_KeyPress && ev->key_repeat));
+
+ if (num_events > 1)
+ kbp->deviceid |= MORE_EVENTS;
+
+ switch(ev->type)
+ {
+ case ET_Motion: kbp->type = DeviceMotionNotify; break;
+ case ET_ButtonPress: kbp->type = DeviceButtonPress; break;
+ case ET_ButtonRelease: kbp->type = DeviceButtonRelease; break;
+ case ET_KeyPress: kbp->type = DeviceKeyPress; break;
+ case ET_KeyRelease: kbp->type = DeviceKeyRelease; break;
+ case ET_ProximityIn: kbp->type = ProximityIn; break;
+ case ET_ProximityOut: kbp->type = ProximityOut; break;
+ default:
+ break;
+ }
+
+ if (num_events > 1)
+ {
+ getValuatorEvents(ev, (deviceValuator*)(kbp + 1));
+ }
+
+ *count = num_events;
+ return Success;
+}
+
+
+/**
+ * Set first to the first valuator in the event ev and return the number of
+ * valuators from first to the last set valuator.
+ */
+static int
+countValuators(DeviceEvent *ev, int *first)
+{
+ int first_valuator = -1, last_valuator = -1, num_valuators = 0;
+ int i;
+
+ for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++)
+ {
+ if (BitIsOn(ev->valuators.mask, i))
+ {
+ if (first_valuator == -1)
+ first_valuator = i;
+ last_valuator = i;
+ }
+ }
+
+ if (first_valuator != -1)
+ {
+ num_valuators = last_valuator - first_valuator + 1;
+ *first = first_valuator;
+ }
+
+ return num_valuators;
+}
+
+static int
+getValuatorEvents(DeviceEvent *ev, deviceValuator *xv)
+{
+ int i;
+ int state = 0;
+ int first_valuator, num_valuators;
+
+
+ num_valuators = countValuators(ev, &first_valuator);
+ if (num_valuators > 0)
+ {
+ DeviceIntPtr dev = NULL;
+ dixLookupDevice(&dev, ev->deviceid, serverClient, DixUseAccess);
+ /* State needs to be assembled BEFORE the device is updated. */
+ state = (dev && dev->key) ? XkbStateFieldFromRec(&dev->key->xkbInfo->state) : 0;
+ state |= (dev && dev->button) ? (dev->button->state) : 0;
+ }
+
+ for (i = 0; i < num_valuators; i += 6, xv++) {
+ INT32 *valuators = &xv->valuator0; // Treat all 6 vals as an array
+ int j;
+
+ xv->type = DeviceValuator;
+ xv->first_valuator = first_valuator + i;
+ xv->num_valuators = ((num_valuators - i) > 6) ? 6 : (num_valuators - i);
+ xv->deviceid = ev->deviceid;
+ xv->device_state = state;
+
+ /* Unset valuators in masked valuator events have the proper data values
+ * in the case of an absolute axis in between two set valuators. */
+ for (j = 0; j < xv->num_valuators; j++)
+ valuators[j] = ev->valuators.data[xv->first_valuator + j];
+
+ if (i + 6 < num_valuators)
+ xv->deviceid |= MORE_EVENTS;
+ }
+
+ return (num_valuators + 5) / 6;
+}
+
+
+static int
+appendKeyInfo(DeviceChangedEvent *dce, xXIKeyInfo* info)
+{
+ uint32_t *kc;
+ int i;
+
+ info->type = XIKeyClass;
+ info->num_keycodes = dce->keys.max_keycode - dce->keys.min_keycode + 1;
+ info->length = sizeof(xXIKeyInfo)/4 + info->num_keycodes;
+ info->sourceid = dce->sourceid;
+
+ kc = (uint32_t*)&info[1];
+ for (i = 0; i < info->num_keycodes; i++)
+ *kc++ = i + dce->keys.min_keycode;
+
+ return info->length * 4;
+}
+
+static int
+appendButtonInfo(DeviceChangedEvent *dce, xXIButtonInfo *info)
+{
+ unsigned char *bits;
+ int mask_len;
+
+ mask_len = bytes_to_int32(bits_to_bytes(dce->buttons.num_buttons));
+
+ info->type = XIButtonClass;
+ info->num_buttons = dce->buttons.num_buttons;
+ info->length = bytes_to_int32(sizeof(xXIButtonInfo)) +
+ info->num_buttons + mask_len;
+ info->sourceid = dce->sourceid;
+
+ bits = (unsigned char*)&info[1];
+ memset(bits, 0, mask_len * 4);
+ /* FIXME: is_down? */
+
+ bits += mask_len * 4;
+ memcpy(bits, dce->buttons.names, dce->buttons.num_buttons * sizeof(Atom));
+
+ return info->length * 4;
+}
+
+static int
+appendValuatorInfo(DeviceChangedEvent *dce, xXIValuatorInfo *info, int axisnumber)
+{
+ info->type = XIValuatorClass;
+ info->length = sizeof(xXIValuatorInfo)/4;
+ info->label = dce->valuators[axisnumber].name;
+ info->min.integral = dce->valuators[axisnumber].min;
+ info->min.frac = 0;
+ info->max.integral = dce->valuators[axisnumber].max;
+ info->max.frac = 0;
+ /* FIXME: value */
+ info->value.integral = 0;
+ info->value.frac = 0;
+ info->resolution = dce->valuators[axisnumber].resolution;
+ info->number = axisnumber;
+ info->mode = dce->valuators[axisnumber].mode;
+ info->sourceid = dce->sourceid;
+
+ return info->length * 4;
+}
+
+static int
+eventToDeviceChanged(DeviceChangedEvent *dce, xEvent **xi)
+{
+ xXIDeviceChangedEvent *dcce;
+ int len = sizeof(xXIDeviceChangedEvent);
+ int nkeys;
+ char *ptr;
+
+ if (dce->buttons.num_buttons)
+ {
+ len += sizeof(xXIButtonInfo);
+ len += dce->buttons.num_buttons * sizeof(Atom); /* button names */
+ len += pad_to_int32(bits_to_bytes(dce->buttons.num_buttons));
+ }
+ if (dce->num_valuators)
+ len += sizeof(xXIValuatorInfo) * dce->num_valuators;
+
+ nkeys = (dce->keys.max_keycode > 0) ?
+ dce->keys.max_keycode - dce->keys.min_keycode + 1 : 0;
+ if (nkeys > 0)
+ {
+ len += sizeof(xXIKeyInfo);
+ len += sizeof(CARD32) * nkeys; /* keycodes */
+ }
+
+ dcce = calloc(1, len);
+ if (!dcce)
+ {
+ ErrorF("[Xi] BadAlloc in SendDeviceChangedEvent.\n");
+ return BadAlloc;
+ }
+
+ dcce->type = GenericEvent;
+ dcce->extension = IReqCode;
+ dcce->evtype = XI_DeviceChanged;
+ dcce->time = dce->time;
+ dcce->deviceid = dce->deviceid;
+ dcce->sourceid = dce->sourceid;
+ dcce->reason = (dce->flags & DEVCHANGE_DEVICE_CHANGE) ? XIDeviceChange : XISlaveSwitch;
+ dcce->num_classes = 0;
+ dcce->length = bytes_to_int32(len - sizeof(xEvent));
+
+ ptr = (char*)&dcce[1];
+ if (dce->buttons.num_buttons)
+ {
+ dcce->num_classes++;
+ ptr += appendButtonInfo(dce, (xXIButtonInfo*)ptr);
+ }
+
+ if (nkeys)
+ {
+ dcce->num_classes++;
+ ptr += appendKeyInfo(dce, (xXIKeyInfo*)ptr);
+ }
+
+ if (dce->num_valuators)
+ {
+ int i;
+
+ dcce->num_classes += dce->num_valuators;
+ for (i = 0; i < dce->num_valuators; i++)
+ ptr += appendValuatorInfo(dce, (xXIValuatorInfo*)ptr, i);
+ }
+
+ *xi = (xEvent*)dcce;
+
+ return Success;
+}
+
+static int count_bits(unsigned char* ptr, int len)
+{
+ int bits = 0;
+ unsigned int i;
+ unsigned char x;
+
+ for (i = 0; i < len; i++)
+ {
+ x = ptr[i];
+ while(x > 0)
+ {
+ bits += (x & 0x1);
+ x >>= 1;
+ }
+ }
+ return bits;
+}
+
+static int
+eventToDeviceEvent(DeviceEvent *ev, xEvent **xi)
+{
+ int len = sizeof(xXIDeviceEvent);
+ xXIDeviceEvent *xde;
+ int i, btlen, vallen;
+ char *ptr;
+ FP3232 *axisval;
+
+ /* FIXME: this should just send the buttons we have, not MAX_BUTTONs. Same
+ * with MAX_VALUATORS below */
+ /* btlen is in 4 byte units */
+ btlen = bytes_to_int32(bits_to_bytes(MAX_BUTTONS));
+ len += btlen * 4; /* buttonmask len */
+
+
+ vallen = count_bits(ev->valuators.mask, sizeof(ev->valuators.mask)/sizeof(ev->valuators.mask[0]));
+ len += vallen * 2 * sizeof(uint32_t); /* axisvalues */
+ vallen = bytes_to_int32(bits_to_bytes(MAX_VALUATORS));
+ len += vallen * 4; /* valuators mask */
+
+ *xi = calloc(1, len);
+ xde = (xXIDeviceEvent*)*xi;
+ xde->type = GenericEvent;
+ xde->extension = IReqCode;
+ xde->evtype = GetXI2Type((InternalEvent*)ev);
+ xde->time = ev->time;
+ xde->length = bytes_to_int32(len - sizeof(xEvent));
+ xde->detail = ev->detail.button;
+ xde->root = ev->root;
+ xde->buttons_len = btlen;
+ xde->valuators_len = vallen;
+ xde->deviceid = ev->deviceid;
+ xde->sourceid = ev->sourceid;
+ xde->root_x = FP1616(ev->root_x, ev->root_x_frac);
+ xde->root_y = FP1616(ev->root_y, ev->root_y_frac);
+
+ if (ev->key_repeat)
+ xde->flags |= XIKeyRepeat;
+
+ xde->mods.base_mods = ev->mods.base;
+ xde->mods.latched_mods = ev->mods.latched;
+ xde->mods.locked_mods = ev->mods.locked;
+ xde->mods.effective_mods = ev->mods.effective;
+
+ xde->group.base_group = ev->group.base;
+ xde->group.latched_group = ev->group.latched;
+ xde->group.locked_group = ev->group.locked;
+ xde->group.effective_group = ev->group.effective;
+
+ ptr = (char*)&xde[1];
+ for (i = 0; i < sizeof(ev->buttons) * 8; i++)
+ {
+ if (BitIsOn(ev->buttons, i))
+ SetBit(ptr, i);
+ }
+
+ ptr += xde->buttons_len * 4;
+ axisval = (FP3232*)(ptr + xde->valuators_len * 4);
+ for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++)
+ {
+ if (BitIsOn(ev->valuators.mask, i))
+ {
+ SetBit(ptr, i);
+ axisval->integral = ev->valuators.data[i];
+ axisval->frac = ev->valuators.data_frac[i];
+ axisval++;
+ }
+ }
+
+ return Success;
+}
+
+static int
+eventToRawEvent(RawDeviceEvent *ev, xEvent **xi)
+{
+ xXIRawEvent* raw;
+ int vallen, nvals;
+ int i, len = sizeof(xXIRawEvent);
+ char *ptr;
+ FP3232 *axisval;
+
+ nvals = count_bits(ev->valuators.mask, sizeof(ev->valuators.mask));
+ len += nvals * sizeof(FP3232) * 2; /* 8 byte per valuator, once
+ raw, once processed */
+ vallen = bytes_to_int32(bits_to_bytes(MAX_VALUATORS));
+ len += vallen * 4; /* valuators mask */
+
+ *xi = calloc(1, len);
+ raw = (xXIRawEvent*)*xi;
+ raw->type = GenericEvent;
+ raw->extension = IReqCode;
+ raw->evtype = GetXI2Type((InternalEvent*)ev);
+ raw->time = ev->time;
+ raw->length = bytes_to_int32(len - sizeof(xEvent));
+ raw->detail = ev->detail.button;
+ raw->deviceid = ev->deviceid;
+ raw->valuators_len = vallen;
+
+ ptr = (char*)&raw[1];
+ axisval = (FP3232*)(ptr + raw->valuators_len * 4);
+ for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++)
+ {
+ if (BitIsOn(ev->valuators.mask, i))
+ {
+ SetBit(ptr, i);
+ axisval->integral = ev->valuators.data[i];
+ axisval->frac = ev->valuators.data_frac[i];
+ (axisval + nvals)->integral = ev->valuators.data_raw[i];
+ (axisval + nvals)->frac = ev->valuators.data_raw_frac[i];
+ axisval++;
+ }
+ }
+
+ return Success;
+}
+
+/**
+ * Return the corresponding core type for the given event or 0 if no core
+ * equivalent exists.
+ */
+int
+GetCoreType(InternalEvent *event)
+{
+ int coretype = 0;
+ switch(event->any.type)
+ {
+ case ET_Motion: coretype = MotionNotify; break;
+ case ET_ButtonPress: coretype = ButtonPress; break;
+ case ET_ButtonRelease: coretype = ButtonRelease; break;
+ case ET_KeyPress: coretype = KeyPress; break;
+ case ET_KeyRelease: coretype = KeyRelease; break;
+ default:
+ break;
+ }
+ return coretype;
+}
+
+/**
+ * Return the corresponding XI 1.x type for the given event or 0 if no
+ * equivalent exists.
+ */
+int
+GetXIType(InternalEvent *event)
+{
+ int xitype = 0;
+ switch(event->any.type)
+ {
+ case ET_Motion: xitype = DeviceMotionNotify; break;
+ case ET_ButtonPress: xitype = DeviceButtonPress; break;
+ case ET_ButtonRelease: xitype = DeviceButtonRelease; break;
+ case ET_KeyPress: xitype = DeviceKeyPress; break;
+ case ET_KeyRelease: xitype = DeviceKeyRelease; break;
+ case ET_ProximityIn: xitype = ProximityIn; break;
+ case ET_ProximityOut: xitype = ProximityOut; break;
+ default:
+ break;
+ }
+ return xitype;
+}
+
+/**
+ * Return the corresponding XI 2.x type for the given event or 0 if no
+ * equivalent exists.
+ */
+int
+GetXI2Type(InternalEvent *event)
+{
+ int xi2type = 0;
+
+ switch(event->any.type)
+ {
+ case ET_Motion: xi2type = XI_Motion; break;
+ case ET_ButtonPress: xi2type = XI_ButtonPress; break;
+ case ET_ButtonRelease: xi2type = XI_ButtonRelease; break;
+ case ET_KeyPress: xi2type = XI_KeyPress; break;
+ case ET_KeyRelease: xi2type = XI_KeyRelease; break;
+ case ET_Enter: xi2type = XI_Enter; break;
+ case ET_Leave: xi2type = XI_Leave; break;
+ case ET_Hierarchy: xi2type = XI_HierarchyChanged; break;
+ case ET_DeviceChanged: xi2type = XI_DeviceChanged; break;
+ case ET_RawKeyPress: xi2type = XI_RawKeyPress; break;
+ case ET_RawKeyRelease: xi2type = XI_RawKeyRelease; break;
+ case ET_RawButtonPress: xi2type = XI_RawButtonPress; break;
+ case ET_RawButtonRelease: xi2type = XI_RawButtonRelease; break;
+ case ET_RawMotion: xi2type = XI_RawMotion; break;
+ case ET_FocusIn: xi2type = XI_FocusIn; break;
+ case ET_FocusOut: xi2type = XI_FocusOut; break;
+ default:
+ break;
+ }
+ return xi2type;
+}
diff --git a/dix/events.c b/dix/events.c
new file mode 100644
index 0000000..f0ea576
--- /dev/null
+++ b/dix/events.c
@@ -0,0 +1,5812 @@
+/************************************************************
+
+Copyright 1987, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+********************************************************/
+
+/* The panoramix components contained the following notice */
+/*****************************************************************
+
+Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
+BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of Digital Equipment Corporation
+shall not be used in advertising or otherwise to promote the sale, use or other
+dealings in this Software without prior written authorization from Digital
+Equipment Corporation.
+
+******************************************************************/
+
+/*
+ * Copyright (c) 2003-2005, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/** @file events.c
+ * This file handles event delivery and a big part of the server-side protocol
+ * handling (the parts for input devices).
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include "misc.h"
+#include "resource.h"
+#include <X11/Xproto.h>
+#include "windowstr.h"
+#include "inputstr.h"
+#include "scrnintstr.h"
+#include "cursorstr.h"
+
+#include "dixstruct.h"
+#ifdef PANORAMIX
+#include "panoramiX.h"
+#include "panoramiXsrv.h"
+#endif
+#include "globals.h"
+
+#include <X11/extensions/XKBproto.h>
+#include "xkbsrv.h"
+#include "xace.h"
+
+#ifdef XSERVER_DTRACE
+#include <sys/types.h>
+typedef const char *string;
+#include "Xserver-dtrace.h"
+#endif
+
+#include <X11/extensions/XIproto.h>
+#include <X11/extensions/XI2proto.h>
+#include <X11/extensions/XI.h>
+#include <X11/extensions/XI2.h>
+#include "exglobals.h"
+#include "exevents.h"
+#include "exglobals.h"
+#include "extnsionst.h"
+
+#include "dixevents.h"
+#include "dixgrabs.h"
+#include "dispatch.h"
+
+#include <X11/extensions/ge.h>
+#include "geext.h"
+#include "geint.h"
+
+#include "eventstr.h"
+#include "enterleave.h"
+#include "eventconvert.h"
+
+/* Extension events type numbering starts at EXTENSION_EVENT_BASE. */
+#define NoSuchEvent 0x80000000 /* so doesn't match NoEventMask */
+#define StructureAndSubMask ( StructureNotifyMask | SubstructureNotifyMask )
+#define AllButtonsMask ( \
+ Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask )
+#define MotionMask ( \
+ PointerMotionMask | Button1MotionMask | \
+ Button2MotionMask | Button3MotionMask | Button4MotionMask | \
+ Button5MotionMask | ButtonMotionMask )
+#define PropagateMask ( \
+ KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | \
+ MotionMask )
+#define PointerGrabMask ( \
+ ButtonPressMask | ButtonReleaseMask | \
+ EnterWindowMask | LeaveWindowMask | \
+ PointerMotionHintMask | KeymapStateMask | \
+ MotionMask )
+#define AllModifiersMask ( \
+ ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \
+ Mod3Mask | Mod4Mask | Mod5Mask )
+#define LastEventMask OwnerGrabButtonMask
+#define AllEventMasks (LastEventMask|(LastEventMask-1))
+
+
+#define CORE_EVENT(event) \
+ (!((event)->u.u.type & EXTENSION_EVENT_BASE) && \
+ (event)->u.u.type != GenericEvent)
+#define XI2_EVENT(event) \
+ (((event)->u.u.type == GenericEvent) && \
+ ((xGenericEvent*)(event))->extension == IReqCode)
+
+/**
+ * Used to indicate a implicit passive grab created by a ButtonPress event.
+ * See DeliverEventsToWindow().
+ */
+#define ImplicitGrabMask (1 << 7)
+
+#define WID(w) ((w) ? ((w)->drawable.id) : 0)
+
+#define XE_KBPTR (xE->u.keyButtonPointer)
+
+
+CallbackListPtr EventCallback;
+CallbackListPtr DeviceEventCallback;
+
+#define DNPMCOUNT 8
+
+Mask DontPropagateMasks[DNPMCOUNT];
+static int DontPropagateRefCnts[DNPMCOUNT];
+
+static void CheckVirtualMotion( DeviceIntPtr pDev, QdEventPtr qe, WindowPtr pWin);
+static void CheckPhysLimits(DeviceIntPtr pDev,
+ CursorPtr cursor,
+ Bool generateEvents,
+ Bool confineToScreen,
+ ScreenPtr pScreen);
+
+/** Key repeat hack. Do not use but in TryClientEvents */
+extern BOOL EventIsKeyRepeat(xEvent *event);
+
+/**
+ * Main input device struct.
+ * inputInfo.pointer
+ * is the core pointer. Referred to as "virtual core pointer", "VCP",
+ * "core pointer" or inputInfo.pointer. The VCP is the first master
+ * pointer device and cannot be deleted.
+ *
+ * inputInfo.keyboard
+ * is the core keyboard ("virtual core keyboard", "VCK", "core keyboard").
+ * See inputInfo.pointer.
+ *
+ * inputInfo.devices
+ * linked list containing all devices including VCP and VCK.
+ *
+ * inputInfo.off_devices
+ * Devices that have not been initialized and are thus turned off.
+ *
+ * inputInfo.numDevices
+ * Total number of devices.
+ *
+ * inputInfo.all_devices
+ * Virtual device used for XIAllDevices passive grabs. This device is
+ * not part of the inputInfo.devices list and mostly unset except for
+ * the deviceid. It exists because passivegrabs need a valid device
+ * reference.
+ *
+ * inputInfo.all_master_devices
+ * Virtual device used for XIAllMasterDevices passive grabs. This device
+ * is not part of the inputInfo.devices list and mostly unset except for
+ * the deviceid. It exists because passivegrabs need a valid device
+ * reference.
+ */
+InputInfo inputInfo;
+
+EventSyncInfoRec syncEvents;
+
+/**
+ * The root window the given device is currently on.
+ */
+#define RootWindow(sprite) sprite->spriteTrace[0]
+
+static xEvent* swapEvent = NULL;
+static int swapEventLen = 0;
+
+void
+NotImplemented(xEvent *from, xEvent *to)
+{
+ FatalError("Not implemented");
+}
+
+/**
+ * Convert the given event type from an XI event to a core event.
+ * @param[in] The XI 1.x event type.
+ * @return The matching core event type or 0 if there is none.
+ */
+int
+XItoCoreType(int xitype)
+{
+ int coretype = 0;
+ if (xitype == DeviceMotionNotify)
+ coretype = MotionNotify;
+ else if (xitype == DeviceButtonPress)
+ coretype = ButtonPress;
+ else if (xitype == DeviceButtonRelease)
+ coretype = ButtonRelease;
+ else if (xitype == DeviceKeyPress)
+ coretype = KeyPress;
+ else if (xitype == DeviceKeyRelease)
+ coretype = KeyRelease;
+
+ return coretype;
+}
+
+/**
+ * @return true if the device owns a cursor, false if device shares a cursor
+ * sprite with another device.
+ */
+Bool
+DevHasCursor(DeviceIntPtr pDev)
+{
+ return pDev->spriteInfo->spriteOwner;
+}
+
+/*
+ * @return true if a device is a pointer, check is the same as used by XI to
+ * fill the 'use' field.
+ */
+Bool
+IsPointerDevice(DeviceIntPtr dev)
+{
+ return (dev->type == MASTER_POINTER) ||
+ (dev->valuator && dev->button) ||
+ (dev->valuator && !dev->key);
+}
+
+/*
+ * @return true if a device is a keyboard, check is the same as used by XI to
+ * fill the 'use' field.
+ *
+ * Some pointer devices have keys as well (e.g. multimedia keys). Try to not
+ * count them as keyboard devices.
+ */
+Bool
+IsKeyboardDevice(DeviceIntPtr dev)
+{
+ return (dev->type == MASTER_KEYBOARD) ||
+ ((dev->key && dev->kbdfeed) && !IsPointerDevice(dev));
+}
+
+Bool
+IsMaster(DeviceIntPtr dev)
+{
+ return dev->type == MASTER_POINTER || dev->type == MASTER_KEYBOARD;
+}
+
+/**
+ * Max event opcode.
+ */
+extern int lastEvent;
+
+extern int DeviceMotionNotify;
+
+#define CantBeFiltered NoEventMask
+/**
+ * Event masks for each event type.
+ *
+ * One set of filters for each device, but only the first layer
+ * is initialized. The rest is memcpy'd in InitEvents.
+ *
+ * Filters are used whether a given event may be delivered to a client,
+ * usually in the form of if (window-event-mask & filter); then deliver event.
+ *
+ * One notable filter is for PointerMotion/DevicePointerMotion events. Each
+ * time a button is pressed, the filter is modified to also contain the
+ * matching ButtonXMotion mask.
+ */
+static Mask filters[MAXDEVICES][128] = {
+{
+ NoSuchEvent, /* 0 */
+ NoSuchEvent, /* 1 */
+ KeyPressMask, /* KeyPress */
+ KeyReleaseMask, /* KeyRelease */
+ ButtonPressMask, /* ButtonPress */
+ ButtonReleaseMask, /* ButtonRelease */
+ PointerMotionMask, /* MotionNotify (initial state) */
+ EnterWindowMask, /* EnterNotify */
+ LeaveWindowMask, /* LeaveNotify */
+ FocusChangeMask, /* FocusIn */
+ FocusChangeMask, /* FocusOut */
+ KeymapStateMask, /* KeymapNotify */
+ ExposureMask, /* Expose */
+ CantBeFiltered, /* GraphicsExpose */
+ CantBeFiltered, /* NoExpose */
+ VisibilityChangeMask, /* VisibilityNotify */
+ SubstructureNotifyMask, /* CreateNotify */
+ StructureAndSubMask, /* DestroyNotify */
+ StructureAndSubMask, /* UnmapNotify */
+ StructureAndSubMask, /* MapNotify */
+ SubstructureRedirectMask, /* MapRequest */
+ StructureAndSubMask, /* ReparentNotify */
+ StructureAndSubMask, /* ConfigureNotify */
+ SubstructureRedirectMask, /* ConfigureRequest */
+ StructureAndSubMask, /* GravityNotify */
+ ResizeRedirectMask, /* ResizeRequest */
+ StructureAndSubMask, /* CirculateNotify */
+ SubstructureRedirectMask, /* CirculateRequest */
+ PropertyChangeMask, /* PropertyNotify */
+ CantBeFiltered, /* SelectionClear */
+ CantBeFiltered, /* SelectionRequest */
+ CantBeFiltered, /* SelectionNotify */
+ ColormapChangeMask, /* ColormapNotify */
+ CantBeFiltered, /* ClientMessage */
+ CantBeFiltered /* MappingNotify */
+}};
+
+/**
+ * For the given event, return the matching event filter. This filter may then
+ * be AND'ed with the selected event mask.
+ *
+ * For XI2 events, the returned filter is simply the byte containing the event
+ * mask we're interested in. E.g. for a mask of (1 << 13), this would be
+ * byte[1].
+ *
+ * @param[in] dev The device the event belongs to, may be NULL.
+ * @param[in] event The event to get the filter for. Only the type of the
+ * event matters, or the extension + evtype for GenericEvents.
+ * @return The filter mask for the given event.
+ *
+ * @see GetEventMask
+ */
+Mask
+GetEventFilter(DeviceIntPtr dev, xEvent *event)
+{
+ if (event->u.u.type != GenericEvent)
+ return filters[dev ? dev->id : 0][event->u.u.type];
+ else if (XI2_EVENT(event))
+ return (1 << (((xXIDeviceEvent*)event)->evtype % 8));
+ ErrorF("[dix] Unknown device type %d. No filter\n", event->u.u.type);
+ return 0;
+}
+
+/**
+ * Return the windows complete XI2 mask for the given XI2 event type.
+ */
+Mask
+GetWindowXI2Mask(DeviceIntPtr dev, WindowPtr win, xEvent* ev)
+{
+ OtherInputMasks *inputMasks = wOtherInputMasks(win);
+ int filter;
+ int evtype;
+
+ if (!inputMasks || !XI2_EVENT(ev))
+ return 0;
+
+ evtype = ((xGenericEvent*)ev)->evtype;
+ filter = GetEventFilter(dev, ev);
+
+ return ((inputMasks->xi2mask[dev->id][evtype/8] & filter) ||
+ inputMasks->xi2mask[XIAllDevices][evtype/8] ||
+ (inputMasks->xi2mask[XIAllMasterDevices][evtype/8] && IsMaster(dev)));
+}
+
+Mask
+GetEventMask(DeviceIntPtr dev, xEvent *event, InputClients* other)
+{
+ /* XI2 filters are only ever 8 bit, so let's return a 8 bit mask */
+ if (XI2_EVENT(event))
+ {
+ int byte = ((xGenericEvent*)event)->evtype / 8;
+ return (other->xi2mask[dev->id][byte] |
+ other->xi2mask[XIAllDevices][byte] |
+ (IsMaster(dev)? other->xi2mask[XIAllMasterDevices][byte] : 0));
+ } else if (CORE_EVENT(event))
+ return other->mask[XIAllDevices];
+ else
+ return other->mask[dev->id];
+}
+
+
+static CARD8 criticalEvents[32] =
+{
+ 0x7c, 0x30, 0x40 /* key, button, expose, and configure events */
+};
+
+static void
+SyntheticMotion(DeviceIntPtr dev, int x, int y) {
+ int screenno = 0;
+
+#ifdef PANORAMIX
+ if (!noPanoramiXExtension)
+ screenno = dev->spriteInfo->sprite->screen->myNum;
+#endif
+ PostSyntheticMotion(dev, x, y, screenno,
+ (syncEvents.playingEvents) ? syncEvents.time.milliseconds : currentTime.milliseconds);
+
+}
+
+#ifdef PANORAMIX
+static void PostNewCursor(DeviceIntPtr pDev);
+
+static Bool
+pointOnScreen(ScreenPtr pScreen, int x, int y)
+{
+ return x >= pScreen->x && x < pScreen->x + pScreen->width &&
+ y >= pScreen->y && y < pScreen->y + pScreen->height;
+}
+
+static Bool
+XineramaSetCursorPosition(
+ DeviceIntPtr pDev,
+ int x,
+ int y,
+ Bool generateEvent
+){
+ ScreenPtr pScreen;
+ int i;
+ SpritePtr pSprite = pDev->spriteInfo->sprite;
+
+ /* x,y are in Screen 0 coordinates. We need to decide what Screen
+ to send the message too and what the coordinates relative to
+ that screen are. */
+
+ pScreen = pSprite->screen;
+ x += screenInfo.screens[0]->x;
+ y += screenInfo.screens[0]->y;
+
+ if(!pointOnScreen(pScreen, x, y))
+ {
+ FOR_NSCREENS(i)
+ {
+ if(i == pScreen->myNum)
+ continue;
+ if(pointOnScreen(screenInfo.screens[i], x, y))
+ {
+ pScreen = screenInfo.screens[i];
+ break;
+ }
+ }
+ }
+
+ pSprite->screen = pScreen;
+ pSprite->hotPhys.x = x - screenInfo.screens[0]->x;
+ pSprite->hotPhys.y = y - screenInfo.screens[0]->y;
+ x -= pScreen->x;
+ y -= pScreen->y;
+
+ return (*pScreen->SetCursorPosition)(pDev, pScreen, x, y, generateEvent);
+}
+
+
+static void
+XineramaConstrainCursor(DeviceIntPtr pDev)
+{
+ SpritePtr pSprite = pDev->spriteInfo->sprite;
+ ScreenPtr pScreen;
+ BoxRec newBox;
+
+ pScreen = pSprite->screen;
+ newBox = pSprite->physLimits;
+
+ /* Translate the constraining box to the screen
+ the sprite is actually on */
+ newBox.x1 += screenInfo.screens[0]->x - pScreen->x;
+ newBox.x2 += screenInfo.screens[0]->x - pScreen->x;
+ newBox.y1 += screenInfo.screens[0]->y - pScreen->y;
+ newBox.y2 += screenInfo.screens[0]->y - pScreen->y;
+
+ (* pScreen->ConstrainCursor)(pDev, pScreen, &newBox);
+}
+
+
+static Bool
+XineramaSetWindowPntrs(DeviceIntPtr pDev, WindowPtr pWin)
+{
+ SpritePtr pSprite = pDev->spriteInfo->sprite;
+
+ if(pWin == screenInfo.screens[0]->root) {
+ int i;
+ for (i = 0; i < PanoramiXNumScreens; i++)
+ pSprite->windows[i] = screenInfo.screens[i]->root;
+ } else {
+ PanoramiXRes *win;
+ int rc, i;
+
+ rc = dixLookupResourceByType((pointer *)&win, pWin->drawable.id,
+ XRT_WINDOW, serverClient, DixReadAccess);
+ if (rc != Success)
+ return FALSE;
+
+ for(i = 0; i < PanoramiXNumScreens; i++) {
+ rc = dixLookupWindow(pSprite->windows + i, win->info[i].id,
+ serverClient, DixReadAccess);
+ if (rc != Success) /* window is being unmapped */
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static void
+XineramaConfineCursorToWindow(DeviceIntPtr pDev,
+ WindowPtr pWin,
+ Bool generateEvents)
+{
+ SpritePtr pSprite = pDev->spriteInfo->sprite;
+
+ int x, y, off_x, off_y, i;
+
+ if(!XineramaSetWindowPntrs(pDev, pWin))
+ return;
+
+ i = PanoramiXNumScreens - 1;
+
+ RegionCopy(&pSprite->Reg1,
+ &pSprite->windows[i]->borderSize);
+ off_x = screenInfo.screens[i]->x;
+ off_y = screenInfo.screens[i]->y;
+
+ while(i--) {
+ x = off_x - screenInfo.screens[i]->x;
+ y = off_y - screenInfo.screens[i]->y;
+
+ if(x || y)
+ RegionTranslate(&pSprite->Reg1, x, y);
+
+ RegionUnion(&pSprite->Reg1, &pSprite->Reg1,
+ &pSprite->windows[i]->borderSize);
+
+ off_x = screenInfo.screens[i]->x;
+ off_y = screenInfo.screens[i]->y;
+ }
+
+ pSprite->hotLimits = *RegionExtents(&pSprite->Reg1);
+
+ if(RegionNumRects(&pSprite->Reg1) > 1)
+ pSprite->hotShape = &pSprite->Reg1;
+ else
+ pSprite->hotShape = NullRegion;
+
+ pSprite->confined = FALSE;
+ pSprite->confineWin = (pWin == screenInfo.screens[0]->root) ? NullWindow : pWin;
+
+ CheckPhysLimits(pDev, pSprite->current, generateEvents, FALSE, NULL);
+}
+
+#endif /* PANORAMIX */
+
+/**
+ * Modifies the filter for the given protocol event type to the given masks.
+ *
+ * There's only two callers: UpdateDeviceState() and XI's SetMaskForExtEvent().
+ * The latter initialises masks for the matching XI events, it's a once-off
+ * setting.
+ * UDS however changes the mask for MotionNotify and DeviceMotionNotify each
+ * time a button is pressed to include the matching ButtonXMotion mask in the
+ * filter.
+ *
+ * @param[in] deviceid The device to modify the filter for.
+ * @param[in] mask The new filter mask.
+ * @param[in] event Protocol event type.
+ */
+void
+SetMaskForEvent(int deviceid, Mask mask, int event)
+{
+ if (deviceid < 0 || deviceid >= MAXDEVICES)
+ FatalError("SetMaskForEvent: bogus device id");
+ filters[deviceid][event] = mask;
+}
+
+void
+SetCriticalEvent(int event)
+{
+ if (event >= 128)
+ FatalError("SetCriticalEvent: bogus event number");
+ criticalEvents[event >> 3] |= 1 << (event & 7);
+}
+
+void
+ConfineToShape(DeviceIntPtr pDev, RegionPtr shape, int *px, int *py)
+{
+ BoxRec box;
+ int x = *px, y = *py;
+ int incx = 1, incy = 1;
+ SpritePtr pSprite;
+
+ pSprite = pDev->spriteInfo->sprite;
+ if (RegionContainsPoint(shape, x, y, &box))
+ return;
+ box = *RegionExtents(shape);
+ /* this is rather crude */
+ do {
+ x += incx;
+ if (x >= box.x2)
+ {
+ incx = -1;
+ x = *px - 1;
+ }
+ else if (x < box.x1)
+ {
+ incx = 1;
+ x = *px;
+ y += incy;
+ if (y >= box.y2)
+ {
+ incy = -1;
+ y = *py - 1;
+ }
+ else if (y < box.y1)
+ return; /* should never get here! */
+ }
+ } while (!RegionContainsPoint(shape, x, y, &box));
+ *px = x;
+ *py = y;
+}
+
+static void
+CheckPhysLimits(
+ DeviceIntPtr pDev,
+ CursorPtr cursor,
+ Bool generateEvents,
+ Bool confineToScreen, /* unused if PanoramiX on */
+ ScreenPtr pScreen) /* unused if PanoramiX on */
+{
+ HotSpot new;
+ SpritePtr pSprite = pDev->spriteInfo->sprite;
+
+ if (!cursor)
+ return;
+ new = pSprite->hotPhys;
+#ifdef PANORAMIX
+ if (!noPanoramiXExtension)
+ /* I don't care what the DDX has to say about it */
+ pSprite->physLimits = pSprite->hotLimits;
+ else
+#endif
+ {
+ if (pScreen)
+ new.pScreen = pScreen;
+ else
+ pScreen = new.pScreen;
+ (*pScreen->CursorLimits) (pDev, pScreen, cursor, &pSprite->hotLimits,
+ &pSprite->physLimits);
+ pSprite->confined = confineToScreen;
+ (* pScreen->ConstrainCursor)(pDev, pScreen, &pSprite->physLimits);
+ }
+
+ /* constrain the pointer to those limits */
+ if (new.x < pSprite->physLimits.x1)
+ new.x = pSprite->physLimits.x1;
+ else
+ if (new.x >= pSprite->physLimits.x2)
+ new.x = pSprite->physLimits.x2 - 1;
+ if (new.y < pSprite->physLimits.y1)
+ new.y = pSprite->physLimits.y1;
+ else
+ if (new.y >= pSprite->physLimits.y2)
+ new.y = pSprite->physLimits.y2 - 1;
+ if (pSprite->hotShape)
+ ConfineToShape(pDev, pSprite->hotShape, &new.x, &new.y);
+ if ((
+#ifdef PANORAMIX
+ noPanoramiXExtension &&
+#endif
+ (pScreen != pSprite->hotPhys.pScreen)) ||
+ (new.x != pSprite->hotPhys.x) || (new.y != pSprite->hotPhys.y))
+ {
+#ifdef PANORAMIX
+ if (!noPanoramiXExtension)
+ XineramaSetCursorPosition (pDev, new.x, new.y, generateEvents);
+ else
+#endif
+ {
+ if (pScreen != pSprite->hotPhys.pScreen)
+ pSprite->hotPhys = new;
+ (*pScreen->SetCursorPosition)
+ (pDev, pScreen, new.x, new.y, generateEvents);
+ }
+ if (!generateEvents)
+ SyntheticMotion(pDev, new.x, new.y);
+ }
+
+#ifdef PANORAMIX
+ /* Tell DDX what the limits are */
+ if (!noPanoramiXExtension)
+ XineramaConstrainCursor(pDev);
+#endif
+}
+
+static void
+CheckVirtualMotion(
+ DeviceIntPtr pDev,
+ QdEventPtr qe,
+ WindowPtr pWin)
+{
+ SpritePtr pSprite = pDev->spriteInfo->sprite;
+ RegionPtr reg = NULL;
+ DeviceEvent *ev = NULL;
+
+ if (qe)
+ {
+ ev = &qe->event->device_event;
+ switch(ev->type)
+ {
+ case ET_Motion:
+ case ET_ButtonPress:
+ case ET_ButtonRelease:
+ case ET_KeyPress:
+ case ET_KeyRelease:
+ case ET_ProximityIn:
+ case ET_ProximityOut:
+ pSprite->hot.pScreen = qe->pScreen;
+ pSprite->hot.x = ev->root_x;
+ pSprite->hot.y = ev->root_y;
+ pWin = pDev->deviceGrab.grab ? pDev->deviceGrab.grab->confineTo : NullWindow;
+ break;
+ default:
+ break;
+ }
+ }
+ if (pWin)
+ {
+ BoxRec lims;
+
+#ifdef PANORAMIX
+ if (!noPanoramiXExtension) {
+ int x, y, off_x, off_y, i;
+
+ if(!XineramaSetWindowPntrs(pDev, pWin))
+ return;
+
+ i = PanoramiXNumScreens - 1;
+
+ RegionCopy(&pSprite->Reg2,
+ &pSprite->windows[i]->borderSize);
+ off_x = screenInfo.screens[i]->x;
+ off_y = screenInfo.screens[i]->y;
+
+ while(i--) {
+ x = off_x - screenInfo.screens[i]->x;
+ y = off_y - screenInfo.screens[i]->y;
+
+ if(x || y)
+ RegionTranslate(&pSprite->Reg2, x, y);
+
+ RegionUnion(&pSprite->Reg2, &pSprite->Reg2,
+ &pSprite->windows[i]->borderSize);
+
+ off_x = screenInfo.screens[i]->x;
+ off_y = screenInfo.screens[i]->y;
+ }
+ } else
+#endif
+ {
+ if (pSprite->hot.pScreen != pWin->drawable.pScreen)
+ {
+ pSprite->hot.pScreen = pWin->drawable.pScreen;
+ pSprite->hot.x = pSprite->hot.y = 0;
+ }
+ }
+
+ lims = *RegionExtents(&pWin->borderSize);
+ if (pSprite->hot.x < lims.x1)
+ pSprite->hot.x = lims.x1;
+ else if (pSprite->hot.x >= lims.x2)
+ pSprite->hot.x = lims.x2 - 1;
+ if (pSprite->hot.y < lims.y1)
+ pSprite->hot.y = lims.y1;
+ else if (pSprite->hot.y >= lims.y2)
+ pSprite->hot.y = lims.y2 - 1;
+
+#ifdef PANORAMIX
+ if (!noPanoramiXExtension)
+ {
+ if (RegionNumRects(&pSprite->Reg2) > 1)
+ reg = &pSprite->Reg2;
+
+ } else
+#endif
+ {
+ if (wBoundingShape(pWin))
+ reg = &pWin->borderSize;
+ }
+
+ if (reg)
+ ConfineToShape(pDev, reg, &pSprite->hot.x, &pSprite->hot.y);
+
+ if (qe && ev)
+ {
+ qe->pScreen = pSprite->hot.pScreen;
+ ev->root_x = pSprite->hot.x;
+ ev->root_y = pSprite->hot.y;
+ }
+ }
+#ifdef PANORAMIX
+ if (noPanoramiXExtension) /* No typo. Only set the root win if disabled */
+#endif
+ RootWindow(pDev->spriteInfo->sprite) = pSprite->hot.pScreen->root;
+}
+
+static void
+ConfineCursorToWindow(DeviceIntPtr pDev, WindowPtr pWin, Bool generateEvents, Bool confineToScreen)
+{
+ SpritePtr pSprite = pDev->spriteInfo->sprite;
+
+ if (syncEvents.playingEvents)
+ {
+ CheckVirtualMotion(pDev, (QdEventPtr)NULL, pWin);
+ SyntheticMotion(pDev, pSprite->hot.x, pSprite->hot.y);
+ }
+ else
+ {
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension) {
+ XineramaConfineCursorToWindow(pDev, pWin, generateEvents);
+ return;
+ }
+#endif
+ pSprite->hotLimits = *RegionExtents(&pWin->borderSize);
+ pSprite->hotShape = wBoundingShape(pWin) ? &pWin->borderSize
+ : NullRegion;
+ CheckPhysLimits(pDev, pSprite->current, generateEvents,
+ confineToScreen, pWin->drawable.pScreen);
+ }
+}
+
+Bool
+PointerConfinedToScreen(DeviceIntPtr pDev)
+{
+ return pDev->spriteInfo->sprite->confined;
+}
+
+/**
+ * Update the sprite cursor to the given cursor.
+ *
+ * ChangeToCursor() will display the new cursor and free the old cursor (if
+ * applicable). If the provided cursor is already the updated cursor, nothing
+ * happens.
+ */
+static void
+ChangeToCursor(DeviceIntPtr pDev, CursorPtr cursor)
+{
+ SpritePtr pSprite = pDev->spriteInfo->sprite;
+ ScreenPtr pScreen;
+
+ if (cursor != pSprite->current)
+ {
+ if ((pSprite->current->bits->xhot != cursor->bits->xhot) ||
+ (pSprite->current->bits->yhot != cursor->bits->yhot))
+ CheckPhysLimits(pDev, cursor, FALSE, pSprite->confined,
+ (ScreenPtr)NULL);
+#ifdef PANORAMIX
+ /* XXX: is this really necessary?? (whot) */
+ if (!noPanoramiXExtension)
+ pScreen = pSprite->screen;
+ else
+#endif
+ pScreen = pSprite->hotPhys.pScreen;
+
+ (*pScreen->DisplayCursor)(pDev, pScreen, cursor);
+ FreeCursor(pSprite->current, (Cursor)0);
+ pSprite->current = cursor;
+ pSprite->current->refcnt++;
+ }
+}
+
+/**
+ * @returns true if b is a descendent of a
+ */
+Bool
+IsParent(WindowPtr a, WindowPtr b)
+{
+ for (b = b->parent; b; b = b->parent)
+ if (b == a) return TRUE;
+ return FALSE;
+}
+
+/**
+ * Update the cursor displayed on the screen.
+ *
+ * Called whenever a cursor may have changed shape or position.
+ */
+static void
+PostNewCursor(DeviceIntPtr pDev)
+{
+ WindowPtr win;
+ GrabPtr grab = pDev->deviceGrab.grab;
+ SpritePtr pSprite = pDev->spriteInfo->sprite;
+ CursorPtr pCursor;
+
+ if (syncEvents.playingEvents)
+ return;
+ if (grab)
+ {
+ if (grab->cursor)
+ {
+ ChangeToCursor(pDev, grab->cursor);
+ return;
+ }
+ if (IsParent(grab->window, pSprite->win))
+ win = pSprite->win;
+ else
+ win = grab->window;
+ }
+ else
+ win = pSprite->win;
+ for (; win; win = win->parent)
+ {
+ if (win->optional)
+ {
+ pCursor = WindowGetDeviceCursor(win, pDev);
+ if (!pCursor && win->optional->cursor != NullCursor)
+ pCursor = win->optional->cursor;
+ if (pCursor)
+ {
+ ChangeToCursor(pDev, pCursor);
+ return;
+ }
+ }
+ }
+}
+
+
+/**
+ * @param dev device which you want to know its current root window
+ * @return root window where dev's sprite is located
+ */
+WindowPtr
+GetCurrentRootWindow(DeviceIntPtr dev)
+{
+ return RootWindow(dev->spriteInfo->sprite);
+}
+
+/**
+ * @return window underneath the cursor sprite.
+ */
+WindowPtr
+GetSpriteWindow(DeviceIntPtr pDev)
+{
+ return pDev->spriteInfo->sprite->win;
+}
+
+/**
+ * @return current sprite cursor.
+ */
+CursorPtr
+GetSpriteCursor(DeviceIntPtr pDev)
+{
+ return pDev->spriteInfo->sprite->current;
+}
+
+/**
+ * Set x/y current sprite position in screen coordinates.
+ */
+void
+GetSpritePosition(DeviceIntPtr pDev, int *px, int *py)
+{
+ SpritePtr pSprite = pDev->spriteInfo->sprite;
+ *px = pSprite->hotPhys.x;
+ *py = pSprite->hotPhys.y;
+}
+
+#ifdef PANORAMIX
+int
+XineramaGetCursorScreen(DeviceIntPtr pDev)
+{
+ if(!noPanoramiXExtension) {
+ return pDev->spriteInfo->sprite->screen->myNum;
+ } else {
+ return 0;
+ }
+}
+#endif /* PANORAMIX */
+
+#define TIMESLOP (5 * 60 * 1000) /* 5 minutes */
+
+static void
+MonthChangedOrBadTime(InternalEvent *ev)
+{
+ /* If the ddx/OS is careless about not processing timestamped events from
+ * different sources in sorted order, then it's possible for time to go
+ * backwards when it should not. Here we ensure a decent time.
+ */
+ if ((currentTime.milliseconds - ev->any.time) > TIMESLOP)
+ currentTime.months++;
+ else
+ ev->any.time = currentTime.milliseconds;
+}
+
+static void
+NoticeTime(InternalEvent *ev)
+{
+ if (ev->any.time < currentTime.milliseconds)
+ MonthChangedOrBadTime(ev);
+ currentTime.milliseconds = ev->any.time;
+ lastDeviceEventTime = currentTime;
+}
+
+void
+NoticeEventTime(InternalEvent *ev)
+{
+ if (!syncEvents.playingEvents)
+ NoticeTime(ev);
+}
+
+/**************************************************************************
+ * The following procedures deal with synchronous events *
+ **************************************************************************/
+
+/**
+ * EnqueueEvent is a device's processInputProc if a device is frozen.
+ * Instead of delivering the events to the client, the event is tacked onto a
+ * linked list for later delivery.
+ */
+void
+EnqueueEvent(InternalEvent *ev, DeviceIntPtr device)
+{
+ QdEventPtr tail = *syncEvents.pendtail;
+ QdEventPtr qe;
+ SpritePtr pSprite = device->spriteInfo->sprite;
+ int eventlen;
+ DeviceEvent *event = &ev->device_event;
+
+ NoticeTime((InternalEvent*)event);
+
+ /* Fix for key repeating bug. */
+ if (device->key != NULL && device->key->xkbInfo != NULL &&
+ event->type == ET_KeyRelease)
+ AccessXCancelRepeatKey(device->key->xkbInfo, event->detail.key);
+
+ if (DeviceEventCallback)
+ {
+ DeviceEventInfoRec eventinfo;
+
+ /* The RECORD spec says that the root window field of motion events
+ * must be valid. At this point, it hasn't been filled in yet, so
+ * we do it here. The long expression below is necessary to get
+ * the current root window; the apparently reasonable alternative
+ * GetCurrentRootWindow()->drawable.id doesn't give you the right
+ * answer on the first motion event after a screen change because
+ * the data that GetCurrentRootWindow relies on hasn't been
+ * updated yet.
+ */
+ if (ev->any.type == ET_Motion)
+ ev->device_event.root = pSprite->hotPhys.pScreen->root->drawable.id;
+
+ eventinfo.event = ev;
+ eventinfo.device = device;
+ CallCallbacks(&DeviceEventCallback, (pointer)&eventinfo);
+ }
+
+ if (event->type == ET_Motion)
+ {
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension) {
+ event->root_x += pSprite->screen->x - screenInfo.screens[0]->x;
+ event->root_y += pSprite->screen->y - screenInfo.screens[0]->y;
+ }
+#endif
+ pSprite->hotPhys.x = event->root_x;
+ pSprite->hotPhys.y = event->root_y;
+ /* do motion compression, but not if from different devices */
+ if (tail &&
+ (tail->event->any.type == ET_Motion) &&
+ (tail->device == device) &&
+ (tail->pScreen == pSprite->hotPhys.pScreen))
+ {
+ DeviceEvent *tailev = &tail->event->device_event;
+ tailev->root_x = pSprite->hotPhys.x;
+ tailev->root_y = pSprite->hotPhys.y;
+ tailev->time = event->time;
+ tail->months = currentTime.months;
+ return;
+ }
+ }
+
+ eventlen = event->length;
+
+ qe = malloc(sizeof(QdEventRec) + eventlen);
+ if (!qe)
+ return;
+ qe->next = (QdEventPtr)NULL;
+ qe->device = device;
+ qe->pScreen = pSprite->hotPhys.pScreen;
+ qe->months = currentTime.months;
+ qe->event = (InternalEvent *)(qe + 1);
+ memcpy(qe->event, event, eventlen);
+ if (tail)
+ syncEvents.pendtail = &tail->next;
+ *syncEvents.pendtail = qe;
+}
+
+/**
+ * Run through the list of events queued up in syncEvents.
+ * For each event do:
+ * If the device for this event is not frozen anymore, take it and process it
+ * as usually.
+ * After that, check if there's any devices in the list that are not frozen.
+ * If there is none, we're done. If there is at least one device that is not
+ * frozen, then re-run from the beginning of the event queue.
+ */
+static void
+PlayReleasedEvents(void)
+{
+ QdEventPtr *prev, qe;
+ DeviceIntPtr dev;
+ DeviceIntPtr pDev;
+
+ prev = &syncEvents.pending;
+ while ( (qe = *prev) )
+ {
+ if (!qe->device->deviceGrab.sync.frozen)
+ {
+ *prev = qe->next;
+ pDev = qe->device;
+ if (*syncEvents.pendtail == *prev)
+ syncEvents.pendtail = prev;
+ if (qe->event->any.type == ET_Motion)
+ CheckVirtualMotion(pDev, qe, NullWindow);
+ syncEvents.time.months = qe->months;
+ syncEvents.time.milliseconds = qe->event->any.time;
+#ifdef PANORAMIX
+ /* Translate back to the sprite screen since processInputProc
+ will translate from sprite screen to screen 0 upon reentry
+ to the DIX layer */
+ if(!noPanoramiXExtension) {
+ DeviceEvent *ev = &qe->event->device_event;
+ switch(ev->type)
+ {
+ case ET_Motion:
+ case ET_ButtonPress:
+ case ET_ButtonRelease:
+ case ET_KeyPress:
+ case ET_KeyRelease:
+ case ET_ProximityIn:
+ case ET_ProximityOut:
+ ev->root_x += screenInfo.screens[0]->x -
+ pDev->spriteInfo->sprite->screen->x;
+ ev->root_y += screenInfo.screens[0]->y -
+ pDev->spriteInfo->sprite->screen->y;
+ break;
+ default:
+ break;
+ }
+
+ }
+#endif
+ (*qe->device->public.processInputProc)(qe->event, qe->device);
+ free(qe);
+ for (dev = inputInfo.devices; dev && dev->deviceGrab.sync.frozen; dev = dev->next)
+ ;
+ if (!dev)
+ break;
+ /* Playing the event may have unfrozen another device. */
+ /* So to play it safe, restart at the head of the queue */
+ prev = &syncEvents.pending;
+ }
+ else
+ prev = &qe->next;
+ }
+}
+
+/**
+ * Freeze or thaw the given devices. The device's processing proc is
+ * switched to either the real processing proc (in case of thawing) or an
+ * enqueuing processing proc (usually EnqueueEvent()).
+ *
+ * @param dev The device to freeze/thaw
+ * @param frozen True to freeze or false to thaw.
+ */
+static void
+FreezeThaw(DeviceIntPtr dev, Bool frozen)
+{
+ dev->deviceGrab.sync.frozen = frozen;
+ if (frozen)
+ dev->public.processInputProc = dev->public.enqueueInputProc;
+ else
+ dev->public.processInputProc = dev->public.realInputProc;
+}
+
+/**
+ * Unfreeze devices and replay all events to the respective clients.
+ *
+ * ComputeFreezes takes the first event in the device's frozen event queue. It
+ * runs up the sprite tree (spriteTrace) and searches for the window to replay
+ * the events from. If it is found, it checks for passive grabs one down from
+ * the window or delivers the events.
+ */
+static void
+ComputeFreezes(void)
+{
+ DeviceIntPtr replayDev = syncEvents.replayDev;
+ WindowPtr w;
+ GrabPtr grab;
+ DeviceIntPtr dev;
+
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ FreezeThaw(dev, dev->deviceGrab.sync.other ||
+ (dev->deviceGrab.sync.state >= FROZEN));
+ if (syncEvents.playingEvents || (!replayDev && !syncEvents.pending))
+ return;
+ syncEvents.playingEvents = TRUE;
+ if (replayDev)
+ {
+ DeviceEvent* event = replayDev->deviceGrab.sync.event;
+
+ syncEvents.replayDev = (DeviceIntPtr)NULL;
+
+ w = XYToWindow(replayDev->spriteInfo->sprite,
+ event->root_x, event->root_y);
+ if (!CheckDeviceGrabs(replayDev, event, syncEvents.replayWin))
+ {
+ if (replayDev->focus && !IsPointerEvent((InternalEvent*)event))
+ DeliverFocusedEvent(replayDev, (InternalEvent*)event, w);
+ else
+ DeliverDeviceEvents(w, (InternalEvent*)event, NullGrab,
+ NullWindow, replayDev);
+ }
+ }
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ {
+ if (!dev->deviceGrab.sync.frozen)
+ {
+ PlayReleasedEvents();
+ break;
+ }
+ }
+ syncEvents.playingEvents = FALSE;
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ {
+ if (DevHasCursor(dev))
+ {
+ /* the following may have been skipped during replay,
+ so do it now */
+ if ((grab = dev->deviceGrab.grab) && grab->confineTo)
+ {
+ if (grab->confineTo->drawable.pScreen !=
+ dev->spriteInfo->sprite->hotPhys.pScreen)
+ dev->spriteInfo->sprite->hotPhys.x =
+ dev->spriteInfo->sprite->hotPhys.y = 0;
+ ConfineCursorToWindow(dev, grab->confineTo, TRUE, TRUE);
+ }
+ else
+ ConfineCursorToWindow(dev,
+ dev->spriteInfo->sprite->hotPhys.pScreen->root,
+ TRUE, FALSE);
+ PostNewCursor(dev);
+ }
+ }
+}
+
+#ifdef RANDR
+void
+ScreenRestructured (ScreenPtr pScreen)
+{
+ GrabPtr grab;
+ DeviceIntPtr pDev;
+
+ for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
+ {
+ if (!DevHasCursor(pDev))
+ continue;
+
+ /* GrabDevice doesn't have a confineTo field, so we don't need to
+ * worry about it. */
+ if ((grab = pDev->deviceGrab.grab) && grab->confineTo)
+ {
+ if (grab->confineTo->drawable.pScreen
+ != pDev->spriteInfo->sprite->hotPhys.pScreen)
+ pDev->spriteInfo->sprite->hotPhys.x = pDev->spriteInfo->sprite->hotPhys.y = 0;
+ ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE);
+ }
+ else
+ ConfineCursorToWindow(pDev,
+ pDev->spriteInfo->sprite->hotPhys.pScreen->root,
+ TRUE, FALSE);
+ }
+}
+#endif
+
+static void
+CheckGrabForSyncs(DeviceIntPtr thisDev, Bool thisMode, Bool otherMode)
+{
+ GrabPtr grab = thisDev->deviceGrab.grab;
+ DeviceIntPtr dev;
+
+ if (thisMode == GrabModeSync)
+ thisDev->deviceGrab.sync.state = FROZEN_NO_EVENT;
+ else
+ { /* free both if same client owns both */
+ thisDev->deviceGrab.sync.state = THAWED;
+ if (thisDev->deviceGrab.sync.other &&
+ (CLIENT_BITS(thisDev->deviceGrab.sync.other->resource) ==
+ CLIENT_BITS(grab->resource)))
+ thisDev->deviceGrab.sync.other = NullGrab;
+ }
+
+ if (IsMaster(thisDev))
+ {
+ dev = GetPairedDevice(thisDev);
+ if (otherMode == GrabModeSync)
+ dev->deviceGrab.sync.other = grab;
+ else
+ { /* free both if same client owns both */
+ if (dev->deviceGrab.sync.other &&
+ (CLIENT_BITS(dev->deviceGrab.sync.other->resource) ==
+ CLIENT_BITS(grab->resource)))
+ dev->deviceGrab.sync.other = NullGrab;
+ }
+ }
+ ComputeFreezes();
+}
+
+/**
+ * Save the device's master device id. This needs to be done
+ * if a client directly grabs a slave device that is attached to a master. For
+ * the duration of the grab, the device is detached, ungrabbing re-attaches it
+ * though.
+ *
+ * We store the ID of the master device only in case the master disappears
+ * while the device has a grab.
+ */
+static void
+DetachFromMaster(DeviceIntPtr dev)
+{
+ if (!dev->u.master)
+ return;
+
+ dev->saved_master_id = dev->u.master->id;
+
+ AttachDevice(NULL, dev, NULL);
+}
+
+static void
+ReattachToOldMaster(DeviceIntPtr dev)
+{
+ DeviceIntPtr master = NULL;
+
+ if (IsMaster(dev))
+ return;
+
+ dixLookupDevice(&master, dev->saved_master_id, serverClient, DixUseAccess);
+
+ if (master)
+ {
+ AttachDevice(serverClient, dev, master);
+ dev->saved_master_id = 0;
+ }
+}
+
+/**
+ * Activate a pointer grab on the given device. A pointer grab will cause all
+ * core pointer events of this device to be delivered to the grabbing client only.
+ * No other device will send core events to the grab client while the grab is
+ * on, but core events will be sent to other clients.
+ * Can cause the cursor to change if a grab cursor is set.
+ *
+ * Note that parameter autoGrab may be (True & ImplicitGrabMask) if the grab
+ * is an implicit grab caused by a ButtonPress event.
+ *
+ * @param mouse The device to grab.
+ * @param grab The grab structure, needs to be setup.
+ * @param autoGrab True if the grab was caused by a button down event and not
+ * explicitely by a client.
+ */
+void
+ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab,
+ TimeStamp time, Bool autoGrab)
+{
+ GrabInfoPtr grabinfo = &mouse->deviceGrab;
+ WindowPtr oldWin = (grabinfo->grab) ?
+ grabinfo->grab->window
+ : mouse->spriteInfo->sprite->win;
+ Bool isPassive = autoGrab & ~ImplicitGrabMask;
+
+ /* slave devices need to float for the duration of the grab. */
+ if (grab->grabtype == GRABTYPE_XI2 &&
+ !(autoGrab & ImplicitGrabMask) && !IsMaster(mouse))
+ DetachFromMaster(mouse);
+
+ if (grab->confineTo)
+ {
+ if (grab->confineTo->drawable.pScreen
+ != mouse->spriteInfo->sprite->hotPhys.pScreen)
+ mouse->spriteInfo->sprite->hotPhys.x =
+ mouse->spriteInfo->sprite->hotPhys.y = 0;
+ ConfineCursorToWindow(mouse, grab->confineTo, FALSE, TRUE);
+ }
+ DoEnterLeaveEvents(mouse, mouse->id, oldWin, grab->window, NotifyGrab);
+ mouse->valuator->motionHintWindow = NullWindow;
+ if (syncEvents.playingEvents)
+ grabinfo->grabTime = syncEvents.time;
+ else
+ grabinfo->grabTime = time;
+ if (grab->cursor)
+ grab->cursor->refcnt++;
+ grabinfo->activeGrab = *grab;
+ grabinfo->grab = &grabinfo->activeGrab;
+ grabinfo->fromPassiveGrab = isPassive;
+ grabinfo->implicitGrab = autoGrab & ImplicitGrabMask;
+ PostNewCursor(mouse);
+ CheckGrabForSyncs(mouse,(Bool)grab->pointerMode, (Bool)grab->keyboardMode);
+}
+
+/**
+ * Delete grab on given device, update the sprite.
+ *
+ * Extension devices are set up for ActivateKeyboardGrab().
+ */
+void
+DeactivatePointerGrab(DeviceIntPtr mouse)
+{
+ GrabPtr grab = mouse->deviceGrab.grab;
+ DeviceIntPtr dev;
+ Bool wasImplicit = (mouse->deviceGrab.fromPassiveGrab &&
+ mouse->deviceGrab.implicitGrab);
+
+ mouse->valuator->motionHintWindow = NullWindow;
+ mouse->deviceGrab.grab = NullGrab;
+ mouse->deviceGrab.sync.state = NOT_GRABBED;
+ mouse->deviceGrab.fromPassiveGrab = FALSE;
+
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ {
+ if (dev->deviceGrab.sync.other == grab)
+ dev->deviceGrab.sync.other = NullGrab;
+ }
+ DoEnterLeaveEvents(mouse, mouse->id, grab->window,
+ mouse->spriteInfo->sprite->win, NotifyUngrab);
+ if (grab->confineTo)
+ ConfineCursorToWindow(mouse, GetCurrentRootWindow(mouse), FALSE, FALSE);
+ PostNewCursor(mouse);
+ if (grab->cursor)
+ FreeCursor(grab->cursor, (Cursor)0);
+
+ if (!wasImplicit && grab->grabtype == GRABTYPE_XI2)
+ ReattachToOldMaster(mouse);
+
+ ComputeFreezes();
+}
+
+/**
+ * Activate a keyboard grab on the given device.
+ *
+ * Extension devices have ActivateKeyboardGrab() set as their grabbing proc.
+ */
+void
+ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time, Bool passive)
+{
+ GrabInfoPtr grabinfo = &keybd->deviceGrab;
+ WindowPtr oldWin;
+
+ /* slave devices need to float for the duration of the grab. */
+ if (grab->grabtype == GRABTYPE_XI2 &&
+ !(passive & ImplicitGrabMask) &&
+ !IsMaster(keybd))
+ DetachFromMaster(keybd);
+
+ if (grabinfo->grab)
+ oldWin = grabinfo->grab->window;
+ else if (keybd->focus)
+ oldWin = keybd->focus->win;
+ else
+ oldWin = keybd->spriteInfo->sprite->win;
+ if (oldWin == FollowKeyboardWin)
+ oldWin = keybd->focus->win;
+ if (keybd->valuator)
+ keybd->valuator->motionHintWindow = NullWindow;
+ DoFocusEvents(keybd, oldWin, grab->window, NotifyGrab);
+ if (syncEvents.playingEvents)
+ grabinfo->grabTime = syncEvents.time;
+ else
+ grabinfo->grabTime = time;
+ grabinfo->activeGrab = *grab;
+ grabinfo->grab = &grabinfo->activeGrab;
+ grabinfo->fromPassiveGrab = passive;
+ grabinfo->implicitGrab = passive & ImplicitGrabMask;
+ CheckGrabForSyncs(keybd, (Bool)grab->keyboardMode, (Bool)grab->pointerMode);
+}
+
+/**
+ * Delete keyboard grab for the given device.
+ */
+void
+DeactivateKeyboardGrab(DeviceIntPtr keybd)
+{
+ GrabPtr grab = keybd->deviceGrab.grab;
+ DeviceIntPtr dev;
+ WindowPtr focusWin = keybd->focus ? keybd->focus->win
+ : keybd->spriteInfo->sprite->win;
+ Bool wasImplicit = (keybd->deviceGrab.fromPassiveGrab &&
+ keybd->deviceGrab.implicitGrab);
+
+ if (focusWin == FollowKeyboardWin)
+ focusWin = inputInfo.keyboard->focus->win;
+ if (keybd->valuator)
+ keybd->valuator->motionHintWindow = NullWindow;
+ keybd->deviceGrab.grab = NullGrab;
+ keybd->deviceGrab.sync.state = NOT_GRABBED;
+ keybd->deviceGrab.fromPassiveGrab = FALSE;
+
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ {
+ if (dev->deviceGrab.sync.other == grab)
+ dev->deviceGrab.sync.other = NullGrab;
+ }
+ DoFocusEvents(keybd, grab->window, focusWin, NotifyUngrab);
+
+ if (!wasImplicit && grab->grabtype == GRABTYPE_XI2)
+ ReattachToOldMaster(keybd);
+
+ ComputeFreezes();
+}
+
+void
+AllowSome(ClientPtr client,
+ TimeStamp time,
+ DeviceIntPtr thisDev,
+ int newState)
+{
+ Bool thisGrabbed, otherGrabbed, othersFrozen, thisSynced;
+ TimeStamp grabTime;
+ DeviceIntPtr dev;
+ GrabInfoPtr devgrabinfo,
+ grabinfo = &thisDev->deviceGrab;
+
+ thisGrabbed = grabinfo->grab && SameClient(grabinfo->grab, client);
+ thisSynced = FALSE;
+ otherGrabbed = FALSE;
+ othersFrozen = FALSE;
+ grabTime = grabinfo->grabTime;
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ {
+ devgrabinfo = &dev->deviceGrab;
+
+ if (dev == thisDev)
+ continue;
+ if (devgrabinfo->grab && SameClient(devgrabinfo->grab, client))
+ {
+ if (!(thisGrabbed || otherGrabbed) ||
+ (CompareTimeStamps(devgrabinfo->grabTime, grabTime) == LATER))
+ grabTime = devgrabinfo->grabTime;
+ otherGrabbed = TRUE;
+ if (grabinfo->sync.other == devgrabinfo->grab)
+ thisSynced = TRUE;
+ if (devgrabinfo->sync.state >= FROZEN)
+ othersFrozen = TRUE;
+ }
+ }
+ if (!((thisGrabbed && grabinfo->sync.state >= FROZEN) || thisSynced))
+ return;
+ if ((CompareTimeStamps(time, currentTime) == LATER) ||
+ (CompareTimeStamps(time, grabTime) == EARLIER))
+ return;
+ switch (newState)
+ {
+ case THAWED: /* Async */
+ if (thisGrabbed)
+ grabinfo->sync.state = THAWED;
+ if (thisSynced)
+ grabinfo->sync.other = NullGrab;
+ ComputeFreezes();
+ break;
+ case FREEZE_NEXT_EVENT: /* Sync */
+ if (thisGrabbed)
+ {
+ grabinfo->sync.state = FREEZE_NEXT_EVENT;
+ if (thisSynced)
+ grabinfo->sync.other = NullGrab;
+ ComputeFreezes();
+ }
+ break;
+ case THAWED_BOTH: /* AsyncBoth */
+ if (othersFrozen)
+ {
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ {
+ devgrabinfo = &dev->deviceGrab;
+ if (devgrabinfo->grab
+ && SameClient(devgrabinfo->grab, client))
+ devgrabinfo->sync.state = THAWED;
+ if (devgrabinfo->sync.other &&
+ SameClient(devgrabinfo->sync.other, client))
+ devgrabinfo->sync.other = NullGrab;
+ }
+ ComputeFreezes();
+ }
+ break;
+ case FREEZE_BOTH_NEXT_EVENT: /* SyncBoth */
+ if (othersFrozen)
+ {
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ {
+ devgrabinfo = &dev->deviceGrab;
+ if (devgrabinfo->grab
+ && SameClient(devgrabinfo->grab, client))
+ devgrabinfo->sync.state = FREEZE_BOTH_NEXT_EVENT;
+ if (devgrabinfo->sync.other
+ && SameClient(devgrabinfo->sync.other, client))
+ devgrabinfo->sync.other = NullGrab;
+ }
+ ComputeFreezes();
+ }
+ break;
+ case NOT_GRABBED: /* Replay */
+ if (thisGrabbed && grabinfo->sync.state == FROZEN_WITH_EVENT)
+ {
+ if (thisSynced)
+ grabinfo->sync.other = NullGrab;
+ syncEvents.replayDev = thisDev;
+ syncEvents.replayWin = grabinfo->grab->window;
+ (*grabinfo->DeactivateGrab)(thisDev);
+ syncEvents.replayDev = (DeviceIntPtr)NULL;
+ }
+ break;
+ case THAW_OTHERS: /* AsyncOthers */
+ if (othersFrozen)
+ {
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ {
+ if (dev == thisDev)
+ continue;
+ devgrabinfo = &dev->deviceGrab;
+ if (devgrabinfo->grab
+ && SameClient(devgrabinfo->grab, client))
+ devgrabinfo->sync.state = THAWED;
+ if (devgrabinfo->sync.other
+ && SameClient(devgrabinfo->sync.other, client))
+ devgrabinfo->sync.other = NullGrab;
+ }
+ ComputeFreezes();
+ }
+ break;
+ }
+}
+
+/**
+ * Server-side protocol handling for AllowEvents request.
+ *
+ * Release some events from a frozen device.
+ */
+int
+ProcAllowEvents(ClientPtr client)
+{
+ TimeStamp time;
+ DeviceIntPtr mouse = NULL;
+ DeviceIntPtr keybd = NULL;
+ REQUEST(xAllowEventsReq);
+
+ REQUEST_SIZE_MATCH(xAllowEventsReq);
+ time = ClientTimeToServerTime(stuff->time);
+
+ mouse = PickPointer(client);
+ keybd = PickKeyboard(client);
+
+ switch (stuff->mode)
+ {
+ case ReplayPointer:
+ AllowSome(client, time, mouse, NOT_GRABBED);
+ break;
+ case SyncPointer:
+ AllowSome(client, time, mouse, FREEZE_NEXT_EVENT);
+ break;
+ case AsyncPointer:
+ AllowSome(client, time, mouse, THAWED);
+ break;
+ case ReplayKeyboard:
+ AllowSome(client, time, keybd, NOT_GRABBED);
+ break;
+ case SyncKeyboard:
+ AllowSome(client, time, keybd, FREEZE_NEXT_EVENT);
+ break;
+ case AsyncKeyboard:
+ AllowSome(client, time, keybd, THAWED);
+ break;
+ case SyncBoth:
+ AllowSome(client, time, keybd, FREEZE_BOTH_NEXT_EVENT);
+ break;
+ case AsyncBoth:
+ AllowSome(client, time, keybd, THAWED_BOTH);
+ break;
+ default:
+ client->errorValue = stuff->mode;
+ return BadValue;
+ }
+ return Success;
+}
+
+/**
+ * Deactivate grabs from any device that has been grabbed by the client.
+ */
+void
+ReleaseActiveGrabs(ClientPtr client)
+{
+ DeviceIntPtr dev;
+ Bool done;
+
+ /* XXX CloseDownClient should remove passive grabs before
+ * releasing active grabs.
+ */
+ do {
+ done = TRUE;
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ {
+ if (dev->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client))
+ {
+ (*dev->deviceGrab.DeactivateGrab)(dev);
+ done = FALSE;
+ }
+ }
+ } while (!done);
+}
+
+/**************************************************************************
+ * The following procedures deal with delivering events *
+ **************************************************************************/
+
+/**
+ * Deliver the given events to the given client.
+ *
+ * More than one event may be delivered at a time. This is the case with
+ * DeviceMotionNotifies which may be followed by DeviceValuator events.
+ *
+ * TryClientEvents() is the last station before actually writing the events to
+ * the socket. Anything that is not filtered here, will get delivered to the
+ * client.
+ * An event is only delivered if
+ * - mask and filter match up.
+ * - no other client has a grab on the device that caused the event.
+ *
+ *
+ * @param client The target client to deliver to.
+ * @param dev The device the event came from. May be NULL.
+ * @param pEvents The events to be delivered.
+ * @param count Number of elements in pEvents.
+ * @param mask Event mask as set by the window.
+ * @param filter Mask based on event type.
+ * @param grab Possible grab on the device that caused the event.
+ *
+ * @return 1 if event was delivered, 0 if not or -1 if grab was not set by the
+ * client.
+ */
+int
+TryClientEvents (ClientPtr client, DeviceIntPtr dev, xEvent *pEvents,
+ int count, Mask mask, Mask filter, GrabPtr grab)
+{
+ int type;
+
+#ifdef DEBUG_EVENTS
+ ErrorF("[dix] Event([%d, %d], mask=0x%lx), client=%d%s",
+ pEvents->u.u.type, pEvents->u.u.detail, mask,
+ client ? client->index : -1,
+ (client && client->clientGone) ? " (gone)" : "");
+#endif
+
+ if (!client || client == serverClient || client->clientGone) {
+#ifdef DEBUG_EVENTS
+ ErrorF(" not delivered to fake/dead client\n");
+#endif
+ return 0;
+ }
+
+ if (filter != CantBeFiltered && !(mask & filter))
+ {
+ #ifdef DEBUG_EVENTS
+ ErrorF(" filtered\n");
+ #endif
+ return 0;
+ }
+
+ if (grab && !SameClient(grab, client))
+ {
+#ifdef DEBUG_EVENTS
+ ErrorF(" not delivered due to grab\n");
+#endif
+ return -1; /* don't send, but notify caller */
+ }
+
+ type = pEvents->u.u.type;
+ if (type == MotionNotify)
+ {
+ if (mask & PointerMotionHintMask)
+ {
+ if (WID(dev->valuator->motionHintWindow) ==
+ pEvents->u.keyButtonPointer.event)
+ {
+#ifdef DEBUG_EVENTS
+ ErrorF("[dix] \n");
+ ErrorF("[dix] motionHintWindow == keyButtonPointer.event\n");
+#endif
+ return 1; /* don't send, but pretend we did */
+ }
+ pEvents->u.u.detail = NotifyHint;
+ }
+ else
+ {
+ pEvents->u.u.detail = NotifyNormal;
+ }
+ }
+ else if (type == DeviceMotionNotify)
+ {
+ if (MaybeSendDeviceMotionNotifyHint((deviceKeyButtonPointer*)pEvents,
+ mask) != 0)
+ return 1;
+ } else if (type == KeyPress)
+ {
+ if (EventIsKeyRepeat(pEvents))
+ {
+ if (!_XkbWantsDetectableAutoRepeat(client))
+ {
+ xEvent release = *pEvents;
+ release.u.u.type = KeyRelease;
+ WriteEventsToClient(client, 1, &release);
+#ifdef DEBUG_EVENTS
+ ErrorF(" (plus fake core release for repeat)");
+#endif
+ } else
+ {
+#ifdef DEBUG_EVENTS
+ ErrorF(" (detectable autorepeat for core)");
+#endif
+ }
+ }
+
+ } else if (type == DeviceKeyPress)
+ {
+ if (EventIsKeyRepeat(pEvents))
+ {
+ if (!_XkbWantsDetectableAutoRepeat(client))
+ {
+ deviceKeyButtonPointer release = *(deviceKeyButtonPointer *)pEvents;
+ release.type = DeviceKeyRelease;
+#ifdef DEBUG_EVENTS
+ ErrorF(" (plus fake xi1 release for repeat)");
+#endif
+ WriteEventsToClient(client, 1, (xEvent *) &release);
+ }
+ else {
+#ifdef DEBUG_EVENTS
+ ErrorF(" (detectable autorepeat for core)");
+#endif
+ }
+ }
+ }
+
+ if (BitIsOn(criticalEvents, type))
+ {
+ if (client->smart_priority < SMART_MAX_PRIORITY)
+ client->smart_priority++;
+ SetCriticalOutputPending();
+ }
+
+ WriteEventsToClient(client, count, pEvents);
+#ifdef DEBUG_EVENTS
+ ErrorF("[dix] delivered\n");
+#endif
+ return 1;
+}
+
+/**
+ * Deliver events to a window. At this point, we do not yet know if the event
+ * actually needs to be delivered. May activate a grab if the event is a
+ * button press.
+ *
+ * Core events are always delivered to the window owner. If the filter is
+ * something other than CantBeFiltered, the event is also delivered to other
+ * clients with the matching mask on the window.
+ *
+ * More than one event may be delivered at a time. This is the case with
+ * DeviceMotionNotifies which may be followed by DeviceValuator events.
+ *
+ * @param pWin The window that would get the event.
+ * @param pEvents The events to be delivered.
+ * @param count Number of elements in pEvents.
+ * @param filter Mask based on event type.
+ * @param grab Possible grab on the device that caused the event.
+ *
+ * @return Number of events delivered to various clients.
+ */
+int
+DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent
+ *pEvents, int count, Mask filter, GrabPtr grab)
+{
+ int deliveries = 0, nondeliveries = 0;
+ int attempt;
+ InputClients *other;
+ ClientPtr client = NullClient;
+ Mask deliveryMask = 0; /* If a grab occurs due to a button press, then
+ this mask is the mask of the grab. */
+ int type = pEvents->u.u.type;
+
+
+ /* Deliver to window owner */
+ if ((filter == CantBeFiltered) || CORE_EVENT(pEvents))
+ {
+ /* if nobody ever wants to see this event, skip some work */
+ if (filter != CantBeFiltered &&
+ !((wOtherEventMasks(pWin)|pWin->eventMask) & filter))
+ return 0;
+
+ if (IsInterferingGrab(wClient(pWin), pDev, pEvents))
+ return 0;
+
+ if (XaceHook(XACE_RECEIVE_ACCESS, wClient(pWin), pWin, pEvents, count))
+ /* do nothing */;
+ else if ( (attempt = TryClientEvents(wClient(pWin), pDev, pEvents,
+ count, pWin->eventMask,
+ filter, grab)) )
+ {
+ if (attempt > 0)
+ {
+ deliveries++;
+ client = wClient(pWin);
+ deliveryMask = pWin->eventMask;
+ } else
+ nondeliveries--;
+ }
+ }
+
+ /* CantBeFiltered means only window owner gets the event */
+ if (filter != CantBeFiltered)
+ {
+ if (CORE_EVENT(pEvents))
+ other = (InputClients *)wOtherClients(pWin);
+ else if (XI2_EVENT(pEvents))
+ {
+ OtherInputMasks *inputMasks = wOtherInputMasks(pWin);
+ /* Has any client selected for the event? */
+ if (!GetWindowXI2Mask(pDev, pWin, pEvents))
+ return 0;
+ other = inputMasks->inputClients;
+ } else {
+ OtherInputMasks *inputMasks = wOtherInputMasks(pWin);
+ /* Has any client selected for the event? */
+ if (!inputMasks ||
+ !(inputMasks->inputEvents[pDev->id] & filter))
+ return 0;
+
+ other = inputMasks->inputClients;
+ }
+
+ for (; other; other = other->next)
+ {
+ Mask mask;
+ if (IsInterferingGrab(rClient(other), pDev, pEvents))
+ continue;
+
+ mask = GetEventMask(pDev, pEvents, other);
+
+ if (XaceHook(XACE_RECEIVE_ACCESS, rClient(other), pWin,
+ pEvents, count))
+ /* do nothing */;
+ else if ( (attempt = TryClientEvents(rClient(other), pDev,
+ pEvents, count,
+ mask, filter, grab)) )
+ {
+ if (attempt > 0)
+ {
+ deliveries++;
+ client = rClient(other);
+ deliveryMask = mask;
+ } else
+ nondeliveries--;
+ }
+ }
+ }
+ /*
+ * Note that since core events are delivered first, an implicit grab may
+ * be activated on a core grab, stopping the XI events.
+ */
+ if ((type == DeviceButtonPress || type == ButtonPress ||
+ ((XI2_EVENT(pEvents) && ((xGenericEvent*)pEvents)->evtype == XI_ButtonPress)))
+ && deliveries
+ && (!grab))
+ {
+ GrabRec tempGrab;
+ OtherInputMasks *inputMasks;
+
+ memset(&tempGrab, 0, sizeof(GrabRec));
+ tempGrab.next = NULL;
+ tempGrab.device = pDev;
+ tempGrab.resource = client->clientAsMask;
+ tempGrab.window = pWin;
+ tempGrab.ownerEvents = (deliveryMask & OwnerGrabButtonMask) ? TRUE : FALSE;
+ tempGrab.eventMask = deliveryMask;
+ tempGrab.keyboardMode = GrabModeAsync;
+ tempGrab.pointerMode = GrabModeAsync;
+ tempGrab.confineTo = NullWindow;
+ tempGrab.cursor = NullCursor;
+ tempGrab.type = type;
+ if (type == ButtonPress)
+ tempGrab.grabtype = GRABTYPE_CORE;
+ else if (type == DeviceButtonPress)
+ tempGrab.grabtype = GRABTYPE_XI;
+ else
+ {
+ tempGrab.type = ((xGenericEvent*)pEvents)->evtype;
+ tempGrab.grabtype = GRABTYPE_XI2;
+ }
+
+ /* get the XI and XI2 device mask */
+ inputMasks = wOtherInputMasks(pWin);
+ tempGrab.deviceMask = (inputMasks) ? inputMasks->inputEvents[pDev->id]: 0;
+
+ if (inputMasks)
+ memcpy(tempGrab.xi2mask, inputMasks->xi2mask,
+ sizeof(tempGrab.xi2mask));
+
+ (*pDev->deviceGrab.ActivateGrab)(pDev, &tempGrab,
+ currentTime, TRUE | ImplicitGrabMask);
+ }
+ else if ((type == MotionNotify) && deliveries)
+ pDev->valuator->motionHintWindow = pWin;
+ else
+ {
+ if ((type == DeviceMotionNotify || type == DeviceButtonPress) &&
+ deliveries)
+ CheckDeviceGrabAndHintWindow (pWin, type,
+ (deviceKeyButtonPointer*) pEvents,
+ grab, client, deliveryMask);
+ }
+ if (deliveries)
+ return deliveries;
+ return nondeliveries;
+}
+
+/* If the event goes to dontClient, don't send it and return 0. if
+ send works, return 1 or if send didn't work, return 2.
+ Only works for core events.
+*/
+
+#ifdef PANORAMIX
+static int
+XineramaTryClientEventsResult(
+ ClientPtr client,
+ GrabPtr grab,
+ Mask mask,
+ Mask filter
+){
+ if ((client) && (client != serverClient) && (!client->clientGone) &&
+ ((filter == CantBeFiltered) || (mask & filter)))
+ {
+ if (grab && !SameClient(grab, client)) return -1;
+ else return 1;
+ }
+ return 0;
+}
+#endif
+
+/**
+ * Try to deliver events to the interested parties.
+ *
+ * @param pWin The window that would get the event.
+ * @param pEvents The events to be delivered.
+ * @param count Number of elements in pEvents.
+ * @param filter Mask based on event type.
+ * @param dontClient Don't deliver to the dontClient.
+ */
+int
+MaybeDeliverEventsToClient(WindowPtr pWin, xEvent *pEvents,
+ int count, Mask filter, ClientPtr dontClient)
+{
+ OtherClients *other;
+
+
+ if (pWin->eventMask & filter)
+ {
+ if (wClient(pWin) == dontClient)
+ return 0;
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum)
+ return XineramaTryClientEventsResult(
+ wClient(pWin), NullGrab, pWin->eventMask, filter);
+#endif
+ if (XaceHook(XACE_RECEIVE_ACCESS, wClient(pWin), pWin, pEvents, count))
+ return 1; /* don't send, but pretend we did */
+ return TryClientEvents(wClient(pWin), NULL, pEvents, count,
+ pWin->eventMask, filter, NullGrab);
+ }
+ for (other = wOtherClients(pWin); other; other = other->next)
+ {
+ if (other->mask & filter)
+ {
+ if (SameClient(other, dontClient))
+ return 0;
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum)
+ return XineramaTryClientEventsResult(
+ rClient(other), NullGrab, other->mask, filter);
+#endif
+ if (XaceHook(XACE_RECEIVE_ACCESS, rClient(other), pWin, pEvents,
+ count))
+ return 1; /* don't send, but pretend we did */
+ return TryClientEvents(rClient(other), NULL, pEvents, count,
+ other->mask, filter, NullGrab);
+ }
+ }
+ return 2;
+}
+
+static Window FindChildForEvent(SpritePtr pSprite, WindowPtr event)
+{
+ WindowPtr w = pSprite->spriteTrace[pSprite->spriteTraceGood-1];
+ Window child = None;
+
+ /* If the search ends up past the root should the child field be
+ set to none or should the value in the argument be passed
+ through. It probably doesn't matter since everyone calls
+ this function with child == None anyway. */
+ while (w)
+ {
+ /* If the source window is same as event window, child should be
+ none. Don't bother going all all the way back to the root. */
+
+ if (w == event)
+ {
+ child = None;
+ break;
+ }
+
+ if (w->parent == event)
+ {
+ child = w->drawable.id;
+ break;
+ }
+ w = w->parent;
+ }
+ return child;
+}
+
+/**
+ * Adjust event fields to comply with the window properties.
+ *
+ * @param xE Event to be modified in place
+ * @param pWin The window to get the information from.
+ * @param child Child window setting for event (if applicable)
+ * @param calcChild If True, calculate the child window.
+ */
+void
+FixUpEventFromWindow(
+ SpritePtr pSprite,
+ xEvent *xE,
+ WindowPtr pWin,
+ Window child,
+ Bool calcChild)
+{
+ if (calcChild)
+ child = FindChildForEvent(pSprite, pWin);
+
+ if (XI2_EVENT(xE))
+ {
+ xXIDeviceEvent* event = (xXIDeviceEvent*)xE;
+
+ if (event->evtype == XI_RawKeyPress ||
+ event->evtype == XI_RawKeyRelease ||
+ event->evtype == XI_RawButtonPress ||
+ event->evtype == XI_RawButtonRelease ||
+ event->evtype == XI_RawMotion ||
+ event->evtype == XI_DeviceChanged ||
+ event->evtype == XI_HierarchyChanged ||
+ event->evtype == XI_PropertyEvent)
+ return;
+
+ event->root = RootWindow(pSprite)->drawable.id;
+ event->event = pWin->drawable.id;
+ if (pSprite->hot.pScreen == pWin->drawable.pScreen)
+ {
+ event->event_x = event->root_x - FP1616(pWin->drawable.x, 0);
+ event->event_y = event->root_y - FP1616(pWin->drawable.y, 0);
+ event->child = child;
+ } else
+ {
+ event->event_x = 0;
+ event->event_y = 0;
+ event->child = None;
+ }
+
+ if (event->evtype == XI_Enter || event->evtype == XI_Leave ||
+ event->evtype == XI_FocusIn || event->evtype == XI_FocusOut)
+ ((xXIEnterEvent*)event)->same_screen =
+ (pSprite->hot.pScreen == pWin->drawable.pScreen);
+
+ } else
+ {
+ XE_KBPTR.root = RootWindow(pSprite)->drawable.id;
+ XE_KBPTR.event = pWin->drawable.id;
+ if (pSprite->hot.pScreen == pWin->drawable.pScreen)
+ {
+ XE_KBPTR.sameScreen = xTrue;
+ XE_KBPTR.child = child;
+ XE_KBPTR.eventX =
+ XE_KBPTR.rootX - pWin->drawable.x;
+ XE_KBPTR.eventY =
+ XE_KBPTR.rootY - pWin->drawable.y;
+ }
+ else
+ {
+ XE_KBPTR.sameScreen = xFalse;
+ XE_KBPTR.child = None;
+ XE_KBPTR.eventX = 0;
+ XE_KBPTR.eventY = 0;
+ }
+ }
+}
+
+/**
+ * Check if a given event is deliverable at all on a given window.
+ *
+ * This function only checks if any client wants it, not for a specific
+ * client.
+ *
+ * @param[in] dev The device this event is being sent for.
+ * @param[in] event The event that is to be sent.
+ * @param[in] win The current event window.
+ *
+ * @return Bitmask of ::XI2_MASK, ::XI_MASK, ::CORE_MASK, and
+ * ::DONT_PROPAGATE_MASK.
+ */
+int
+EventIsDeliverable(DeviceIntPtr dev, InternalEvent* event, WindowPtr win)
+{
+ int rc = 0;
+ int filter = 0;
+ int type;
+ OtherInputMasks *inputMasks = wOtherInputMasks(win);
+ xEvent ev;
+
+ /* XXX: this makes me gag */
+ type = GetXI2Type(event);
+ ev.u.u.type = GenericEvent; /* GetEventFilter only cares about type and evtype*/
+ ((xGenericEvent*)&ev)->extension = IReqCode;
+ ((xGenericEvent*)&ev)->evtype = type;
+ filter = GetEventFilter(dev, &ev);
+ if (type && inputMasks &&
+ ((inputMasks->xi2mask[XIAllDevices][type/8] & filter) ||
+ ((inputMasks->xi2mask[XIAllMasterDevices][type/8] & filter) && IsMaster(dev)) ||
+ (inputMasks->xi2mask[dev->id][type/8] & filter)))
+ rc |= XI2_MASK;
+
+ type = GetXIType(event);
+ ev.u.u.type = type;
+ filter = GetEventFilter(dev, &ev);
+
+ /* Check for XI mask */
+ if (type && inputMasks &&
+ (inputMasks->deliverableEvents[dev->id] & filter) &&
+ (inputMasks->inputEvents[dev->id] & filter))
+ rc |= XI_MASK;
+
+ /* Check for XI DontPropagate mask */
+ if (type && inputMasks &&
+ (inputMasks->dontPropagateMask[dev->id] & filter))
+ rc |= DONT_PROPAGATE_MASK;
+
+ /* Check for core mask */
+ type = GetCoreType(event);
+ if (type && (win->deliverableEvents & filter) &&
+ ((wOtherEventMasks(win) | win->eventMask) & filter))
+ rc |= CORE_MASK;
+
+ /* Check for core DontPropagate mask */
+ if (type && (filter & wDontPropagateMask(win)))
+ rc |= DONT_PROPAGATE_MASK;
+
+ return rc;
+}
+
+/**
+ * Deliver events caused by input devices.
+ *
+ * For events from a non-grabbed, non-focus device, DeliverDeviceEvents is
+ * called directly from the processInputProc.
+ * For grabbed devices, DeliverGrabbedEvent is called first, and _may_ call
+ * DeliverDeviceEvents.
+ * For focused events, DeliverFocusedEvent is called first, and _may_ call
+ * DeliverDeviceEvents.
+ *
+ * @param pWin Window to deliver event to.
+ * @param event The events to deliver, not yet in wire format.
+ * @param grab Possible grab on a device.
+ * @param stopAt Don't recurse up to the root window.
+ * @param dev The device that is responsible for the event.
+ *
+ * @see DeliverGrabbedEvent
+ * @see DeliverFocusedEvent
+ */
+int
+DeliverDeviceEvents(WindowPtr pWin, InternalEvent *event, GrabPtr grab,
+ WindowPtr stopAt, DeviceIntPtr dev)
+{
+ SpritePtr pSprite = dev->spriteInfo->sprite;
+ Window child = None;
+ Mask filter;
+ int deliveries = 0;
+ xEvent core;
+ xEvent *xE = NULL;
+ int rc, mask, count = 0;
+
+ CHECKEVENT(event);
+
+ while (pWin)
+ {
+ if ((mask = EventIsDeliverable(dev, event, pWin)))
+ {
+ /* XI2 events first */
+ if (mask & XI2_MASK)
+ {
+ xEvent *xi2 = NULL;
+ rc = EventToXI2(event, &xi2);
+ if (rc == Success)
+ {
+ /* XXX: XACE */
+ filter = GetEventFilter(dev, xi2);
+ FixUpEventFromWindow(pSprite, xi2, pWin, child, FALSE);
+ deliveries = DeliverEventsToWindow(dev, pWin, xi2, 1,
+ filter, grab);
+ free(xi2);
+ if (deliveries > 0)
+ goto unwind;
+ } else if (rc != BadMatch)
+ ErrorF("[dix] %s: XI2 conversion failed in DDE (%d).\n",
+ dev->name, rc);
+ }
+
+ /* XI events */
+ if (mask & XI_MASK)
+ {
+ rc = EventToXI(event, &xE, &count);
+ if (rc == Success) {
+ if (XaceHook(XACE_SEND_ACCESS, NULL, dev, pWin, xE, count) == Success) {
+ filter = GetEventFilter(dev, xE);
+ FixUpEventFromWindow(pSprite, xE, pWin, child, FALSE);
+ deliveries = DeliverEventsToWindow(dev, pWin, xE, count,
+ filter, grab);
+ if (deliveries > 0)
+ goto unwind;
+ }
+ } else if (rc != BadMatch)
+ ErrorF("[dix] %s: XI conversion failed in DDE (%d, %d). Skipping delivery.\n",
+ dev->name, event->any.type, rc);
+ }
+
+ /* Core event */
+ if ((mask & CORE_MASK) && IsMaster(dev) && dev->coreEvents)
+ {
+ rc = EventToCore(event, &core);
+ if (rc == Success) {
+ if (XaceHook(XACE_SEND_ACCESS, NULL, dev, pWin, &core, 1) == Success) {
+ filter = GetEventFilter(dev, &core);
+ FixUpEventFromWindow(pSprite, &core, pWin, child, FALSE);
+ deliveries = DeliverEventsToWindow(dev, pWin, &core, 1,
+ filter, grab);
+ if (deliveries > 0)
+ goto unwind;
+ }
+ } else if (rc != BadMatch)
+ ErrorF("[dix] %s: Core conversion failed in DDE (%d, %d).\n",
+ dev->name, event->any.type, rc);
+ }
+
+ if ((deliveries < 0) || (pWin == stopAt) ||
+ (mask & DONT_PROPAGATE_MASK))
+ {
+ deliveries = 0;
+ goto unwind;
+ }
+ }
+
+ child = pWin->drawable.id;
+ pWin = pWin->parent;
+ }
+
+unwind:
+ free(xE);
+ return deliveries;
+}
+
+#undef XI_MASK
+#undef CORE_MASK
+#undef DONT_PROPAGATE_MASK
+
+/**
+ * Deliver event to a window and it's immediate parent. Used for most window
+ * events (CreateNotify, ConfigureNotify, etc.). Not useful for events that
+ * propagate up the tree or extension events
+ *
+ * In case of a ReparentNotify event, the event will be delivered to the
+ * otherParent as well.
+ *
+ * @param pWin Window to deliver events to.
+ * @param xE Events to deliver.
+ * @param count number of events in xE.
+ * @param otherParent Used for ReparentNotify events.
+ */
+int
+DeliverEvents(WindowPtr pWin, xEvent *xE, int count,
+ WindowPtr otherParent)
+{
+ Mask filter;
+ int deliveries;
+ DeviceIntRec dummy;
+
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum)
+ return count;
+#endif
+
+ if (!count)
+ return 0;
+
+ dummy.id = XIAllDevices;
+ filter = GetEventFilter(&dummy, xE);
+ if ((filter & SubstructureNotifyMask) && (xE->u.u.type != CreateNotify))
+ xE->u.destroyNotify.event = pWin->drawable.id;
+ if (filter != StructureAndSubMask)
+ return DeliverEventsToWindow(&dummy, pWin, xE, count, filter, NullGrab);
+ deliveries = DeliverEventsToWindow(&dummy, pWin, xE, count,
+ StructureNotifyMask, NullGrab);
+ if (pWin->parent)
+ {
+ xE->u.destroyNotify.event = pWin->parent->drawable.id;
+ deliveries += DeliverEventsToWindow(&dummy, pWin->parent, xE, count,
+ SubstructureNotifyMask, NullGrab);
+ if (xE->u.u.type == ReparentNotify)
+ {
+ xE->u.destroyNotify.event = otherParent->drawable.id;
+ deliveries += DeliverEventsToWindow(&dummy,
+ otherParent, xE, count, SubstructureNotifyMask,
+ NullGrab);
+ }
+ }
+ return deliveries;
+}
+
+
+static Bool
+PointInBorderSize(WindowPtr pWin, int x, int y)
+{
+ BoxRec box;
+
+ if(RegionContainsPoint(&pWin->borderSize, x, y, &box))
+ return TRUE;
+
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension &&
+ XineramaSetWindowPntrs(inputInfo.pointer, pWin)) {
+ SpritePtr pSprite = inputInfo.pointer->spriteInfo->sprite;
+ int i;
+
+ for(i = 1; i < PanoramiXNumScreens; i++) {
+ if(RegionContainsPoint(&pSprite->windows[i]->borderSize,
+ x + screenInfo.screens[0]->x - screenInfo.screens[i]->x,
+ y + screenInfo.screens[0]->y - screenInfo.screens[i]->y,
+ &box))
+ return TRUE;
+ }
+ }
+#endif
+ return FALSE;
+}
+
+/**
+ * Traversed from the root window to the window at the position x/y. While
+ * traversing, it sets up the traversal history in the spriteTrace array.
+ * After completing, the spriteTrace history is set in the following way:
+ * spriteTrace[0] ... root window
+ * spriteTrace[1] ... top level window that encloses x/y
+ * ...
+ * spriteTrace[spriteTraceGood - 1] ... window at x/y
+ *
+ * @returns the window at the given coordinates.
+ */
+WindowPtr
+XYToWindow(SpritePtr pSprite, int x, int y)
+{
+ WindowPtr pWin;
+ BoxRec box;
+
+ pSprite->spriteTraceGood = 1; /* root window still there */
+ pWin = RootWindow(pSprite)->firstChild;
+ while (pWin)
+ {
+ if ((pWin->mapped) &&
+ (x >= pWin->drawable.x - wBorderWidth (pWin)) &&
+ (x < pWin->drawable.x + (int)pWin->drawable.width +
+ wBorderWidth(pWin)) &&
+ (y >= pWin->drawable.y - wBorderWidth (pWin)) &&
+ (y < pWin->drawable.y + (int)pWin->drawable.height +
+ wBorderWidth (pWin))
+ /* When a window is shaped, a further check
+ * is made to see if the point is inside
+ * borderSize
+ */
+ && (!wBoundingShape(pWin) || PointInBorderSize(pWin, x, y))
+ && (!wInputShape(pWin) ||
+ RegionContainsPoint(wInputShape(pWin),
+ x - pWin->drawable.x,
+ y - pWin->drawable.y, &box))
+#ifdef ROOTLESS
+ /* In rootless mode windows may be offscreen, even when
+ * they're in X's stack. (E.g. if the native window system
+ * implements some form of virtual desktop system).
+ */
+ && !pWin->rootlessUnhittable
+#endif
+ )
+ {
+ if (pSprite->spriteTraceGood >= pSprite->spriteTraceSize)
+ {
+ pSprite->spriteTraceSize += 10;
+ pSprite->spriteTrace = realloc(pSprite->spriteTrace,
+ pSprite->spriteTraceSize*sizeof(WindowPtr));
+ }
+ pSprite->spriteTrace[pSprite->spriteTraceGood++] = pWin;
+ pWin = pWin->firstChild;
+ }
+ else
+ pWin = pWin->nextSib;
+ }
+ return pSprite->spriteTrace[pSprite->spriteTraceGood-1];
+}
+
+/**
+ * Ungrab a currently FocusIn grabbed device and grab the device on the
+ * given window. If the win given is the NoneWin, the device is ungrabbed if
+ * applicable and FALSE is returned.
+ *
+ * @returns TRUE if the device has been grabbed, or FALSE otherwise.
+ */
+BOOL
+ActivateFocusInGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win)
+{
+ BOOL rc = FALSE;
+ DeviceEvent event;
+
+ if (dev->deviceGrab.grab)
+ {
+ if (!dev->deviceGrab.fromPassiveGrab ||
+ dev->deviceGrab.grab->type != XI_Enter ||
+ dev->deviceGrab.grab->window == win ||
+ IsParent(dev->deviceGrab.grab->window, win))
+ return FALSE;
+ DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab);
+ (*dev->deviceGrab.DeactivateGrab)(dev);
+ }
+
+ if (win == NoneWin || win == PointerRootWin)
+ return FALSE;
+
+ memset(&event, 0, sizeof(DeviceEvent));
+ event.header = ET_Internal;
+ event.type = ET_FocusIn;
+ event.length = sizeof(DeviceEvent);
+ event.time = GetTimeInMillis();
+ event.deviceid = dev->id;
+ event.sourceid = dev->id;
+ event.detail.button = 0;
+ rc = (CheckPassiveGrabsOnWindow(win, dev, &event, FALSE, TRUE) != NULL);
+ if (rc)
+ DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab);
+ return rc;
+}
+
+/**
+ * Ungrab a currently Enter grabbed device and grab the device for the given
+ * window.
+ *
+ * @returns TRUE if the device has been grabbed, or FALSE otherwise.
+ */
+static BOOL
+ActivateEnterGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win)
+{
+ BOOL rc = FALSE;
+ DeviceEvent event;
+
+ if (dev->deviceGrab.grab)
+ {
+ if (!dev->deviceGrab.fromPassiveGrab ||
+ dev->deviceGrab.grab->type != XI_Enter ||
+ dev->deviceGrab.grab->window == win ||
+ IsParent(dev->deviceGrab.grab->window, win))
+ return FALSE;
+ DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab);
+ (*dev->deviceGrab.DeactivateGrab)(dev);
+ }
+
+ memset(&event, 0, sizeof(DeviceEvent));
+ event.header = ET_Internal;
+ event.type = ET_Enter;
+ event.length = sizeof(DeviceEvent);
+ event.time = GetTimeInMillis();
+ event.deviceid = dev->id;
+ event.sourceid = dev->id;
+ event.detail.button = 0;
+ rc = (CheckPassiveGrabsOnWindow(win, dev, &event, FALSE, TRUE) != NULL);
+ if (rc)
+ DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveGrab);
+ return rc;
+}
+
+/**
+ * Update the sprite coordinates based on the event. Update the cursor
+ * position, then update the event with the new coordinates that may have been
+ * changed. If the window underneath the sprite has changed, change to new
+ * cursor and send enter/leave events.
+ *
+ * CheckMotion() will not do anything and return FALSE if the event is not a
+ * pointer event.
+ *
+ * @return TRUE if the sprite has moved or FALSE otherwise.
+ */
+Bool
+CheckMotion(DeviceEvent *ev, DeviceIntPtr pDev)
+{
+ WindowPtr prevSpriteWin, newSpriteWin;
+ SpritePtr pSprite = pDev->spriteInfo->sprite;
+
+ CHECKEVENT(ev);
+
+ prevSpriteWin = pSprite->win;
+
+ if (ev && !syncEvents.playingEvents)
+ {
+ /* GetPointerEvents() guarantees that pointer events have the correct
+ rootX/Y set already. */
+ switch (ev->type)
+ {
+ case ET_ButtonPress:
+ case ET_ButtonRelease:
+ case ET_Motion:
+ break;
+ default:
+ /* all other events return FALSE */
+ return FALSE;
+ }
+
+
+#ifdef PANORAMIX
+ if (!noPanoramiXExtension)
+ {
+ /* Motion events entering DIX get translated to Screen 0
+ coordinates. Replayed events have already been
+ translated since they've entered DIX before */
+ ev->root_x += pSprite->screen->x - screenInfo.screens[0]->x;
+ ev->root_y += pSprite->screen->y - screenInfo.screens[0]->y;
+ } else
+#endif
+ {
+ if (pSprite->hot.pScreen != pSprite->hotPhys.pScreen)
+ {
+ pSprite->hot.pScreen = pSprite->hotPhys.pScreen;
+ RootWindow(pDev->spriteInfo->sprite) =
+ pSprite->hot.pScreen->root;
+ }
+ }
+
+ pSprite->hot.x = ev->root_x;
+ pSprite->hot.y = ev->root_y;
+ if (pSprite->hot.x < pSprite->physLimits.x1)
+ pSprite->hot.x = pSprite->physLimits.x1;
+ else if (pSprite->hot.x >= pSprite->physLimits.x2)
+ pSprite->hot.x = pSprite->physLimits.x2 - 1;
+ if (pSprite->hot.y < pSprite->physLimits.y1)
+ pSprite->hot.y = pSprite->physLimits.y1;
+ else if (pSprite->hot.y >= pSprite->physLimits.y2)
+ pSprite->hot.y = pSprite->physLimits.y2 - 1;
+ if (pSprite->hotShape)
+ ConfineToShape(pDev, pSprite->hotShape, &pSprite->hot.x, &pSprite->hot.y);
+ pSprite->hotPhys = pSprite->hot;
+
+ if ((pSprite->hotPhys.x != ev->root_x) ||
+ (pSprite->hotPhys.y != ev->root_y))
+ {
+#ifdef PANORAMIX
+ if (!noPanoramiXExtension)
+ {
+ XineramaSetCursorPosition(
+ pDev, pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE);
+ } else
+#endif
+ {
+ (*pSprite->hotPhys.pScreen->SetCursorPosition)(
+ pDev, pSprite->hotPhys.pScreen,
+ pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE);
+ }
+ }
+
+ ev->root_x = pSprite->hot.x;
+ ev->root_y = pSprite->hot.y;
+ }
+
+ newSpriteWin = XYToWindow(pSprite, pSprite->hot.x, pSprite->hot.y);
+
+ if (newSpriteWin != prevSpriteWin)
+ {
+ int sourceid;
+ if (!ev) {
+ UpdateCurrentTimeIf();
+ sourceid = pDev->id; /* when from WindowsRestructured */
+ } else
+ sourceid = ev->sourceid;
+
+ if (prevSpriteWin != NullWindow) {
+ if (!ActivateEnterGrab(pDev, prevSpriteWin, newSpriteWin))
+ DoEnterLeaveEvents(pDev, sourceid, prevSpriteWin,
+ newSpriteWin, NotifyNormal);
+ }
+ /* set pSprite->win after ActivateEnterGrab, otherwise
+ sprite window == grab_window and no enter/leave events are
+ sent. */
+ pSprite->win = newSpriteWin;
+ PostNewCursor(pDev);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Windows have restructured, we need to update the sprite position and the
+ * sprite's cursor.
+ */
+void
+WindowsRestructured(void)
+{
+ DeviceIntPtr pDev = inputInfo.devices;
+ while(pDev)
+ {
+ if (IsMaster(pDev) || !pDev->u.master)
+ CheckMotion(NULL, pDev);
+ pDev = pDev->next;
+ }
+}
+
+#ifdef PANORAMIX
+/* This was added to support reconfiguration under Xdmx. The problem is
+ * that if the 0th screen (i.e., screenInfo.screens[0]) is moved to an origin
+ * other than 0,0, the information in the private sprite structure must
+ * be updated accordingly, or XYToWindow (and other routines) will not
+ * compute correctly. */
+void ReinitializeRootWindow(WindowPtr win, int xoff, int yoff)
+{
+ GrabPtr grab;
+ DeviceIntPtr pDev;
+ SpritePtr pSprite;
+
+ if (noPanoramiXExtension) return;
+
+ pDev = inputInfo.devices;
+ while(pDev)
+ {
+ if (DevHasCursor(pDev))
+ {
+ pSprite = pDev->spriteInfo->sprite;
+ pSprite->hot.x -= xoff;
+ pSprite->hot.y -= yoff;
+
+ pSprite->hotPhys.x -= xoff;
+ pSprite->hotPhys.y -= yoff;
+
+ pSprite->hotLimits.x1 -= xoff;
+ pSprite->hotLimits.y1 -= yoff;
+ pSprite->hotLimits.x2 -= xoff;
+ pSprite->hotLimits.y2 -= yoff;
+
+ if (RegionNotEmpty(&pSprite->Reg1))
+ RegionTranslate(&pSprite->Reg1, xoff, yoff);
+ if (RegionNotEmpty(&pSprite->Reg2))
+ RegionTranslate(&pSprite->Reg2, xoff, yoff);
+
+ /* FIXME: if we call ConfineCursorToWindow, must we do anything else? */
+ if ((grab = pDev->deviceGrab.grab) && grab->confineTo) {
+ if (grab->confineTo->drawable.pScreen
+ != pSprite->hotPhys.pScreen)
+ pSprite->hotPhys.x = pSprite->hotPhys.y = 0;
+ ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE);
+ } else
+ ConfineCursorToWindow(
+ pDev,
+ pSprite->hotPhys.pScreen->root,
+ TRUE, FALSE);
+
+ }
+ pDev = pDev->next;
+ }
+}
+#endif
+
+/**
+ * Initialize a sprite for the given device and set it to some sane values. If
+ * the device already has a sprite alloc'd, don't realloc but just reset to
+ * default values.
+ * If a window is supplied, the sprite will be initialized with the window's
+ * cursor and positioned in the center of the window's screen. The root window
+ * is a good choice to pass in here.
+ *
+ * It's a good idea to call it only for pointer devices, unless you have a
+ * really talented keyboard.
+ *
+ * @param pDev The device to initialize.
+ * @param pWin The window where to generate the sprite in.
+ *
+ */
+void
+InitializeSprite(DeviceIntPtr pDev, WindowPtr pWin)
+{
+ SpritePtr pSprite;
+ ScreenPtr pScreen;
+ CursorPtr pCursor;
+
+ if (!pDev->spriteInfo->sprite)
+ {
+ DeviceIntPtr it;
+
+ pDev->spriteInfo->sprite = (SpritePtr)calloc(1, sizeof(SpriteRec));
+ if (!pDev->spriteInfo->sprite)
+ FatalError("InitializeSprite: failed to allocate sprite struct");
+
+ /* We may have paired another device with this device before our
+ * device had a actual sprite. We need to check for this and reset the
+ * sprite field for all paired devices.
+ *
+ * The VCK is always paired with the VCP before the VCP has a sprite.
+ */
+ for (it = inputInfo.devices; it; it = it->next)
+ {
+ if (it->spriteInfo->paired == pDev)
+ it->spriteInfo->sprite = pDev->spriteInfo->sprite;
+ }
+ if (inputInfo.keyboard->spriteInfo->paired == pDev)
+ inputInfo.keyboard->spriteInfo->sprite = pDev->spriteInfo->sprite;
+ }
+
+ pSprite = pDev->spriteInfo->sprite;
+ pDev->spriteInfo->spriteOwner = TRUE;
+
+ pScreen = (pWin) ? pWin->drawable.pScreen : (ScreenPtr)NULL;
+ pSprite->hot.pScreen = pScreen;
+ pSprite->hotPhys.pScreen = pScreen;
+ if (pScreen)
+ {
+ pSprite->hotPhys.x = pScreen->width / 2;
+ pSprite->hotPhys.y = pScreen->height / 2;
+ pSprite->hotLimits.x2 = pScreen->width;
+ pSprite->hotLimits.y2 = pScreen->height;
+ }
+
+ pSprite->hot = pSprite->hotPhys;
+ pSprite->win = pWin;
+
+ if (pWin)
+ {
+ pCursor = wCursor(pWin);
+ pSprite->spriteTrace = (WindowPtr *)calloc(1, 32*sizeof(WindowPtr));
+ if (!pSprite->spriteTrace)
+ FatalError("Failed to allocate spriteTrace");
+ pSprite->spriteTraceSize = 32;
+
+ RootWindow(pDev->spriteInfo->sprite) = pWin;
+ pSprite->spriteTraceGood = 1;
+
+ pSprite->pEnqueueScreen = pScreen;
+ pSprite->pDequeueScreen = pSprite->pEnqueueScreen;
+
+ } else {
+ pCursor = NullCursor;
+ pSprite->spriteTrace = NULL;
+ pSprite->spriteTraceSize = 0;
+ pSprite->spriteTraceGood = 0;
+ pSprite->pEnqueueScreen = screenInfo.screens[0];
+ pSprite->pDequeueScreen = pSprite->pEnqueueScreen;
+ }
+ if (pCursor)
+ pCursor->refcnt++;
+ if (pSprite->current)
+ FreeCursor(pSprite->current, None);
+ pSprite->current = pCursor;
+
+ if (pScreen)
+ {
+ (*pScreen->RealizeCursor) ( pDev, pScreen, pSprite->current);
+ (*pScreen->CursorLimits) ( pDev, pScreen, pSprite->current,
+ &pSprite->hotLimits, &pSprite->physLimits);
+ pSprite->confined = FALSE;
+
+ (*pScreen->ConstrainCursor) (pDev, pScreen,
+ &pSprite->physLimits);
+ (*pScreen->SetCursorPosition) (pDev, pScreen, pSprite->hot.x,
+ pSprite->hot.y,
+ FALSE);
+ (*pScreen->DisplayCursor) (pDev, pScreen, pSprite->current);
+ }
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension) {
+ pSprite->hotLimits.x1 = -screenInfo.screens[0]->x;
+ pSprite->hotLimits.y1 = -screenInfo.screens[0]->y;
+ pSprite->hotLimits.x2 = PanoramiXPixWidth - screenInfo.screens[0]->x;
+ pSprite->hotLimits.y2 = PanoramiXPixHeight - screenInfo.screens[0]->y;
+ pSprite->physLimits = pSprite->hotLimits;
+ pSprite->confineWin = NullWindow;
+ pSprite->hotShape = NullRegion;
+ pSprite->screen = pScreen;
+ /* gotta UNINIT these someplace */
+ RegionNull(&pSprite->Reg1);
+ RegionNull(&pSprite->Reg2);
+ }
+#endif
+}
+
+/**
+ * Update the mouse sprite info when the server switches from a pScreen to another.
+ * Otherwise, the pScreen of the mouse sprite is never updated when we switch
+ * from a pScreen to another. Never updating the pScreen of the mouse sprite
+ * implies that windows that are in pScreen whose pScreen->myNum >0 will never
+ * get pointer events. This is because in CheckMotion(), sprite.hotPhys.pScreen
+ * always points to the first pScreen it has been set by
+ * DefineInitialRootWindow().
+ *
+ * Calling this function is useful for use cases where the server
+ * has more than one pScreen.
+ * This function is similar to DefineInitialRootWindow() but it does not
+ * reset the mouse pointer position.
+ * @param win must be the new pScreen we are switching to.
+ */
+void
+UpdateSpriteForScreen(DeviceIntPtr pDev, ScreenPtr pScreen)
+{
+ SpritePtr pSprite = NULL;
+ WindowPtr win = NULL;
+ CursorPtr pCursor;
+ if (!pScreen)
+ return ;
+
+ if (!pDev->spriteInfo->sprite)
+ return;
+
+ pSprite = pDev->spriteInfo->sprite;
+
+ win = pScreen->root;
+
+ pSprite->hotPhys.pScreen = pScreen;
+ pSprite->hot = pSprite->hotPhys;
+ pSprite->hotLimits.x2 = pScreen->width;
+ pSprite->hotLimits.y2 = pScreen->height;
+ pSprite->win = win;
+ pCursor = wCursor(win);
+ if (pCursor)
+ pCursor->refcnt++;
+ if (pSprite->current)
+ FreeCursor(pSprite->current, 0);
+ pSprite->current = pCursor;
+ pSprite->spriteTraceGood = 1;
+ pSprite->spriteTrace[0] = win;
+ (*pScreen->CursorLimits) (pDev,
+ pScreen,
+ pSprite->current,
+ &pSprite->hotLimits,
+ &pSprite->physLimits);
+ pSprite->confined = FALSE;
+ (*pScreen->ConstrainCursor) (pDev, pScreen, &pSprite->physLimits);
+ (*pScreen->DisplayCursor) (pDev, pScreen, pSprite->current);
+
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension) {
+ pSprite->hotLimits.x1 = -screenInfo.screens[0]->x;
+ pSprite->hotLimits.y1 = -screenInfo.screens[0]->y;
+ pSprite->hotLimits.x2 = PanoramiXPixWidth - screenInfo.screens[0]->x;
+ pSprite->hotLimits.y2 = PanoramiXPixHeight - screenInfo.screens[0]->y;
+ pSprite->physLimits = pSprite->hotLimits;
+ pSprite->screen = pScreen;
+ }
+#endif
+}
+
+/*
+ * This does not take any shortcuts, and even ignores its argument, since
+ * it does not happen very often, and one has to walk up the tree since
+ * this might be a newly instantiated cursor for an intermediate window
+ * between the one the pointer is in and the one that the last cursor was
+ * instantiated from.
+ */
+void
+WindowHasNewCursor(WindowPtr pWin)
+{
+ DeviceIntPtr pDev;
+
+ for(pDev = inputInfo.devices; pDev; pDev = pDev->next)
+ if (DevHasCursor(pDev))
+ PostNewCursor(pDev);
+}
+
+void
+NewCurrentScreen(DeviceIntPtr pDev, ScreenPtr newScreen, int x, int y)
+{
+ SpritePtr pSprite = pDev->spriteInfo->sprite;
+
+ pSprite->hotPhys.x = x;
+ pSprite->hotPhys.y = y;
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension) {
+ pSprite->hotPhys.x += newScreen->x - screenInfo.screens[0]->x;
+ pSprite->hotPhys.y += newScreen->y - screenInfo.screens[0]->y;
+ if (newScreen != pSprite->screen) {
+ pSprite->screen = newScreen;
+ /* Make sure we tell the DDX to update its copy of the screen */
+ if(pSprite->confineWin)
+ XineramaConfineCursorToWindow(pDev,
+ pSprite->confineWin, TRUE);
+ else
+ XineramaConfineCursorToWindow(pDev, screenInfo.screens[0]->root, TRUE);
+ /* if the pointer wasn't confined, the DDX won't get
+ told of the pointer warp so we reposition it here */
+ if(!syncEvents.playingEvents)
+ (*pSprite->screen->SetCursorPosition)(
+ pDev,
+ pSprite->screen,
+ pSprite->hotPhys.x + screenInfo.screens[0]->x -
+ pSprite->screen->x,
+ pSprite->hotPhys.y + screenInfo.screens[0]->y -
+ pSprite->screen->y, FALSE);
+ }
+ } else
+#endif
+ if (newScreen != pSprite->hotPhys.pScreen)
+ ConfineCursorToWindow(pDev, newScreen->root, TRUE, FALSE);
+}
+
+#ifdef PANORAMIX
+
+static Bool
+XineramaPointInWindowIsVisible(
+ WindowPtr pWin,
+ int x,
+ int y
+)
+{
+ BoxRec box;
+ int i, xoff, yoff;
+
+ if (!pWin->realized) return FALSE;
+
+ if (RegionContainsPoint(&pWin->borderClip, x, y, &box))
+ return TRUE;
+
+ if(!XineramaSetWindowPntrs(inputInfo.pointer, pWin)) return FALSE;
+
+ xoff = x + screenInfo.screens[0]->x;
+ yoff = y + screenInfo.screens[0]->y;
+
+ for(i = 1; i < PanoramiXNumScreens; i++) {
+ pWin = inputInfo.pointer->spriteInfo->sprite->windows[i];
+ x = xoff - screenInfo.screens[i]->x;
+ y = yoff - screenInfo.screens[i]->y;
+
+ if(RegionContainsPoint(&pWin->borderClip, x, y, &box)
+ && (!wInputShape(pWin) ||
+ RegionContainsPoint(wInputShape(pWin),
+ x - pWin->drawable.x,
+ y - pWin->drawable.y, &box)))
+ return TRUE;
+
+ }
+
+ return FALSE;
+}
+
+static int
+XineramaWarpPointer(ClientPtr client)
+{
+ WindowPtr dest = NULL;
+ int x, y, rc;
+ SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite;
+
+ REQUEST(xWarpPointerReq);
+
+
+ if (stuff->dstWid != None) {
+ rc = dixLookupWindow(&dest, stuff->dstWid, client, DixReadAccess);
+ if (rc != Success)
+ return rc;
+ }
+ x = pSprite->hotPhys.x;
+ y = pSprite->hotPhys.y;
+
+ if (stuff->srcWid != None)
+ {
+ int winX, winY;
+ XID winID = stuff->srcWid;
+ WindowPtr source;
+
+ rc = dixLookupWindow(&source, winID, client, DixReadAccess);
+ if (rc != Success)
+ return rc;
+
+ winX = source->drawable.x;
+ winY = source->drawable.y;
+ if(source == screenInfo.screens[0]->root) {
+ winX -= screenInfo.screens[0]->x;
+ winY -= screenInfo.screens[0]->y;
+ }
+ if (x < winX + stuff->srcX ||
+ y < winY + stuff->srcY ||
+ (stuff->srcWidth != 0 &&
+ winX + stuff->srcX + (int)stuff->srcWidth < x) ||
+ (stuff->srcHeight != 0 &&
+ winY + stuff->srcY + (int)stuff->srcHeight < y) ||
+ !XineramaPointInWindowIsVisible(source, x, y))
+ return Success;
+ }
+ if (dest) {
+ x = dest->drawable.x;
+ y = dest->drawable.y;
+ if(dest == screenInfo.screens[0]->root) {
+ x -= screenInfo.screens[0]->x;
+ y -= screenInfo.screens[0]->y;
+ }
+ }
+
+ x += stuff->dstX;
+ y += stuff->dstY;
+
+ if (x < pSprite->physLimits.x1)
+ x = pSprite->physLimits.x1;
+ else if (x >= pSprite->physLimits.x2)
+ x = pSprite->physLimits.x2 - 1;
+ if (y < pSprite->physLimits.y1)
+ y = pSprite->physLimits.y1;
+ else if (y >= pSprite->physLimits.y2)
+ y = pSprite->physLimits.y2 - 1;
+ if (pSprite->hotShape)
+ ConfineToShape(PickPointer(client), pSprite->hotShape, &x, &y);
+
+ XineramaSetCursorPosition(PickPointer(client), x, y, TRUE);
+
+ return Success;
+}
+
+#endif
+
+
+/**
+ * Server-side protocol handling for WarpPointer request.
+ * Warps the cursor position to the coordinates given in the request.
+ */
+int
+ProcWarpPointer(ClientPtr client)
+{
+ WindowPtr dest = NULL;
+ int x, y, rc;
+ ScreenPtr newScreen;
+ DeviceIntPtr dev, tmp;
+ SpritePtr pSprite;
+
+ REQUEST(xWarpPointerReq);
+ REQUEST_SIZE_MATCH(xWarpPointerReq);
+
+ dev = PickPointer(client);
+
+ for (tmp = inputInfo.devices; tmp; tmp = tmp->next) {
+ if ((tmp == dev) || (!IsMaster(tmp) && tmp->u.master == dev)) {
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixWriteAccess);
+ if (rc != Success)
+ return rc;
+ }
+ }
+
+ if (dev->u.lastSlave)
+ dev = dev->u.lastSlave;
+ pSprite = dev->spriteInfo->sprite;
+
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension)
+ return XineramaWarpPointer(client);
+#endif
+
+ if (stuff->dstWid != None) {
+ rc = dixLookupWindow(&dest, stuff->dstWid, client, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+ }
+ x = pSprite->hotPhys.x;
+ y = pSprite->hotPhys.y;
+
+ if (stuff->srcWid != None)
+ {
+ int winX, winY;
+ XID winID = stuff->srcWid;
+ WindowPtr source;
+
+ rc = dixLookupWindow(&source, winID, client, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ winX = source->drawable.x;
+ winY = source->drawable.y;
+ if (source->drawable.pScreen != pSprite->hotPhys.pScreen ||
+ x < winX + stuff->srcX ||
+ y < winY + stuff->srcY ||
+ (stuff->srcWidth != 0 &&
+ winX + stuff->srcX + (int)stuff->srcWidth < x) ||
+ (stuff->srcHeight != 0 &&
+ winY + stuff->srcY + (int)stuff->srcHeight < y) ||
+ !PointInWindowIsVisible(source, x, y))
+ return Success;
+ }
+ if (dest)
+ {
+ x = dest->drawable.x;
+ y = dest->drawable.y;
+ newScreen = dest->drawable.pScreen;
+ } else
+ newScreen = pSprite->hotPhys.pScreen;
+
+ x += stuff->dstX;
+ y += stuff->dstY;
+
+ if (x < 0)
+ x = 0;
+ else if (x >= newScreen->width)
+ x = newScreen->width - 1;
+ if (y < 0)
+ y = 0;
+ else if (y >= newScreen->height)
+ y = newScreen->height - 1;
+
+ if (newScreen == pSprite->hotPhys.pScreen)
+ {
+ if (x < pSprite->physLimits.x1)
+ x = pSprite->physLimits.x1;
+ else if (x >= pSprite->physLimits.x2)
+ x = pSprite->physLimits.x2 - 1;
+ if (y < pSprite->physLimits.y1)
+ y = pSprite->physLimits.y1;
+ else if (y >= pSprite->physLimits.y2)
+ y = pSprite->physLimits.y2 - 1;
+ if (pSprite->hotShape)
+ ConfineToShape(dev, pSprite->hotShape, &x, &y);
+ (*newScreen->SetCursorPosition)(dev, newScreen, x, y, TRUE);
+ }
+ else if (!PointerConfinedToScreen(dev))
+ {
+ NewCurrentScreen(dev, newScreen, x, y);
+ }
+ return Success;
+}
+
+static Bool
+BorderSizeNotEmpty(DeviceIntPtr pDev, WindowPtr pWin)
+{
+ if(RegionNotEmpty(&pWin->borderSize))
+ return TRUE;
+
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension && XineramaSetWindowPntrs(pDev, pWin)) {
+ int i;
+
+ for(i = 1; i < PanoramiXNumScreens; i++) {
+ if(RegionNotEmpty(&pDev->spriteInfo->sprite->windows[i]->borderSize))
+ return TRUE;
+ }
+ }
+#endif
+ return FALSE;
+}
+
+/**
+ * "CheckPassiveGrabsOnWindow" checks to see if the event passed in causes a
+ * passive grab set on the window to be activated.
+ * If activate is true and a passive grab is found, it will be activated,
+ * and the event will be delivered to the client.
+ *
+ * @param pWin The window that may be subject to a passive grab.
+ * @param device Device that caused the event.
+ * @param event The current device event.
+ * @param checkCore Check for core grabs too.
+ * @param activate If a grab is found, activate it and deliver the event.
+ */
+
+GrabPtr
+CheckPassiveGrabsOnWindow(
+ WindowPtr pWin,
+ DeviceIntPtr device,
+ DeviceEvent *event,
+ BOOL checkCore,
+ BOOL activate)
+{
+ SpritePtr pSprite = device->spriteInfo->sprite;
+ GrabPtr grab = wPassiveGrabs(pWin);
+ GrabRec tempGrab;
+ GrabInfoPtr grabinfo;
+#define CORE_MATCH 0x1
+#define XI_MATCH 0x2
+#define XI2_MATCH 0x4
+ int match = 0;
+
+ if (!grab)
+ return NULL;
+ /* Fill out the grab details, but leave the type for later before
+ * comparing */
+ tempGrab.window = pWin;
+ tempGrab.device = device;
+ tempGrab.detail.exact = event->detail.key;
+ tempGrab.detail.pMask = NULL;
+ tempGrab.modifiersDetail.pMask = NULL;
+ tempGrab.next = NULL;
+ for (; grab; grab = grab->next)
+ {
+ DeviceIntPtr gdev;
+ XkbSrvInfoPtr xkbi = NULL;
+
+ gdev= grab->modifierDevice;
+ if (grab->grabtype == GRABTYPE_CORE)
+ {
+ if (IsPointerDevice(device))
+ gdev = GetPairedDevice(device);
+ else
+ gdev = device;
+ } else if (grab->grabtype == GRABTYPE_XI2)
+ {
+ /* if the device is an attached slave device, gdev must be the
+ * attached master keyboard. Since the slave may have been
+ * reattached after the grab, the modifier device may not be the
+ * same. */
+ if (!IsMaster(grab->device) && device->u.master)
+ gdev = GetMaster(device, MASTER_KEYBOARD);
+ }
+
+
+ if (gdev && gdev->key)
+ xkbi= gdev->key->xkbInfo;
+ tempGrab.modifierDevice = grab->modifierDevice;
+ tempGrab.modifiersDetail.exact = xkbi ? xkbi->state.grab_mods : 0;
+
+ /* Check for XI2 and XI grabs first */
+ tempGrab.type = GetXI2Type((InternalEvent*)event);
+ tempGrab.grabtype = GRABTYPE_XI2;
+ if (GrabMatchesSecond(&tempGrab, grab, FALSE))
+ match = XI2_MATCH;
+
+ tempGrab.detail.exact = event->detail.key;
+ if (!match)
+ {
+ tempGrab.grabtype = GRABTYPE_XI;
+ if ((tempGrab.type = GetXIType((InternalEvent*)event)) &&
+ (GrabMatchesSecond(&tempGrab, grab, FALSE)))
+ match = XI_MATCH;
+ }
+
+ /* Check for a core grab (ignore the device when comparing) */
+ if (!match && checkCore)
+ {
+ tempGrab.grabtype = GRABTYPE_CORE;
+ if ((tempGrab.type = GetCoreType((InternalEvent*)event)) &&
+ (GrabMatchesSecond(&tempGrab, grab, TRUE)))
+ match = CORE_MATCH;
+ }
+
+ if (match && (!grab->confineTo ||
+ (grab->confineTo->realized &&
+ BorderSizeNotEmpty(device, grab->confineTo))))
+ {
+ int rc, count = 0;
+ xEvent *xE = NULL;
+ xEvent core;
+
+ event->corestate &= 0x1f00;
+ event->corestate |= tempGrab.modifiersDetail.exact & (~0x1f00);
+ grabinfo = &device->deviceGrab;
+ /* In some cases a passive core grab may exist, but the client
+ * already has a core grab on some other device. In this case we
+ * must not get the grab, otherwise we may never ungrab the
+ * device.
+ */
+
+ if (grab->grabtype == GRABTYPE_CORE)
+ {
+ DeviceIntPtr other;
+ BOOL interfering = FALSE;
+
+ /* A passive grab may have been created for a different device
+ than it is assigned to at this point in time.
+ Update the grab's device and modifier device to reflect the
+ current state.
+ Since XGrabDeviceButton requires to specify the
+ modifierDevice explicitly, we don't override this choice.
+ */
+ if (tempGrab.type < GenericEvent)
+ {
+ grab->device = device;
+ grab->modifierDevice = GetPairedDevice(device);
+ }
+
+ for (other = inputInfo.devices; other; other = other->next)
+ {
+ GrabPtr othergrab = other->deviceGrab.grab;
+ if (othergrab && othergrab->grabtype == GRABTYPE_CORE &&
+ SameClient(grab, rClient(othergrab)) &&
+ ((IsPointerDevice(grab->device) &&
+ IsPointerDevice(othergrab->device)) ||
+ (IsKeyboardDevice(grab->device) &&
+ IsKeyboardDevice(othergrab->device))))
+ {
+ interfering = TRUE;
+ break;
+ }
+ }
+ if (interfering)
+ continue;
+ }
+
+ if (!activate)
+ return grab;
+
+ if (match & CORE_MATCH)
+ {
+ rc = EventToCore((InternalEvent*)event, &core);
+ if (rc != Success)
+ {
+ if (rc != BadMatch)
+ ErrorF("[dix] %s: core conversion failed in CPGFW "
+ "(%d, %d).\n", device->name, event->type, rc);
+ continue;
+ }
+ xE = &core;
+ count = 1;
+ } else if (match & XI2_MATCH)
+ {
+ rc = EventToXI2((InternalEvent*)event, &xE);
+ if (rc != Success)
+ {
+ if (rc != BadMatch)
+ ErrorF("[dix] %s: XI2 conversion failed in CPGFW "
+ "(%d, %d).\n", device->name, event->type, rc);
+ continue;
+ }
+ count = 1;
+ } else
+ {
+ rc = EventToXI((InternalEvent*)event, &xE, &count);
+ if (rc != Success)
+ {
+ if (rc != BadMatch)
+ ErrorF("[dix] %s: XI conversion failed in CPGFW "
+ "(%d, %d).\n", device->name, event->type, rc);
+ continue;
+ }
+ }
+
+ (*grabinfo->ActivateGrab)(device, grab, currentTime, TRUE);
+
+ if (xE)
+ {
+ FixUpEventFromWindow(pSprite, xE, grab->window, None, TRUE);
+
+ TryClientEvents(rClient(grab), device, xE, count,
+ GetEventFilter(device, xE),
+ GetEventFilter(device, xE), grab);
+ }
+
+ if (grabinfo->sync.state == FROZEN_NO_EVENT)
+ {
+ if (!grabinfo->sync.event)
+ grabinfo->sync.event = calloc(1, sizeof(InternalEvent));
+ *grabinfo->sync.event = *event;
+ grabinfo->sync.state = FROZEN_WITH_EVENT;
+ }
+
+ if (match & (XI_MATCH | XI2_MATCH))
+ free(xE); /* on core match xE == &core */
+ return grab;
+ }
+ }
+ return NULL;
+#undef CORE_MATCH
+#undef XI_MATCH
+#undef XI2_MATCH
+}
+
+/**
+ * CheckDeviceGrabs handles both keyboard and pointer events that may cause
+ * a passive grab to be activated.
+ *
+ * If the event is a keyboard event, the ancestors of the focus window are
+ * traced down and tried to see if they have any passive grabs to be
+ * activated. If the focus window itself is reached and it's descendants
+ * contain the pointer, the ancestors of the window that the pointer is in
+ * are then traced down starting at the focus window, otherwise no grabs are
+ * activated.
+ * If the event is a pointer event, the ancestors of the window that the
+ * pointer is in are traced down starting at the root until CheckPassiveGrabs
+ * causes a passive grab to activate or all the windows are
+ * tried. PRH
+ *
+ * If a grab is activated, the event has been sent to the client already!
+ *
+ * The event we pass in must always be an XI event. From this, we then emulate
+ * the core event and then check for grabs.
+ *
+ * @param device The device that caused the event.
+ * @param xE The event to handle (Device{Button|Key}Press).
+ * @param count Number of events in list.
+ * @return TRUE if a grab has been activated or false otherwise.
+*/
+
+Bool
+CheckDeviceGrabs(DeviceIntPtr device, DeviceEvent *event, WindowPtr ancestor)
+{
+ int i;
+ WindowPtr pWin = NULL;
+ FocusClassPtr focus = IsPointerEvent((InternalEvent*)event) ? NULL : device->focus;
+ BOOL sendCore = (IsMaster(device) && device->coreEvents);
+
+ if (event->type != ET_ButtonPress &&
+ event->type != ET_KeyPress)
+ return FALSE;
+
+ if (event->type == ET_ButtonPress
+ && (device->button->buttonsDown != 1))
+ return FALSE;
+
+ if (device->deviceGrab.grab)
+ return FALSE;
+
+ i = 0;
+ if (ancestor)
+ {
+ while (i < device->spriteInfo->sprite->spriteTraceGood)
+ if (device->spriteInfo->sprite->spriteTrace[i++] == ancestor)
+ break;
+ if (i == device->spriteInfo->sprite->spriteTraceGood)
+ return FALSE;
+ }
+
+ if (focus)
+ {
+ for (; i < focus->traceGood; i++)
+ {
+ pWin = focus->trace[i];
+ if (CheckPassiveGrabsOnWindow(pWin, device, event, sendCore, TRUE))
+ return TRUE;
+ }
+
+ if ((focus->win == NoneWin) ||
+ (i >= device->spriteInfo->sprite->spriteTraceGood) ||
+ (pWin && pWin != device->spriteInfo->sprite->spriteTrace[i-1]))
+ return FALSE;
+ }
+
+ for (; i < device->spriteInfo->sprite->spriteTraceGood; i++)
+ {
+ pWin = device->spriteInfo->sprite->spriteTrace[i];
+ if (CheckPassiveGrabsOnWindow(pWin, device, event, sendCore, TRUE))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * Called for keyboard events to deliver event to whatever client owns the
+ * focus.
+ *
+ * The event is delivered to the keyboard's focus window, the root window or
+ * to the window owning the input focus.
+ *
+ * @param keybd The keyboard originating the event.
+ * @param event The event, not yet in wire format.
+ * @param window Window underneath the sprite.
+ */
+void
+DeliverFocusedEvent(DeviceIntPtr keybd, InternalEvent *event, WindowPtr window)
+{
+ DeviceIntPtr ptr;
+ WindowPtr focus = keybd->focus->win;
+ BOOL sendCore = (IsMaster(keybd) && keybd->coreEvents);
+ xEvent core;
+ xEvent *xE = NULL, *xi2 = NULL;
+ int count, rc;
+ int deliveries = 0;
+
+ if (focus == FollowKeyboardWin)
+ focus = inputInfo.keyboard->focus->win;
+ if (!focus)
+ return;
+ if (focus == PointerRootWin)
+ {
+ DeliverDeviceEvents(window, event, NullGrab, NullWindow, keybd);
+ return;
+ }
+ if ((focus == window) || IsParent(focus, window))
+ {
+ if (DeliverDeviceEvents(window, event, NullGrab, focus, keybd))
+ return;
+ }
+
+ /* just deliver it to the focus window */
+ ptr = GetPairedDevice(keybd);
+
+
+ rc = EventToXI2(event, &xi2);
+ if (rc == Success)
+ {
+ /* XXX: XACE */
+ int filter = GetEventFilter(keybd, xi2);
+ FixUpEventFromWindow(ptr->spriteInfo->sprite, xi2, focus, None, FALSE);
+ deliveries = DeliverEventsToWindow(keybd, focus, xi2, 1,
+ filter, NullGrab);
+ if (deliveries > 0)
+ goto unwind;
+ } else if (rc != BadMatch)
+ ErrorF("[dix] %s: XI2 conversion failed in DFE (%d, %d). Skipping delivery.\n",
+ keybd->name, event->any.type, rc);
+
+ rc = EventToXI(event, &xE, &count);
+ if (rc == Success &&
+ XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, xE, count) == Success)
+ {
+ FixUpEventFromWindow(ptr->spriteInfo->sprite, xE, focus, None, FALSE);
+ deliveries = DeliverEventsToWindow(keybd, focus, xE, count,
+ GetEventFilter(keybd, xE),
+ NullGrab);
+
+ if (deliveries > 0)
+ goto unwind;
+ } else if (rc != BadMatch)
+ ErrorF("[dix] %s: XI conversion failed in DFE (%d, %d). Skipping delivery.\n",
+ keybd->name, event->any.type, rc);
+
+ if (sendCore)
+ {
+ rc = EventToCore(event, &core);
+ if (rc == Success) {
+ if (XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, &core, 1) == Success) {
+ FixUpEventFromWindow(keybd->spriteInfo->sprite, &core, focus,
+ None, FALSE);
+ deliveries = DeliverEventsToWindow(keybd, focus, &core, 1,
+ GetEventFilter(keybd, &core),
+ NullGrab);
+ }
+ } else if (rc != BadMatch)
+ ErrorF("[dix] %s: core conversion failed DFE (%d, %d). Skipping delivery.\n",
+ keybd->name, event->any.type, rc);
+ }
+
+unwind:
+ free(xE);
+ free(xi2);
+ return;
+}
+
+/**
+ * Deliver an event from a device that is currently grabbed. Uses
+ * DeliverDeviceEvents() for further delivery if a ownerEvents is set on the
+ * grab. If not, TryClientEvents() is used.
+ *
+ * @param deactivateGrab True if the device's grab should be deactivated.
+ */
+void
+DeliverGrabbedEvent(InternalEvent *event, DeviceIntPtr thisDev,
+ Bool deactivateGrab)
+{
+ GrabPtr grab;
+ GrabInfoPtr grabinfo;
+ int deliveries = 0;
+ DeviceIntPtr dev;
+ SpritePtr pSprite = thisDev->spriteInfo->sprite;
+ BOOL sendCore = FALSE;
+ int rc, count = 0;
+ xEvent *xi = NULL;
+ xEvent *xi2 = NULL;
+
+ grabinfo = &thisDev->deviceGrab;
+ grab = grabinfo->grab;
+
+ if (grab->ownerEvents)
+ {
+ WindowPtr focus;
+
+ /* Hack: Some pointer device have a focus class. So we need to check
+ * for the type of event, to see if we really want to deliver it to
+ * the focus window. For pointer events, the answer is no.
+ */
+ if (IsPointerEvent(event))
+ focus = PointerRootWin;
+ else if (thisDev->focus)
+ {
+ focus = thisDev->focus->win;
+ if (focus == FollowKeyboardWin)
+ focus = inputInfo.keyboard->focus->win;
+ }
+ else
+ focus = PointerRootWin;
+ if (focus == PointerRootWin)
+ deliveries = DeliverDeviceEvents(pSprite->win, event, grab,
+ NullWindow, thisDev);
+ else if (focus && (focus == pSprite->win ||
+ IsParent(focus, pSprite->win)))
+ deliveries = DeliverDeviceEvents(pSprite->win, event, grab, focus,
+ thisDev);
+ else if (focus)
+ deliveries = DeliverDeviceEvents(focus, event, grab, focus,
+ thisDev);
+ }
+ if (!deliveries)
+ {
+ Mask mask;
+
+ /* XXX: In theory, we could pass the internal events through to
+ * everything and only convert just before hitting the wire. We can't
+ * do that yet, so DGE is the last stop for internal events. From here
+ * onwards, we deal with core/XI events.
+ */
+
+ mask = grab->eventMask;
+
+ sendCore = (IsMaster(thisDev) && thisDev->coreEvents);
+ /* try core event */
+ if (sendCore && grab->grabtype == GRABTYPE_CORE)
+ {
+ xEvent core;
+
+ rc = EventToCore(event, &core);
+ if (rc == Success)
+ {
+ FixUpEventFromWindow(pSprite, &core, grab->window, None, TRUE);
+ if (XaceHook(XACE_SEND_ACCESS, 0, thisDev,
+ grab->window, &core, 1) ||
+ XaceHook(XACE_RECEIVE_ACCESS, rClient(grab),
+ grab->window, &core, 1))
+ deliveries = 1; /* don't send, but pretend we did */
+ else if (!IsInterferingGrab(rClient(grab), thisDev, &core))
+ {
+ deliveries = TryClientEvents(rClient(grab), thisDev,
+ &core, 1, mask,
+ GetEventFilter(thisDev, &core),
+ grab);
+ }
+ } else if (rc != BadMatch)
+ ErrorF("[dix] DeliverGrabbedEvent. Core conversion failed.\n");
+ }
+
+ if (!deliveries)
+ {
+ rc = EventToXI2(event, &xi2);
+ if (rc == Success)
+ {
+ int evtype = ((xGenericEvent*)xi2)->evtype;
+ mask = grab->xi2mask[XIAllDevices][evtype/8] |
+ grab->xi2mask[XIAllMasterDevices][evtype/8] |
+ grab->xi2mask[thisDev->id][evtype/8];
+ /* try XI2 event */
+ FixUpEventFromWindow(pSprite, xi2, grab->window, None, TRUE);
+ /* XXX: XACE */
+ deliveries = TryClientEvents(rClient(grab), thisDev, xi2, 1, mask,
+ GetEventFilter(thisDev, xi2), grab);
+ } else if (rc != BadMatch)
+ ErrorF("[dix] %s: XI2 conversion failed in DGE (%d, %d). Skipping delivery.\n",
+ thisDev->name, event->any.type, rc);
+ }
+
+ if (!deliveries)
+ {
+ rc = EventToXI(event, &xi, &count);
+ if (rc == Success)
+ {
+ /* try XI event */
+ if (grabinfo->fromPassiveGrab &&
+ grabinfo->implicitGrab)
+ mask = grab->deviceMask;
+ else
+ mask = grab->eventMask;
+
+ FixUpEventFromWindow(pSprite, xi, grab->window, None, TRUE);
+
+ if (XaceHook(XACE_SEND_ACCESS, 0, thisDev,
+ grab->window, xi, count) ||
+ XaceHook(XACE_RECEIVE_ACCESS, rClient(grab),
+ grab->window, xi, count))
+ deliveries = 1; /* don't send, but pretend we did */
+ else
+ {
+ deliveries =
+ TryClientEvents(rClient(grab), thisDev,
+ xi, count,
+ mask,
+ GetEventFilter(thisDev, xi),
+ grab);
+ }
+ } else if (rc != BadMatch)
+ ErrorF("[dix] %s: XI conversion failed in DGE (%d, %d). Skipping delivery.\n",
+ thisDev->name, event->any.type, rc);
+ }
+
+ if (deliveries && (event->any.type == ET_Motion))
+ thisDev->valuator->motionHintWindow = grab->window;
+ }
+ if (deliveries && !deactivateGrab && event->any.type != ET_Motion)
+ {
+ switch (grabinfo->sync.state)
+ {
+ case FREEZE_BOTH_NEXT_EVENT:
+ dev = GetPairedDevice(thisDev);
+ if (dev)
+ {
+ FreezeThaw(dev, TRUE);
+ if ((dev->deviceGrab.sync.state == FREEZE_BOTH_NEXT_EVENT) &&
+ (CLIENT_BITS(grab->resource) ==
+ CLIENT_BITS(dev->deviceGrab.grab->resource)))
+ dev->deviceGrab.sync.state = FROZEN_NO_EVENT;
+ else
+ dev->deviceGrab.sync.other = grab;
+ }
+ /* fall through */
+ case FREEZE_NEXT_EVENT:
+ grabinfo->sync.state = FROZEN_WITH_EVENT;
+ FreezeThaw(thisDev, TRUE);
+ if (!grabinfo->sync.event)
+ grabinfo->sync.event = calloc(1, sizeof(InternalEvent));
+ *grabinfo->sync.event = event->device_event;
+ break;
+ }
+ }
+
+ free(xi);
+ free(xi2);
+}
+
+/* This function is used to set the key pressed or key released state -
+ this is only used when the pressing of keys does not cause
+ the device's processInputProc to be called, as in for example Mouse Keys.
+*/
+void
+FixKeyState (DeviceEvent *event, DeviceIntPtr keybd)
+{
+ int key = event->detail.key;
+
+ if (event->type == ET_KeyPress) {
+ DebugF("FixKeyState: Key %d %s\n",key,
+ ((event->type == ET_KeyPress) ? "down" : "up"));
+ }
+
+ if (event->type == ET_KeyPress)
+ set_key_down(keybd, key, KEY_PROCESSED);
+ else if (event->type == ET_KeyRelease)
+ set_key_up(keybd, key, KEY_PROCESSED);
+ else
+ FatalError("Impossible keyboard event");
+}
+
+#define AtMostOneClient \
+ (SubstructureRedirectMask | ResizeRedirectMask | ButtonPressMask)
+#define ManagerMask \
+ (SubstructureRedirectMask | ResizeRedirectMask)
+
+/**
+ * Recalculate which events may be deliverable for the given window.
+ * Recalculated mask is used for quicker determination which events may be
+ * delivered to a window.
+ *
+ * The otherEventMasks on a WindowOptional is the combination of all event
+ * masks set by all clients on the window.
+ * deliverableEventMask is the combination of the eventMask and the
+ * otherEventMask plus the events that may be propagated to the parent.
+ *
+ * Traverses to siblings and parents of the window.
+ */
+void
+RecalculateDeliverableEvents(WindowPtr pWin)
+{
+ OtherClients *others;
+ WindowPtr pChild;
+
+ pChild = pWin;
+ while (1)
+ {
+ if (pChild->optional)
+ {
+ pChild->optional->otherEventMasks = 0;
+ for (others = wOtherClients(pChild); others; others = others->next)
+ {
+ pChild->optional->otherEventMasks |= others->mask;
+ }
+ }
+ pChild->deliverableEvents = pChild->eventMask|
+ wOtherEventMasks(pChild);
+ if (pChild->parent)
+ pChild->deliverableEvents |=
+ (pChild->parent->deliverableEvents &
+ ~wDontPropagateMask(pChild) & PropagateMask);
+ if (pChild->firstChild)
+ {
+ pChild = pChild->firstChild;
+ continue;
+ }
+ while (!pChild->nextSib && (pChild != pWin))
+ pChild = pChild->parent;
+ if (pChild == pWin)
+ break;
+ pChild = pChild->nextSib;
+ }
+}
+
+/**
+ *
+ * \param value must conform to DeleteType
+ */
+int
+OtherClientGone(pointer value, XID id)
+{
+ OtherClientsPtr other, prev;
+ WindowPtr pWin = (WindowPtr)value;
+
+ prev = 0;
+ for (other = wOtherClients(pWin); other; other = other->next)
+ {
+ if (other->resource == id)
+ {
+ if (prev)
+ prev->next = other->next;
+ else
+ {
+ if (!(pWin->optional->otherClients = other->next))
+ CheckWindowOptionalNeed (pWin);
+ }
+ free(other);
+ RecalculateDeliverableEvents(pWin);
+ return Success;
+ }
+ prev = other;
+ }
+ FatalError("client not on event list");
+ /*NOTREACHED*/
+ return -1; /* make compiler happy */
+}
+
+int
+EventSelectForWindow(WindowPtr pWin, ClientPtr client, Mask mask)
+{
+ Mask check;
+ OtherClients * others;
+ DeviceIntPtr dev;
+ int rc;
+
+ if (mask & ~AllEventMasks)
+ {
+ client->errorValue = mask;
+ return BadValue;
+ }
+ check = (mask & ManagerMask);
+ if (check) {
+ rc = XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id,
+ RT_WINDOW, pWin, RT_NONE, NULL, DixManageAccess);
+ if (rc != Success)
+ return rc;
+ }
+ check = (mask & AtMostOneClient);
+ if (check & (pWin->eventMask|wOtherEventMasks(pWin)))
+ { /* It is illegal for two different
+ clients to select on any of the
+ events for AtMostOneClient. However,
+ it is OK, for some client to
+ continue selecting on one of those
+ events. */
+ if ((wClient(pWin) != client) && (check & pWin->eventMask))
+ return BadAccess;
+ for (others = wOtherClients (pWin); others; others = others->next)
+ {
+ if (!SameClient(others, client) && (check & others->mask))
+ return BadAccess;
+ }
+ }
+ if (wClient (pWin) == client)
+ {
+ check = pWin->eventMask;
+ pWin->eventMask = mask;
+ }
+ else
+ {
+ for (others = wOtherClients (pWin); others; others = others->next)
+ {
+ if (SameClient(others, client))
+ {
+ check = others->mask;
+ if (mask == 0)
+ {
+ FreeResource(others->resource, RT_NONE);
+ return Success;
+ }
+ else
+ others->mask = mask;
+ goto maskSet;
+ }
+ }
+ check = 0;
+ if (!pWin->optional && !MakeWindowOptional (pWin))
+ return BadAlloc;
+ others = malloc(sizeof(OtherClients));
+ if (!others)
+ return BadAlloc;
+ others->mask = mask;
+ others->resource = FakeClientID(client->index);
+ others->next = pWin->optional->otherClients;
+ pWin->optional->otherClients = others;
+ if (!AddResource(others->resource, RT_OTHERCLIENT, (pointer)pWin))
+ return BadAlloc;
+ }
+maskSet:
+ if ((mask & PointerMotionHintMask) && !(check & PointerMotionHintMask))
+ {
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ {
+ if (dev->valuator && dev->valuator->motionHintWindow == pWin)
+ dev->valuator->motionHintWindow = NullWindow;
+ }
+ }
+ RecalculateDeliverableEvents(pWin);
+ return Success;
+}
+
+int
+EventSuppressForWindow(WindowPtr pWin, ClientPtr client,
+ Mask mask, Bool *checkOptional)
+{
+ int i, free;
+
+ if (mask & ~PropagateMask)
+ {
+ client->errorValue = mask;
+ return BadValue;
+ }
+ if (pWin->dontPropagate)
+ DontPropagateRefCnts[pWin->dontPropagate]--;
+ if (!mask)
+ i = 0;
+ else
+ {
+ for (i = DNPMCOUNT, free = 0; --i > 0; )
+ {
+ if (!DontPropagateRefCnts[i])
+ free = i;
+ else if (mask == DontPropagateMasks[i])
+ break;
+ }
+ if (!i && free)
+ {
+ i = free;
+ DontPropagateMasks[i] = mask;
+ }
+ }
+ if (i || !mask)
+ {
+ pWin->dontPropagate = i;
+ if (i)
+ DontPropagateRefCnts[i]++;
+ if (pWin->optional)
+ {
+ pWin->optional->dontPropagateMask = mask;
+ *checkOptional = TRUE;
+ }
+ }
+ else
+ {
+ if (!pWin->optional && !MakeWindowOptional (pWin))
+ {
+ if (pWin->dontPropagate)
+ DontPropagateRefCnts[pWin->dontPropagate]++;
+ return BadAlloc;
+ }
+ pWin->dontPropagate = 0;
+ pWin->optional->dontPropagateMask = mask;
+ }
+ RecalculateDeliverableEvents(pWin);
+ return Success;
+}
+
+/**
+ * Assembles an EnterNotify or LeaveNotify and sends it event to the client.
+ * Uses the paired keyboard to get some additional information.
+ */
+void
+CoreEnterLeaveEvent(
+ DeviceIntPtr mouse,
+ int type,
+ int mode,
+ int detail,
+ WindowPtr pWin,
+ Window child)
+{
+ xEvent event;
+ WindowPtr focus;
+ DeviceIntPtr keybd;
+ GrabPtr grab = mouse->deviceGrab.grab;
+ Mask mask;
+
+ keybd = GetPairedDevice(mouse);
+
+ if ((pWin == mouse->valuator->motionHintWindow) &&
+ (detail != NotifyInferior))
+ mouse->valuator->motionHintWindow = NullWindow;
+ if (grab)
+ {
+ mask = (pWin == grab->window) ? grab->eventMask : 0;
+ if (grab->ownerEvents)
+ mask |= EventMaskForClient(pWin, rClient(grab));
+ }
+ else
+ {
+ mask = pWin->eventMask | wOtherEventMasks(pWin);
+ }
+
+ memset(&event, 0, sizeof(xEvent));
+ event.u.u.type = type;
+ event.u.u.detail = detail;
+ event.u.enterLeave.time = currentTime.milliseconds;
+ event.u.enterLeave.rootX = mouse->spriteInfo->sprite->hot.x;
+ event.u.enterLeave.rootY = mouse->spriteInfo->sprite->hot.y;
+ /* Counts on the same initial structure of crossing & button events! */
+ FixUpEventFromWindow(mouse->spriteInfo->sprite, &event, pWin, None, FALSE);
+ /* Enter/Leave events always set child */
+ event.u.enterLeave.child = child;
+ event.u.enterLeave.flags = event.u.keyButtonPointer.sameScreen ?
+ ELFlagSameScreen : 0;
+ event.u.enterLeave.state = mouse->button ? (mouse->button->state & 0x1f00) : 0;
+ if (keybd)
+ event.u.enterLeave.state |=
+ XkbGrabStateFromRec(&keybd->key->xkbInfo->state);
+ event.u.enterLeave.mode = mode;
+ focus = (keybd) ? keybd->focus->win : None;
+ if ((focus != NoneWin) &&
+ ((pWin == focus) || (focus == PointerRootWin) ||
+ IsParent(focus, pWin)))
+ event.u.enterLeave.flags |= ELFlagFocus;
+
+ if ((mask & GetEventFilter(mouse, &event)))
+ {
+ if (grab)
+ TryClientEvents(rClient(grab), mouse, &event, 1, mask,
+ GetEventFilter(mouse, &event), grab);
+ else
+ DeliverEventsToWindow(mouse, pWin, &event, 1,
+ GetEventFilter(mouse, &event),
+ NullGrab);
+ }
+
+ if ((type == EnterNotify) && (mask & KeymapStateMask))
+ {
+ xKeymapEvent ke;
+ ClientPtr client = grab ? rClient(grab) : wClient(pWin);
+ if (XaceHook(XACE_DEVICE_ACCESS, client, keybd, DixReadAccess))
+ memset((char *)&ke.map[0], 0, 31);
+ else
+ memmove((char *)&ke.map[0], (char *)&keybd->key->down[1], 31);
+
+ ke.type = KeymapNotify;
+ if (grab)
+ TryClientEvents(rClient(grab), keybd, (xEvent *)&ke, 1,
+ mask, KeymapStateMask, grab);
+ else
+ DeliverEventsToWindow(mouse, pWin, (xEvent *)&ke, 1,
+ KeymapStateMask, NullGrab);
+ }
+}
+
+void
+DeviceEnterLeaveEvent(
+ DeviceIntPtr mouse,
+ int sourceid,
+ int type,
+ int mode,
+ int detail,
+ WindowPtr pWin,
+ Window child)
+{
+ GrabPtr grab = mouse->deviceGrab.grab;
+ xXIEnterEvent *event;
+ int filter;
+ int btlen, len, i;
+ DeviceIntPtr kbd;
+
+ if ((mode == XINotifyPassiveGrab && type == XI_Leave) ||
+ (mode == XINotifyPassiveUngrab && type == XI_Enter))
+ return;
+
+ btlen = (mouse->button) ? bits_to_bytes(mouse->button->numButtons) : 0;
+ btlen = bytes_to_int32(btlen);
+ len = sizeof(xXIEnterEvent) + btlen * 4;
+
+ event = calloc(1, len);
+ event->type = GenericEvent;
+ event->extension = IReqCode;
+ event->evtype = type;
+ event->length = (len - sizeof(xEvent))/4;
+ event->buttons_len = btlen;
+ event->detail = detail;
+ event->time = currentTime.milliseconds;
+ event->deviceid = mouse->id;
+ event->sourceid = sourceid;
+ event->mode = mode;
+ event->root_x = FP1616(mouse->spriteInfo->sprite->hot.x, 0);
+ event->root_y = FP1616(mouse->spriteInfo->sprite->hot.y, 0);
+
+ for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++)
+ if (BitIsOn(mouse->button->down, i))
+ SetBit(&event[1], i);
+
+ kbd = (IsMaster(mouse) || mouse->u.master) ? GetPairedDevice(mouse) : NULL;
+ if (kbd && kbd->key)
+ {
+ event->mods.base_mods = kbd->key->xkbInfo->state.base_mods;
+ event->mods.latched_mods = kbd->key->xkbInfo->state.latched_mods;
+ event->mods.locked_mods = kbd->key->xkbInfo->state.locked_mods;
+
+ event->group.base_group = kbd->key->xkbInfo->state.base_group;
+ event->group.latched_group = kbd->key->xkbInfo->state.latched_group;
+ event->group.locked_group = kbd->key->xkbInfo->state.locked_group;
+ }
+
+ FixUpEventFromWindow(mouse->spriteInfo->sprite, (xEvent*)event, pWin,
+ None, FALSE);
+
+ filter = GetEventFilter(mouse, (xEvent*)event);
+
+ if (grab)
+ {
+ Mask mask;
+ mask = grab->xi2mask[XIAllDevices][type/8] |
+ grab->xi2mask[XIAllMasterDevices][type/8] |
+ grab->xi2mask[mouse->id][type/8];
+ TryClientEvents(rClient(grab), mouse, (xEvent*)event, 1, mask,
+ filter, grab);
+ } else {
+ if (!GetWindowXI2Mask(mouse, pWin, (xEvent*)event))
+ goto out;
+ DeliverEventsToWindow(mouse, pWin, (xEvent*)event, 1, filter,
+ NullGrab);
+ }
+
+out:
+ free(event);
+}
+
+void
+CoreFocusEvent(DeviceIntPtr dev, int type, int mode, int detail, WindowPtr pWin)
+{
+ xEvent event;
+
+ memset(&event, 0, sizeof(xEvent));
+ event.u.focus.mode = mode;
+ event.u.u.type = type;
+ event.u.u.detail = detail;
+ event.u.focus.window = pWin->drawable.id;
+
+ DeliverEventsToWindow(dev, pWin, &event, 1,
+ GetEventFilter(dev, &event), NullGrab);
+ if ((type == FocusIn) &&
+ ((pWin->eventMask | wOtherEventMasks(pWin)) & KeymapStateMask))
+ {
+ xKeymapEvent ke;
+ ClientPtr client = wClient(pWin);
+ if (XaceHook(XACE_DEVICE_ACCESS, client, dev, DixReadAccess))
+ memset((char *)&ke.map[0], 0, 31);
+ else
+ memmove((char *)&ke.map[0], (char *)&dev->key->down[1], 31);
+
+ ke.type = KeymapNotify;
+ DeliverEventsToWindow(dev, pWin, (xEvent *)&ke, 1,
+ KeymapStateMask, NullGrab);
+ }
+}
+
+/**
+ * Set the input focus to the given window. Subsequent keyboard events will be
+ * delivered to the given window.
+ *
+ * Usually called from ProcSetInputFocus as result of a client request. If so,
+ * the device is the inputInfo.keyboard.
+ * If called from ProcXSetInputFocus as result of a client xinput request, the
+ * device is set to the device specified by the client.
+ *
+ * @param client Client that requested input focus change.
+ * @param dev Focus device.
+ * @param focusID The window to obtain the focus. Can be PointerRoot or None.
+ * @param revertTo Specifies where the focus reverts to when window becomes
+ * unviewable.
+ * @param ctime Specifies the time.
+ * @param followOK True if pointer is allowed to follow the keyboard.
+ */
+int
+SetInputFocus(
+ ClientPtr client,
+ DeviceIntPtr dev,
+ Window focusID,
+ CARD8 revertTo,
+ Time ctime,
+ Bool followOK)
+{
+ FocusClassPtr focus;
+ WindowPtr focusWin;
+ int mode, rc;
+ TimeStamp time;
+ DeviceIntPtr keybd; /* used for FollowKeyboard or FollowKeyboardWin */
+
+
+ UpdateCurrentTime();
+ if ((revertTo != RevertToParent) &&
+ (revertTo != RevertToPointerRoot) &&
+ (revertTo != RevertToNone) &&
+ ((revertTo != RevertToFollowKeyboard) || !followOK))
+ {
+ client->errorValue = revertTo;
+ return BadValue;
+ }
+ time = ClientTimeToServerTime(ctime);
+
+ if (IsKeyboardDevice(dev))
+ keybd = dev;
+ else
+ keybd = GetPairedDevice(dev);
+
+ if ((focusID == None) || (focusID == PointerRoot))
+ focusWin = (WindowPtr)(long)focusID;
+ else if ((focusID == FollowKeyboard) && followOK)
+ {
+ focusWin = keybd->focus->win;
+ }
+ else {
+ rc = dixLookupWindow(&focusWin, focusID, client, DixSetAttrAccess);
+ if (rc != Success)
+ return rc;
+ /* It is a match error to try to set the input focus to an
+ unviewable window. */
+ if(!focusWin->realized)
+ return BadMatch;
+ }
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixSetFocusAccess);
+ if (rc != Success)
+ return Success;
+
+ focus = dev->focus;
+ if ((CompareTimeStamps(time, currentTime) == LATER) ||
+ (CompareTimeStamps(time, focus->time) == EARLIER))
+ return Success;
+ mode = (dev->deviceGrab.grab) ? NotifyWhileGrabbed : NotifyNormal;
+ if (focus->win == FollowKeyboardWin)
+ {
+ if (!ActivateFocusInGrab(dev, keybd->focus->win, focusWin))
+ DoFocusEvents(dev, keybd->focus->win, focusWin, mode);
+ } else
+ {
+ if (!ActivateFocusInGrab(dev, focus->win, focusWin))
+ DoFocusEvents(dev, focus->win, focusWin, mode);
+ }
+ focus->time = time;
+ focus->revert = revertTo;
+ if (focusID == FollowKeyboard)
+ focus->win = FollowKeyboardWin;
+ else
+ focus->win = focusWin;
+ if ((focusWin == NoneWin) || (focusWin == PointerRootWin))
+ focus->traceGood = 0;
+ else
+ {
+ int depth = 0;
+ WindowPtr pWin;
+
+ for (pWin = focusWin; pWin; pWin = pWin->parent) depth++;
+ if (depth > focus->traceSize)
+ {
+ focus->traceSize = depth+1;
+ focus->trace = realloc(focus->trace,
+ focus->traceSize * sizeof(WindowPtr));
+ }
+ focus->traceGood = depth;
+ for (pWin = focusWin, depth--; pWin; pWin = pWin->parent, depth--)
+ focus->trace[depth] = pWin;
+ }
+ return Success;
+}
+
+/**
+ * Server-side protocol handling for SetInputFocus request.
+ *
+ * Sets the input focus for the virtual core keyboard.
+ */
+int
+ProcSetInputFocus(ClientPtr client)
+{
+ DeviceIntPtr kbd = PickKeyboard(client);
+ REQUEST(xSetInputFocusReq);
+
+ REQUEST_SIZE_MATCH(xSetInputFocusReq);
+
+ return SetInputFocus(client, kbd, stuff->focus,
+ stuff->revertTo, stuff->time, FALSE);
+}
+
+/**
+ * Server-side protocol handling for GetInputFocus request.
+ *
+ * Sends the current input focus for the client's keyboard back to the
+ * client.
+ */
+int
+ProcGetInputFocus(ClientPtr client)
+{
+ DeviceIntPtr kbd = PickKeyboard(client);
+ xGetInputFocusReply rep;
+ FocusClassPtr focus = kbd->focus;
+ int rc;
+ /* REQUEST(xReq); */
+ REQUEST_SIZE_MATCH(xReq);
+
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetFocusAccess);
+ if (rc != Success)
+ return rc;
+
+ memset(&rep, 0, sizeof(xGetInputFocusReply));
+ rep.type = X_Reply;
+ rep.length = 0;
+ rep.sequenceNumber = client->sequence;
+ if (focus->win == NoneWin)
+ rep.focus = None;
+ else if (focus->win == PointerRootWin)
+ rep.focus = PointerRoot;
+ else rep.focus = focus->win->drawable.id;
+ rep.revertTo = focus->revert;
+ WriteReplyToClient(client, sizeof(xGetInputFocusReply), &rep);
+ return Success;
+}
+
+/**
+ * Server-side protocol handling for GrabPointer request.
+ *
+ * Sets an active grab on the client's ClientPointer and returns success
+ * status to client.
+ */
+int
+ProcGrabPointer(ClientPtr client)
+{
+ xGrabPointerReply rep;
+ DeviceIntPtr device = PickPointer(client);
+ GrabPtr grab;
+ GrabMask mask;
+ WindowPtr confineTo;
+ CursorPtr oldCursor;
+ REQUEST(xGrabPointerReq);
+ TimeStamp time;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xGrabPointerReq);
+ UpdateCurrentTime();
+
+ if (stuff->eventMask & ~PointerGrabMask)
+ {
+ client->errorValue = stuff->eventMask;
+ return BadValue;
+ }
+
+ if (stuff->confineTo == None)
+ confineTo = NullWindow;
+ else
+ {
+ rc = dixLookupWindow(&confineTo, stuff->confineTo, client,
+ DixSetAttrAccess);
+ if (rc != Success)
+ return rc;
+ }
+
+ memset(&rep, 0, sizeof(xGrabPointerReply));
+ oldCursor = NullCursor;
+ grab = device->deviceGrab.grab;
+
+ if (grab)
+ {
+ if (grab->confineTo && !confineTo)
+ ConfineCursorToWindow(device, GetCurrentRootWindow(device), FALSE,
+ FALSE);
+ oldCursor = grab->cursor;
+ }
+
+ mask.core = stuff->eventMask;
+
+ rc = GrabDevice(client, device, stuff->pointerMode, stuff->keyboardMode,
+ stuff->grabWindow, stuff->ownerEvents, stuff->time,
+ &mask, GRABTYPE_CORE, stuff->cursor,
+ stuff->confineTo, &rep.status);
+ if (rc != Success)
+ return rc;
+
+ if (oldCursor && rep.status == GrabSuccess)
+ FreeCursor (oldCursor, (Cursor)0);
+
+ time = ClientTimeToServerTime(stuff->time);
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ rep.length = 0;
+ WriteReplyToClient(client, sizeof(xGrabPointerReply), &rep);
+ return Success;
+}
+
+/**
+ * Server-side protocol handling for ChangeActivePointerGrab request.
+ *
+ * Changes properties of the grab hold by the client. If the client does not
+ * hold an active grab on the device, nothing happens.
+ */
+int
+ProcChangeActivePointerGrab(ClientPtr client)
+{
+ DeviceIntPtr device;
+ GrabPtr grab;
+ CursorPtr newCursor, oldCursor;
+ REQUEST(xChangeActivePointerGrabReq);
+ TimeStamp time;
+
+ REQUEST_SIZE_MATCH(xChangeActivePointerGrabReq);
+ if (stuff->eventMask & ~PointerGrabMask)
+ {
+ client->errorValue = stuff->eventMask;
+ return BadValue;
+ }
+ if (stuff->cursor == None)
+ newCursor = NullCursor;
+ else
+ {
+ int rc = dixLookupResourceByType((pointer *)&newCursor, stuff->cursor,
+ RT_CURSOR, client, DixUseAccess);
+ if (rc != Success)
+ {
+ client->errorValue = stuff->cursor;
+ return rc;
+ }
+ }
+
+ device = PickPointer(client);
+ grab = device->deviceGrab.grab;
+
+ if (!grab)
+ return Success;
+ if (!SameClient(grab, client))
+ return Success;
+ time = ClientTimeToServerTime(stuff->time);
+ if ((CompareTimeStamps(time, currentTime) == LATER) ||
+ (CompareTimeStamps(time, device->deviceGrab.grabTime) == EARLIER))
+ return Success;
+ oldCursor = grab->cursor;
+ grab->cursor = newCursor;
+ if (newCursor)
+ newCursor->refcnt++;
+ PostNewCursor(device);
+ if (oldCursor)
+ FreeCursor(oldCursor, (Cursor)0);
+ grab->eventMask = stuff->eventMask;
+ return Success;
+}
+
+/**
+ * Server-side protocol handling for UngrabPointer request.
+ *
+ * Deletes a pointer grab on a device the client has grabbed.
+ */
+int
+ProcUngrabPointer(ClientPtr client)
+{
+ DeviceIntPtr device = PickPointer(client);
+ GrabPtr grab;
+ TimeStamp time;
+ REQUEST(xResourceReq);
+
+ REQUEST_SIZE_MATCH(xResourceReq);
+ UpdateCurrentTime();
+ grab = device->deviceGrab.grab;
+
+ time = ClientTimeToServerTime(stuff->id);
+ if ((CompareTimeStamps(time, currentTime) != LATER) &&
+ (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) &&
+ (grab) && SameClient(grab, client))
+ (*device->deviceGrab.DeactivateGrab)(device);
+ return Success;
+}
+
+/**
+ * Sets a grab on the given device.
+ *
+ * Called from ProcGrabKeyboard to work on the client's keyboard.
+ * Called from ProcXGrabDevice to work on the device specified by the client.
+ *
+ * The parameters this_mode and other_mode represent the keyboard_mode and
+ * pointer_mode parameters of XGrabKeyboard().
+ * See man page for details on all the parameters
+ *
+ * @param client Client that owns the grab.
+ * @param dev The device to grab.
+ * @param this_mode GrabModeSync or GrabModeAsync
+ * @param other_mode GrabModeSync or GrabModeAsync
+ * @param status Return code to be returned to the caller.
+ *
+ * @returns Success or BadValue.
+ */
+int
+GrabDevice(ClientPtr client, DeviceIntPtr dev,
+ unsigned pointer_mode, unsigned keyboard_mode, Window grabWindow,
+ unsigned ownerEvents, Time ctime, GrabMask *mask,
+ int grabtype, Cursor curs, Window confineToWin, CARD8 *status)
+{
+ WindowPtr pWin, confineTo;
+ GrabPtr grab;
+ TimeStamp time;
+ Mask access_mode = DixGrabAccess;
+ int rc;
+ GrabInfoPtr grabInfo = &dev->deviceGrab;
+ CursorPtr cursor;
+
+ UpdateCurrentTime();
+ if ((keyboard_mode != GrabModeSync) && (keyboard_mode != GrabModeAsync))
+ {
+ client->errorValue = keyboard_mode;
+ return BadValue;
+ }
+ if ((pointer_mode != GrabModeSync) && (pointer_mode != GrabModeAsync))
+ {
+ client->errorValue = pointer_mode;
+ return BadValue;
+ }
+ if ((ownerEvents != xFalse) && (ownerEvents != xTrue))
+ {
+ client->errorValue = ownerEvents;
+ return BadValue;
+ }
+
+ rc = dixLookupWindow(&pWin, grabWindow, client, DixSetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ if (confineToWin == None)
+ confineTo = NullWindow;
+ else
+ {
+ rc = dixLookupWindow(&confineTo, confineToWin, client,
+ DixSetAttrAccess);
+ if (rc != Success)
+ return rc;
+ }
+
+ if (curs == None)
+ cursor = NullCursor;
+ else
+ {
+ rc = dixLookupResourceByType((pointer *)&cursor, curs, RT_CURSOR,
+ client, DixUseAccess);
+ if (rc != Success)
+ {
+ client->errorValue = curs;
+ return rc;
+ }
+ access_mode |= DixForceAccess;
+ }
+
+ if (keyboard_mode == GrabModeSync || pointer_mode == GrabModeSync)
+ access_mode |= DixFreezeAccess;
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode);
+ if (rc != Success)
+ return rc;
+
+ time = ClientTimeToServerTime(ctime);
+ grab = grabInfo->grab;
+ if (grab && grab->grabtype != grabtype)
+ *status = AlreadyGrabbed;
+ if (grab && !SameClient(grab, client))
+ *status = AlreadyGrabbed;
+ else if ((!pWin->realized) ||
+ (confineTo &&
+ !(confineTo->realized
+ && BorderSizeNotEmpty(dev, confineTo))))
+ *status = GrabNotViewable;
+ else if ((CompareTimeStamps(time, currentTime) == LATER) ||
+ (CompareTimeStamps(time, grabInfo->grabTime) == EARLIER))
+ *status = GrabInvalidTime;
+ else if (grabInfo->sync.frozen &&
+ grabInfo->sync.other && !SameClient(grabInfo->sync.other, client))
+ *status = GrabFrozen;
+ else
+ {
+ GrabRec tempGrab;
+
+ /* Otherwise segfaults happen on grabbed MPX devices */
+ memset(&tempGrab, 0, sizeof(GrabRec));
+
+ tempGrab.next = NULL;
+ tempGrab.window = pWin;
+ tempGrab.resource = client->clientAsMask;
+ tempGrab.ownerEvents = ownerEvents;
+ tempGrab.keyboardMode = keyboard_mode;
+ tempGrab.pointerMode = pointer_mode;
+ if (grabtype == GRABTYPE_CORE)
+ tempGrab.eventMask = mask->core;
+ else if (grabtype == GRABTYPE_XI)
+ tempGrab.eventMask = mask->xi;
+ else
+ memcpy(tempGrab.xi2mask, mask->xi2mask, sizeof(tempGrab.xi2mask));
+ tempGrab.device = dev;
+ tempGrab.cursor = cursor;
+ tempGrab.confineTo = confineTo;
+ tempGrab.grabtype = grabtype;
+ (*grabInfo->ActivateGrab)(dev, &tempGrab, time, FALSE);
+ *status = GrabSuccess;
+ }
+ return Success;
+}
+
+/**
+ * Server-side protocol handling for GrabKeyboard request.
+ *
+ * Grabs the client's keyboard and returns success status to client.
+ */
+int
+ProcGrabKeyboard(ClientPtr client)
+{
+ xGrabKeyboardReply rep;
+ REQUEST(xGrabKeyboardReq);
+ int result;
+ DeviceIntPtr keyboard = PickKeyboard(client);
+ GrabMask mask;
+
+ REQUEST_SIZE_MATCH(xGrabKeyboardReq);
+
+ memset(&rep, 0, sizeof(xGrabKeyboardReply));
+ mask.core = KeyPressMask | KeyReleaseMask;
+
+ result = GrabDevice(client, keyboard, stuff->pointerMode,
+ stuff->keyboardMode, stuff->grabWindow, stuff->ownerEvents,
+ stuff->time, &mask, GRABTYPE_CORE, None, None,
+ &rep.status);
+
+ if (result != Success)
+ return result;
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ rep.length = 0;
+ WriteReplyToClient(client, sizeof(xGrabKeyboardReply), &rep);
+ return Success;
+}
+
+/**
+ * Server-side protocol handling for UngrabKeyboard request.
+ *
+ * Deletes a possible grab on the client's keyboard.
+ */
+int
+ProcUngrabKeyboard(ClientPtr client)
+{
+ DeviceIntPtr device = PickKeyboard(client);
+ GrabPtr grab;
+ TimeStamp time;
+ REQUEST(xResourceReq);
+
+ REQUEST_SIZE_MATCH(xResourceReq);
+ UpdateCurrentTime();
+
+ grab = device->deviceGrab.grab;
+
+ time = ClientTimeToServerTime(stuff->id);
+ if ((CompareTimeStamps(time, currentTime) != LATER) &&
+ (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) &&
+ (grab) && SameClient(grab, client) && grab->grabtype == GRABTYPE_CORE)
+ (*device->deviceGrab.DeactivateGrab)(device);
+ return Success;
+}
+
+/**
+ * Server-side protocol handling for QueryPointer request.
+ *
+ * Returns the current state and position of the client's ClientPointer to the
+ * client.
+ */
+int
+ProcQueryPointer(ClientPtr client)
+{
+ xQueryPointerReply rep;
+ WindowPtr pWin, t;
+ DeviceIntPtr mouse = PickPointer(client);
+ DeviceIntPtr keyboard;
+ SpritePtr pSprite;
+ int rc;
+ REQUEST(xResourceReq);
+ REQUEST_SIZE_MATCH(xResourceReq);
+
+ rc = dixLookupWindow(&pWin, stuff->id, client, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, mouse, DixReadAccess);
+ if (rc != Success && rc != BadAccess)
+ return rc;
+
+ keyboard = GetPairedDevice(mouse);
+
+ pSprite = mouse->spriteInfo->sprite;
+ if (mouse->valuator->motionHintWindow)
+ MaybeStopHint(mouse, client);
+ memset(&rep, 0, sizeof(xQueryPointerReply));
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ rep.mask = mouse->button ? (mouse->button->state) : 0;
+ rep.mask |= XkbStateFieldFromRec(&keyboard->key->xkbInfo->state);
+ rep.length = 0;
+ rep.root = (GetCurrentRootWindow(mouse))->drawable.id;
+ rep.rootX = pSprite->hot.x;
+ rep.rootY = pSprite->hot.y;
+ rep.child = None;
+ if (pSprite->hot.pScreen == pWin->drawable.pScreen)
+ {
+ rep.sameScreen = xTrue;
+ rep.winX = pSprite->hot.x - pWin->drawable.x;
+ rep.winY = pSprite->hot.y - pWin->drawable.y;
+ for (t = pSprite->win; t; t = t->parent)
+ if (t->parent == pWin)
+ {
+ rep.child = t->drawable.id;
+ break;
+ }
+ }
+ else
+ {
+ rep.sameScreen = xFalse;
+ rep.winX = 0;
+ rep.winY = 0;
+ }
+
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension) {
+ rep.rootX += screenInfo.screens[0]->x;
+ rep.rootY += screenInfo.screens[0]->y;
+ if(stuff->id == rep.root) {
+ rep.winX += screenInfo.screens[0]->x;
+ rep.winY += screenInfo.screens[0]->y;
+ }
+ }
+#endif
+
+ if (rc == BadAccess) {
+ rep.mask = 0;
+ rep.child = None;
+ rep.rootX = 0;
+ rep.rootY = 0;
+ rep.winX = 0;
+ rep.winY = 0;
+ }
+
+ WriteReplyToClient(client, sizeof(xQueryPointerReply), &rep);
+
+ return Success;
+}
+
+/**
+ * Initializes the device list and the DIX sprite to sane values. Allocates
+ * trace memory used for quick window traversal.
+ */
+void
+InitEvents(void)
+{
+ int i;
+
+ inputInfo.numDevices = 0;
+ inputInfo.devices = (DeviceIntPtr)NULL;
+ inputInfo.off_devices = (DeviceIntPtr)NULL;
+ inputInfo.keyboard = (DeviceIntPtr)NULL;
+ inputInfo.pointer = (DeviceIntPtr)NULL;
+ /* The mask for pointer motion events may have changed in the last server
+ * generation. See comment above definition of filters. */
+ filters[0][PointerMotionMask] = MotionNotify;
+ for (i = 1; i < MAXDEVICES; i++)
+ {
+ memcpy(&filters[i], filters[0], sizeof(filters[0]));
+ }
+
+ syncEvents.replayDev = (DeviceIntPtr)NULL;
+ syncEvents.replayWin = NullWindow;
+ while (syncEvents.pending)
+ {
+ QdEventPtr next = syncEvents.pending->next;
+ free(syncEvents.pending);
+ syncEvents.pending = next;
+ }
+ syncEvents.pendtail = &syncEvents.pending;
+ syncEvents.playingEvents = FALSE;
+ syncEvents.time.months = 0;
+ syncEvents.time.milliseconds = 0; /* hardly matters */
+ currentTime.months = 0;
+ currentTime.milliseconds = GetTimeInMillis();
+ lastDeviceEventTime = currentTime;
+ for (i = 0; i < DNPMCOUNT; i++)
+ {
+ DontPropagateMasks[i] = 0;
+ DontPropagateRefCnts[i] = 0;
+ }
+
+ InputEventListLen = GetMaximumEventsNum();
+ InputEventList = InitEventList(InputEventListLen);
+ if (!InputEventList)
+ FatalError("[dix] Failed to allocate input event list.\n");
+}
+
+void
+CloseDownEvents(void)
+{
+ FreeEventList(InputEventList, InputEventListLen);
+ InputEventListLen = 0;
+ InputEventList = NULL;
+}
+
+/**
+ * Server-side protocol handling for SendEvent request.
+ *
+ * Locates the window to send the event to and forwards the event.
+ */
+int
+ProcSendEvent(ClientPtr client)
+{
+ WindowPtr pWin;
+ WindowPtr effectiveFocus = NullWindow; /* only set if dest==InputFocus */
+ DeviceIntPtr dev = PickPointer(client);
+ DeviceIntPtr keybd = GetPairedDevice(dev);
+ SpritePtr pSprite = dev->spriteInfo->sprite;
+ REQUEST(xSendEventReq);
+
+ REQUEST_SIZE_MATCH(xSendEventReq);
+
+ /* The client's event type must be a core event type or one defined by an
+ extension. */
+
+ if ( ! ((stuff->event.u.u.type > X_Reply &&
+ stuff->event.u.u.type < LASTEvent) ||
+ (stuff->event.u.u.type >= EXTENSION_EVENT_BASE &&
+ stuff->event.u.u.type < (unsigned)lastEvent)))
+ {
+ client->errorValue = stuff->event.u.u.type;
+ return BadValue;
+ }
+ if (stuff->event.u.u.type == ClientMessage &&
+ stuff->event.u.u.detail != 8 &&
+ stuff->event.u.u.detail != 16 &&
+ stuff->event.u.u.detail != 32)
+ {
+ client->errorValue = stuff->event.u.u.detail;
+ return BadValue;
+ }
+ if (stuff->eventMask & ~AllEventMasks)
+ {
+ client->errorValue = stuff->eventMask;
+ return BadValue;
+ }
+
+ if (stuff->destination == PointerWindow)
+ pWin = pSprite->win;
+ else if (stuff->destination == InputFocus)
+ {
+ WindowPtr inputFocus = (keybd) ? keybd->focus->win : NoneWin;
+
+ if (inputFocus == NoneWin)
+ return Success;
+
+ /* If the input focus is PointerRootWin, send the event to where
+ the pointer is if possible, then perhaps propogate up to root. */
+ if (inputFocus == PointerRootWin)
+ inputFocus = GetCurrentRootWindow(dev);
+
+ if (IsParent(inputFocus, pSprite->win))
+ {
+ effectiveFocus = inputFocus;
+ pWin = pSprite->win;
+ }
+ else
+ effectiveFocus = pWin = inputFocus;
+ }
+ else
+ dixLookupWindow(&pWin, stuff->destination, client, DixSendAccess);
+
+ if (!pWin)
+ return BadWindow;
+ if ((stuff->propagate != xFalse) && (stuff->propagate != xTrue))
+ {
+ client->errorValue = stuff->propagate;
+ return BadValue;
+ }
+ stuff->event.u.u.type |= 0x80;
+ if (stuff->propagate)
+ {
+ for (;pWin; pWin = pWin->parent)
+ {
+ if (XaceHook(XACE_SEND_ACCESS, client, NULL, pWin,
+ &stuff->event, 1))
+ return Success;
+ if (DeliverEventsToWindow(dev, pWin,
+ &stuff->event, 1, stuff->eventMask, NullGrab))
+ return Success;
+ if (pWin == effectiveFocus)
+ return Success;
+ stuff->eventMask &= ~wDontPropagateMask(pWin);
+ if (!stuff->eventMask)
+ break;
+ }
+ }
+ else if (!XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, &stuff->event, 1))
+ DeliverEventsToWindow(dev, pWin, &stuff->event,
+ 1, stuff->eventMask, NullGrab);
+ return Success;
+}
+
+/**
+ * Server-side protocol handling for UngrabKey request.
+ *
+ * Deletes a passive grab for the given key. Works on the
+ * client's keyboard.
+ */
+int
+ProcUngrabKey(ClientPtr client)
+{
+ REQUEST(xUngrabKeyReq);
+ WindowPtr pWin;
+ GrabRec tempGrab;
+ DeviceIntPtr keybd = PickKeyboard(client);
+ int rc;
+
+ REQUEST_SIZE_MATCH(xUngrabKeyReq);
+ rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ if (((stuff->key > keybd->key->xkbInfo->desc->max_key_code) ||
+ (stuff->key < keybd->key->xkbInfo->desc->min_key_code))
+ && (stuff->key != AnyKey))
+ {
+ client->errorValue = stuff->key;
+ return BadValue;
+ }
+ if ((stuff->modifiers != AnyModifier) &&
+ (stuff->modifiers & ~AllModifiersMask))
+ {
+ client->errorValue = stuff->modifiers;
+ return BadValue;
+ }
+ tempGrab.resource = client->clientAsMask;
+ tempGrab.device = keybd;
+ tempGrab.window = pWin;
+ tempGrab.modifiersDetail.exact = stuff->modifiers;
+ tempGrab.modifiersDetail.pMask = NULL;
+ tempGrab.modifierDevice = GetPairedDevice(keybd);
+ tempGrab.type = KeyPress;
+ tempGrab.grabtype = GRABTYPE_CORE;
+ tempGrab.detail.exact = stuff->key;
+ tempGrab.detail.pMask = NULL;
+ tempGrab.next = NULL;
+
+ if (!DeletePassiveGrabFromList(&tempGrab))
+ return BadAlloc;
+ return Success;
+}
+
+/**
+ * Server-side protocol handling for GrabKey request.
+ *
+ * Creates a grab for the client's keyboard and adds it to the list of passive
+ * grabs.
+ */
+int
+ProcGrabKey(ClientPtr client)
+{
+ WindowPtr pWin;
+ REQUEST(xGrabKeyReq);
+ GrabPtr grab;
+ DeviceIntPtr keybd = PickKeyboard(client);
+ int rc;
+ GrabParameters param;
+ GrabMask mask;
+
+ REQUEST_SIZE_MATCH(xGrabKeyReq);
+
+ memset(&param, 0, sizeof(param));
+ param.grabtype = GRABTYPE_CORE;
+ param.ownerEvents = stuff->ownerEvents;
+ param.this_device_mode = stuff->keyboardMode;
+ param.other_devices_mode = stuff->pointerMode;
+ param.modifiers = stuff->modifiers;
+
+ rc = CheckGrabValues(client, &param);
+ if (rc != Success)
+ return rc;
+
+ if (((stuff->key > keybd->key->xkbInfo->desc->max_key_code) ||
+ (stuff->key < keybd->key->xkbInfo->desc->min_key_code))
+ && (stuff->key != AnyKey))
+ {
+ client->errorValue = stuff->key;
+ return BadValue;
+ }
+ rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixSetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+
+ mask.core = (KeyPressMask | KeyReleaseMask);
+
+ grab = CreateGrab(client->index, keybd, keybd, pWin, GRABTYPE_CORE, &mask,
+ &param, KeyPress, stuff->key, NullWindow, NullCursor);
+ if (!grab)
+ return BadAlloc;
+ return AddPassiveGrabToList(client, grab);
+}
+
+
+/**
+ * Server-side protocol handling for GrabButton request.
+ *
+ * Creates a grab for the client's ClientPointer and adds it as a passive grab
+ * to the list.
+ */
+int
+ProcGrabButton(ClientPtr client)
+{
+ WindowPtr pWin, confineTo;
+ REQUEST(xGrabButtonReq);
+ CursorPtr cursor;
+ GrabPtr grab;
+ DeviceIntPtr ptr, modifierDevice;
+ Mask access_mode = DixGrabAccess;
+ GrabMask mask;
+ GrabParameters param;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xGrabButtonReq);
+ if ((stuff->pointerMode != GrabModeSync) &&
+ (stuff->pointerMode != GrabModeAsync))
+ {
+ client->errorValue = stuff->pointerMode;
+ return BadValue;
+ }
+ if ((stuff->keyboardMode != GrabModeSync) &&
+ (stuff->keyboardMode != GrabModeAsync))
+ {
+ client->errorValue = stuff->keyboardMode;
+ return BadValue;
+ }
+ if ((stuff->modifiers != AnyModifier) &&
+ (stuff->modifiers & ~AllModifiersMask))
+ {
+ client->errorValue = stuff->modifiers;
+ return BadValue;
+ }
+ if ((stuff->ownerEvents != xFalse) && (stuff->ownerEvents != xTrue))
+ {
+ client->errorValue = stuff->ownerEvents;
+ return BadValue;
+ }
+ if (stuff->eventMask & ~PointerGrabMask)
+ {
+ client->errorValue = stuff->eventMask;
+ return BadValue;
+ }
+ rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixSetAttrAccess);
+ if (rc != Success)
+ return rc;
+ if (stuff->confineTo == None)
+ confineTo = NullWindow;
+ else {
+ rc = dixLookupWindow(&confineTo, stuff->confineTo, client,
+ DixSetAttrAccess);
+ if (rc != Success)
+ return rc;
+ }
+ if (stuff->cursor == None)
+ cursor = NullCursor;
+ else
+ {
+ rc = dixLookupResourceByType((pointer *)&cursor, stuff->cursor, RT_CURSOR,
+ client, DixUseAccess);
+ if (rc != Success)
+ {
+ client->errorValue = stuff->cursor;
+ return rc;
+ }
+ access_mode |= DixForceAccess;
+ }
+
+ ptr = PickPointer(client);
+ modifierDevice = GetPairedDevice(ptr);
+ if (stuff->pointerMode == GrabModeSync ||
+ stuff->keyboardMode == GrabModeSync)
+ access_mode |= DixFreezeAccess;
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, access_mode);
+ if (rc != Success)
+ return rc;
+
+ memset(&param, 0, sizeof(param));
+ param.grabtype = GRABTYPE_CORE;
+ param.ownerEvents = stuff->ownerEvents;
+ param.this_device_mode = stuff->keyboardMode;
+ param.other_devices_mode = stuff->pointerMode;
+ param.modifiers = stuff->modifiers;
+
+ mask.core = stuff->eventMask;
+
+ grab = CreateGrab(client->index, ptr, modifierDevice, pWin,
+ GRABTYPE_CORE, &mask, &param, ButtonPress,
+ stuff->button, confineTo, cursor);
+ if (!grab)
+ return BadAlloc;
+ return AddPassiveGrabToList(client, grab);
+}
+
+/**
+ * Server-side protocol handling for UngrabButton request.
+ *
+ * Deletes a passive grab on the client's ClientPointer from the list.
+ */
+int
+ProcUngrabButton(ClientPtr client)
+{
+ REQUEST(xUngrabButtonReq);
+ WindowPtr pWin;
+ GrabRec tempGrab;
+ int rc;
+ DeviceIntPtr ptr;
+
+ REQUEST_SIZE_MATCH(xUngrabButtonReq);
+ if ((stuff->modifiers != AnyModifier) &&
+ (stuff->modifiers & ~AllModifiersMask))
+ {
+ client->errorValue = stuff->modifiers;
+ return BadValue;
+ }
+ rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixReadAccess);
+ if (rc != Success)
+ return rc;
+
+ ptr = PickPointer(client);
+
+ tempGrab.resource = client->clientAsMask;
+ tempGrab.device = ptr;
+ tempGrab.window = pWin;
+ tempGrab.modifiersDetail.exact = stuff->modifiers;
+ tempGrab.modifiersDetail.pMask = NULL;
+ tempGrab.modifierDevice = GetPairedDevice(ptr);
+ tempGrab.type = ButtonPress;
+ tempGrab.detail.exact = stuff->button;
+ tempGrab.grabtype = GRABTYPE_CORE;
+ tempGrab.detail.pMask = NULL;
+ tempGrab.next = NULL;
+
+ if (!DeletePassiveGrabFromList(&tempGrab))
+ return BadAlloc;
+ return Success;
+}
+
+/**
+ * Deactivate any grab that may be on the window, remove the focus.
+ * Delete any XInput extension events from the window too. Does not change the
+ * window mask. Use just before the window is deleted.
+ *
+ * If freeResources is set, passive grabs on the window are deleted.
+ *
+ * @param pWin The window to delete events from.
+ * @param freeResources True if resources associated with the window should be
+ * deleted.
+ */
+void
+DeleteWindowFromAnyEvents(WindowPtr pWin, Bool freeResources)
+{
+ WindowPtr parent;
+ DeviceIntPtr mouse = inputInfo.pointer;
+ DeviceIntPtr keybd = inputInfo.keyboard;
+ FocusClassPtr focus;
+ OtherClientsPtr oc;
+ GrabPtr passive;
+ GrabPtr grab;
+
+
+ /* Deactivate any grabs performed on this window, before making any
+ input focus changes. */
+ grab = mouse->deviceGrab.grab;
+ if (grab &&
+ ((grab->window == pWin) || (grab->confineTo == pWin)))
+ (*mouse->deviceGrab.DeactivateGrab)(mouse);
+
+
+ /* Deactivating a keyboard grab should cause focus events. */
+ grab = keybd->deviceGrab.grab;
+ if (grab && (grab->window == pWin))
+ (*keybd->deviceGrab.DeactivateGrab)(keybd);
+
+ /* And now the real devices */
+ for (mouse = inputInfo.devices; mouse; mouse = mouse->next)
+ {
+ grab = mouse->deviceGrab.grab;
+ if (grab && ((grab->window == pWin) || (grab->confineTo == pWin)))
+ (*mouse->deviceGrab.DeactivateGrab)(mouse);
+ }
+
+
+ for (keybd = inputInfo.devices; keybd; keybd = keybd->next)
+ {
+ if (IsKeyboardDevice(keybd))
+ {
+ focus = keybd->focus;
+
+ /* If the focus window is a root window (ie. has no parent) then don't
+ delete the focus from it. */
+
+ if ((pWin == focus->win) && (pWin->parent != NullWindow))
+ {
+ int focusEventMode = NotifyNormal;
+
+ /* If a grab is in progress, then alter the mode of focus events. */
+
+ if (keybd->deviceGrab.grab)
+ focusEventMode = NotifyWhileGrabbed;
+
+ switch (focus->revert)
+ {
+ case RevertToNone:
+ DoFocusEvents(keybd, pWin, NoneWin, focusEventMode);
+ focus->win = NoneWin;
+ focus->traceGood = 0;
+ break;
+ case RevertToParent:
+ parent = pWin;
+ do
+ {
+ parent = parent->parent;
+ focus->traceGood--;
+ } while (!parent->realized
+ /* This would be a good protocol change -- windows being reparented
+ during SaveSet processing would cause the focus to revert to the
+ nearest enclosing window which will survive the death of the exiting
+ client, instead of ending up reverting to a dying window and thence
+ to None
+ */
+#ifdef NOTDEF
+ || wClient(parent)->clientGone
+#endif
+ );
+ if (!ActivateFocusInGrab(keybd, pWin, parent))
+ DoFocusEvents(keybd, pWin, parent, focusEventMode);
+ focus->win = parent;
+ focus->revert = RevertToNone;
+ break;
+ case RevertToPointerRoot:
+ if (!ActivateFocusInGrab(keybd, pWin, PointerRootWin))
+ DoFocusEvents(keybd, pWin, PointerRootWin, focusEventMode);
+ focus->win = PointerRootWin;
+ focus->traceGood = 0;
+ break;
+ }
+ }
+ }
+
+ if (IsPointerDevice(keybd))
+ {
+ if (keybd->valuator->motionHintWindow == pWin)
+ keybd->valuator->motionHintWindow = NullWindow;
+ }
+ }
+
+ if (freeResources)
+ {
+ if (pWin->dontPropagate)
+ DontPropagateRefCnts[pWin->dontPropagate]--;
+ while ( (oc = wOtherClients(pWin)) )
+ FreeResource(oc->resource, RT_NONE);
+ while ( (passive = wPassiveGrabs(pWin)) )
+ FreeResource(passive->resource, RT_NONE);
+ }
+
+ DeleteWindowFromAnyExtEvents(pWin, freeResources);
+}
+
+/**
+ * Call this whenever some window at or below pWin has changed geometry. If
+ * there is a grab on the window, the cursor will be re-confined into the
+ * window.
+ */
+void
+CheckCursorConfinement(WindowPtr pWin)
+{
+ GrabPtr grab;
+ WindowPtr confineTo;
+ DeviceIntPtr pDev;
+
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) return;
+#endif
+
+ for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
+ {
+ if (DevHasCursor(pDev))
+ {
+ grab = pDev->deviceGrab.grab;
+ if (grab && (confineTo = grab->confineTo))
+ {
+ if (!BorderSizeNotEmpty(pDev, confineTo))
+ (*pDev->deviceGrab.DeactivateGrab)(pDev);
+ else if ((pWin == confineTo) || IsParent(pWin, confineTo))
+ ConfineCursorToWindow(pDev, confineTo, TRUE, TRUE);
+ }
+ }
+ }
+}
+
+Mask
+EventMaskForClient(WindowPtr pWin, ClientPtr client)
+{
+ OtherClientsPtr other;
+
+ if (wClient (pWin) == client)
+ return pWin->eventMask;
+ for (other = wOtherClients(pWin); other; other = other->next)
+ {
+ if (SameClient(other, client))
+ return other->mask;
+ }
+ return 0;
+}
+
+/**
+ * Server-side protocol handling for RecolorCursor request.
+ */
+int
+ProcRecolorCursor(ClientPtr client)
+{
+ CursorPtr pCursor;
+ int rc, nscr;
+ ScreenPtr pscr;
+ Bool displayed;
+ SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite;
+ REQUEST(xRecolorCursorReq);
+
+ REQUEST_SIZE_MATCH(xRecolorCursorReq);
+ rc = dixLookupResourceByType((pointer *)&pCursor, stuff->cursor, RT_CURSOR,
+ client, DixWriteAccess);
+ if (rc != Success)
+ {
+ client->errorValue = stuff->cursor;
+ return rc;
+ }
+
+ pCursor->foreRed = stuff->foreRed;
+ pCursor->foreGreen = stuff->foreGreen;
+ pCursor->foreBlue = stuff->foreBlue;
+
+ pCursor->backRed = stuff->backRed;
+ pCursor->backGreen = stuff->backGreen;
+ pCursor->backBlue = stuff->backBlue;
+
+ for (nscr = 0; nscr < screenInfo.numScreens; nscr++)
+ {
+ pscr = screenInfo.screens[nscr];
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension)
+ displayed = (pscr == pSprite->screen);
+ else
+#endif
+ displayed = (pscr == pSprite->hotPhys.pScreen);
+ ( *pscr->RecolorCursor)(PickPointer(client), pscr, pCursor,
+ (pCursor == pSprite->current) && displayed);
+ }
+ return Success;
+}
+
+/**
+ * Write the given events to a client, swapping the byte order if necessary.
+ * To swap the byte ordering, a callback is called that has to be set up for
+ * the given event type.
+ *
+ * In the case of DeviceMotionNotify trailed by DeviceValuators, the events
+ * can be more than one. Usually it's just one event.
+ *
+ * Do not modify the event structure passed in. See comment below.
+ *
+ * @param pClient Client to send events to.
+ * @param count Number of events.
+ * @param events The event list.
+ */
+void
+WriteEventsToClient(ClientPtr pClient, int count, xEvent *events)
+{
+#ifdef PANORAMIX
+ xEvent eventCopy;
+#endif
+ xEvent *eventTo, *eventFrom;
+ int i,
+ eventlength = sizeof(xEvent);
+
+ if (!pClient || pClient == serverClient || pClient->clientGone)
+ return;
+
+ for (i = 0; i < count; i++)
+ if ((events[i].u.u.type & 0x7f) != KeymapNotify)
+ events[i].u.u.sequenceNumber = pClient->sequence;
+
+ /* Let XKB rewrite the state, as it depends on client preferences. */
+ XkbFilterEvents(pClient, count, events);
+
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension &&
+ (screenInfo.screens[0]->x || screenInfo.screens[0]->y))
+ {
+ switch(events->u.u.type) {
+ case MotionNotify:
+ case ButtonPress:
+ case ButtonRelease:
+ case KeyPress:
+ case KeyRelease:
+ case EnterNotify:
+ case LeaveNotify:
+ /*
+ When multiple clients want the same event DeliverEventsToWindow
+ passes the same event structure multiple times so we can't
+ modify the one passed to us
+ */
+ count = 1; /* should always be 1 */
+ memcpy(&eventCopy, events, sizeof(xEvent));
+ eventCopy.u.keyButtonPointer.rootX += screenInfo.screens[0]->x;
+ eventCopy.u.keyButtonPointer.rootY += screenInfo.screens[0]->y;
+ if(eventCopy.u.keyButtonPointer.event ==
+ eventCopy.u.keyButtonPointer.root)
+ {
+ eventCopy.u.keyButtonPointer.eventX += screenInfo.screens[0]->x;
+ eventCopy.u.keyButtonPointer.eventY += screenInfo.screens[0]->y;
+ }
+ events = &eventCopy;
+ break;
+ default: break;
+ }
+ }
+#endif
+
+ if (EventCallback)
+ {
+ EventInfoRec eventinfo;
+ eventinfo.client = pClient;
+ eventinfo.events = events;
+ eventinfo.count = count;
+ CallCallbacks(&EventCallback, (pointer)&eventinfo);
+ }
+#ifdef XSERVER_DTRACE
+ if (XSERVER_SEND_EVENT_ENABLED()) {
+ for (i = 0; i < count; i++)
+ {
+ XSERVER_SEND_EVENT(pClient->index, events[i].u.u.type, &events[i]);
+ }
+ }
+#endif
+ /* Just a safety check to make sure we only have one GenericEvent, it just
+ * makes things easier for me right now. (whot) */
+ for (i = 1; i < count; i++)
+ {
+ if (events[i].u.u.type == GenericEvent)
+ {
+ ErrorF("[dix] TryClientEvents: Only one GenericEvent at a time.\n");
+ return;
+ }
+ }
+
+ if (events->u.u.type == GenericEvent)
+ {
+ eventlength += ((xGenericEvent*)events)->length * 4;
+ }
+
+ if(pClient->swapped)
+ {
+ if (eventlength > swapEventLen)
+ {
+ swapEventLen = eventlength;
+ swapEvent = realloc(swapEvent, swapEventLen);
+ if (!swapEvent)
+ {
+ FatalError("WriteEventsToClient: Out of memory.\n");
+ return;
+ }
+ }
+
+ for(i = 0; i < count; i++)
+ {
+ eventFrom = &events[i];
+ eventTo = swapEvent;
+
+ /* Remember to strip off the leading bit of type in case
+ this event was sent with "SendEvent." */
+ (*EventSwapVector[eventFrom->u.u.type & 0177])
+ (eventFrom, eventTo);
+
+ WriteToClient(pClient, eventlength, (char *)eventTo);
+ }
+ }
+ else
+ {
+ /* only one GenericEvent, remember? that means either count is 1 and
+ * eventlength is arbitrary or eventlength is 32 and count doesn't
+ * matter. And we're all set. Woohoo. */
+ WriteToClient(pClient, count * eventlength, (char *) events);
+ }
+}
+
+/*
+ * Set the client pointer for the given client.
+ *
+ * A client can have exactly one ClientPointer. Each time a
+ * request/reply/event is processed and the choice of devices is ambiguous
+ * (e.g. QueryPointer request), the server will pick the ClientPointer (see
+ * PickPointer()).
+ * If a keyboard is needed, the first keyboard paired with the CP is used.
+ */
+int
+SetClientPointer(ClientPtr client, DeviceIntPtr device)
+{
+ int rc = XaceHook(XACE_DEVICE_ACCESS, client, device, DixUseAccess);
+ if (rc != Success)
+ return rc;
+
+ if (!IsMaster(device))
+ {
+ ErrorF("[dix] Need master device for ClientPointer. This is a bug.\n");
+ return BadDevice;
+ } else if (!device->spriteInfo->spriteOwner)
+ {
+ ErrorF("[dix] Device %d does not have a sprite. "
+ "Cannot be ClientPointer\n", device->id);
+ return BadDevice;
+ }
+ client->clientPtr = device;
+ return Success;
+}
+
+/* PickPointer will pick an appropriate pointer for the given client.
+ *
+ * An "appropriate device" is (in order of priority):
+ * 1) A device the given client has a core grab on.
+ * 2) A device set as ClientPointer for the given client.
+ * 3) The first master device.
+ */
+DeviceIntPtr
+PickPointer(ClientPtr client)
+{
+ DeviceIntPtr it = inputInfo.devices;
+
+ /* First, check if the client currently has a grab on a device. Even
+ * keyboards count. */
+ for(it = inputInfo.devices; it; it = it->next)
+ {
+ GrabPtr grab = it->deviceGrab.grab;
+ if (grab && grab->grabtype == GRABTYPE_CORE && SameClient(grab, client))
+ {
+ it = GetMaster(it, MASTER_POINTER);
+ return it; /* Always return a core grabbed device */
+ }
+ }
+
+ if (!client->clientPtr)
+ {
+ DeviceIntPtr it = inputInfo.devices;
+ while (it)
+ {
+ if (IsMaster(it) && it->spriteInfo->spriteOwner)
+ {
+ client->clientPtr = it;
+ break;
+ }
+ it = it->next;
+ }
+ }
+ return client->clientPtr;
+}
+
+/* PickKeyboard will pick an appropriate keyboard for the given client by
+ * searching the list of devices for the keyboard device that is paired with
+ * the client's pointer.
+ */
+DeviceIntPtr
+PickKeyboard(ClientPtr client)
+{
+ DeviceIntPtr ptr = PickPointer(client);
+ DeviceIntPtr kbd = GetMaster(ptr, MASTER_KEYBOARD);
+
+ if (!kbd)
+ {
+ ErrorF("[dix] ClientPointer not paired with a keyboard. This "
+ "is a bug.\n");
+ }
+
+ return kbd;
+}
+
+/* A client that has one or more core grabs does not get core events from
+ * devices it does not have a grab on. Legacy applications behave bad
+ * otherwise because they are not used to it and the events interfere.
+ * Only applies for core events.
+ *
+ * Return true if a core event from the device would interfere and should not
+ * be delivered.
+ */
+Bool
+IsInterferingGrab(ClientPtr client, DeviceIntPtr dev, xEvent* event)
+{
+ DeviceIntPtr it = inputInfo.devices;
+
+ switch(event->u.u.type)
+ {
+ case KeyPress:
+ case KeyRelease:
+ case ButtonPress:
+ case ButtonRelease:
+ case MotionNotify:
+ case EnterNotify:
+ case LeaveNotify:
+ break;
+ default:
+ return FALSE;
+ }
+
+ if (dev->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client))
+ return FALSE;
+
+ while(it)
+ {
+ if (it != dev)
+ {
+ if (it->deviceGrab.grab && SameClient(it->deviceGrab.grab, client)
+ && !it->deviceGrab.fromPassiveGrab)
+ {
+ if ((IsPointerDevice(it) && IsPointerDevice(dev)) ||
+ (IsKeyboardDevice(it) && IsKeyboardDevice(dev)))
+ return TRUE;
+ }
+ }
+ it = it->next;
+ }
+
+ return FALSE;
+}
+
diff --git a/dix/extension.c b/dix/extension.c
new file mode 100644
index 0000000..c7bbac5
--- /dev/null
+++ b/dix/extension.c
@@ -0,0 +1,360 @@
+/***********************************************************
+
+Copyright 1987, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+******************************************************************/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include "misc.h"
+#include "dixstruct.h"
+#include "extnsionst.h"
+#include "gcstruct.h"
+#include "scrnintstr.h"
+#include "dispatch.h"
+#include "privates.h"
+#include "registry.h"
+#include "xace.h"
+
+#define LAST_EVENT 128
+#define LAST_ERROR 255
+
+static ExtensionEntry **extensions = (ExtensionEntry **)NULL;
+
+int lastEvent = EXTENSION_EVENT_BASE;
+static int lastError = FirstExtensionError;
+static unsigned int NumExtensions = 0;
+
+ExtensionEntry *
+AddExtension(char *name, int NumEvents, int NumErrors,
+ int (*MainProc)(ClientPtr c1),
+ int (*SwappedMainProc)(ClientPtr c2),
+ void (*CloseDownProc)(ExtensionEntry *e),
+ unsigned short (*MinorOpcodeProc)(ClientPtr c3))
+{
+ int i;
+ ExtensionEntry *ext, **newexts;
+
+ if (!MainProc || !SwappedMainProc || !MinorOpcodeProc)
+ return((ExtensionEntry *) NULL);
+ if ((lastEvent + NumEvents > LAST_EVENT) ||
+ (unsigned)(lastError + NumErrors > LAST_ERROR)) {
+ LogMessage(X_ERROR, "Not enabling extension %s: maximum number of "
+ "events or errors exceeded.\n", name);
+ return((ExtensionEntry *) NULL);
+ }
+
+ ext = calloc(sizeof (ExtensionEntry), 1);
+ if (!ext)
+ return NULL;
+ if (!dixAllocatePrivates(&ext->devPrivates, PRIVATE_EXTENSION)) {
+ free(ext);
+ return NULL;
+ }
+ ext->name = strdup(name);
+ ext->num_aliases = 0;
+ ext->aliases = (char **)NULL;
+ if (!ext->name)
+ {
+ dixFreePrivates(ext->devPrivates, PRIVATE_EXTENSION);
+ free(ext);
+ return((ExtensionEntry *) NULL);
+ }
+ i = NumExtensions;
+ newexts = (ExtensionEntry **) realloc(extensions,
+ (i + 1) * sizeof(ExtensionEntry *));
+ if (!newexts)
+ {
+ free(ext->name);
+ dixFreePrivates(ext->devPrivates, PRIVATE_EXTENSION);
+ free(ext);
+ return((ExtensionEntry *) NULL);
+ }
+ NumExtensions++;
+ extensions = newexts;
+ extensions[i] = ext;
+ ext->index = i;
+ ext->base = i + EXTENSION_BASE;
+ ext->CloseDown = CloseDownProc;
+ ext->MinorOpcode = MinorOpcodeProc;
+ ProcVector[i + EXTENSION_BASE] = MainProc;
+ SwappedProcVector[i + EXTENSION_BASE] = SwappedMainProc;
+ if (NumEvents)
+ {
+ ext->eventBase = lastEvent;
+ ext->eventLast = lastEvent + NumEvents;
+ lastEvent += NumEvents;
+ }
+ else
+ {
+ ext->eventBase = 0;
+ ext->eventLast = 0;
+ }
+ if (NumErrors)
+ {
+ ext->errorBase = lastError;
+ ext->errorLast = lastError + NumErrors;
+ lastError += NumErrors;
+ }
+ else
+ {
+ ext->errorBase = 0;
+ ext->errorLast = 0;
+ }
+
+ RegisterExtensionNames(ext);
+ return ext;
+}
+
+Bool AddExtensionAlias(char *alias, ExtensionEntry *ext)
+{
+ char *name;
+ char **aliases;
+
+ if (!ext)
+ return FALSE ;
+ aliases = (char **)realloc(ext->aliases,
+ (ext->num_aliases + 1) * sizeof(char *));
+ if (!aliases)
+ return FALSE;
+ ext->aliases = aliases;
+ name = strdup(alias);
+ if (!name)
+ return FALSE;
+ ext->aliases[ext->num_aliases] = name;
+ ext->num_aliases++;
+ return TRUE;
+}
+
+static int
+FindExtension(char *extname, int len)
+{
+ int i, j;
+
+ for (i=0; i<NumExtensions; i++)
+ {
+ if ((strlen(extensions[i]->name) == len) &&
+ !strncmp(extname, extensions[i]->name, len))
+ break;
+ for (j = extensions[i]->num_aliases; --j >= 0;)
+ {
+ if ((strlen(extensions[i]->aliases[j]) == len) &&
+ !strncmp(extname, extensions[i]->aliases[j], len))
+ break;
+ }
+ if (j >= 0) break;
+ }
+ return ((i == NumExtensions) ? -1 : i);
+}
+
+/*
+ * CheckExtension returns the extensions[] entry for the requested
+ * extension name. Maybe this could just return a Bool instead?
+ */
+ExtensionEntry *
+CheckExtension(const char *extname)
+{
+ int n;
+
+ n = FindExtension((char*)extname, strlen(extname));
+ if (n != -1)
+ return extensions[n];
+ else
+ return NULL;
+}
+
+/*
+ * Added as part of Xace.
+ */
+ExtensionEntry *
+GetExtensionEntry(int major)
+{
+ if (major < EXTENSION_BASE)
+ return NULL;
+ major -= EXTENSION_BASE;
+ if (major >= NumExtensions)
+ return NULL;
+ return extensions[major];
+}
+
+unsigned short
+StandardMinorOpcode(ClientPtr client)
+{
+ return ((xReq *)client->requestBuffer)->data;
+}
+
+unsigned short
+MinorOpcodeOfRequest(ClientPtr client)
+{
+ unsigned char major;
+
+ major = ((xReq *)client->requestBuffer)->reqType;
+ if (major < EXTENSION_BASE)
+ return 0;
+ major -= EXTENSION_BASE;
+ if (major >= NumExtensions)
+ return 0;
+ return (*extensions[major]->MinorOpcode)(client);
+}
+
+void
+CloseDownExtensions(void)
+{
+ int i,j;
+
+ for (i = NumExtensions - 1; i >= 0; i--)
+ {
+ if (extensions[i]->CloseDown)
+ extensions[i]->CloseDown(extensions[i]);
+ NumExtensions = i;
+ free(extensions[i]->name);
+ for (j = extensions[i]->num_aliases; --j >= 0;)
+ free(extensions[i]->aliases[j]);
+ free(extensions[i]->aliases);
+ dixFreePrivates(extensions[i]->devPrivates, PRIVATE_EXTENSION);
+ free(extensions[i]);
+ }
+ free(extensions);
+ extensions = (ExtensionEntry **)NULL;
+ lastEvent = EXTENSION_EVENT_BASE;
+ lastError = FirstExtensionError;
+}
+
+int
+ProcQueryExtension(ClientPtr client)
+{
+ xQueryExtensionReply reply;
+ int i;
+ REQUEST(xQueryExtensionReq);
+
+ REQUEST_FIXED_SIZE(xQueryExtensionReq, stuff->nbytes);
+
+ memset(&reply, 0, sizeof(xQueryExtensionReply));
+ reply.type = X_Reply;
+ reply.length = 0;
+ reply.major_opcode = 0;
+ reply.sequenceNumber = client->sequence;
+
+ if ( ! NumExtensions )
+ reply.present = xFalse;
+ else
+ {
+ i = FindExtension((char *)&stuff[1], stuff->nbytes);
+ if (i < 0 || XaceHook(XACE_EXT_ACCESS, client, extensions[i]))
+ reply.present = xFalse;
+ else
+ {
+ reply.present = xTrue;
+ reply.major_opcode = extensions[i]->base;
+ reply.first_event = extensions[i]->eventBase;
+ reply.first_error = extensions[i]->errorBase;
+ }
+ }
+ WriteReplyToClient(client, sizeof(xQueryExtensionReply), &reply);
+ return Success;
+}
+
+int
+ProcListExtensions(ClientPtr client)
+{
+ xListExtensionsReply reply;
+ char *bufptr, *buffer;
+ int total_length = 0;
+
+ REQUEST_SIZE_MATCH(xReq);
+
+ memset(&reply, 0, sizeof(xListExtensionsReply));
+ reply.type = X_Reply;
+ reply.nExtensions = 0;
+ reply.length = 0;
+ reply.sequenceNumber = client->sequence;
+ buffer = NULL;
+
+ if ( NumExtensions )
+ {
+ int i, j;
+
+ for (i=0; i<NumExtensions; i++)
+ {
+ /* call callbacks to find out whether to show extension */
+ if (XaceHook(XACE_EXT_ACCESS, client, extensions[i]) != Success)
+ continue;
+
+ total_length += strlen(extensions[i]->name) + 1;
+ reply.nExtensions += 1 + extensions[i]->num_aliases;
+ for (j = extensions[i]->num_aliases; --j >= 0;)
+ total_length += strlen(extensions[i]->aliases[j]) + 1;
+ }
+ reply.length = bytes_to_int32(total_length);
+ buffer = bufptr = malloc(total_length);
+ if (!buffer)
+ return BadAlloc;
+ for (i=0; i<NumExtensions; i++)
+ {
+ int len;
+ if (XaceHook(XACE_EXT_ACCESS, client, extensions[i]) != Success)
+ continue;
+
+ *bufptr++ = len = strlen(extensions[i]->name);
+ memmove(bufptr, extensions[i]->name, len);
+ bufptr += len;
+ for (j = extensions[i]->num_aliases; --j >= 0;)
+ {
+ *bufptr++ = len = strlen(extensions[i]->aliases[j]);
+ memmove(bufptr, extensions[i]->aliases[j], len);
+ bufptr += len;
+ }
+ }
+ }
+ WriteReplyToClient(client, sizeof(xListExtensionsReply), &reply);
+ if (reply.length)
+ WriteToClient(client, total_length, buffer);
+
+ free(buffer);
+ return Success;
+}
diff --git a/dix/ffs.c b/dix/ffs.c
new file mode 100644
index 0000000..d0bd3e5
--- /dev/null
+++ b/dix/ffs.c
@@ -0,0 +1,48 @@
+/*
+
+Copyright 1996, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABIL-
+ITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization from
+The Open Group.
+
+*/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#ifndef HAVE_FFS
+
+#include "dix.h"
+
+int
+ffs(int i)
+{
+ int j;
+ if (i == 0)
+ return 0;
+ for (j = 1; (i & 1) == 0; j++)
+ i >>= 1;
+ return j;
+}
+
+#endif
diff --git a/dix/gc.c b/dix/gc.c
new file mode 100644
index 0000000..fc251dd
--- /dev/null
+++ b/dix/gc.c
@@ -0,0 +1,1149 @@
+/***********************************************************
+
+Copyright 1987, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+******************************************************************/
+
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/Xmd.h>
+#include <X11/Xproto.h>
+#include "misc.h"
+#include "resource.h"
+#include "gcstruct.h"
+#include "pixmapstr.h"
+#include "dixfontstr.h"
+#include "scrnintstr.h"
+#include "region.h"
+#include "dixstruct.h"
+
+#include "privates.h"
+#include "dix.h"
+#include "xace.h"
+#include <assert.h>
+
+extern FontPtr defaultFont;
+
+static Bool CreateDefaultTile(GCPtr pGC);
+
+static unsigned char DefaultDash[2] = {4, 4};
+
+void
+ValidateGC(DrawablePtr pDraw, GC *pGC)
+{
+ (*pGC->funcs->ValidateGC) (pGC, pGC->stateChanges, pDraw);
+ pGC->stateChanges = 0;
+ pGC->serialNumber = pDraw->serialNumber;
+}
+
+
+/*
+ * ChangeGC/ChangeGCXIDs:
+ *
+ * The client performing the gc change must be passed so that access
+ * checks can be performed on any tiles, stipples, or fonts that are
+ * specified. ddxen can call this too; they should normally pass
+ * NullClient for the client since any access checking should have
+ * already been done at a higher level.
+ *
+ * If you have any XIDs, you must use ChangeGCXIDs:
+ *
+ * CARD32 v[2];
+ * v[0] = FillTiled;
+ * v[1] = pid;
+ * ChangeGCXIDs(client, pGC, GCFillStyle|GCTile, v);
+ *
+ * However, if you need to pass a pointer to a pixmap or font, you must
+ * use ChangeGC:
+ *
+ * ChangeGCVal v[2];
+ * v[0].val = FillTiled;
+ * v[1].ptr = pPixmap;
+ * ChangeGC(client, pGC, GCFillStyle|GCTile, v);
+ *
+ * If you have neither XIDs nor pointers, you can use either function,
+ * but ChangeGC will do less work.
+ *
+ * ChangeGCVal v[2];
+ * v[0].val = foreground;
+ * v[1].val = background;
+ * ChangeGC(client, pGC, GCForeground|GCBackground, v);
+ */
+
+#define NEXTVAL(_type, _var) { \
+ _var = (_type)(pUnion->val); pUnion++; \
+ }
+
+#define NEXT_PTR(_type, _var) { \
+ _var = (_type)pUnion->ptr; pUnion++; }
+
+int
+ChangeGC(ClientPtr client, GC *pGC, BITS32 mask, ChangeGCValPtr pUnion)
+{
+ BITS32 index2;
+ int error = 0;
+ PixmapPtr pPixmap;
+ BITS32 maskQ;
+
+ assert(pUnion);
+ pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
+
+ maskQ = mask; /* save these for when we walk the GCque */
+ while (mask && !error)
+ {
+ index2 = (BITS32) lowbit (mask);
+ mask &= ~index2;
+ pGC->stateChanges |= index2;
+ switch (index2)
+ {
+ case GCFunction:
+ {
+ CARD8 newalu;
+ NEXTVAL(CARD8, newalu);
+ if (newalu <= GXset)
+ pGC->alu = newalu;
+ else
+ {
+ if (client)
+ client->errorValue = newalu;
+ error = BadValue;
+ }
+ break;
+ }
+ case GCPlaneMask:
+ NEXTVAL(unsigned long, pGC->planemask);
+ break;
+ case GCForeground:
+ NEXTVAL(unsigned long, pGC->fgPixel);
+ /*
+ * this is for CreateGC
+ */
+ if (!pGC->tileIsPixel && !pGC->tile.pixmap)
+ {
+ pGC->tileIsPixel = TRUE;
+ pGC->tile.pixel = pGC->fgPixel;
+ }
+ break;
+ case GCBackground:
+ NEXTVAL(unsigned long, pGC->bgPixel);
+ break;
+ case GCLineWidth: /* ??? line width is a CARD16 */
+ NEXTVAL(CARD16, pGC->lineWidth);
+ break;
+ case GCLineStyle:
+ {
+ unsigned int newlinestyle;
+ NEXTVAL(unsigned int, newlinestyle);
+ if (newlinestyle <= LineDoubleDash)
+ pGC->lineStyle = newlinestyle;
+ else
+ {
+ if (client)
+ client->errorValue = newlinestyle;
+ error = BadValue;
+ }
+ break;
+ }
+ case GCCapStyle:
+ {
+ unsigned int newcapstyle;
+ NEXTVAL(unsigned int, newcapstyle);
+ if (newcapstyle <= CapProjecting)
+ pGC->capStyle = newcapstyle;
+ else
+ {
+ if (client)
+ client->errorValue = newcapstyle;
+ error = BadValue;
+ }
+ break;
+ }
+ case GCJoinStyle:
+ {
+ unsigned int newjoinstyle;
+ NEXTVAL(unsigned int, newjoinstyle);
+ if (newjoinstyle <= JoinBevel)
+ pGC->joinStyle = newjoinstyle;
+ else
+ {
+ if (client)
+ client->errorValue = newjoinstyle;
+ error = BadValue;
+ }
+ break;
+ }
+ case GCFillStyle:
+ {
+ unsigned int newfillstyle;
+ NEXTVAL(unsigned int, newfillstyle);
+ if (newfillstyle <= FillOpaqueStippled)
+ pGC->fillStyle = newfillstyle;
+ else
+ {
+ if (client)
+ client->errorValue = newfillstyle;
+ error = BadValue;
+ }
+ break;
+ }
+ case GCFillRule:
+ {
+ unsigned int newfillrule;
+ NEXTVAL(unsigned int, newfillrule);
+ if (newfillrule <= WindingRule)
+ pGC->fillRule = newfillrule;
+ else
+ {
+ if (client)
+ client->errorValue = newfillrule;
+ error = BadValue;
+ }
+ break;
+ }
+ case GCTile:
+ NEXT_PTR(PixmapPtr, pPixmap);
+ if ((pPixmap->drawable.depth != pGC->depth) ||
+ (pPixmap->drawable.pScreen != pGC->pScreen))
+ {
+ error = BadMatch;
+ }
+ else
+ {
+ pPixmap->refcnt++;
+ if (!pGC->tileIsPixel)
+ (* pGC->pScreen->DestroyPixmap)(pGC->tile.pixmap);
+ pGC->tileIsPixel = FALSE;
+ pGC->tile.pixmap = pPixmap;
+ }
+ break;
+ case GCStipple:
+ NEXT_PTR(PixmapPtr, pPixmap);
+ if ((pPixmap->drawable.depth != 1) ||
+ (pPixmap->drawable.pScreen != pGC->pScreen))
+ {
+ error = BadMatch;
+ }
+ else
+ {
+ pPixmap->refcnt++;
+ if (pGC->stipple)
+ (* pGC->pScreen->DestroyPixmap)(pGC->stipple);
+ pGC->stipple = pPixmap;
+ }
+ break;
+ case GCTileStipXOrigin:
+ NEXTVAL(INT16, pGC->patOrg.x);
+ break;
+ case GCTileStipYOrigin:
+ NEXTVAL(INT16, pGC->patOrg.y);
+ break;
+ case GCFont:
+ {
+ FontPtr pFont;
+ NEXT_PTR(FontPtr, pFont);
+ pFont->refcnt++;
+ if (pGC->font)
+ CloseFont(pGC->font, (Font)0);
+ pGC->font = pFont;
+ break;
+ }
+ case GCSubwindowMode:
+ {
+ unsigned int newclipmode;
+ NEXTVAL(unsigned int, newclipmode);
+ if (newclipmode <= IncludeInferiors)
+ pGC->subWindowMode = newclipmode;
+ else
+ {
+ if (client)
+ client->errorValue = newclipmode;
+ error = BadValue;
+ }
+ break;
+ }
+ case GCGraphicsExposures:
+ {
+ unsigned int newge;
+ NEXTVAL(unsigned int, newge);
+ if (newge <= xTrue)
+ pGC->graphicsExposures = newge;
+ else
+ {
+ if (client)
+ client->errorValue = newge;
+ error = BadValue;
+ }
+ break;
+ }
+ case GCClipXOrigin:
+ NEXTVAL(INT16, pGC->clipOrg.x);
+ break;
+ case GCClipYOrigin:
+ NEXTVAL(INT16, pGC->clipOrg.y);
+ break;
+ case GCClipMask:
+ NEXT_PTR(PixmapPtr, pPixmap);
+ if (pPixmap)
+ {
+ if ((pPixmap->drawable.depth != 1) ||
+ (pPixmap->drawable.pScreen != pGC->pScreen))
+ {
+ error = BadMatch;
+ break;
+ }
+ pPixmap->refcnt++;
+ }
+ (*pGC->funcs->ChangeClip)(pGC, pPixmap ? CT_PIXMAP : CT_NONE,
+ (pointer)pPixmap, 0);
+ break;
+ case GCDashOffset:
+ NEXTVAL(INT16, pGC->dashOffset);
+ break;
+ case GCDashList:
+ {
+ CARD8 newdash;
+ NEXTVAL(CARD8, newdash);
+ if (newdash == 4)
+ {
+ if (pGC->dash != DefaultDash)
+ {
+ free(pGC->dash);
+ pGC->numInDashList = 2;
+ pGC->dash = DefaultDash;
+ }
+ }
+ else if (newdash != 0)
+ {
+ unsigned char *dash;
+
+ dash = malloc(2 * sizeof(unsigned char));
+ if (dash)
+ {
+ if (pGC->dash != DefaultDash)
+ free(pGC->dash);
+ pGC->numInDashList = 2;
+ pGC->dash = dash;
+ dash[0] = newdash;
+ dash[1] = newdash;
+ }
+ else
+ error = BadAlloc;
+ }
+ else
+ {
+ if (client)
+ client->errorValue = newdash;
+ error = BadValue;
+ }
+ break;
+ }
+ case GCArcMode:
+ {
+ unsigned int newarcmode;
+ NEXTVAL(unsigned int, newarcmode);
+ if (newarcmode <= ArcPieSlice)
+ pGC->arcMode = newarcmode;
+ else
+ {
+ if (client)
+ client->errorValue = newarcmode;
+ error = BadValue;
+ }
+ break;
+ }
+ default:
+ if (client)
+ client->errorValue = maskQ;
+ error = BadValue;
+ break;
+ }
+ } /* end while mask && !error */
+
+ if (pGC->fillStyle == FillTiled && pGC->tileIsPixel)
+ {
+ if (!CreateDefaultTile (pGC))
+ {
+ pGC->fillStyle = FillSolid;
+ error = BadAlloc;
+ }
+ }
+ (*pGC->funcs->ChangeGC)(pGC, maskQ);
+ return error;
+}
+
+#undef NEXTVAL
+#undef NEXT_PTR
+
+static const struct {
+ BITS32 mask;
+ RESTYPE type;
+ Mask access_mode;
+} xidfields[] = {
+ { GCTile, RT_PIXMAP, DixReadAccess },
+ { GCStipple, RT_PIXMAP, DixReadAccess },
+ { GCFont, RT_FONT, DixUseAccess },
+ { GCClipMask, RT_PIXMAP, DixReadAccess },
+};
+
+int
+ChangeGCXIDs(ClientPtr client, GC *pGC, BITS32 mask, CARD32 *pC32)
+{
+ ChangeGCVal vals[GCLastBit + 1];
+ int i;
+ if (mask & ~GCAllBits)
+ {
+ client->errorValue = mask;
+ return BadValue;
+ }
+ for (i = Ones(mask); i--; )
+ vals[i].val = pC32[i];
+ for (i = 0; i < sizeof(xidfields) / sizeof(*xidfields); ++i)
+ {
+ int offset, rc;
+ if (!(mask & xidfields[i].mask))
+ continue;
+ offset = Ones(mask & (xidfields[i].mask - 1));
+ if (xidfields[i].mask == GCClipMask && vals[offset].val == None)
+ {
+ vals[offset].ptr = NullPixmap;
+ continue;
+ }
+ rc = dixLookupResourceByType(&vals[offset].ptr, vals[offset].val,
+ xidfields[i].type, client, xidfields[i].access_mode);
+ if (rc != Success)
+ {
+ client->errorValue = vals[offset].val;
+ return rc;
+ }
+ }
+ return ChangeGC(client, pGC, mask, vals);
+}
+
+/* CreateGC(pDrawable, mask, pval, pStatus)
+ creates a default GC for the given drawable, using mask to fill
+ in any non-default values.
+ Returns a pointer to the new GC on success, NULL otherwise.
+ returns status of non-default fields in pStatus
+BUG:
+ should check for failure to create default tile
+
+*/
+GCPtr
+CreateGC(DrawablePtr pDrawable, BITS32 mask, XID *pval, int *pStatus,
+ XID gcid, ClientPtr client)
+{
+ GCPtr pGC;
+
+ pGC = dixAllocateObjectWithPrivates(GC, PRIVATE_GC);
+ if (!pGC)
+ {
+ *pStatus = BadAlloc;
+ return (GCPtr)NULL;
+ }
+
+ pGC->pScreen = pDrawable->pScreen;
+ pGC->depth = pDrawable->depth;
+ pGC->alu = GXcopy; /* dst <- src */
+ pGC->planemask = ~0;
+ pGC->serialNumber = GC_CHANGE_SERIAL_BIT;
+ pGC->funcs = 0;
+ pGC->fgPixel = 0;
+ pGC->bgPixel = 1;
+ pGC->lineWidth = 0;
+ pGC->lineStyle = LineSolid;
+ pGC->capStyle = CapButt;
+ pGC->joinStyle = JoinMiter;
+ pGC->fillStyle = FillSolid;
+ pGC->fillRule = EvenOddRule;
+ pGC->arcMode = ArcPieSlice;
+ pGC->tile.pixel = 0;
+ pGC->tile.pixmap = NullPixmap;
+ if (mask & GCForeground)
+ {
+ /*
+ * magic special case -- ChangeGC checks for this condition
+ * and snags the Foreground value to create a pseudo default-tile
+ */
+ pGC->tileIsPixel = FALSE;
+ }
+ else
+ {
+ pGC->tileIsPixel = TRUE;
+ }
+
+ pGC->patOrg.x = 0;
+ pGC->patOrg.y = 0;
+ pGC->subWindowMode = ClipByChildren;
+ pGC->graphicsExposures = TRUE;
+ pGC->clipOrg.x = 0;
+ pGC->clipOrg.y = 0;
+ pGC->clientClipType = CT_NONE;
+ pGC->clientClip = (pointer)NULL;
+ pGC->numInDashList = 2;
+ pGC->dash = DefaultDash;
+ pGC->dashOffset = 0;
+
+ /* use the default font and stipple */
+ pGC->font = defaultFont;
+ defaultFont->refcnt++;
+ pGC->stipple = pGC->pScreen->PixmapPerDepth[0];
+ pGC->stipple->refcnt++;
+
+ /* this is not a scratch GC */
+ pGC->scratch_inuse = FALSE;
+
+ /* security creation/labeling check */
+ *pStatus = XaceHook(XACE_RESOURCE_ACCESS, client, gcid, RT_GC, pGC,
+ RT_NONE, NULL, DixCreateAccess|DixSetAttrAccess);
+ if (*pStatus != Success)
+ goto out;
+
+ pGC->stateChanges = GCAllBits;
+ if (!(*pGC->pScreen->CreateGC)(pGC))
+ *pStatus = BadAlloc;
+ else if (mask)
+ *pStatus = ChangeGCXIDs(client, pGC, mask, pval);
+ else
+ *pStatus = Success;
+
+out:
+ if (*pStatus != Success)
+ {
+ if (!pGC->tileIsPixel && !pGC->tile.pixmap)
+ pGC->tileIsPixel = TRUE; /* undo special case */
+ FreeGC(pGC, (XID)0);
+ pGC = (GCPtr)NULL;
+ }
+
+ return pGC;
+}
+
+static Bool
+CreateDefaultTile (GCPtr pGC)
+{
+ ChangeGCVal tmpval[3];
+ PixmapPtr pTile;
+ GCPtr pgcScratch;
+ xRectangle rect;
+ CARD16 w, h;
+
+ w = 1;
+ h = 1;
+ (*pGC->pScreen->QueryBestSize)(TileShape, &w, &h, pGC->pScreen);
+ pTile = (PixmapPtr)
+ (*pGC->pScreen->CreatePixmap)(pGC->pScreen,
+ w, h, pGC->depth, 0);
+ pgcScratch = GetScratchGC(pGC->depth, pGC->pScreen);
+ if (!pTile || !pgcScratch)
+ {
+ if (pTile)
+ (*pTile->drawable.pScreen->DestroyPixmap)(pTile);
+ if (pgcScratch)
+ FreeScratchGC(pgcScratch);
+ return FALSE;
+ }
+ tmpval[0].val = GXcopy;
+ tmpval[1].val = pGC->tile.pixel;
+ tmpval[2].val = FillSolid;
+ (void)ChangeGC(NullClient, pgcScratch, GCFunction | GCForeground | GCFillStyle, tmpval);
+ ValidateGC((DrawablePtr)pTile, pgcScratch);
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = w;
+ rect.height = h;
+ (*pgcScratch->ops->PolyFillRect)((DrawablePtr)pTile, pgcScratch, 1, &rect);
+ /* Always remember to free the scratch graphics context after use. */
+ FreeScratchGC(pgcScratch);
+
+ pGC->tileIsPixel = FALSE;
+ pGC->tile.pixmap = pTile;
+ return TRUE;
+}
+
+int
+CopyGC(GC *pgcSrc, GC *pgcDst, BITS32 mask)
+{
+ BITS32 index2;
+ BITS32 maskQ;
+ int error = 0;
+
+ if (pgcSrc == pgcDst)
+ return Success;
+ pgcDst->serialNumber |= GC_CHANGE_SERIAL_BIT;
+ pgcDst->stateChanges |= mask;
+ maskQ = mask;
+ while (mask)
+ {
+ index2 = (BITS32) lowbit (mask);
+ mask &= ~index2;
+ switch (index2)
+ {
+ case GCFunction:
+ pgcDst->alu = pgcSrc->alu;
+ break;
+ case GCPlaneMask:
+ pgcDst->planemask = pgcSrc->planemask;
+ break;
+ case GCForeground:
+ pgcDst->fgPixel = pgcSrc->fgPixel;
+ break;
+ case GCBackground:
+ pgcDst->bgPixel = pgcSrc->bgPixel;
+ break;
+ case GCLineWidth:
+ pgcDst->lineWidth = pgcSrc->lineWidth;
+ break;
+ case GCLineStyle:
+ pgcDst->lineStyle = pgcSrc->lineStyle;
+ break;
+ case GCCapStyle:
+ pgcDst->capStyle = pgcSrc->capStyle;
+ break;
+ case GCJoinStyle:
+ pgcDst->joinStyle = pgcSrc->joinStyle;
+ break;
+ case GCFillStyle:
+ pgcDst->fillStyle = pgcSrc->fillStyle;
+ break;
+ case GCFillRule:
+ pgcDst->fillRule = pgcSrc->fillRule;
+ break;
+ case GCTile:
+ {
+ if (EqualPixUnion(pgcDst->tileIsPixel,
+ pgcDst->tile,
+ pgcSrc->tileIsPixel,
+ pgcSrc->tile))
+ {
+ break;
+ }
+ if (!pgcDst->tileIsPixel)
+ (* pgcDst->pScreen->DestroyPixmap)(pgcDst->tile.pixmap);
+ pgcDst->tileIsPixel = pgcSrc->tileIsPixel;
+ pgcDst->tile = pgcSrc->tile;
+ if (!pgcDst->tileIsPixel)
+ pgcDst->tile.pixmap->refcnt++;
+ break;
+ }
+ case GCStipple:
+ {
+ if (pgcDst->stipple == pgcSrc->stipple)
+ break;
+ if (pgcDst->stipple)
+ (* pgcDst->pScreen->DestroyPixmap)(pgcDst->stipple);
+ pgcDst->stipple = pgcSrc->stipple;
+ if (pgcDst->stipple)
+ pgcDst->stipple->refcnt ++;
+ break;
+ }
+ case GCTileStipXOrigin:
+ pgcDst->patOrg.x = pgcSrc->patOrg.x;
+ break;
+ case GCTileStipYOrigin:
+ pgcDst->patOrg.y = pgcSrc->patOrg.y;
+ break;
+ case GCFont:
+ if (pgcDst->font == pgcSrc->font)
+ break;
+ if (pgcDst->font)
+ CloseFont(pgcDst->font, (Font)0);
+ if ((pgcDst->font = pgcSrc->font) != NullFont)
+ (pgcDst->font)->refcnt++;
+ break;
+ case GCSubwindowMode:
+ pgcDst->subWindowMode = pgcSrc->subWindowMode;
+ break;
+ case GCGraphicsExposures:
+ pgcDst->graphicsExposures = pgcSrc->graphicsExposures;
+ break;
+ case GCClipXOrigin:
+ pgcDst->clipOrg.x = pgcSrc->clipOrg.x;
+ break;
+ case GCClipYOrigin:
+ pgcDst->clipOrg.y = pgcSrc->clipOrg.y;
+ break;
+ case GCClipMask:
+ (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
+ break;
+ case GCDashOffset:
+ pgcDst->dashOffset = pgcSrc->dashOffset;
+ break;
+ case GCDashList:
+ if (pgcSrc->dash == DefaultDash)
+ {
+ if (pgcDst->dash != DefaultDash)
+ {
+ free(pgcDst->dash);
+ pgcDst->numInDashList = pgcSrc->numInDashList;
+ pgcDst->dash = pgcSrc->dash;
+ }
+ }
+ else
+ {
+ unsigned char *dash;
+ unsigned int i;
+
+ dash = malloc(pgcSrc->numInDashList * sizeof(unsigned char));
+ if (dash)
+ {
+ if (pgcDst->dash != DefaultDash)
+ free(pgcDst->dash);
+ pgcDst->numInDashList = pgcSrc->numInDashList;
+ pgcDst->dash = dash;
+ for (i=0; i<pgcSrc->numInDashList; i++)
+ dash[i] = pgcSrc->dash[i];
+ }
+ else
+ error = BadAlloc;
+ }
+ break;
+ case GCArcMode:
+ pgcDst->arcMode = pgcSrc->arcMode;
+ break;
+ default:
+ FatalError ("CopyGC: Unhandled mask!\n");
+ }
+ }
+ if (pgcDst->fillStyle == FillTiled && pgcDst->tileIsPixel)
+ {
+ if (!CreateDefaultTile (pgcDst))
+ {
+ pgcDst->fillStyle = FillSolid;
+ error = BadAlloc;
+ }
+ }
+ (*pgcDst->funcs->CopyGC) (pgcSrc, maskQ, pgcDst);
+ return error;
+}
+
+/**
+ * does the diX part of freeing the characteristics in the GC.
+ *
+ * \param value must conform to DeleteType
+ */
+int
+FreeGC(pointer value, XID gid)
+{
+ GCPtr pGC = (GCPtr)value;
+
+ CloseFont(pGC->font, (Font)0);
+ (* pGC->funcs->DestroyClip)(pGC);
+
+ if (!pGC->tileIsPixel)
+ (* pGC->pScreen->DestroyPixmap)(pGC->tile.pixmap);
+ if (pGC->stipple)
+ (* pGC->pScreen->DestroyPixmap)(pGC->stipple);
+
+ (*pGC->funcs->DestroyGC) (pGC);
+ if (pGC->dash != DefaultDash)
+ free(pGC->dash);
+ dixFreeObjectWithPrivates(pGC, PRIVATE_GC);
+ return Success;
+}
+
+/* CreateScratchGC(pScreen, depth)
+ like CreateGC, but doesn't do the default tile or stipple,
+since we can't create them without already having a GC. any code
+using the tile or stipple has to set them explicitly anyway,
+since the state of the scratch gc is unknown. This is OK
+because ChangeGC() has to be able to deal with NULL tiles and
+stipples anyway (in case the CreateGC() call has provided a
+value for them -- we can't set the default tile until the
+client-supplied attributes are installed, since the fgPixel
+is what fills the default tile. (maybe this comment should
+go with CreateGC() or ChangeGC().)
+*/
+
+static GCPtr
+CreateScratchGC(ScreenPtr pScreen, unsigned depth)
+{
+ GCPtr pGC;
+
+ pGC = dixAllocateObjectWithPrivates(GC, PRIVATE_GC);
+ if (!pGC)
+ return (GCPtr)NULL;
+
+ pGC->pScreen = pScreen;
+ pGC->depth = depth;
+ pGC->alu = GXcopy; /* dst <- src */
+ pGC->planemask = ~0;
+ pGC->serialNumber = 0;
+ pGC->fgPixel = 0;
+ pGC->bgPixel = 1;
+ pGC->lineWidth = 0;
+ pGC->lineStyle = LineSolid;
+ pGC->capStyle = CapButt;
+ pGC->joinStyle = JoinMiter;
+ pGC->fillStyle = FillSolid;
+ pGC->fillRule = EvenOddRule;
+ pGC->arcMode = ArcPieSlice;
+ pGC->font = defaultFont;
+ if ( pGC->font) /* necessary, because open of default font could fail */
+ pGC->font->refcnt++;
+ pGC->tileIsPixel = TRUE;
+ pGC->tile.pixel = 0;
+ pGC->tile.pixmap = NullPixmap;
+ pGC->stipple = NullPixmap;
+ pGC->patOrg.x = 0;
+ pGC->patOrg.y = 0;
+ pGC->subWindowMode = ClipByChildren;
+ pGC->graphicsExposures = TRUE;
+ pGC->clipOrg.x = 0;
+ pGC->clipOrg.y = 0;
+ pGC->clientClipType = CT_NONE;
+ pGC->dashOffset = 0;
+ pGC->numInDashList = 2;
+ pGC->dash = DefaultDash;
+
+ /* scratch GCs in the GCperDepth pool start off unused */
+ pGC->scratch_inuse = FALSE;
+
+ pGC->stateChanges = GCAllBits;
+ if (!(*pScreen->CreateGC)(pGC))
+ {
+ FreeGC(pGC, (XID)0);
+ pGC = (GCPtr)NULL;
+ }
+ return pGC;
+}
+
+void
+FreeGCperDepth(int screenNum)
+{
+ int i;
+ ScreenPtr pScreen;
+ GCPtr *ppGC;
+
+ pScreen = screenInfo.screens[screenNum];
+ ppGC = pScreen->GCperDepth;
+
+ for (i = 0; i <= pScreen->numDepths; i++)
+ {
+ (void)FreeGC(ppGC[i], (XID)0);
+ ppGC[i] = NULL;
+ }
+}
+
+
+Bool
+CreateGCperDepth(int screenNum)
+{
+ int i;
+ ScreenPtr pScreen;
+ DepthPtr pDepth;
+ GCPtr *ppGC;
+
+ pScreen = screenInfo.screens[screenNum];
+ ppGC = pScreen->GCperDepth;
+ /* do depth 1 separately because it's not included in list */
+ if (!(ppGC[0] = CreateScratchGC(pScreen, 1)))
+ return FALSE;
+ ppGC[0]->graphicsExposures = FALSE;
+ /* Make sure we don't overflow GCperDepth[] */
+ if( pScreen->numDepths > MAXFORMATS )
+ return FALSE;
+
+ pDepth = pScreen->allowedDepths;
+ for (i=0; i<pScreen->numDepths; i++, pDepth++)
+ {
+ if (!(ppGC[i+1] = CreateScratchGC(pScreen, pDepth->depth)))
+ {
+ for (; i >= 0; i--)
+ (void)FreeGC(ppGC[i], (XID)0);
+ return FALSE;
+ }
+ ppGC[i+1]->graphicsExposures = FALSE;
+ }
+ return TRUE;
+}
+
+Bool
+CreateDefaultStipple(int screenNum)
+{
+ ScreenPtr pScreen;
+ ChangeGCVal tmpval[3];
+ xRectangle rect;
+ CARD16 w, h;
+ GCPtr pgcScratch;
+
+ pScreen = screenInfo.screens[screenNum];
+
+ w = 16;
+ h = 16;
+ (* pScreen->QueryBestSize)(StippleShape, &w, &h, pScreen);
+ if (!(pScreen->PixmapPerDepth[0] =
+ (*pScreen->CreatePixmap)(pScreen, w, h, 1, 0)))
+ return FALSE;
+ /* fill stipple with 1 */
+ tmpval[0].val = GXcopy;
+ tmpval[1].val = 1;
+ tmpval[2].val = FillSolid;
+ pgcScratch = GetScratchGC(1, pScreen);
+ if (!pgcScratch)
+ {
+ (*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]);
+ return FALSE;
+ }
+ (void)ChangeGC(NullClient, pgcScratch, GCFunction|GCForeground|GCFillStyle, tmpval);
+ ValidateGC((DrawablePtr)pScreen->PixmapPerDepth[0], pgcScratch);
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = w;
+ rect.height = h;
+ (*pgcScratch->ops->PolyFillRect)((DrawablePtr)pScreen->PixmapPerDepth[0],
+ pgcScratch, 1, &rect);
+ FreeScratchGC(pgcScratch);
+ return TRUE;
+}
+
+void
+FreeDefaultStipple(int screenNum)
+{
+ ScreenPtr pScreen = screenInfo.screens[screenNum];
+ (*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]);
+}
+
+int
+SetDashes(GCPtr pGC, unsigned offset, unsigned ndash, unsigned char *pdash)
+{
+ long i;
+ unsigned char *p, *indash;
+ BITS32 maskQ = 0;
+
+ i = ndash;
+ p = pdash;
+ while (i--)
+ {
+ if (!*p++)
+ {
+ /* dash segment must be > 0 */
+ return BadValue;
+ }
+ }
+
+ if (ndash & 1)
+ p = malloc(2 * ndash * sizeof(unsigned char));
+ else
+ p = malloc(ndash * sizeof(unsigned char));
+ if (!p)
+ return BadAlloc;
+
+ pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
+ if (offset != pGC->dashOffset)
+ {
+ pGC->dashOffset = offset;
+ pGC->stateChanges |= GCDashOffset;
+ maskQ |= GCDashOffset;
+ }
+
+ if (pGC->dash != DefaultDash)
+ free(pGC->dash);
+ pGC->numInDashList = ndash;
+ pGC->dash = p;
+ if (ndash & 1)
+ {
+ pGC->numInDashList += ndash;
+ indash = pdash;
+ i = ndash;
+ while (i--)
+ *p++ = *indash++;
+ }
+ while(ndash--)
+ *p++ = *pdash++;
+ pGC->stateChanges |= GCDashList;
+ maskQ |= GCDashList;
+
+ if (pGC->funcs->ChangeGC)
+ (*pGC->funcs->ChangeGC) (pGC, maskQ);
+ return Success;
+}
+
+int
+VerifyRectOrder(int nrects, xRectangle *prects, int ordering)
+{
+ xRectangle *prectP, *prectN;
+ int i;
+
+ switch(ordering)
+ {
+ case Unsorted:
+ return CT_UNSORTED;
+ case YSorted:
+ if(nrects > 1)
+ {
+ for(i = 1, prectP = prects, prectN = prects + 1;
+ i < nrects;
+ i++, prectP++, prectN++)
+ if(prectN->y < prectP->y)
+ return -1;
+ }
+ return CT_YSORTED;
+ case YXSorted:
+ if(nrects > 1)
+ {
+ for(i = 1, prectP = prects, prectN = prects + 1;
+ i < nrects;
+ i++, prectP++, prectN++)
+ if((prectN->y < prectP->y) ||
+ ( (prectN->y == prectP->y) &&
+ (prectN->x < prectP->x) ) )
+ return -1;
+ }
+ return CT_YXSORTED;
+ case YXBanded:
+ if(nrects > 1)
+ {
+ for(i = 1, prectP = prects, prectN = prects + 1;
+ i < nrects;
+ i++, prectP++, prectN++)
+ if((prectN->y != prectP->y &&
+ prectN->y < prectP->y + (int) prectP->height) ||
+ ((prectN->y == prectP->y) &&
+ (prectN->height != prectP->height ||
+ prectN->x < prectP->x + (int) prectP->width)))
+ return -1;
+ }
+ return CT_YXBANDED;
+ }
+ return -1;
+}
+
+int
+SetClipRects(GCPtr pGC, int xOrigin, int yOrigin, int nrects,
+ xRectangle *prects, int ordering)
+{
+ int newct, size;
+ xRectangle *prectsNew;
+
+ newct = VerifyRectOrder(nrects, prects, ordering);
+ if (newct < 0)
+ return BadMatch;
+ size = nrects * sizeof(xRectangle);
+ prectsNew = malloc(size);
+ if (!prectsNew && size)
+ return BadAlloc;
+
+ pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
+ pGC->clipOrg.x = xOrigin;
+ pGC->stateChanges |= GCClipXOrigin;
+
+ pGC->clipOrg.y = yOrigin;
+ pGC->stateChanges |= GCClipYOrigin;
+
+ if (size)
+ memmove((char *)prectsNew, (char *)prects, size);
+ (*pGC->funcs->ChangeClip)(pGC, newct, (pointer)prectsNew, nrects);
+ if (pGC->funcs->ChangeGC)
+ (*pGC->funcs->ChangeGC) (pGC, GCClipXOrigin|GCClipYOrigin|GCClipMask);
+ return Success;
+}
+
+
+/*
+ sets reasonable defaults
+ if we can get a pre-allocated one, use it and mark it as used.
+ if we can't, create one out of whole cloth (The Velveteen GC -- if
+ you use it often enough it will become real.)
+*/
+GCPtr
+GetScratchGC(unsigned depth, ScreenPtr pScreen)
+{
+ int i;
+ GCPtr pGC;
+
+ for (i=0; i<=pScreen->numDepths; i++)
+ {
+ pGC = pScreen->GCperDepth[i];
+ if (pGC && pGC->depth == depth && !pGC->scratch_inuse)
+ {
+ pGC->scratch_inuse = TRUE;
+
+ pGC->alu = GXcopy;
+ pGC->planemask = ~0;
+ pGC->serialNumber = 0;
+ pGC->fgPixel = 0;
+ pGC->bgPixel = 1;
+ pGC->lineWidth = 0;
+ pGC->lineStyle = LineSolid;
+ pGC->capStyle = CapButt;
+ pGC->joinStyle = JoinMiter;
+ pGC->fillStyle = FillSolid;
+ pGC->fillRule = EvenOddRule;
+ pGC->arcMode = ArcChord;
+ pGC->patOrg.x = 0;
+ pGC->patOrg.y = 0;
+ pGC->subWindowMode = ClipByChildren;
+ pGC->graphicsExposures = FALSE;
+ pGC->clipOrg.x = 0;
+ pGC->clipOrg.y = 0;
+ if (pGC->clientClipType != CT_NONE)
+ (*pGC->funcs->ChangeClip) (pGC, CT_NONE, NULL, 0);
+ pGC->stateChanges = GCAllBits;
+ return pGC;
+ }
+ }
+ /* if we make it this far, need to roll our own */
+ pGC = CreateScratchGC(pScreen, depth);
+ if (pGC)
+ pGC->graphicsExposures = FALSE;
+ return pGC;
+}
+
+/*
+ if the gc to free is in the table of pre-existing ones,
+mark it as available.
+ if not, free it for real
+*/
+void
+FreeScratchGC(GCPtr pGC)
+{
+ if (pGC->scratch_inuse)
+ pGC->scratch_inuse = FALSE;
+ else
+ FreeGC(pGC, (GContext)0);
+}
diff --git a/dix/getevents.c b/dix/getevents.c
new file mode 100644
index 0000000..8355040
--- /dev/null
+++ b/dix/getevents.c
@@ -0,0 +1,1327 @@
+/*
+ * Copyright © 2006 Nokia Corporation
+ * Copyright © 2006-2007 Daniel Stone
+ * Copyright © 2008 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Daniel Stone <daniel@fooishbar.org>
+ * Peter Hutterer <peter.hutterer@who-t.net>
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/keysym.h>
+#include <X11/Xproto.h>
+#include <math.h>
+
+#include "misc.h"
+#include "resource.h"
+#include "inputstr.h"
+#include "scrnintstr.h"
+#include "cursorstr.h"
+#include "dixstruct.h"
+#include "globals.h"
+#include "dixevents.h"
+#include "mipointer.h"
+#include "eventstr.h"
+#include "eventconvert.h"
+#include "inpututils.h"
+
+#include <X11/extensions/XKBproto.h>
+#include "xkbsrv.h"
+
+#ifdef PANORAMIX
+#include "panoramiX.h"
+#include "panoramiXsrv.h"
+#endif
+
+#include <X11/extensions/XI.h>
+#include <X11/extensions/XIproto.h>
+#include <pixman.h>
+#include "exglobals.h"
+#include "exevents.h"
+#include "exglobals.h"
+#include "extnsionst.h"
+#include "listdev.h" /* for sizing up DeviceClassesChangedEvent */
+
+/* Number of motion history events to store. */
+#define MOTION_HISTORY_SIZE 256
+
+/* InputEventList is the container list for all input events generated by the
+ * DDX. The DDX is expected to call GetEventList() and then pass the list into
+ * Get{Pointer|Keyboard}Events.
+ */
+EventListPtr InputEventList = NULL;
+int InputEventListLen = 0;
+
+int
+GetEventList(EventListPtr* list)
+{
+ *list = InputEventList;
+ return InputEventListLen;
+}
+
+/**
+ * Pick some arbitrary size for Xi motion history.
+ */
+int
+GetMotionHistorySize(void)
+{
+ return MOTION_HISTORY_SIZE;
+}
+
+void
+set_button_down(DeviceIntPtr pDev, int button, int type)
+{
+ if (type == BUTTON_PROCESSED)
+ SetBit(pDev->button->down, button);
+ else
+ SetBit(pDev->button->postdown, button);
+}
+
+void
+set_button_up(DeviceIntPtr pDev, int button, int type)
+{
+ if (type == BUTTON_PROCESSED)
+ ClearBit(pDev->button->down, button);
+ else
+ ClearBit(pDev->button->postdown, button);
+}
+
+Bool
+button_is_down(DeviceIntPtr pDev, int button, int type)
+{
+ Bool ret = FALSE;
+
+ if (type & BUTTON_PROCESSED)
+ ret = ret || BitIsOn(pDev->button->down, button);
+ if (type & BUTTON_POSTED)
+ ret = ret || BitIsOn(pDev->button->postdown, button);
+
+ return ret;
+}
+
+void
+set_key_down(DeviceIntPtr pDev, int key_code, int type)
+{
+ if (type == KEY_PROCESSED)
+ SetBit(pDev->key->down, key_code);
+ else
+ SetBit(pDev->key->postdown, key_code);
+}
+
+void
+set_key_up(DeviceIntPtr pDev, int key_code, int type)
+{
+ if (type == KEY_PROCESSED)
+ ClearBit(pDev->key->down, key_code);
+ else
+ ClearBit(pDev->key->postdown, key_code);
+}
+
+Bool
+key_is_down(DeviceIntPtr pDev, int key_code, int type)
+{
+ Bool ret = FALSE;
+
+ if (type & KEY_PROCESSED)
+ ret = ret || BitIsOn(pDev->key->down, key_code);
+ if (type & KEY_POSTED)
+ ret = ret || BitIsOn(pDev->key->postdown, key_code);
+
+ return ret;
+}
+
+static Bool
+key_autorepeats(DeviceIntPtr pDev, int key_code)
+{
+ return !!(pDev->kbdfeed->ctrl.autoRepeats[key_code >> 3] &
+ (1 << (key_code & 7)));
+}
+
+static void
+init_event(DeviceIntPtr dev, DeviceEvent* event, Time ms)
+{
+ memset(event, 0, sizeof(DeviceEvent));
+ event->header = ET_Internal;
+ event->length = sizeof(DeviceEvent);
+ event->time = ms;
+ event->deviceid = dev->id;
+ event->sourceid = dev->id;
+}
+
+static void
+init_raw(DeviceIntPtr dev, RawDeviceEvent *event, Time ms, int type, int detail)
+{
+ memset(event, 0, sizeof(RawDeviceEvent));
+ event->header = ET_Internal;
+ event->length = sizeof(RawDeviceEvent);
+ event->type = ET_RawKeyPress - ET_KeyPress + type;
+ event->time = ms;
+ event->deviceid = dev->id;
+ event->sourceid = dev->id;
+ event->detail.button = detail;
+}
+
+static void
+set_raw_valuators(RawDeviceEvent *event, ValuatorMask *mask, int32_t* data)
+{
+ int i;
+
+ for (i = 0; i < valuator_mask_size(mask); i++)
+ {
+ if (valuator_mask_isset(mask, i))
+ {
+ SetBit(event->valuators.mask, i);
+ data[i] = valuator_mask_get(mask, i);
+ }
+ }
+}
+
+
+static void
+set_valuators(DeviceIntPtr dev, DeviceEvent* event, ValuatorMask *mask)
+{
+ int i;
+
+ /* Set the data to the previous value for unset absolute axes. The values
+ * may be used when sent as part of an XI 1.x valuator event. */
+ for (i = 0; i < valuator_mask_size(mask); i++)
+ {
+ if (valuator_mask_isset(mask, i))
+ {
+ SetBit(event->valuators.mask, i);
+ if (valuator_get_mode(dev, i) == Absolute)
+ SetBit(event->valuators.mode, i);
+ event->valuators.data[i] = valuator_mask_get(mask, i);
+ event->valuators.data_frac[i] =
+ dev->last.remainder[i] * (1 << 16) * (1 << 16);
+ }
+ else if (valuator_get_mode(dev, i) == Absolute)
+ event->valuators.data[i] = dev->valuator->axisVal[i];
+ }
+}
+
+void
+CreateClassesChangedEvent(EventList* event,
+ DeviceIntPtr master,
+ DeviceIntPtr slave,
+ int type)
+{
+ int i;
+ DeviceChangedEvent *dce;
+ CARD32 ms = GetTimeInMillis();
+
+ dce = (DeviceChangedEvent*)event->event;
+ memset(dce, 0, sizeof(DeviceChangedEvent));
+ dce->deviceid = slave->id;
+ dce->masterid = master->id;
+ dce->header = ET_Internal;
+ dce->length = sizeof(DeviceChangedEvent);
+ dce->type = ET_DeviceChanged;
+ dce->time = ms;
+ dce->flags = type;
+ dce->flags |= DEVCHANGE_SLAVE_SWITCH;
+ dce->sourceid = slave->id;
+
+ if (slave->button)
+ {
+ dce->buttons.num_buttons = slave->button->numButtons;
+ for (i = 0; i < dce->buttons.num_buttons; i++)
+ dce->buttons.names[i] = slave->button->labels[i];
+ }
+ if (slave->valuator)
+ {
+ dce->num_valuators = slave->valuator->numAxes;
+ for (i = 0; i < dce->num_valuators; i++)
+ {
+ dce->valuators[i].min = slave->valuator->axes[i].min_value;
+ dce->valuators[i].max = slave->valuator->axes[i].max_value;
+ dce->valuators[i].resolution = slave->valuator->axes[i].resolution;
+ dce->valuators[i].mode = slave->valuator->axes[i].mode;
+ dce->valuators[i].name = slave->valuator->axes[i].label;
+ }
+ }
+ if (slave->key)
+ {
+ dce->keys.min_keycode = slave->key->xkbInfo->desc->min_key_code;
+ dce->keys.max_keycode = slave->key->xkbInfo->desc->max_key_code;
+ }
+}
+
+/**
+ * Rescale the coord between the two axis ranges.
+ */
+static int
+rescaleValuatorAxis(int coord, float remainder, float *remainder_return, AxisInfoPtr from, AxisInfoPtr to,
+ int defmax)
+{
+ int fmin = 0, tmin = 0, fmax = defmax, tmax = defmax, coord_return;
+ float value;
+
+ if(from && from->min_value < from->max_value) {
+ fmin = from->min_value;
+ fmax = from->max_value;
+ }
+ if(to && to->min_value < to->max_value) {
+ tmin = to->min_value;
+ tmax = to->max_value;
+ }
+
+ if(fmin == tmin && fmax == tmax) {
+ if (remainder_return)
+ *remainder_return = remainder;
+ return coord;
+ }
+
+ if(fmax == fmin) { /* avoid division by 0 */
+ if (remainder_return)
+ *remainder_return = 0.0;
+ return 0;
+ }
+
+ value = (coord + remainder - fmin) * (tmax - tmin) / (fmax - fmin) + tmin;
+ coord_return = lroundf(value);
+ if (remainder_return)
+ *remainder_return = value - coord_return;
+ return coord_return;
+}
+
+/**
+ * Update all coordinates when changing to a different SD
+ * to ensure that relative reporting will work as expected
+ * without loss of precision.
+ *
+ * pDev->last.valuators will be in absolute device coordinates after this
+ * function.
+ */
+static void
+updateSlaveDeviceCoords(DeviceIntPtr master, DeviceIntPtr pDev)
+{
+ ScreenPtr scr = miPointerGetScreen(pDev);
+ int i;
+ DeviceIntPtr lastSlave;
+
+ /* master->last.valuators[0]/[1] is in screen coords and the actual
+ * position of the pointer */
+ pDev->last.valuators[0] = master->last.valuators[0];
+ pDev->last.valuators[1] = master->last.valuators[1];
+
+ if (!pDev->valuator)
+ return;
+
+ /* scale back to device coordinates */
+ if(pDev->valuator->numAxes > 0)
+ pDev->last.valuators[0] = rescaleValuatorAxis(pDev->last.valuators[0], pDev->last.remainder[0],
+ &pDev->last.remainder[0], NULL, pDev->valuator->axes + 0, scr->width);
+ if(pDev->valuator->numAxes > 1)
+ pDev->last.valuators[1] = rescaleValuatorAxis(pDev->last.valuators[1], pDev->last.remainder[1],
+ &pDev->last.remainder[1], NULL, pDev->valuator->axes + 1, scr->height);
+
+ /* calculate the other axis as well based on info from the old
+ * slave-device. If the old slave had less axes than this one,
+ * last.valuators is reset to 0.
+ */
+ if ((lastSlave = master->last.slave) && lastSlave->valuator) {
+ for (i = 2; i < pDev->valuator->numAxes; i++) {
+ if (i >= lastSlave->valuator->numAxes)
+ pDev->last.valuators[i] = 0;
+ else
+ pDev->last.valuators[i] =
+ rescaleValuatorAxis(pDev->last.valuators[i],
+ pDev->last.remainder[i],
+ &pDev->last.remainder[i],
+ lastSlave->valuator->axes + i,
+ pDev->valuator->axes + i, 0);
+ }
+ }
+
+}
+
+/**
+ * Allocate the motion history buffer.
+ */
+void
+AllocateMotionHistory(DeviceIntPtr pDev)
+{
+ int size;
+ free(pDev->valuator->motion);
+
+ if (pDev->valuator->numMotionEvents < 1)
+ return;
+
+ /* An MD must have a motion history size large enough to keep all
+ * potential valuators, plus the respective range of the valuators.
+ * 3 * INT32 for (min_val, max_val, curr_val))
+ */
+ if (IsMaster(pDev))
+ size = sizeof(INT32) * 3 * MAX_VALUATORS;
+ else {
+ ValuatorClassPtr v = pDev->valuator;
+ int numAxes;
+ /* XI1 doesn't understand mixed mode devices */
+ for (numAxes = 0; numAxes < v->numAxes; numAxes++)
+ if (valuator_get_mode(pDev, numAxes) != valuator_get_mode(pDev, 0))
+ break;
+ size = sizeof(INT32) * numAxes;
+ }
+
+ size += sizeof(Time);
+
+ pDev->valuator->motion = calloc(pDev->valuator->numMotionEvents, size);
+ pDev->valuator->first_motion = 0;
+ pDev->valuator->last_motion = 0;
+ if (!pDev->valuator->motion)
+ ErrorF("[dix] %s: Failed to alloc motion history (%d bytes).\n",
+ pDev->name, size * pDev->valuator->numMotionEvents);
+}
+
+/**
+ * Dump the motion history between start and stop into the supplied buffer.
+ * Only records the event for a given screen in theory, but in practice, we
+ * sort of ignore this.
+ *
+ * If core is set, we only generate x/y, in INT16, scaled to screen coords.
+ */
+int
+GetMotionHistory(DeviceIntPtr pDev, xTimecoord **buff, unsigned long start,
+ unsigned long stop, ScreenPtr pScreen, BOOL core)
+{
+ char *ibuff = NULL, *obuff;
+ int i = 0, ret = 0;
+ int j, coord;
+ Time current;
+ /* The size of a single motion event. */
+ int size;
+ int dflt;
+ AxisInfo from, *to; /* for scaling */
+ INT32 *ocbuf, *icbuf; /* pointer to coordinates for copying */
+ INT16 *corebuf;
+ AxisInfo core_axis = {0};
+
+ if (!pDev->valuator || !pDev->valuator->numMotionEvents)
+ return 0;
+
+ if (core && !pScreen)
+ return 0;
+
+ if (IsMaster(pDev))
+ size = (sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(Time);
+ else
+ size = (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time);
+
+ *buff = malloc(size * pDev->valuator->numMotionEvents);
+ if (!(*buff))
+ return 0;
+ obuff = (char *)*buff;
+
+ for (i = pDev->valuator->first_motion;
+ i != pDev->valuator->last_motion;
+ i = (i + 1) % pDev->valuator->numMotionEvents) {
+ /* We index the input buffer by which element we're accessing, which
+ * is not monotonic, and the output buffer by how many events we've
+ * written so far. */
+ ibuff = (char *) pDev->valuator->motion + (i * size);
+ memcpy(&current, ibuff, sizeof(Time));
+
+ if (current > stop) {
+ return ret;
+ }
+ else if (current >= start) {
+ if (core)
+ {
+ memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */
+
+ icbuf = (INT32*)(ibuff + sizeof(Time));
+ corebuf = (INT16*)(obuff + sizeof(Time));
+
+ /* fetch x coordinate + range */
+ memcpy(&from.min_value, icbuf++, sizeof(INT32));
+ memcpy(&from.max_value, icbuf++, sizeof(INT32));
+ memcpy(&coord, icbuf++, sizeof(INT32));
+
+ /* scale to screen coords */
+ to = &core_axis;
+ to->max_value = pScreen->width;
+ coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, pScreen->width);
+
+ memcpy(corebuf, &coord, sizeof(INT16));
+ corebuf++;
+
+ /* fetch y coordinate + range */
+ memcpy(&from.min_value, icbuf++, sizeof(INT32));
+ memcpy(&from.max_value, icbuf++, sizeof(INT32));
+ memcpy(&coord, icbuf++, sizeof(INT32));
+
+ to->max_value = pScreen->height;
+ coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, pScreen->height);
+ memcpy(corebuf, &coord, sizeof(INT16));
+
+ } else if (IsMaster(pDev))
+ {
+ memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */
+
+ ocbuf = (INT32*)(obuff + sizeof(Time));
+ icbuf = (INT32*)(ibuff + sizeof(Time));
+ for (j = 0; j < MAX_VALUATORS; j++)
+ {
+ if (j >= pDev->valuator->numAxes)
+ break;
+
+ /* fetch min/max/coordinate */
+ memcpy(&from.min_value, icbuf++, sizeof(INT32));
+ memcpy(&from.max_value, icbuf++, sizeof(INT32));
+ memcpy(&coord, icbuf++, sizeof(INT32));
+
+ to = (j < pDev->valuator->numAxes) ? &pDev->valuator->axes[j] : NULL;
+
+ /* x/y scaled to screen if no range is present */
+ if (j == 0 && (from.max_value < from.min_value))
+ from.max_value = pScreen->width;
+ else if (j == 1 && (from.max_value < from.min_value))
+ from.max_value = pScreen->height;
+
+ if (j == 0 && (to->max_value < to->min_value))
+ dflt = pScreen->width;
+ else if (j == 1 && (to->max_value < to->min_value))
+ dflt = pScreen->height;
+ else
+ dflt = 0;
+
+ /* scale from stored range into current range */
+ coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, 0);
+ memcpy(ocbuf, &coord, sizeof(INT32));
+ ocbuf++;
+ }
+ } else
+ memcpy(obuff, ibuff, size);
+
+ /* don't advance by size here. size may be different to the
+ * actually written size if the MD has less valuators than MAX */
+ if (core)
+ obuff += sizeof(INT32) + sizeof(Time);
+ else
+ obuff += (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time);
+ ret++;
+ }
+ }
+
+ return ret;
+}
+
+
+/**
+ * Update the motion history for a specific device, with the list of
+ * valuators.
+ *
+ * Layout of the history buffer:
+ * for SDs: [time] [val0] [val1] ... [valn]
+ * for MDs: [time] [min_val0] [max_val0] [val0] [min_val1] ... [valn]
+ *
+ * For events that have some valuators unset:
+ * min_val == max_val == val == 0.
+ */
+static void
+updateMotionHistory(DeviceIntPtr pDev, CARD32 ms, ValuatorMask *mask,
+ int *valuators)
+{
+ char *buff = (char *) pDev->valuator->motion;
+ ValuatorClassPtr v;
+ int i;
+
+ if (!pDev->valuator->numMotionEvents)
+ return;
+
+ v = pDev->valuator;
+ if (IsMaster(pDev))
+ {
+ buff += ((sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(CARD32)) *
+ v->last_motion;
+
+ memcpy(buff, &ms, sizeof(Time));
+ buff += sizeof(Time);
+
+ memset(buff, 0, sizeof(INT32) * 3 * MAX_VALUATORS);
+
+ for (i = 0; i < v->numAxes; i++)
+ {
+ /* XI1 doesn't support mixed mode devices */
+ if (valuator_get_mode(pDev, i) != valuator_get_mode(pDev, 0))
+ break;
+ if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i))
+ {
+ buff += 3 * sizeof(INT32);
+ continue;
+ }
+ memcpy(buff, &v->axes[i].min_value, sizeof(INT32));
+ buff += sizeof(INT32);
+ memcpy(buff, &v->axes[i].max_value, sizeof(INT32));
+ buff += sizeof(INT32);
+ memcpy(buff, &valuators[i], sizeof(INT32));
+ buff += sizeof(INT32);
+ }
+ } else
+ {
+
+ buff += ((sizeof(INT32) * pDev->valuator->numAxes) + sizeof(CARD32)) *
+ pDev->valuator->last_motion;
+
+ memcpy(buff, &ms, sizeof(Time));
+ buff += sizeof(Time);
+
+ memset(buff, 0, sizeof(INT32) * pDev->valuator->numAxes);
+
+ for (i = 0; i < MAX_VALUATORS; i++)
+ {
+ if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i))
+ {
+ buff += sizeof(INT32);
+ continue;
+ }
+ memcpy(buff, &valuators[i], sizeof(INT32));
+ buff += sizeof(INT32);
+ }
+ }
+
+ pDev->valuator->last_motion = (pDev->valuator->last_motion + 1) %
+ pDev->valuator->numMotionEvents;
+ /* If we're wrapping around, just keep the circular buffer going. */
+ if (pDev->valuator->first_motion == pDev->valuator->last_motion)
+ pDev->valuator->first_motion = (pDev->valuator->first_motion + 1) %
+ pDev->valuator->numMotionEvents;
+
+ return;
+}
+
+
+/**
+ * Returns the maximum number of events GetKeyboardEvents,
+ * GetKeyboardValuatorEvents, and GetPointerEvents will ever return.
+ *
+ * This MUST be absolutely constant, from init until exit.
+ */
+int
+GetMaximumEventsNum(void) {
+ /* One raw event
+ * One device event
+ * One possible device changed event
+ */
+ return 3;
+}
+
+
+/**
+ * Clip an axis to its bounds, which are declared in the call to
+ * InitValuatorAxisClassStruct.
+ */
+static void
+clipAxis(DeviceIntPtr pDev, int axisNum, int *val)
+{
+ AxisInfoPtr axis;
+
+ if (axisNum >= pDev->valuator->numAxes)
+ return;
+
+ axis = pDev->valuator->axes + axisNum;
+
+ /* If a value range is defined, clip. If not, do nothing */
+ if (axis->max_value <= axis->min_value)
+ return;
+
+ if (*val < axis->min_value)
+ *val = axis->min_value;
+ if (*val > axis->max_value)
+ *val = axis->max_value;
+}
+
+/**
+ * Clip every axis in the list of valuators to its bounds.
+ */
+static void
+clipValuators(DeviceIntPtr pDev, ValuatorMask *mask)
+{
+ int i;
+
+ for (i = 0; i < valuator_mask_size(mask); i++)
+ if (valuator_mask_isset(mask, i))
+ {
+ int val = valuator_mask_get(mask, i);
+ clipAxis(pDev, i, &val);
+ valuator_mask_set(mask, i, val);
+ }
+}
+
+/**
+ * Create the DCCE event (does not update the master's device state yet, this
+ * is done in the event processing).
+ * Pull in the coordinates from the MD if necessary.
+ *
+ * @param events Pointer to a pre-allocated event list.
+ * @param dev The slave device that generated an event.
+ * @param type Either DEVCHANGE_POINTER_EVENT and/or DEVCHANGE_KEYBOARD_EVENT
+ * @param num_events The current number of events, returns the number of
+ * events if a DCCE was generated.
+ * @return The updated @events pointer.
+ */
+EventListPtr
+UpdateFromMaster(EventListPtr events, DeviceIntPtr dev, int type, int *num_events)
+{
+ DeviceIntPtr master;
+
+ master = GetMaster(dev, (type & DEVCHANGE_POINTER_EVENT) ? MASTER_POINTER : MASTER_KEYBOARD);
+
+ if (master && master->last.slave != dev)
+ {
+ CreateClassesChangedEvent(events, master, dev, type);
+ if (IsPointerDevice(master))
+ {
+ updateSlaveDeviceCoords(master, dev);
+ master->last.numValuators = dev->last.numValuators;
+ }
+ master->last.slave = dev;
+ (*num_events)++;
+ events++;
+ }
+ return events;
+}
+
+/**
+ * Move the device's pointer to the position given in the valuators.
+ *
+ * @param dev The device which's pointer is to be moved.
+ * @param x Returns the x position of the pointer after the move.
+ * @param y Returns the y position of the pointer after the move.
+ * @param mask Bit mask of valid valuators.
+ * @param valuators Valuator data for each axis between @first and
+ * @first+@num.
+ */
+static void
+moveAbsolute(DeviceIntPtr dev, int *x, int *y, ValuatorMask *mask)
+{
+ int i;
+
+ if (valuator_mask_isset(mask, 0))
+ *x = valuator_mask_get(mask, 0);
+ else
+ *x = dev->last.valuators[0];
+
+ if (valuator_mask_isset(mask, 1))
+ *y = valuator_mask_get(mask, 1);
+ else
+ *y = dev->last.valuators[1];
+
+ clipAxis(dev, 0, x);
+ clipAxis(dev, 1, y);
+
+ for (i = 2; i < valuator_mask_size(mask); i++)
+ {
+ if (valuator_mask_isset(mask, i))
+ {
+ dev->last.valuators[i] = valuator_mask_get(mask, i);
+ clipAxis(dev, i, &dev->last.valuators[i]);
+ }
+ }
+}
+
+/**
+ * Move the device's pointer by the values given in @valuators.
+ *
+ * @param dev The device which's pointer is to be moved.
+ * @param x Returns the x position of the pointer after the move.
+ * @param y Returns the y position of the pointer after the move.
+ * @param mask Bit mask of valid valuators.
+ * @param valuators Valuator data for each axis between @first and
+ * @first+@num.
+ */
+static void
+moveRelative(DeviceIntPtr dev, int *x, int *y, ValuatorMask *mask)
+{
+ int i;
+
+ *x = dev->last.valuators[0];
+ *y = dev->last.valuators[1];
+
+ if (valuator_mask_isset(mask, 0))
+ *x += valuator_mask_get(mask, 0);
+
+ if (valuator_mask_isset(mask, 1))
+ *y += valuator_mask_get(mask, 1);
+
+ /* if attached, clip both x and y to the defined limits (usually
+ * co-ord space limit). If it is attached, we need x/y to go over the
+ * limits to be able to change screens. */
+ if(dev->u.master && dev->valuator) {
+ if (valuator_get_mode(dev, 0) == Absolute)
+ clipAxis(dev, 0, x);
+ if (valuator_get_mode(dev, 1) == Absolute)
+ clipAxis(dev, 1, y);
+ }
+
+ /* calc other axes, clip, drop back into valuators */
+ for (i = 2; i < valuator_mask_size(mask); i++)
+ {
+ if (valuator_mask_isset(mask, i))
+ {
+ dev->last.valuators[i] += valuator_mask_get(mask, i);
+ if (valuator_get_mode(dev, i) == Absolute)
+ clipAxis(dev, i, &dev->last.valuators[i]);
+ valuator_mask_set(mask, i, dev->last.valuators[i]);
+ }
+ }
+}
+
+/**
+ * Accelerate the data in valuators based on the device's acceleration scheme.
+ *
+ * @param dev The device which's pointer is to be moved.
+ * @param first The first valuator in @valuators
+ * @param num Total number of valuators in @valuators.
+ * @param valuators Valuator data for each axis between @first and
+ * @first+@num.
+ * @param ms Current time.
+ */
+static void
+accelPointer(DeviceIntPtr dev, int first, int num, int *valuators, CARD32 ms)
+{
+ if (dev->valuator->accelScheme.AccelSchemeProc)
+ dev->valuator->accelScheme.AccelSchemeProc(dev, first, num, valuators, ms);
+}
+
+/**
+ * If we have HW cursors, this actually moves the visible sprite. If not, we
+ * just do all the screen crossing, etc.
+ *
+ * We scale from device to screen coordinates here, call
+ * miPointerSetPosition() and then scale back into device coordinates (if
+ * needed). miPSP will change x/y if the screen was crossed.
+ *
+ * @param dev The device to be moved.
+ * @param x Pointer to current x-axis value, may be modified.
+ * @param y Pointer to current y-axis value, may be modified.
+ * @param x_frac Fractional part of current x-axis value, may be modified.
+ * @param y_frac Fractional part of current y-axis value, may be modified.
+ * @param scr Screen the device's sprite is currently on.
+ * @param screenx Screen x coordinate the sprite is on after the update.
+ * @param screeny Screen y coordinate the sprite is on after the update.
+ * @param screenx_frac Fractional part of screen x coordinate, as above.
+ * @param screeny_frac Fractional part of screen y coordinate, as above.
+ */
+static void
+positionSprite(DeviceIntPtr dev, int *x, int *y, float x_frac, float y_frac,
+ ScreenPtr scr, int *screenx, int *screeny, float *screenx_frac, float *screeny_frac)
+{
+ int old_screenx, old_screeny;
+
+ /* scale x&y to screen */
+ if (dev->valuator && dev->valuator->numAxes > 0) {
+ *screenx = rescaleValuatorAxis(*x, x_frac, screenx_frac,
+ dev->valuator->axes + 0, NULL, scr->width);
+ } else {
+ *screenx = dev->last.valuators[0];
+ *screenx_frac = dev->last.remainder[0];
+ }
+
+ if (dev->valuator && dev->valuator->numAxes > 1) {
+ *screeny = rescaleValuatorAxis(*y, y_frac, screeny_frac,
+ dev->valuator->axes + 1, NULL, scr->height);
+ } else {
+ *screeny = dev->last.valuators[1];
+ *screeny_frac = dev->last.remainder[1];
+ }
+
+ /* Hit the left screen edge? */
+ if (*screenx <= 0 && *screenx_frac < 0.0f)
+ {
+ *screenx_frac = 0.0f;
+ x_frac = 0.0f;
+ }
+ if (*screeny <= 0 && *screeny_frac < 0.0f)
+ {
+ *screeny_frac = 0.0f;
+ y_frac = 0.0f;
+ }
+
+
+ old_screenx = *screenx;
+ old_screeny = *screeny;
+ /* This takes care of crossing screens for us, as well as clipping
+ * to the current screen. */
+ miPointerSetPosition(dev, screenx, screeny);
+
+ if (dev->u.master) {
+ dev->u.master->last.valuators[0] = *screenx;
+ dev->u.master->last.valuators[1] = *screeny;
+ dev->u.master->last.remainder[0] = *screenx_frac;
+ dev->u.master->last.remainder[1] = *screeny_frac;
+ }
+
+ if (dev->valuator)
+ {
+ /* Crossed screen? Scale back to device coordiantes */
+ if(*screenx != old_screenx)
+ {
+ scr = miPointerGetScreen(dev);
+ *x = rescaleValuatorAxis(*screenx, *screenx_frac, &x_frac, NULL,
+ dev->valuator->axes + 0, scr->width);
+ }
+ if(*screeny != old_screeny)
+ {
+ scr = miPointerGetScreen(dev);
+ *y = rescaleValuatorAxis(*screeny, *screeny_frac, &y_frac, NULL,
+ dev->valuator->axes + 1, scr->height);
+ }
+ }
+
+ /* dropy x/y (device coordinates) back into valuators for next event */
+ dev->last.valuators[0] = *x;
+ dev->last.valuators[1] = *y;
+ dev->last.remainder[0] = x_frac;
+ dev->last.remainder[1] = y_frac;
+}
+
+/**
+ * Update the motion history for the device and (if appropriate) for its
+ * master device.
+ * @param dev Slave device to update.
+ * @param mask Bit mask of valid valuators to append to history.
+ * @param num Total number of valuators to append to history.
+ * @param ms Current time
+ */
+static void
+updateHistory(DeviceIntPtr dev, ValuatorMask *mask, CARD32 ms)
+{
+ if (!dev->valuator)
+ return;
+
+ updateMotionHistory(dev, ms, mask, dev->last.valuators);
+ if (dev->u.master)
+ {
+ DeviceIntPtr master = GetMaster(dev, MASTER_POINTER);
+ updateMotionHistory(master, ms, mask, dev->last.valuators);
+ }
+}
+
+/**
+ * Convenience wrapper around GetKeyboardValuatorEvents, that takes no
+ * valuators.
+ */
+int
+GetKeyboardEvents(EventList *events, DeviceIntPtr pDev, int type, int key_code) {
+ ValuatorMask mask;
+
+ valuator_mask_zero(&mask);
+ return GetKeyboardValuatorEvents(events, pDev, type, key_code, &mask);
+}
+
+
+/**
+ * Returns a set of InternalEvents for KeyPress/KeyRelease, optionally
+ * also with valuator events.
+ *
+ * events is not NULL-terminated; the return value is the number of events.
+ * The DDX is responsible for allocating the event structure in the first
+ * place via GetMaximumEventsNum(), and for freeing it.
+ */
+int
+GetKeyboardValuatorEvents(EventList *events, DeviceIntPtr pDev, int type,
+ int key_code, const ValuatorMask *mask_in) {
+ int num_events = 0;
+ CARD32 ms = 0;
+ DeviceEvent *event;
+ RawDeviceEvent *raw;
+ ValuatorMask mask;
+
+ /* refuse events from disabled devices */
+ if (!pDev->enabled)
+ return 0;
+
+ if (!events ||!pDev->key || !pDev->focus || !pDev->kbdfeed ||
+ (type != KeyPress && type != KeyRelease) ||
+ (key_code < 8 || key_code > 255))
+ return 0;
+
+ num_events = 1;
+
+ events = UpdateFromMaster(events, pDev, DEVCHANGE_KEYBOARD_EVENT, &num_events);
+
+ /* Handle core repeating, via press/release/press/release. */
+ if (type == KeyPress && key_is_down(pDev, key_code, KEY_POSTED)) {
+ /* If autorepeating is disabled either globally or just for that key,
+ * or we have a modifier, don't generate a repeat event. */
+ if (!pDev->kbdfeed->ctrl.autoRepeat ||
+ !key_autorepeats(pDev, key_code) ||
+ pDev->key->xkbInfo->desc->map->modmap[key_code])
+ return 0;
+ }
+
+ ms = GetTimeInMillis();
+
+ raw = (RawDeviceEvent*)events->event;
+ events++;
+ num_events++;
+
+ valuator_mask_copy(&mask, mask_in);
+
+ init_raw(pDev, raw, ms, type, key_code);
+ set_raw_valuators(raw, &mask, raw->valuators.data_raw);
+
+ clipValuators(pDev, &mask);
+
+ set_raw_valuators(raw, &mask, raw->valuators.data);
+
+ event = (DeviceEvent*) events->event;
+ init_event(pDev, event, ms);
+ event->detail.key = key_code;
+
+ if (type == KeyPress) {
+ event->type = ET_KeyPress;
+ set_key_down(pDev, key_code, KEY_POSTED);
+ }
+ else if (type == KeyRelease) {
+ event->type = ET_KeyRelease;
+ set_key_up(pDev, key_code, KEY_POSTED);
+ }
+
+ clipValuators(pDev, &mask);
+
+ set_valuators(pDev, event, &mask);
+
+ return num_events;
+}
+
+/**
+ * Initialize an event list and fill with 32 byte sized events.
+ * This event list is to be passed into GetPointerEvents() and
+ * GetKeyboardEvents().
+ *
+ * @param num_events Number of elements in list.
+ */
+EventListPtr
+InitEventList(int num_events)
+{
+ EventListPtr events;
+ int i;
+
+ events = (EventListPtr)calloc(num_events, sizeof(EventList));
+ if (!events)
+ return NULL;
+
+ for (i = 0; i < num_events; i++)
+ {
+ events[i].evlen = sizeof(InternalEvent);
+ events[i].event = calloc(1, sizeof(InternalEvent));
+ if (!events[i].event)
+ {
+ /* rollback */
+ while(i--)
+ free(events[i].event);
+ free(events);
+ events = NULL;
+ break;
+ }
+ }
+
+ return events;
+}
+
+/**
+ * Free an event list.
+ *
+ * @param list The list to be freed.
+ * @param num_events Number of elements in list.
+ */
+void
+FreeEventList(EventListPtr list, int num_events)
+{
+ if (!list)
+ return;
+ while(num_events--)
+ free(list[num_events].event);
+ free(list);
+}
+
+static void
+transformAbsolute(DeviceIntPtr dev, ValuatorMask *mask)
+{
+ struct pixman_f_vector p;
+
+ /* p' = M * p in homogeneous coordinates */
+ p.v[0] = (valuator_mask_isset(mask, 0) ? valuator_mask_get(mask, 0) :
+ dev->last.valuators[0]);
+ p.v[1] = (valuator_mask_isset(mask, 1) ? valuator_mask_get(mask, 1) :
+ dev->last.valuators[1]);
+ p.v[2] = 1.0;
+
+ pixman_f_transform_point(&dev->transform, &p);
+
+ if (lround(p.v[0]) != dev->last.valuators[0])
+ valuator_mask_set(mask, 0, lround(p.v[0]));
+ if (lround(p.v[1]) != dev->last.valuators[1])
+ valuator_mask_set(mask, 1, lround(p.v[1]));
+}
+
+/**
+ * Generate a series of InternalEvents (filled into the EventList)
+ * representing pointer motion, or button presses.
+ *
+ * events is not NULL-terminated; the return value is the number of events.
+ * The DDX is responsible for allocating the event structure in the first
+ * place via InitEventList() and GetMaximumEventsNum(), and for freeing it.
+ *
+ * In the generated events rootX/Y will be in absolute screen coords and
+ * the valuator information in the absolute or relative device coords.
+ *
+ * last.valuators[x] of the device is always in absolute device coords.
+ * last.valuators[x] of the master device is in absolute screen coords.
+ *
+ * master->last.valuators[x] for x > 2 is undefined.
+ */
+int
+GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons,
+ int flags, const ValuatorMask *mask_in) {
+ int num_events = 1;
+ CARD32 ms;
+ DeviceEvent *event;
+ RawDeviceEvent *raw;
+ int x = 0, y = 0, /* device coords */
+ cx, cy; /* only screen coordinates */
+ float x_frac = 0.0, y_frac = 0.0, cx_frac, cy_frac;
+ ScreenPtr scr = miPointerGetScreen(pDev);
+ ValuatorMask mask;
+
+ /* refuse events from disabled devices */
+ if (!pDev->enabled)
+ return 0;
+
+ if (!scr)
+ return 0;
+
+ switch (type)
+ {
+ case MotionNotify:
+ if (!mask_in || valuator_mask_num_valuators(mask_in) <= 0)
+ return 0;
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ if (!pDev->button || !buttons)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+
+ ms = GetTimeInMillis(); /* before pointer update to help precision */
+
+ events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events);
+
+ raw = (RawDeviceEvent*)events->event;
+ events++;
+ num_events++;
+
+ valuator_mask_copy(&mask, mask_in);
+
+ init_raw(pDev, raw, ms, type, buttons);
+ set_raw_valuators(raw, &mask, raw->valuators.data_raw);
+
+ if (flags & POINTER_ABSOLUTE)
+ {
+ if (flags & POINTER_SCREEN) /* valuators are in screen coords */
+ {
+ int scaled;
+
+ if (valuator_mask_isset(&mask, 0))
+ {
+ scaled = rescaleValuatorAxis(valuator_mask_get(&mask, 0),
+ 0.0, &x_frac, NULL,
+ pDev->valuator->axes + 0,
+ scr->width);
+ valuator_mask_set(&mask, 0, scaled);
+ }
+ if (valuator_mask_isset(&mask, 1))
+ {
+ scaled = rescaleValuatorAxis(valuator_mask_get(&mask, 1),
+ 0.0, &y_frac, NULL,
+ pDev->valuator->axes + 1,
+ scr->height);
+ valuator_mask_set(&mask, 1, scaled);
+ }
+ }
+
+ transformAbsolute(pDev, &mask);
+ moveAbsolute(pDev, &x, &y, &mask);
+ } else {
+ if (flags & POINTER_ACCELERATE) {
+ /* FIXME: Pointer acceleration only requires X and Y values. This
+ * should be converted to masked valuators. */
+ int vals[2];
+ vals[0] = valuator_mask_isset(&mask, 0) ?
+ valuator_mask_get(&mask, 0) : 0;
+ vals[1] = valuator_mask_isset(&mask, 1) ?
+ valuator_mask_get(&mask, 1) : 0;
+ accelPointer(pDev, 0, 2, vals, ms);
+
+ if (valuator_mask_isset(&mask, 0))
+ valuator_mask_set(&mask, 0, vals[0]);
+ if (valuator_mask_isset(&mask, 1))
+ valuator_mask_set(&mask, 1, vals[1]);
+
+ /* The pointer acceleration code modifies the fractional part
+ * in-place, so we need to extract this information first */
+ x_frac = pDev->last.remainder[0];
+ y_frac = pDev->last.remainder[1];
+ }
+ moveRelative(pDev, &x, &y, &mask);
+ }
+
+ set_raw_valuators(raw, &mask, raw->valuators.data);
+
+ positionSprite(pDev, &x, &y, x_frac, y_frac, scr, &cx, &cy, &cx_frac, &cy_frac);
+ updateHistory(pDev, &mask, ms);
+
+ /* Update the valuators with the true value sent to the client*/
+ if (valuator_mask_isset(&mask, 0))
+ valuator_mask_set(&mask, 0, x);
+ if (valuator_mask_isset(&mask, 1))
+ valuator_mask_set(&mask, 1, y);
+
+ clipValuators(pDev, &mask);
+
+ event = (DeviceEvent*) events->event;
+ init_event(pDev, event, ms);
+
+ if (type == MotionNotify) {
+ event->type = ET_Motion;
+ event->detail.button = 0;
+ }
+ else {
+ if (type == ButtonPress) {
+ event->type = ET_ButtonPress;
+ set_button_down(pDev, buttons, BUTTON_POSTED);
+ }
+ else if (type == ButtonRelease) {
+ event->type = ET_ButtonRelease;
+ set_button_up(pDev, buttons, BUTTON_POSTED);
+ }
+ event->detail.button = buttons;
+ }
+
+ event->root_x = cx; /* root_x/y always in screen coords */
+ event->root_y = cy;
+ event->root_x_frac = cx_frac;
+ event->root_y_frac = cy_frac;
+
+ set_valuators(pDev, event, &mask);
+
+ return num_events;
+}
+
+
+/**
+ * Generate ProximityIn/ProximityOut InternalEvents, accompanied by
+ * valuators.
+ *
+ * events is not NULL-terminated; the return value is the number of events.
+ * The DDX is responsible for allocating the event structure in the first
+ * place via GetMaximumEventsNum(), and for freeing it.
+ */
+int
+GetProximityEvents(EventList *events, DeviceIntPtr pDev, int type, const ValuatorMask *mask_in)
+{
+ int num_events = 1, i;
+ DeviceEvent *event;
+ ValuatorMask mask;
+
+ /* refuse events from disabled devices */
+ if (!pDev->enabled)
+ return 0;
+
+ /* Sanity checks. */
+ if ((type != ProximityIn && type != ProximityOut) || !mask_in)
+ return 0;
+ if (!pDev->valuator)
+ return 0;
+
+ valuator_mask_copy(&mask, mask_in);
+
+ /* ignore relative axes for proximity. */
+ for (i = 0; i < valuator_mask_size(&mask); i++)
+ {
+ if (valuator_mask_isset(&mask, i) &&
+ valuator_get_mode(pDev, i) == Relative)
+ valuator_mask_unset(&mask, i);
+ }
+
+ /* FIXME: posting proximity events with relative valuators only results
+ * in an empty event, EventToXI() will fail to convert → no event sent
+ * to client. */
+
+ events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events);
+
+ event = (DeviceEvent *) events->event;
+ init_event(pDev, event, GetTimeInMillis());
+ event->type = (type == ProximityIn) ? ET_ProximityIn : ET_ProximityOut;
+
+ clipValuators(pDev, &mask);
+
+ set_valuators(pDev, event, &mask);
+
+ return num_events;
+}
+
+/**
+ * Synthesize a single motion event for the core pointer.
+ *
+ * Used in cursor functions, e.g. when cursor confinement changes, and we need
+ * to shift the pointer to get it inside the new bounds.
+ */
+void
+PostSyntheticMotion(DeviceIntPtr pDev,
+ int x,
+ int y,
+ int screen,
+ unsigned long time)
+{
+ DeviceEvent ev;
+
+#ifdef PANORAMIX
+ /* Translate back to the sprite screen since processInputProc
+ will translate from sprite screen to screen 0 upon reentry
+ to the DIX layer. */
+ if (!noPanoramiXExtension) {
+ x += screenInfo.screens[0]->x - screenInfo.screens[screen]->x;
+ y += screenInfo.screens[0]->y - screenInfo.screens[screen]->y;
+ }
+#endif
+
+ memset(&ev, 0, sizeof(DeviceEvent));
+ init_event(pDev, &ev, time);
+ ev.root_x = x;
+ ev.root_y = y;
+ ev.type = ET_Motion;
+ ev.time = time;
+
+ /* FIXME: MD/SD considerations? */
+ (*pDev->public.processInputProc)((InternalEvent*)&ev, pDev);
+}
diff --git a/dix/globals.c b/dix/globals.c
new file mode 100644
index 0000000..0a6b170
--- /dev/null
+++ b/dix/globals.c
@@ -0,0 +1,131 @@
+/************************************************************
+
+Copyright 1987, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+********************************************************/
+
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/Xmd.h>
+#include "misc.h"
+#include "windowstr.h"
+#include "scrnintstr.h"
+#include "input.h"
+#include "dixfont.h"
+#include "site.h"
+#include "dixstruct.h"
+#include "os.h"
+
+ScreenInfo screenInfo;
+KeybdCtrl defaultKeyboardControl = {
+ DEFAULT_KEYBOARD_CLICK,
+ DEFAULT_BELL,
+ DEFAULT_BELL_PITCH,
+ DEFAULT_BELL_DURATION,
+ DEFAULT_AUTOREPEAT,
+ DEFAULT_AUTOREPEATS,
+ DEFAULT_LEDS,
+ 0};
+
+PtrCtrl defaultPointerControl = {
+ DEFAULT_PTR_NUMERATOR,
+ DEFAULT_PTR_DENOMINATOR,
+ DEFAULT_PTR_THRESHOLD,
+ 0};
+
+ClientPtr clients[MAXCLIENTS];
+ClientPtr serverClient;
+int currentMaxClients; /* current size of clients array */
+long maxBigRequestSize = MAX_BIG_REQUEST_SIZE;
+
+unsigned long globalSerialNumber = 0;
+unsigned long serverGeneration = 0;
+
+/* these next four are initialized in main.c */
+CARD32 ScreenSaverTime;
+CARD32 ScreenSaverInterval;
+int ScreenSaverBlanking;
+int ScreenSaverAllowExposures;
+
+#ifdef DPMSExtension
+CARD16 DPMSPowerLevel = 0;
+Bool DPMSDisabledSwitch = FALSE;
+Bool DPMSCapableFlag = FALSE;
+CARD32 DPMSStandbyTime;
+CARD32 DPMSSuspendTime;
+CARD32 DPMSOffTime;
+Bool DPMSEnabled;
+#endif
+
+CARD32 defaultScreenSaverTime = DEFAULT_SCREEN_SAVER_TIME;
+CARD32 defaultScreenSaverInterval = DEFAULT_SCREEN_SAVER_INTERVAL;
+int defaultScreenSaverBlanking = DEFAULT_SCREEN_SAVER_BLANKING;
+int defaultScreenSaverAllowExposures = DEFAULT_SCREEN_SAVER_EXPOSURES;
+#ifdef SCREENSAVER
+Bool screenSaverSuspended = FALSE;
+#endif
+
+char *defaultFontPath = COMPILEDDEFAULTFONTPATH;
+char *defaultTextFont = COMPILEDDEFAULTFONT;
+char *defaultCursorFont = COMPILEDCURSORFONT;
+FontPtr defaultFont; /* not declared in dix.h to avoid including font.h in
+ every compilation of dix code */
+CursorPtr rootCursor;
+Bool party_like_its_1989 = FALSE;
+Bool whiteRoot = FALSE;
+
+TimeStamp currentTime;
+TimeStamp lastDeviceEventTime;
+
+int defaultColorVisualClass = -1;
+int monitorResolution = 0;
+
+char *display;
+char *ConnectionInfo;
+
+CARD32 TimeOutValue = DEFAULT_TIMEOUT * MILLI_PER_SECOND;
diff --git a/dix/glyphcurs.c b/dix/glyphcurs.c
new file mode 100644
index 0000000..fa2aeca
--- /dev/null
+++ b/dix/glyphcurs.c
@@ -0,0 +1,191 @@
+/************************************************************************
+
+Copyright 1987, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+************************************************************************/
+
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "misc.h"
+#include <X11/fonts/fontstruct.h>
+#include "dixfontstr.h"
+#include "scrnintstr.h"
+#include "gcstruct.h"
+#include "resource.h"
+#include "dix.h"
+#include "cursorstr.h"
+#include "opaque.h"
+#include "servermd.h"
+
+
+/*
+ get the bits out of the font in a portable way. to avoid
+dealing with padding and such-like, we draw the glyph into
+a bitmap, then read the bits out with GetImage, which
+uses server-natural format.
+ since all screens return the same bitmap format, we'll just use
+the first one we find.
+ the character origin lines up with the hotspot in the
+cursor metrics.
+*/
+
+int
+ServerBitsFromGlyph(FontPtr pfont, unsigned ch, CursorMetricPtr cm, unsigned char **ppbits)
+{
+ ScreenPtr pScreen;
+ GCPtr pGC;
+ xRectangle rect;
+ PixmapPtr ppix;
+ long nby;
+ char *pbits;
+ ChangeGCVal gcval[3];
+ unsigned char char2b[2];
+
+ /* turn glyph index into a protocol-format char2b */
+ char2b[0] = (unsigned char)(ch >> 8);
+ char2b[1] = (unsigned char)(ch & 0xff);
+
+ pScreen = screenInfo.screens[0];
+ nby = BitmapBytePad(cm->width) * (long)cm->height;
+ pbits = calloc(1, nby);
+ if (!pbits)
+ return BadAlloc;
+
+ ppix = (PixmapPtr)(*pScreen->CreatePixmap)(pScreen, cm->width,
+ cm->height, 1,
+ CREATE_PIXMAP_USAGE_SCRATCH);
+ pGC = GetScratchGC(1, pScreen);
+ if (!ppix || !pGC)
+ {
+ if (ppix)
+ (*pScreen->DestroyPixmap)(ppix);
+ if (pGC)
+ FreeScratchGC(pGC);
+ free(pbits);
+ return BadAlloc;
+ }
+
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = cm->width;
+ rect.height = cm->height;
+
+ /* fill the pixmap with 0 */
+ gcval[0].val = GXcopy;
+ gcval[1].val = 0;
+ gcval[2].ptr = (pointer)pfont;
+ ChangeGC(NullClient, pGC, GCFunction | GCForeground | GCFont, gcval);
+ ValidateGC((DrawablePtr)ppix, pGC);
+ (*pGC->ops->PolyFillRect)((DrawablePtr)ppix, pGC, 1, &rect);
+
+ /* draw the glyph */
+ gcval[0].val = 1;
+ ChangeGC(NullClient, pGC, GCForeground, gcval);
+ ValidateGC((DrawablePtr)ppix, pGC);
+ (*pGC->ops->PolyText16)((DrawablePtr)ppix, pGC, cm->xhot, cm->yhot,
+ 1, (unsigned short *)char2b);
+ (*pScreen->GetImage)((DrawablePtr)ppix, 0, 0, cm->width, cm->height,
+ XYPixmap, 1, pbits);
+ *ppbits = (unsigned char *)pbits;
+ FreeScratchGC(pGC);
+ (*pScreen->DestroyPixmap)(ppix);
+ return Success;
+}
+
+
+Bool
+CursorMetricsFromGlyph(FontPtr pfont, unsigned ch, CursorMetricPtr cm)
+{
+ CharInfoPtr pci;
+ unsigned long nglyphs;
+ CARD8 chs[2];
+ FontEncoding encoding;
+
+ chs[0] = ch >> 8;
+ chs[1] = ch;
+ encoding = (FONTLASTROW(pfont) == 0) ? Linear16Bit : TwoD16Bit;
+ if (encoding == Linear16Bit)
+ {
+ if (ch < pfont->info.firstCol || pfont->info.lastCol < ch)
+ return FALSE;
+ }
+ else
+ {
+ if (chs[0] < pfont->info.firstRow || pfont->info.lastRow < chs[0])
+ return FALSE;
+ if (chs[1] < pfont->info.firstCol || pfont->info.lastCol < chs[1])
+ return FALSE;
+ }
+ (*pfont->get_glyphs) (pfont, 1, chs, encoding, &nglyphs, &pci);
+ if (nglyphs == 0)
+ return FALSE;
+ cm->width = pci->metrics.rightSideBearing - pci->metrics.leftSideBearing;
+ cm->height = pci->metrics.descent + pci->metrics.ascent;
+ if (pci->metrics.leftSideBearing > 0)
+ {
+ cm->width += pci->metrics.leftSideBearing;
+ cm->xhot = 0;
+ }
+ else
+ {
+ cm->xhot = -pci->metrics.leftSideBearing;
+ if (pci->metrics.rightSideBearing < 0)
+ cm->width -= pci->metrics.rightSideBearing;
+ }
+ if (pci->metrics.ascent < 0)
+ {
+ cm->height -= pci->metrics.ascent;
+ cm->yhot = 0;
+ }
+ else
+ {
+ cm->yhot = pci->metrics.ascent;
+ if (pci->metrics.descent < 0)
+ cm->height -= pci->metrics.descent;
+ }
+ return TRUE;
+}
diff --git a/dix/grabs.c b/dix/grabs.c
new file mode 100644
index 0000000..69c58df
--- /dev/null
+++ b/dix/grabs.c
@@ -0,0 +1,557 @@
+/*
+
+Copyright 1987, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+*/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include "misc.h"
+#include <X11/Xproto.h>
+#include <X11/extensions/XI2.h>
+#include "windowstr.h"
+#include "inputstr.h"
+#include "cursorstr.h"
+#include "dixgrabs.h"
+#include "xace.h"
+#include "exevents.h"
+
+#define BITMASK(i) (((Mask)1) << ((i) & 31))
+#define MASKIDX(i) ((i) >> 5)
+#define MASKWORD(buf, i) buf[MASKIDX(i)]
+#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i)
+#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i)
+#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i))
+
+GrabPtr
+CreateGrab(
+ int client,
+ DeviceIntPtr device,
+ DeviceIntPtr modDevice,
+ WindowPtr window,
+ GrabType grabtype,
+ GrabMask *mask,
+ GrabParameters *param,
+ int type,
+ KeyCode keybut, /* key or button */
+ WindowPtr confineTo,
+ CursorPtr cursor)
+{
+ GrabPtr grab;
+
+ grab = calloc(1, sizeof(GrabRec));
+ if (!grab)
+ return (GrabPtr)NULL;
+ grab->resource = FakeClientID(client);
+ grab->device = device;
+ grab->window = window;
+ grab->eventMask = mask->core; /* same for XI */
+ grab->deviceMask = 0;
+ grab->ownerEvents = param->ownerEvents;
+ grab->keyboardMode = param->this_device_mode;
+ grab->pointerMode = param->other_devices_mode;
+ grab->modifiersDetail.exact = param->modifiers;
+ grab->modifiersDetail.pMask = NULL;
+ grab->modifierDevice = modDevice;
+ grab->type = type;
+ grab->grabtype = grabtype;
+ grab->detail.exact = keybut;
+ grab->detail.pMask = NULL;
+ grab->confineTo = confineTo;
+ grab->cursor = cursor;
+ grab->next = NULL;
+
+ if (grabtype == GRABTYPE_XI2)
+ memcpy(grab->xi2mask, mask->xi2mask, sizeof(mask->xi2mask));
+ if (cursor)
+ cursor->refcnt++;
+ return grab;
+
+}
+
+static void
+FreeGrab(GrabPtr pGrab)
+{
+ free(pGrab->modifiersDetail.pMask);
+ free(pGrab->detail.pMask);
+
+ if (pGrab->cursor)
+ FreeCursor(pGrab->cursor, (Cursor)0);
+
+ free(pGrab);
+}
+
+int
+DeletePassiveGrab(pointer value, XID id)
+{
+ GrabPtr g, prev;
+ GrabPtr pGrab = (GrabPtr)value;
+
+ /* it is OK if the grab isn't found */
+ prev = 0;
+ for (g = (wPassiveGrabs (pGrab->window)); g; g = g->next)
+ {
+ if (pGrab == g)
+ {
+ if (prev)
+ prev->next = g->next;
+ else
+ if (!(pGrab->window->optional->passiveGrabs = g->next))
+ CheckWindowOptionalNeed (pGrab->window);
+ break;
+ }
+ prev = g;
+ }
+ FreeGrab(pGrab);
+ return Success;
+}
+
+static Mask *
+DeleteDetailFromMask(Mask *pDetailMask, unsigned int detail)
+{
+ Mask *mask;
+ int i;
+
+ mask = malloc(sizeof(Mask) * MasksPerDetailMask);
+ if (mask)
+ {
+ if (pDetailMask)
+ for (i = 0; i < MasksPerDetailMask; i++)
+ mask[i]= pDetailMask[i];
+ else
+ for (i = 0; i < MasksPerDetailMask; i++)
+ mask[i]= ~0L;
+ BITCLEAR(mask, detail);
+ }
+ return mask;
+}
+
+static Bool
+IsInGrabMask(
+ DetailRec firstDetail,
+ DetailRec secondDetail,
+ unsigned int exception)
+{
+ if (firstDetail.exact == exception)
+ {
+ if (firstDetail.pMask == NULL)
+ return TRUE;
+
+ /* (at present) never called with two non-null pMasks */
+ if (secondDetail.exact == exception)
+ return FALSE;
+
+ if (GETBIT(firstDetail.pMask, secondDetail.exact))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static Bool
+IdenticalExactDetails(
+ unsigned int firstExact,
+ unsigned int secondExact,
+ unsigned int exception)
+{
+ if ((firstExact == exception) || (secondExact == exception))
+ return FALSE;
+
+ if (firstExact == secondExact)
+ return TRUE;
+
+ return FALSE;
+}
+
+static Bool
+DetailSupersedesSecond(
+ DetailRec firstDetail,
+ DetailRec secondDetail,
+ unsigned int exception)
+{
+ if (IsInGrabMask(firstDetail, secondDetail, exception))
+ return TRUE;
+
+ if (IdenticalExactDetails(firstDetail.exact, secondDetail.exact,
+ exception))
+ return TRUE;
+
+ return FALSE;
+}
+
+static Bool
+GrabSupersedesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
+{
+ unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ?
+ (unsigned int)XIAnyModifier :
+ (unsigned int)AnyModifier;
+ if (!DetailSupersedesSecond(pFirstGrab->modifiersDetail,
+ pSecondGrab->modifiersDetail,
+ any_modifier))
+ return FALSE;
+
+ if (DetailSupersedesSecond(pFirstGrab->detail,
+ pSecondGrab->detail, (unsigned int)AnyKey))
+ return TRUE;
+
+ return FALSE;
+}
+
+/**
+ * Compares two grabs and returns TRUE if the first grab matches the second
+ * grab.
+ *
+ * A match is when
+ * - the devices set for the grab are equal (this is optional).
+ * - the event types for both grabs are equal.
+ * - XXX
+ *
+ * @param ignoreDevice TRUE if the device settings on the grabs are to be
+ * ignored.
+ * @return TRUE if the grabs match or FALSE otherwise.
+ */
+Bool
+GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab, Bool ignoreDevice)
+{
+ unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ?
+ (unsigned int)XIAnyModifier :
+ (unsigned int)AnyModifier;
+
+ if (pFirstGrab->grabtype != pSecondGrab->grabtype)
+ return FALSE;
+
+ if (pFirstGrab->grabtype == GRABTYPE_XI2)
+ {
+ if (pFirstGrab->device == inputInfo.all_devices ||
+ pSecondGrab->device == inputInfo.all_devices)
+ {
+ /* do nothing */
+ } else if (pFirstGrab->device == inputInfo.all_master_devices)
+ {
+ if (pSecondGrab->device != inputInfo.all_master_devices &&
+ !IsMaster(pSecondGrab->device))
+ return FALSE;
+ } else if (pSecondGrab->device == inputInfo.all_master_devices)
+ {
+ if (pFirstGrab->device != inputInfo.all_master_devices &&
+ !IsMaster(pFirstGrab->device))
+ return FALSE;
+ } else if (pSecondGrab->device != pFirstGrab->device)
+ return FALSE;
+ } else if (!ignoreDevice &&
+ ((pFirstGrab->device != pSecondGrab->device) ||
+ (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice)))
+ return FALSE;
+
+ if (pFirstGrab->type != pSecondGrab->type)
+ return FALSE;
+
+ if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) ||
+ GrabSupersedesSecond(pSecondGrab, pFirstGrab))
+ return TRUE;
+
+ if (DetailSupersedesSecond(pSecondGrab->detail, pFirstGrab->detail,
+ (unsigned int)AnyKey)
+ &&
+ DetailSupersedesSecond(pFirstGrab->modifiersDetail,
+ pSecondGrab->modifiersDetail,
+ any_modifier))
+ return TRUE;
+
+ if (DetailSupersedesSecond(pFirstGrab->detail, pSecondGrab->detail,
+ (unsigned int)AnyKey)
+ &&
+ DetailSupersedesSecond(pSecondGrab->modifiersDetail,
+ pFirstGrab->modifiersDetail,
+ any_modifier))
+ return TRUE;
+
+ return FALSE;
+}
+
+static Bool
+GrabsAreIdentical(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
+{
+ unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ?
+ (unsigned int)XIAnyModifier :
+ (unsigned int)AnyModifier;
+
+ if (pFirstGrab->grabtype != pSecondGrab->grabtype)
+ return FALSE;
+
+ if (pFirstGrab->device != pSecondGrab->device ||
+ (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) ||
+ (pFirstGrab->type != pSecondGrab->type))
+ return FALSE;
+
+ if (!(DetailSupersedesSecond(pFirstGrab->detail,
+ pSecondGrab->detail,
+ (unsigned int)AnyKey) &&
+ DetailSupersedesSecond(pSecondGrab->detail,
+ pFirstGrab->detail,
+ (unsigned int)AnyKey)))
+ return FALSE;
+
+
+ if (!(DetailSupersedesSecond(pFirstGrab->modifiersDetail,
+ pSecondGrab->modifiersDetail,
+ any_modifier) &&
+ DetailSupersedesSecond(pSecondGrab->modifiersDetail,
+ pFirstGrab->modifiersDetail,
+ any_modifier)))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/**
+ * Prepend the new grab to the list of passive grabs on the window.
+ * Any previously existing grab that matches the new grab will be removed.
+ * Adding a new grab that would override another client's grab will result in
+ * a BadAccess.
+ *
+ * @return Success or X error code on failure.
+ */
+int
+AddPassiveGrabToList(ClientPtr client, GrabPtr pGrab)
+{
+ GrabPtr grab;
+ Mask access_mode = DixGrabAccess;
+ int rc;
+
+ for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next)
+ {
+ if (GrabMatchesSecond(pGrab, grab, FALSE))
+ {
+ if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource))
+ {
+ FreeGrab(pGrab);
+ return BadAccess;
+ }
+ }
+ }
+
+ if (pGrab->keyboardMode == GrabModeSync||pGrab->pointerMode == GrabModeSync)
+ access_mode |= DixFreezeAccess;
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, pGrab->device, access_mode);
+ if (rc != Success)
+ return rc;
+
+ /* Remove all grabs that match the new one exactly */
+ for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next)
+ {
+ if (GrabsAreIdentical(pGrab, grab))
+ {
+ DeletePassiveGrabFromList(grab);
+ break;
+ }
+ }
+
+ if (!pGrab->window->optional && !MakeWindowOptional (pGrab->window))
+ {
+ FreeGrab(pGrab);
+ return BadAlloc;
+ }
+
+ pGrab->next = pGrab->window->optional->passiveGrabs;
+ pGrab->window->optional->passiveGrabs = pGrab;
+ if (AddResource(pGrab->resource, RT_PASSIVEGRAB, (pointer)pGrab))
+ return Success;
+ return BadAlloc;
+}
+
+/* the following is kinda complicated, because we need to be able to back out
+ * if any allocation fails
+ */
+
+Bool
+DeletePassiveGrabFromList(GrabPtr pMinuendGrab)
+{
+ GrabPtr grab;
+ GrabPtr *deletes, *adds;
+ Mask ***updates, **details;
+ int i, ndels, nadds, nups;
+ Bool ok;
+ unsigned int any_modifier;
+ unsigned int any_key;
+
+#define UPDATE(mask,exact) \
+ if (!(details[nups] = DeleteDetailFromMask(mask, exact))) \
+ ok = FALSE; \
+ else \
+ updates[nups++] = &(mask)
+
+ i = 0;
+ for (grab = wPassiveGrabs(pMinuendGrab->window); grab; grab = grab->next)
+ i++;
+ if (!i)
+ return TRUE;
+ deletes = malloc(i * sizeof(GrabPtr));
+ adds = malloc(i * sizeof(GrabPtr));
+ updates = malloc(i * sizeof(Mask **));
+ details = malloc(i * sizeof(Mask *));
+ if (!deletes || !adds || !updates || !details)
+ {
+ free(details);
+ free(updates);
+ free(adds);
+ free(deletes);
+ return FALSE;
+ }
+
+ any_modifier = (pMinuendGrab->grabtype == GRABTYPE_XI2) ?
+ (unsigned int)XIAnyModifier : (unsigned int)AnyModifier;
+ any_key = (pMinuendGrab->grabtype == GRABTYPE_XI2) ?
+ (unsigned int)XIAnyKeycode : (unsigned int)AnyKey;
+ ndels = nadds = nups = 0;
+ ok = TRUE;
+ for (grab = wPassiveGrabs(pMinuendGrab->window);
+ grab && ok;
+ grab = grab->next)
+ {
+ if ((CLIENT_BITS(grab->resource) != CLIENT_BITS(pMinuendGrab->resource)) ||
+ !GrabMatchesSecond(grab, pMinuendGrab,
+ (grab->grabtype == GRABTYPE_CORE)))
+ continue;
+ if (GrabSupersedesSecond(pMinuendGrab, grab))
+ {
+ deletes[ndels++] = grab;
+ }
+ else if ((grab->detail.exact == any_key)
+ && (grab->modifiersDetail.exact != any_modifier))
+ {
+ UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
+ }
+ else if ((grab->modifiersDetail.exact == any_modifier)
+ && (grab->detail.exact != any_key))
+ {
+ UPDATE(grab->modifiersDetail.pMask,
+ pMinuendGrab->modifiersDetail.exact);
+ }
+ else if ((pMinuendGrab->detail.exact != any_key)
+ && (pMinuendGrab->modifiersDetail.exact != any_modifier))
+ {
+ GrabPtr pNewGrab;
+ GrabParameters param;
+
+ UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
+
+ memset(&param, 0, sizeof(param));
+ param.ownerEvents = grab->ownerEvents;
+ param.this_device_mode = grab->keyboardMode;
+ param.other_devices_mode = grab->pointerMode;
+ param.modifiers = any_modifier;
+
+ pNewGrab = CreateGrab(CLIENT_ID(grab->resource), grab->device,
+ grab->modifierDevice, grab->window,
+ grab->grabtype,
+ (GrabMask*)&grab->eventMask,
+ &param, (int)grab->type,
+ pMinuendGrab->detail.exact,
+ grab->confineTo, grab->cursor);
+ if (!pNewGrab)
+ ok = FALSE;
+ else if (!(pNewGrab->modifiersDetail.pMask =
+ DeleteDetailFromMask(grab->modifiersDetail.pMask,
+ pMinuendGrab->modifiersDetail.exact))
+ ||
+ (!pNewGrab->window->optional &&
+ !MakeWindowOptional(pNewGrab->window)))
+ {
+ FreeGrab(pNewGrab);
+ ok = FALSE;
+ }
+ else if (!AddResource(pNewGrab->resource, RT_PASSIVEGRAB,
+ (pointer)pNewGrab))
+ ok = FALSE;
+ else
+ adds[nadds++] = pNewGrab;
+ }
+ else if (pMinuendGrab->detail.exact == any_key)
+ {
+ UPDATE(grab->modifiersDetail.pMask,
+ pMinuendGrab->modifiersDetail.exact);
+ }
+ else
+ {
+ UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
+ }
+ }
+
+ if (!ok)
+ {
+ for (i = 0; i < nadds; i++)
+ FreeResource(adds[i]->resource, RT_NONE);
+ for (i = 0; i < nups; i++)
+ free(details[i]);
+ }
+ else
+ {
+ for (i = 0; i < ndels; i++)
+ FreeResource(deletes[i]->resource, RT_NONE);
+ for (i = 0; i < nadds; i++)
+ {
+ grab = adds[i];
+ grab->next = grab->window->optional->passiveGrabs;
+ grab->window->optional->passiveGrabs = grab;
+ }
+ for (i = 0; i < nups; i++)
+ {
+ free(*updates[i]);
+ *updates[i] = details[i];
+ }
+ }
+ free(details);
+ free(updates);
+ free(adds);
+ free(deletes);
+ return ok;
+
+#undef UPDATE
+}
diff --git a/dix/initatoms.c b/dix/initatoms.c
new file mode 100644
index 0000000..de101bd
--- /dev/null
+++ b/dix/initatoms.c
@@ -0,0 +1,84 @@
+/* THIS IS A GENERATED FILE
+ *
+ * Do not change! Changing this file implies a protocol change!
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/Xatom.h>
+#include "misc.h"
+#include "dix.h"
+void MakePredeclaredAtoms(void)
+{
+ if (MakeAtom("PRIMARY", 7, 1) != XA_PRIMARY) AtomError();
+ if (MakeAtom("SECONDARY", 9, 1) != XA_SECONDARY) AtomError();
+ if (MakeAtom("ARC", 3, 1) != XA_ARC) AtomError();
+ if (MakeAtom("ATOM", 4, 1) != XA_ATOM) AtomError();
+ if (MakeAtom("BITMAP", 6, 1) != XA_BITMAP) AtomError();
+ if (MakeAtom("CARDINAL", 8, 1) != XA_CARDINAL) AtomError();
+ if (MakeAtom("COLORMAP", 8, 1) != XA_COLORMAP) AtomError();
+ if (MakeAtom("CURSOR", 6, 1) != XA_CURSOR) AtomError();
+ if (MakeAtom("CUT_BUFFER0", 11, 1) != XA_CUT_BUFFER0) AtomError();
+ if (MakeAtom("CUT_BUFFER1", 11, 1) != XA_CUT_BUFFER1) AtomError();
+ if (MakeAtom("CUT_BUFFER2", 11, 1) != XA_CUT_BUFFER2) AtomError();
+ if (MakeAtom("CUT_BUFFER3", 11, 1) != XA_CUT_BUFFER3) AtomError();
+ if (MakeAtom("CUT_BUFFER4", 11, 1) != XA_CUT_BUFFER4) AtomError();
+ if (MakeAtom("CUT_BUFFER5", 11, 1) != XA_CUT_BUFFER5) AtomError();
+ if (MakeAtom("CUT_BUFFER6", 11, 1) != XA_CUT_BUFFER6) AtomError();
+ if (MakeAtom("CUT_BUFFER7", 11, 1) != XA_CUT_BUFFER7) AtomError();
+ if (MakeAtom("DRAWABLE", 8, 1) != XA_DRAWABLE) AtomError();
+ if (MakeAtom("FONT", 4, 1) != XA_FONT) AtomError();
+ if (MakeAtom("INTEGER", 7, 1) != XA_INTEGER) AtomError();
+ if (MakeAtom("PIXMAP", 6, 1) != XA_PIXMAP) AtomError();
+ if (MakeAtom("POINT", 5, 1) != XA_POINT) AtomError();
+ if (MakeAtom("RECTANGLE", 9, 1) != XA_RECTANGLE) AtomError();
+ if (MakeAtom("RESOURCE_MANAGER", 16, 1) != XA_RESOURCE_MANAGER) AtomError();
+ if (MakeAtom("RGB_COLOR_MAP", 13, 1) != XA_RGB_COLOR_MAP) AtomError();
+ if (MakeAtom("RGB_BEST_MAP", 12, 1) != XA_RGB_BEST_MAP) AtomError();
+ if (MakeAtom("RGB_BLUE_MAP", 12, 1) != XA_RGB_BLUE_MAP) AtomError();
+ if (MakeAtom("RGB_DEFAULT_MAP", 15, 1) != XA_RGB_DEFAULT_MAP) AtomError();
+ if (MakeAtom("RGB_GRAY_MAP", 12, 1) != XA_RGB_GRAY_MAP) AtomError();
+ if (MakeAtom("RGB_GREEN_MAP", 13, 1) != XA_RGB_GREEN_MAP) AtomError();
+ if (MakeAtom("RGB_RED_MAP", 11, 1) != XA_RGB_RED_MAP) AtomError();
+ if (MakeAtom("STRING", 6, 1) != XA_STRING) AtomError();
+ if (MakeAtom("VISUALID", 8, 1) != XA_VISUALID) AtomError();
+ if (MakeAtom("WINDOW", 6, 1) != XA_WINDOW) AtomError();
+ if (MakeAtom("WM_COMMAND", 10, 1) != XA_WM_COMMAND) AtomError();
+ if (MakeAtom("WM_HINTS", 8, 1) != XA_WM_HINTS) AtomError();
+ if (MakeAtom("WM_CLIENT_MACHINE", 17, 1) != XA_WM_CLIENT_MACHINE) AtomError();
+ if (MakeAtom("WM_ICON_NAME", 12, 1) != XA_WM_ICON_NAME) AtomError();
+ if (MakeAtom("WM_ICON_SIZE", 12, 1) != XA_WM_ICON_SIZE) AtomError();
+ if (MakeAtom("WM_NAME", 7, 1) != XA_WM_NAME) AtomError();
+ if (MakeAtom("WM_NORMAL_HINTS", 15, 1) != XA_WM_NORMAL_HINTS) AtomError();
+ if (MakeAtom("WM_SIZE_HINTS", 13, 1) != XA_WM_SIZE_HINTS) AtomError();
+ if (MakeAtom("WM_ZOOM_HINTS", 13, 1) != XA_WM_ZOOM_HINTS) AtomError();
+ if (MakeAtom("MIN_SPACE", 9, 1) != XA_MIN_SPACE) AtomError();
+ if (MakeAtom("NORM_SPACE", 10, 1) != XA_NORM_SPACE) AtomError();
+ if (MakeAtom("MAX_SPACE", 9, 1) != XA_MAX_SPACE) AtomError();
+ if (MakeAtom("END_SPACE", 9, 1) != XA_END_SPACE) AtomError();
+ if (MakeAtom("SUPERSCRIPT_X", 13, 1) != XA_SUPERSCRIPT_X) AtomError();
+ if (MakeAtom("SUPERSCRIPT_Y", 13, 1) != XA_SUPERSCRIPT_Y) AtomError();
+ if (MakeAtom("SUBSCRIPT_X", 11, 1) != XA_SUBSCRIPT_X) AtomError();
+ if (MakeAtom("SUBSCRIPT_Y", 11, 1) != XA_SUBSCRIPT_Y) AtomError();
+ if (MakeAtom("UNDERLINE_POSITION", 18, 1) != XA_UNDERLINE_POSITION) AtomError();
+ if (MakeAtom("UNDERLINE_THICKNESS", 19, 1) != XA_UNDERLINE_THICKNESS) AtomError();
+ if (MakeAtom("STRIKEOUT_ASCENT", 16, 1) != XA_STRIKEOUT_ASCENT) AtomError();
+ if (MakeAtom("STRIKEOUT_DESCENT", 17, 1) != XA_STRIKEOUT_DESCENT) AtomError();
+ if (MakeAtom("ITALIC_ANGLE", 12, 1) != XA_ITALIC_ANGLE) AtomError();
+ if (MakeAtom("X_HEIGHT", 8, 1) != XA_X_HEIGHT) AtomError();
+ if (MakeAtom("QUAD_WIDTH", 10, 1) != XA_QUAD_WIDTH) AtomError();
+ if (MakeAtom("WEIGHT", 6, 1) != XA_WEIGHT) AtomError();
+ if (MakeAtom("POINT_SIZE", 10, 1) != XA_POINT_SIZE) AtomError();
+ if (MakeAtom("RESOLUTION", 10, 1) != XA_RESOLUTION) AtomError();
+ if (MakeAtom("COPYRIGHT", 9, 1) != XA_COPYRIGHT) AtomError();
+ if (MakeAtom("NOTICE", 6, 1) != XA_NOTICE) AtomError();
+ if (MakeAtom("FONT_NAME", 9, 1) != XA_FONT_NAME) AtomError();
+ if (MakeAtom("FAMILY_NAME", 11, 1) != XA_FAMILY_NAME) AtomError();
+ if (MakeAtom("FULL_NAME", 9, 1) != XA_FULL_NAME) AtomError();
+ if (MakeAtom("CAP_HEIGHT", 10, 1) != XA_CAP_HEIGHT) AtomError();
+ if (MakeAtom("WM_CLASS", 8, 1) != XA_WM_CLASS) AtomError();
+ if (MakeAtom("WM_TRANSIENT_FOR", 16, 1) != XA_WM_TRANSIENT_FOR) AtomError();
+}
diff --git a/dix/inpututils.c b/dix/inpututils.c
new file mode 100644
index 0000000..ef3142c
--- /dev/null
+++ b/dix/inpututils.c
@@ -0,0 +1,558 @@
+/*
+ * Copyright © 2008 Daniel Stone
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Daniel Stone <daniel@fooishbar.org>
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include "dix-config.h"
+#endif
+
+#include "exevents.h"
+#include "exglobals.h"
+#include "misc.h"
+#include "input.h"
+#include "inputstr.h"
+#include "xace.h"
+#include "xkbsrv.h"
+#include "xkbstr.h"
+#include "inpututils.h"
+
+/* Check if a button map change is okay with the device.
+ * Returns -1 for BadValue, as it collides with MappingBusy. */
+static int
+check_butmap_change(DeviceIntPtr dev, CARD8 *map, int len, CARD32 *errval_out,
+ ClientPtr client)
+{
+ int i, ret;
+
+ if (!dev || !dev->button)
+ {
+ client->errorValue = (dev) ? dev->id : 0;
+ return BadDevice;
+ }
+
+ ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess);
+ if (ret != Success)
+ {
+ client->errorValue = dev->id;
+ return ret;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (dev->button->map[i + 1] != map[i] && dev->button->down[i + 1])
+ return MappingBusy;
+ }
+
+ return Success;
+}
+
+static void
+do_butmap_change(DeviceIntPtr dev, CARD8 *map, int len, ClientPtr client)
+{
+ int i;
+ xEvent core_mn;
+ deviceMappingNotify xi_mn;
+
+ /* The map in ButtonClassRec refers to button numbers, whereas the
+ * protocol is zero-indexed. Sigh. */
+ memcpy(&(dev->button->map[1]), map, len);
+
+ core_mn.u.u.type = MappingNotify;
+ core_mn.u.mappingNotify.request = MappingPointer;
+
+ /* 0 is the server client. */
+ for (i = 1; i < currentMaxClients; i++) {
+ /* Don't send irrelevant events to naïve clients. */
+ if (!clients[i] || clients[i]->clientState != ClientStateRunning)
+ continue;
+
+ if (!XIShouldNotify(clients[i], dev))
+ continue;
+
+ WriteEventsToClient(clients[i], 1, &core_mn);
+ }
+
+ xi_mn.type = DeviceMappingNotify;
+ xi_mn.request = MappingPointer;
+ xi_mn.deviceid = dev->id;
+ xi_mn.time = GetTimeInMillis();
+
+ SendEventToAllWindows(dev, DeviceMappingNotifyMask, (xEvent *) &xi_mn, 1);
+}
+
+/*
+ * Does what it says on the box, both for core and Xi.
+ *
+ * Faithfully reports any errors encountered while trying to apply the map
+ * to the requested device, faithfully ignores any errors encountered while
+ * trying to apply the map to its master/slaves.
+ */
+int
+ApplyPointerMapping(DeviceIntPtr dev, CARD8 *map, int len, ClientPtr client)
+{
+ int ret;
+
+ /* If we can't perform the change on the requested device, bail out. */
+ ret = check_butmap_change(dev, map, len, &client->errorValue, client);
+ if (ret != Success)
+ return ret;
+ do_butmap_change(dev, map, len, client);
+
+ return Success;
+}
+
+/* Check if a modifier map change is okay with the device.
+ * Returns -1 for BadValue, as it collides with MappingBusy; this particular
+ * caveat can be removed with LegalModifier, as we have no other reason to
+ * set MappingFailed. Sigh. */
+static int
+check_modmap_change(ClientPtr client, DeviceIntPtr dev, KeyCode *modmap)
+{
+ int ret, i;
+ XkbDescPtr xkb;
+
+ ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess);
+ if (ret != Success)
+ return ret;
+
+ if (!dev->key)
+ return BadMatch;
+ xkb = dev->key->xkbInfo->desc;
+
+ for (i = 0; i < MAP_LENGTH; i++) {
+ if (!modmap[i])
+ continue;
+
+ /* Check that all the new modifiers fall within the advertised
+ * keycode range. */
+ if (i < xkb->min_key_code || i > xkb->max_key_code) {
+ client->errorValue = i;
+ return -1;
+ }
+
+ /* Make sure the mapping is okay with the DDX. */
+ if (!LegalModifier(i, dev)) {
+ client->errorValue = i;
+ return MappingFailed;
+ }
+
+ /* None of the new modifiers may be down while we change the
+ * map. */
+ if (key_is_down(dev, i, KEY_POSTED | KEY_PROCESSED)) {
+ client->errorValue = i;
+ return MappingBusy;
+ }
+ }
+
+ /* None of the old modifiers may be down while we change the map,
+ * either. */
+ for (i = xkb->min_key_code; i < xkb->max_key_code; i++) {
+ if (!xkb->map->modmap[i])
+ continue;
+ if (key_is_down(dev, i, KEY_POSTED | KEY_PROCESSED)) {
+ client->errorValue = i;
+ return MappingBusy;
+ }
+ }
+
+ return Success;
+}
+
+static int
+check_modmap_change_slave(ClientPtr client, DeviceIntPtr master,
+ DeviceIntPtr slave, CARD8 *modmap)
+{
+ XkbDescPtr master_xkb, slave_xkb;
+ int i, j;
+
+ if (!slave->key || !master->key)
+ return 0;
+
+ master_xkb = master->key->xkbInfo->desc;
+ slave_xkb = slave->key->xkbInfo->desc;
+
+ /* Ignore devices with a clearly different keymap. */
+ if (slave_xkb->min_key_code != master_xkb->min_key_code ||
+ slave_xkb->max_key_code != master_xkb->max_key_code)
+ return 0;
+
+ for (i = 0; i < MAP_LENGTH; i++) {
+ if (!modmap[i])
+ continue;
+
+ /* If we have different symbols for any modifier on an
+ * extended keyboard, ignore the whole remap request. */
+ for (j = 0;
+ j < XkbKeyNumSyms(slave_xkb, i) &&
+ j < XkbKeyNumSyms(master_xkb, i);
+ j++)
+ if (XkbKeySymsPtr(slave_xkb, i)[j] != XkbKeySymsPtr(master_xkb, i)[j])
+ return 0;
+ }
+
+ if (check_modmap_change(client, slave, modmap) != Success)
+ return 0;
+
+ return 1;
+}
+
+/* Actually change the modifier map, and send notifications. Cannot fail. */
+static void
+do_modmap_change(ClientPtr client, DeviceIntPtr dev, CARD8 *modmap)
+{
+ XkbApplyMappingChange(dev, NULL, 0, 0, modmap, serverClient);
+}
+
+/* Rebuild modmap (key -> mod) from map (mod -> key). */
+static int build_modmap_from_modkeymap(CARD8 *modmap, KeyCode *modkeymap,
+ int max_keys_per_mod)
+{
+ int i, len = max_keys_per_mod * 8;
+
+ memset(modmap, 0, MAP_LENGTH);
+
+ for (i = 0; i < len; i++) {
+ if (!modkeymap[i])
+ continue;
+
+ if (modkeymap[i] >= MAP_LENGTH)
+ return BadValue;
+
+ if (modmap[modkeymap[i]])
+ return BadValue;
+
+ modmap[modkeymap[i]] = 1 << (i / max_keys_per_mod);
+ }
+
+ return Success;
+}
+
+int
+change_modmap(ClientPtr client, DeviceIntPtr dev, KeyCode *modkeymap,
+ int max_keys_per_mod)
+{
+ int ret;
+ CARD8 modmap[MAP_LENGTH];
+ DeviceIntPtr tmp;
+
+ ret = build_modmap_from_modkeymap(modmap, modkeymap, max_keys_per_mod);
+ if (ret != Success)
+ return ret;
+
+ /* If we can't perform the change on the requested device, bail out. */
+ ret = check_modmap_change(client, dev, modmap);
+ if (ret != Success)
+ return ret;
+ do_modmap_change(client, dev, modmap);
+
+ /* Change any attached masters/slaves. */
+ if (IsMaster(dev)) {
+ for (tmp = inputInfo.devices; tmp; tmp = tmp->next) {
+ if (!IsMaster(tmp) && tmp->u.master == dev)
+ if (check_modmap_change_slave(client, dev, tmp, modmap))
+ do_modmap_change(client, tmp, modmap);
+ }
+ }
+ else if (dev->u.master && dev->u.master->u.lastSlave == dev) {
+ /* If this fails, expect the results to be weird. */
+ if (check_modmap_change(client, dev->u.master, modmap))
+ do_modmap_change(client, dev->u.master, modmap);
+ }
+
+ return Success;
+}
+
+int generate_modkeymap(ClientPtr client, DeviceIntPtr dev,
+ KeyCode **modkeymap_out, int *max_keys_per_mod_out)
+{
+ CARD8 keys_per_mod[8];
+ int max_keys_per_mod;
+ KeyCode *modkeymap = NULL;
+ int i, j, ret;
+
+ ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGetAttrAccess);
+ if (ret != Success)
+ return ret;
+
+ if (!dev->key)
+ return BadMatch;
+
+ /* Count the number of keys per modifier to determine how wide we
+ * should make the map. */
+ max_keys_per_mod = 0;
+ for (i = 0; i < 8; i++)
+ keys_per_mod[i] = 0;
+ for (i = 8; i < MAP_LENGTH; i++) {
+ for (j = 0; j < 8; j++) {
+ if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) {
+ if (++keys_per_mod[j] > max_keys_per_mod)
+ max_keys_per_mod = keys_per_mod[j];
+ }
+ }
+ }
+
+ if (max_keys_per_mod != 0) {
+ modkeymap = calloc(max_keys_per_mod * 8, sizeof(KeyCode));
+ if (!modkeymap)
+ return BadAlloc;
+
+ for (i = 0; i < 8; i++)
+ keys_per_mod[i] = 0;
+
+ for (i = 8; i < MAP_LENGTH; i++) {
+ for (j = 0; j < 8; j++) {
+ if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) {
+ modkeymap[(j * max_keys_per_mod) + keys_per_mod[j]] = i;
+ keys_per_mod[j]++;
+ }
+ }
+ }
+ }
+
+ *max_keys_per_mod_out = max_keys_per_mod;
+ *modkeymap_out = modkeymap;
+
+ return Success;
+}
+
+/**
+ * Duplicate the InputAttributes in the most obvious way.
+ * No special memory handling is used to give drivers the maximum
+ * flexibility with the data. Drivers should be able to call realloc on the
+ * product string if needed and perform similar operations.
+ */
+InputAttributes*
+DuplicateInputAttributes(InputAttributes *attrs)
+{
+ InputAttributes *new_attr;
+ int ntags = 0;
+ char **tags, **new_tags;
+
+ if (!attrs)
+ return NULL;
+
+ if (!(new_attr = calloc(1, sizeof(InputAttributes))))
+ goto unwind;
+
+ if (attrs->product && !(new_attr->product = strdup(attrs->product)))
+ goto unwind;
+ if (attrs->vendor && !(new_attr->vendor = strdup(attrs->vendor)))
+ goto unwind;
+ if (attrs->device && !(new_attr->device = strdup(attrs->device)))
+ goto unwind;
+ if (attrs->pnp_id && !(new_attr->pnp_id = strdup(attrs->pnp_id)))
+ goto unwind;
+ if (attrs->usb_id && !(new_attr->usb_id = strdup(attrs->usb_id)))
+ goto unwind;
+
+ new_attr->flags = attrs->flags;
+
+ if ((tags = attrs->tags))
+ {
+ while(*tags++)
+ ntags++;
+
+ new_attr->tags = calloc(ntags + 1, sizeof(char*));
+ if (!new_attr->tags)
+ goto unwind;
+
+ tags = attrs->tags;
+ new_tags = new_attr->tags;
+
+ while(*tags)
+ {
+ *new_tags = strdup(*tags);
+ if (!*new_tags)
+ goto unwind;
+
+ tags++;
+ new_tags++;
+ }
+ }
+
+ return new_attr;
+
+unwind:
+ FreeInputAttributes(new_attr);
+ return NULL;
+}
+
+void
+FreeInputAttributes(InputAttributes *attrs)
+{
+ char **tags;
+
+ if (!attrs)
+ return;
+
+ free(attrs->product);
+ free(attrs->vendor);
+ free(attrs->device);
+ free(attrs->pnp_id);
+ free(attrs->usb_id);
+
+ if ((tags = attrs->tags))
+ while(*tags)
+ free(*tags++);
+
+ free(attrs->tags);
+ free(attrs);
+}
+
+/**
+ * Alloc a valuator mask large enough for num_valuators.
+ */
+ValuatorMask*
+valuator_mask_new(int num_valuators)
+{
+ /* alloc a fixed size mask for now and ignore num_valuators. in the
+ * flying-car future, when we can dynamically alloc the masks and are
+ * not constrained by signals, we can start using num_valuators */
+ ValuatorMask *mask = calloc(1, sizeof(ValuatorMask));
+ mask->last_bit = -1;
+ return mask;
+}
+
+void
+valuator_mask_free(ValuatorMask **mask)
+{
+ free(*mask);
+ *mask = NULL;
+}
+
+
+/**
+ * Sets a range of valuators between first_valuator and num_valuators with
+ * the data in the valuators array. All other values are set to 0.
+ */
+void
+valuator_mask_set_range(ValuatorMask *mask, int first_valuator, int num_valuators,
+ const int* valuators)
+{
+ int i;
+
+ valuator_mask_zero(mask);
+
+ for (i = first_valuator; i < min(first_valuator + num_valuators, MAX_VALUATORS); i++)
+ valuator_mask_set(mask, i, valuators[i - first_valuator]);
+}
+
+/**
+ * Reset mask to zero.
+ */
+void
+valuator_mask_zero(ValuatorMask *mask)
+{
+ memset(mask, 0, sizeof(*mask));
+ mask->last_bit = -1;
+}
+
+/**
+ * Returns the current size of the mask (i.e. the highest number of
+ * valuators currently set + 1).
+ */
+int
+valuator_mask_size(const ValuatorMask *mask)
+{
+ return mask->last_bit + 1;
+}
+
+/**
+ * Returns the number of valuators set in the given mask.
+ */
+int
+valuator_mask_num_valuators(const ValuatorMask *mask)
+{
+ return CountBits(mask->mask, min(mask->last_bit + 1, MAX_VALUATORS));
+}
+
+/**
+ * Return true if the valuator is set in the mask, or false otherwise.
+ */
+int
+valuator_mask_isset(const ValuatorMask *mask, int valuator)
+{
+ return mask->last_bit >= valuator && BitIsOn(mask->mask, valuator);
+}
+
+/**
+ * Set the valuator to the given data.
+ */
+void
+valuator_mask_set(ValuatorMask *mask, int valuator, int data)
+{
+ mask->last_bit = max(valuator, mask->last_bit);
+ SetBit(mask->mask, valuator);
+ mask->valuators[valuator] = data;
+}
+
+/**
+ * Return the requested valuator value. If the mask bit is not set for the
+ * given valuator, the returned value is undefined.
+ */
+int
+valuator_mask_get(const ValuatorMask *mask, int valuator)
+{
+ return mask->valuators[valuator];
+}
+
+/**
+ * Remove the valuator from the mask.
+ */
+void
+valuator_mask_unset(ValuatorMask *mask, int valuator)
+{
+ if (mask->last_bit >= valuator) {
+ int i, lastbit = -1;
+
+ ClearBit(mask->mask, valuator);
+ mask->valuators[valuator] = 0;
+
+ for (i = 0; i <= mask->last_bit; i++)
+ if (valuator_mask_isset(mask, i))
+ lastbit = max(lastbit, i);
+ mask->last_bit = lastbit;
+ }
+}
+
+void
+valuator_mask_copy(ValuatorMask *dest, const ValuatorMask *src)
+{
+ if (src)
+ memcpy(dest, src, sizeof(*dest));
+ else
+ valuator_mask_zero(dest);
+}
+
+int
+CountBits(const uint8_t *mask, int len)
+{
+ int i;
+ int ret = 0;
+
+ for (i = 0; i < len; i++)
+ if (BitIsOn(mask, i))
+ ret++;
+
+ return ret;
+}
diff --git a/dix/main.c b/dix/main.c
new file mode 100644
index 0000000..e20ffd6
--- /dev/null
+++ b/dix/main.c
@@ -0,0 +1,358 @@
+/***********************************************************
+
+Copyright 1987, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+******************************************************************/
+
+/* The panoramix components contained the following notice */
+/*****************************************************************
+
+Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
+BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of Digital Equipment Corporation
+shall not be used in advertising or otherwise to promote the sale, use or other
+dealings in this Software without prior written authorization from Digital
+Equipment Corporation.
+
+******************************************************************/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#include <version-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/Xos.h> /* for unistd.h */
+#include <X11/Xproto.h>
+#include <pixman.h>
+#include "scrnintstr.h"
+#include "misc.h"
+#include "os.h"
+#include "windowstr.h"
+#include "resource.h"
+#include "dixstruct.h"
+#include "gcstruct.h"
+#include "extension.h"
+#include "colormap.h"
+#include "colormapst.h"
+#include "cursorstr.h"
+#include "selection.h"
+#include <X11/fonts/font.h>
+#include "opaque.h"
+#include "servermd.h"
+#include "hotplug.h"
+#include "site.h"
+#include "dixfont.h"
+#include "extnsionst.h"
+#include "privates.h"
+#include "registry.h"
+#ifdef PANORAMIX
+#include "panoramiXsrv.h"
+#else
+#include "dixevents.h" /* InitEvents() */
+#endif
+
+#ifdef DPMSExtension
+#include <X11/extensions/dpmsconst.h>
+#include "dpmsproc.h"
+#endif
+
+extern void Dispatch(void);
+
+#ifdef XQUARTZ
+#include <pthread.h>
+
+BOOL serverRunning = FALSE;
+pthread_mutex_t serverRunningMutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t serverRunningCond = PTHREAD_COND_INITIALIZER;
+
+int dix_main(int argc, char *argv[], char *envp[]);
+
+int dix_main(int argc, char *argv[], char *envp[])
+#else
+int main(int argc, char *argv[], char *envp[])
+#endif
+{
+ int i;
+ HWEventQueueType alwaysCheckForInput[2];
+
+ display = "0";
+
+ InitRegions();
+
+ pixman_disable_out_of_bounds_workaround();
+
+ CheckUserParameters(argc, argv, envp);
+
+ CheckUserAuthorization();
+
+ InitConnectionLimits();
+
+ ProcessCommandLine(argc, argv);
+
+ alwaysCheckForInput[0] = 0;
+ alwaysCheckForInput[1] = 1;
+ while(1)
+ {
+ serverGeneration++;
+ ScreenSaverTime = defaultScreenSaverTime;
+ ScreenSaverInterval = defaultScreenSaverInterval;
+ ScreenSaverBlanking = defaultScreenSaverBlanking;
+ ScreenSaverAllowExposures = defaultScreenSaverAllowExposures;
+#ifdef DPMSExtension
+ DPMSStandbyTime = DPMSSuspendTime = DPMSOffTime = ScreenSaverTime;
+ DPMSEnabled = TRUE;
+ DPMSPowerLevel = 0;
+#endif
+ InitBlockAndWakeupHandlers();
+ /* Perform any operating system dependent initializations you'd like */
+ OsInit();
+ if(serverGeneration == 1)
+ {
+ CreateWellKnownSockets();
+ for (i=1; i<MAXCLIENTS; i++)
+ clients[i] = NullClient;
+ serverClient = calloc(sizeof(ClientRec), 1);
+ if (!serverClient)
+ FatalError("couldn't create server client");
+ InitClient(serverClient, 0, (pointer)NULL);
+ }
+ else
+ ResetWellKnownSockets ();
+ clients[0] = serverClient;
+ currentMaxClients = 1;
+
+ /* Initialize privates before first allocation */
+ dixResetPrivates();
+
+ /* Initialize server client devPrivates, to be reallocated as
+ * more client privates are registered
+ */
+ if (!dixAllocatePrivates(&serverClient->devPrivates, PRIVATE_CLIENT))
+ FatalError("failed to create server client privates");
+
+ if (!InitClientResources(serverClient)) /* for root resources */
+ FatalError("couldn't init server resources");
+
+ SetInputCheck(&alwaysCheckForInput[0], &alwaysCheckForInput[1]);
+ screenInfo.numScreens = 0;
+
+ InitAtoms();
+ InitEvents();
+ InitSelections();
+ InitGlyphCaching();
+ dixResetRegistry();
+ ResetFontPrivateIndex();
+ InitCallbackManager();
+ InitOutput(&screenInfo, argc, argv);
+
+ if (screenInfo.numScreens < 1)
+ FatalError("no screens found");
+ InitExtensions(argc, argv);
+
+ for (i = 0; i < screenInfo.numScreens; i++)
+ {
+ ScreenPtr pScreen = screenInfo.screens[i];
+ if (!CreateScratchPixmapsForScreen(i))
+ FatalError("failed to create scratch pixmaps");
+ if (pScreen->CreateScreenResources &&
+ !(*pScreen->CreateScreenResources)(pScreen))
+ FatalError("failed to create screen resources");
+ if (!CreateGCperDepth(i))
+ FatalError("failed to create scratch GCs");
+ if (!CreateDefaultStipple(i))
+ FatalError("failed to create default stipple");
+ if (!CreateRootWindow(pScreen))
+ FatalError("failed to create root window");
+ }
+
+ InitFonts();
+ if (SetDefaultFontPath(defaultFontPath) != Success) {
+ ErrorF("[dix] failed to set default font path '%s'", defaultFontPath);
+ }
+ if (!SetDefaultFont(defaultTextFont)) {
+ FatalError("could not open default font '%s'", defaultTextFont);
+ }
+
+ if (!(rootCursor = CreateRootCursor(NULL, 0))) {
+ FatalError("could not open default cursor font '%s'",
+ defaultCursorFont);
+ }
+
+#ifdef DPMSExtension
+ /* check all screens, looking for DPMS Capabilities */
+ DPMSCapableFlag = DPMSSupported();
+ if (!DPMSCapableFlag)
+ DPMSEnabled = FALSE;
+#endif
+
+#ifdef PANORAMIX
+ /*
+ * Consolidate window and colourmap information for each screen
+ */
+ if (!noPanoramiXExtension)
+ PanoramiXConsolidate();
+#endif
+
+ for (i = 0; i < screenInfo.numScreens; i++)
+ InitRootWindow(screenInfo.screens[i]->root);
+
+ InitCoreDevices();
+ InitInput(argc, argv);
+ InitAndStartDevices();
+
+ dixSaveScreens(serverClient, SCREEN_SAVER_FORCER, ScreenSaverReset);
+
+#ifdef PANORAMIX
+ if (!noPanoramiXExtension) {
+ if (!PanoramiXCreateConnectionBlock()) {
+ FatalError("could not create connection block info");
+ }
+ } else
+#endif
+ {
+ if (!CreateConnectionBlock()) {
+ FatalError("could not create connection block info");
+ }
+ }
+
+#ifdef XQUARTZ
+ /* Let the other threads know the server is done with its init */
+ pthread_mutex_lock(&serverRunningMutex);
+ serverRunning = TRUE;
+ pthread_cond_broadcast(&serverRunningCond);
+ pthread_mutex_unlock(&serverRunningMutex);
+#endif
+
+ NotifyParentProcess();
+
+ Dispatch();
+
+#ifdef XQUARTZ
+ /* Let the other threads know the server is no longer running */
+ pthread_mutex_lock(&serverRunningMutex);
+ serverRunning = FALSE;
+ pthread_mutex_unlock(&serverRunningMutex);
+#endif
+
+ UndisplayDevices();
+
+ /* Now free up whatever must be freed */
+ if (screenIsSaved == SCREEN_SAVER_ON)
+ dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset);
+ FreeScreenSaverTimer();
+ CloseDownExtensions();
+
+#ifdef PANORAMIX
+ {
+ Bool remember_it = noPanoramiXExtension;
+ noPanoramiXExtension = TRUE;
+ FreeAllResources();
+ noPanoramiXExtension = remember_it;
+ }
+#else
+ FreeAllResources();
+#endif
+
+ CloseInput();
+
+ for (i = 0; i < screenInfo.numScreens; i++)
+ screenInfo.screens[i]->root = NullWindow;
+ CloseDownDevices();
+ CloseDownEvents();
+
+ for (i = screenInfo.numScreens - 1; i >= 0; i--)
+ {
+ FreeScratchPixmapsForScreen(i);
+ FreeGCperDepth(i);
+ FreeDefaultStipple(i);
+ (* screenInfo.screens[i]->CloseScreen)(i, screenInfo.screens[i]);
+ dixFreePrivates(screenInfo.screens[i]->devPrivates, PRIVATE_SCREEN);
+ free(screenInfo.screens[i]);
+ screenInfo.numScreens = i;
+ }
+
+ dixFreePrivates(serverClient->devPrivates, PRIVATE_CLIENT);
+ serverClient->devPrivates = NULL;
+
+ FreeFonts();
+
+ FreeAuditTimer();
+
+ if (dispatchException & DE_TERMINATE)
+ {
+ CloseWellKnownConnections();
+ }
+
+ OsCleanup((dispatchException & DE_TERMINATE) != 0);
+
+ if (dispatchException & DE_TERMINATE)
+ {
+ ddxGiveUp();
+ break;
+ }
+
+ free(ConnectionInfo);
+ ConnectionInfo = NULL;
+ }
+ return 0;
+}
+
diff --git a/dix/pixmap.c b/dix/pixmap.c
new file mode 100644
index 0000000..cbb5e7f
--- /dev/null
+++ b/dix/pixmap.c
@@ -0,0 +1,137 @@
+/*
+
+Copyright 1993, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+*/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include "scrnintstr.h"
+#include "misc.h"
+#include "os.h"
+#include "windowstr.h"
+#include "resource.h"
+#include "dixstruct.h"
+#include "gcstruct.h"
+#include "servermd.h"
+#include "site.h"
+
+
+/*
+ * Scratch pixmap management and device independent pixmap allocation
+ * function.
+ */
+
+
+/* callable by ddx */
+PixmapPtr
+GetScratchPixmapHeader(ScreenPtr pScreen, int width, int height, int depth,
+ int bitsPerPixel, int devKind, pointer pPixData)
+{
+ PixmapPtr pPixmap = pScreen->pScratchPixmap;
+
+ if (pPixmap)
+ pScreen->pScratchPixmap = NULL;
+ else
+ /* width and height of 0 means don't allocate any pixmap data */
+ pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0);
+
+ if (pPixmap) {
+ if ((*pScreen->ModifyPixmapHeader)(pPixmap, width, height, depth,
+ bitsPerPixel, devKind, pPixData))
+ return pPixmap;
+ (*pScreen->DestroyPixmap)(pPixmap);
+ }
+ return NullPixmap;
+}
+
+
+/* callable by ddx */
+void
+FreeScratchPixmapHeader(PixmapPtr pPixmap)
+{
+ if (pPixmap)
+ {
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+
+ pPixmap->devPrivate.ptr = NULL; /* lest ddx chases bad ptr */
+ if (pScreen->pScratchPixmap)
+ (*pScreen->DestroyPixmap)(pPixmap);
+ else
+ pScreen->pScratchPixmap = pPixmap;
+ }
+}
+
+
+Bool
+CreateScratchPixmapsForScreen(int scrnum)
+{
+ unsigned int pixmap_size;
+
+ pixmap_size = sizeof(PixmapRec) + dixPrivatesSize(PRIVATE_PIXMAP);
+ screenInfo.screens[scrnum]->totalPixmapSize = BitmapBytePad(pixmap_size * 8);
+
+ /* let it be created on first use */
+ screenInfo.screens[scrnum]->pScratchPixmap = NULL;
+ return TRUE;
+}
+
+
+void
+FreeScratchPixmapsForScreen(int scrnum)
+{
+ FreeScratchPixmapHeader(screenInfo.screens[scrnum]->pScratchPixmap);
+}
+
+
+/* callable by ddx */
+PixmapPtr
+AllocatePixmap(ScreenPtr pScreen, int pixDataSize)
+{
+ PixmapPtr pPixmap;
+
+ assert(pScreen->totalPixmapSize > 0);
+
+ if (pScreen->totalPixmapSize > ((size_t)-1) - pixDataSize)
+ return NullPixmap;
+
+ pPixmap = malloc(pScreen->totalPixmapSize + pixDataSize);
+ if (!pPixmap)
+ return NullPixmap;
+
+ dixInitPrivates(pPixmap, pPixmap + 1, PRIVATE_PIXMAP);
+ return pPixmap;
+}
+
+/* callable by ddx */
+void
+FreePixmap(PixmapPtr pPixmap)
+{
+ dixFiniPrivates(pPixmap, PRIVATE_PIXMAP);
+ free(pPixmap);
+}
diff --git a/dix/privates.c b/dix/privates.c
new file mode 100644
index 0000000..d651258
--- /dev/null
+++ b/dix/privates.c
@@ -0,0 +1,502 @@
+/*
+
+Copyright 1993, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+*/
+/*
+ * Copyright © 2010, Keith Packard
+ * Copyright © 2010, Jamey Sharp
+ *
+ * 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 the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stddef.h>
+#include "windowstr.h"
+#include "resource.h"
+#include "privates.h"
+#include "gcstruct.h"
+#include "cursorstr.h"
+#include "colormapst.h"
+#include "inputstr.h"
+#include "scrnintstr.h"
+#include "extnsionst.h"
+
+static struct {
+ DevPrivateKey key;
+ unsigned offset;
+ int created;
+ int allocated;
+} keys[PRIVATE_LAST];
+
+static const Bool xselinux_private[PRIVATE_LAST] = {
+ [PRIVATE_SCREEN] = TRUE,
+ [PRIVATE_CLIENT] = TRUE,
+ [PRIVATE_WINDOW] = TRUE,
+ [PRIVATE_PIXMAP] = TRUE,
+ [PRIVATE_GC] = TRUE,
+ [PRIVATE_CURSOR] = TRUE,
+ [PRIVATE_COLORMAP] = TRUE,
+ [PRIVATE_DEVICE] = TRUE,
+ [PRIVATE_EXTENSION] = TRUE,
+ [PRIVATE_SELECTION] = TRUE,
+ [PRIVATE_PROPERTY] = TRUE,
+ [PRIVATE_PICTURE] = TRUE,
+ [PRIVATE_GLYPHSET] = TRUE,
+};
+
+typedef Bool (*FixupFunc)(PrivatePtr *privates, int offset, unsigned bytes);
+
+static Bool
+dixReallocPrivates(PrivatePtr *privates, int old_offset, unsigned bytes)
+{
+ void *new_privates;
+
+ new_privates = realloc(*privates, old_offset + bytes);
+ if (!new_privates)
+ return FALSE;
+ memset((char *) new_privates + old_offset, '\0', bytes);
+ *privates = new_privates;
+ return TRUE;
+}
+
+static Bool
+dixMovePrivates(PrivatePtr *privates, int new_offset, unsigned bytes)
+{
+ memmove((char *) *privates + bytes, *privates, new_offset - bytes);
+ memset(*privates, '\0', bytes);
+ return TRUE;
+}
+
+static Bool
+fixupScreens(FixupFunc fixup, unsigned bytes)
+{
+ int s;
+ for (s = 0; s < screenInfo.numScreens; s++)
+ if (!fixup(&screenInfo.screens[s]->devPrivates, keys[PRIVATE_SCREEN].offset, bytes))
+ return FALSE;
+ return TRUE;
+}
+
+static Bool
+fixupServerClient(FixupFunc fixup, unsigned bytes)
+{
+ if (serverClient)
+ return fixup(&serverClient->devPrivates, keys[PRIVATE_CLIENT].offset, bytes);
+ return TRUE;
+}
+
+static Bool
+fixupExtensions(FixupFunc fixup, unsigned bytes)
+{
+ unsigned char major;
+ ExtensionEntry *extension;
+ for (major = EXTENSION_BASE; (extension = GetExtensionEntry(major)); major++)
+ if (!fixup(&extension->devPrivates, keys[PRIVATE_EXTENSION].offset, bytes))
+ return FALSE;
+ return TRUE;
+}
+
+static Bool
+fixupDefaultColormaps(FixupFunc fixup, unsigned bytes)
+{
+ int s;
+ for (s = 0; s < screenInfo.numScreens; s++) {
+ ColormapPtr cmap;
+ dixLookupResourceByType((pointer *) &cmap, screenInfo.screens[s]->defColormap,
+ RT_COLORMAP, serverClient, DixCreateAccess);
+ if (cmap && !fixup(&cmap->devPrivates, keys[PRIVATE_COLORMAP].offset, bytes))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static Bool (* const allocated_early[PRIVATE_LAST])(FixupFunc, unsigned) = {
+ [PRIVATE_SCREEN] = fixupScreens,
+ [PRIVATE_CLIENT] = fixupServerClient,
+ [PRIVATE_EXTENSION] = fixupExtensions,
+ [PRIVATE_COLORMAP] = fixupDefaultColormaps,
+};
+
+/*
+ * Register a private key. This takes the type of object the key will
+ * be used with, which may be PRIVATE_ALL indicating that this key
+ * will be used with all of the private objects. If 'size' is
+ * non-zero, then the specified amount of space will be allocated in
+ * the private storage. Otherwise, space for a single pointer will
+ * be allocated which can be set with dixSetPrivate
+ */
+Bool
+dixRegisterPrivateKey(DevPrivateKey key, DevPrivateType type, unsigned size)
+{
+ DevPrivateType t;
+ int offset;
+ unsigned bytes;
+
+ if (key->initialized) {
+ assert (size == key->size);
+ return TRUE;
+ }
+
+ /* Compute required space */
+ bytes = size;
+ if (size == 0)
+ bytes = sizeof (void *);
+
+ /* align to void * size */
+ bytes = (bytes + sizeof (void *) - 1) & ~(sizeof (void *) - 1);
+
+ /* Update offsets for all affected keys */
+ if (type == PRIVATE_XSELINUX) {
+ DevPrivateKey k;
+
+ /* Resize if we can, or make sure nothing's allocated if we can't
+ */
+ for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++)
+ if (xselinux_private[t]) {
+ if (!allocated_early[t])
+ assert (!keys[t].created);
+ else if (!allocated_early[t](dixReallocPrivates, bytes))
+ return FALSE;
+ }
+
+ /* Move all existing keys up in the privates space to make
+ * room for this new global key
+ */
+ for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++) {
+ if (xselinux_private[t]) {
+ for (k = keys[t].key; k; k = k->next)
+ k->offset += bytes;
+ keys[t].offset += bytes;
+ if (allocated_early[t])
+ allocated_early[t](dixMovePrivates, bytes);
+ }
+ }
+
+ offset = 0;
+ } else {
+ /* Resize if we can, or make sure nothing's allocated if we can't */
+ if (!allocated_early[type])
+ assert(!keys[type].created);
+ else if (!allocated_early[type](dixReallocPrivates, bytes))
+ return FALSE;
+ offset = keys[type].offset;
+ keys[type].offset += bytes;
+ }
+
+ /* Setup this key */
+ key->offset = offset;
+ key->size = size;
+ key->initialized = TRUE;
+ key->type = type;
+ key->allocated = FALSE;
+ key->next = keys[type].key;
+ keys[type].key = key;
+
+ return TRUE;
+}
+
+Bool
+dixRegisterScreenPrivateKey(DevScreenPrivateKey screenKey, ScreenPtr pScreen, DevPrivateType type, unsigned size)
+{
+ DevPrivateKey key;
+
+ if (!dixRegisterPrivateKey(&screenKey->screenKey, PRIVATE_SCREEN, 0))
+ return FALSE;
+ key = dixGetPrivate(&pScreen->devPrivates, &screenKey->screenKey);
+ if (key != NULL) {
+ assert(key->size == size);
+ assert(key->type == type);
+ return TRUE;
+ }
+ key = calloc(sizeof (DevPrivateKeyRec), 1);
+ if (!key)
+ return FALSE;
+ if (!dixRegisterPrivateKey(key, type, size)) {
+ free(key);
+ return FALSE;
+ }
+ key->allocated = TRUE;
+ dixSetPrivate(&pScreen->devPrivates, &screenKey->screenKey, key);
+ return TRUE;
+}
+
+DevPrivateKey
+_dixGetScreenPrivateKey(const DevScreenPrivateKey key, ScreenPtr pScreen)
+{
+ return dixGetPrivate(&pScreen->devPrivates, &key->screenKey);
+}
+
+/*
+ * Initialize privates by zeroing them
+ */
+void
+_dixInitPrivates(PrivatePtr *privates, void *addr, DevPrivateType type)
+{
+ keys[type].created++;
+ if (xselinux_private[type])
+ keys[PRIVATE_XSELINUX].created++;
+ if (keys[type].offset == 0)
+ addr = 0;
+ *privates = addr;
+ memset(addr, '\0', keys[type].offset);
+}
+
+/*
+ * Clean up privates
+ */
+void
+_dixFiniPrivates(PrivatePtr privates, DevPrivateType type)
+{
+ keys[type].created--;
+ if (xselinux_private[type])
+ keys[PRIVATE_XSELINUX].created--;
+}
+
+/*
+ * Allocate new object with privates.
+ *
+ * This is expected to be invoked from the
+ * dixAllocateObjectWithPrivates macro
+ */
+void *
+_dixAllocateObjectWithPrivates(unsigned baseSize, unsigned clear, unsigned offset, DevPrivateType type)
+{
+ unsigned totalSize;
+ void *object;
+ PrivatePtr privates;
+ PrivatePtr *devPrivates;
+
+ assert (type > PRIVATE_SCREEN && type < PRIVATE_LAST);
+
+ /* round up so that void * is aligned */
+ baseSize = (baseSize + sizeof (void *) - 1) & ~(sizeof (void *) - 1);
+ totalSize = baseSize + keys[type].offset;
+ object = malloc(totalSize);
+ if (!object)
+ return NULL;
+
+ memset(object, '\0', clear);
+ privates = (PrivatePtr) (((char *) object) + baseSize);
+ devPrivates = (PrivatePtr *) ((char *) object + offset);
+
+ _dixInitPrivates(devPrivates, privates, type);
+
+ return object;
+}
+
+/*
+ * Allocate privates separately from containing object.
+ * Used for clients and screens.
+ */
+Bool
+dixAllocatePrivates(PrivatePtr *privates, DevPrivateType type)
+{
+ unsigned size;
+ PrivatePtr p;
+
+ assert (type > PRIVATE_XSELINUX && type < PRIVATE_LAST);
+
+ size = keys[type].offset;
+ if (!size) {
+ p = NULL;
+ } else {
+ if (!(p = malloc(size)))
+ return FALSE;
+ }
+
+ _dixInitPrivates(privates, p, type);
+ ++keys[type].allocated;
+
+ return TRUE;
+}
+
+/*
+ * Free an object that has privates
+ *
+ * This is expected to be invoked from the
+ * dixFreeObjectWithPrivates macro
+ */
+void
+_dixFreeObjectWithPrivates(void *object, PrivatePtr privates, DevPrivateType type)
+{
+ _dixFiniPrivates(privates, type);
+ free(object);
+}
+
+/*
+ * Called to free screen or client privates
+ */
+void
+dixFreePrivates(PrivatePtr privates, DevPrivateType type)
+{
+ _dixFiniPrivates(privates, type);
+ --keys[type].allocated;
+ free(privates);
+}
+
+/*
+ * Return size of privates for the specified type
+ */
+extern _X_EXPORT int
+dixPrivatesSize(DevPrivateType type)
+{
+ assert (type >= PRIVATE_SCREEN && type < PRIVATE_LAST);
+
+ return keys[type].offset;
+}
+
+/* Table of devPrivates offsets */
+static const int offsets[] = {
+ -1, /* RT_NONE */
+ offsetof(WindowRec, devPrivates), /* RT_WINDOW */
+ offsetof(PixmapRec, devPrivates), /* RT_PIXMAP */
+ offsetof(GC, devPrivates), /* RT_GC */
+ -1, /* RT_FONT */
+ offsetof(CursorRec, devPrivates), /* RT_CURSOR */
+ offsetof(ColormapRec, devPrivates), /* RT_COLORMAP */
+};
+
+#define NUM_OFFSETS (sizeof (offsets) / sizeof (offsets[0]))
+
+int
+dixLookupPrivateOffset(RESTYPE type)
+{
+ /*
+ * Special kludge for DBE which registers a new resource type that
+ * points at pixmaps (thanks, DBE)
+ */
+ if (type & RC_DRAWABLE) {
+ if (type == RT_WINDOW)
+ return offsets[RT_WINDOW & TypeMask];
+ else
+ return offsets[RT_PIXMAP & TypeMask];
+ }
+ type = type & TypeMask;
+ if (type < NUM_OFFSETS)
+ return offsets[type];
+ return -1;
+}
+
+static const char *key_names[PRIVATE_LAST] = {
+ /* XSELinux uses the same private keys for numerous objects */
+ [PRIVATE_XSELINUX] = "XSELINUX",
+
+ /* Otherwise, you get a private in just the requested structure
+ */
+ /* These can have objects created before all of the keys are registered */
+ [PRIVATE_SCREEN] = "SCREEN",
+ [PRIVATE_EXTENSION] = "EXTENSION",
+ [PRIVATE_COLORMAP] = "COLORMAP",
+
+ /* These cannot have any objects before all relevant keys are registered */
+ [PRIVATE_DEVICE] = "DEVICE",
+ [PRIVATE_CLIENT] = "CLIENT",
+ [PRIVATE_PROPERTY] = "PROPERTY",
+ [PRIVATE_SELECTION] = "SELECTION",
+ [PRIVATE_WINDOW] = "WINDOW",
+ [PRIVATE_PIXMAP] = "PIXMAP",
+ [PRIVATE_GC] = "GC",
+ [PRIVATE_CURSOR] = "CURSOR",
+ [PRIVATE_CURSOR_BITS] = "CURSOR_BITS",
+
+ /* extension privates */
+ [PRIVATE_DBE_WINDOW] = "DBE_WINDOW",
+ [PRIVATE_DAMAGE] = "DAMAGE",
+ [PRIVATE_GLYPH] = "GLYPH",
+ [PRIVATE_GLYPHSET] = "GLYPHSET",
+ [PRIVATE_PICTURE] = "PICTURE",
+ [PRIVATE_SYNC_FENCE] = "SYNC_FENCE",
+};
+
+void
+dixPrivateUsage(void)
+{
+ int objects = 0;
+ int bytes = 0;
+ int alloc = 0;
+ DevPrivateType t;
+
+ for (t = PRIVATE_XSELINUX + 1; t < PRIVATE_LAST; t++) {
+ if (keys[t].offset) {
+ ErrorF("%s: %d objects of %d bytes = %d total bytes %d private allocs\n",
+ key_names[t], keys[t].created, keys[t].offset, keys[t].created * keys[t].offset,
+ keys[t].allocated);
+ bytes += keys[t].created * keys[t].offset;
+ objects += keys[t].created;
+ alloc += keys[t].allocated;
+ }
+ }
+ ErrorF("TOTAL: %d objects, %d bytes, %d allocs\n",
+ objects, bytes, alloc);
+}
+
+void
+dixResetPrivates(void)
+{
+ DevPrivateType t;
+
+ for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++) {
+ DevPrivateKey key, next;
+
+ for (key = keys[t].key; key; key = next) {
+ next = key->next;
+ key->offset = 0;
+ key->initialized = FALSE;
+ key->size = 0;
+ key->type = 0;
+ if (key->allocated)
+ free(key);
+ }
+ if (keys[t].created) {
+ ErrorF("%d %ss still allocated at reset\n",
+ keys[t].created, key_names[t]);
+ dixPrivateUsage();
+ }
+ keys[t].key = NULL;
+ keys[t].offset = 0;
+ keys[t].created = 0;
+ keys[t].allocated = 0;
+ }
+}
diff --git a/dix/property.c b/dix/property.c
new file mode 100644
index 0000000..a1ae530
--- /dev/null
+++ b/dix/property.c
@@ -0,0 +1,644 @@
+/***********************************************************
+
+Copyright 1987, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+******************************************************************/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include "windowstr.h"
+#include "propertyst.h"
+#include "dixstruct.h"
+#include "dispatch.h"
+#include "swaprep.h"
+#include "xace.h"
+
+/*****************************************************************
+ * Property Stuff
+ *
+ * dixLookupProperty, dixChangeProperty, DeleteProperty
+ *
+ * Properties belong to windows. The list of properties should not be
+ * traversed directly. Instead, use the three functions listed above.
+ *
+ *****************************************************************/
+
+#ifdef notdef
+static void
+PrintPropertys(WindowPtr pWin)
+{
+ PropertyPtr pProp;
+ int j;
+
+ pProp = pWin->userProps;
+ while (pProp)
+ {
+ ErrorF("[dix] %x %x\n", pProp->propertyName, pProp->type);
+ ErrorF("[dix] property format: %d\n", pProp->format);
+ ErrorF("[dix] property data: \n");
+ for (j=0; j<(pProp->format/8)*pProp->size; j++)
+ ErrorF("[dix] %c\n", pProp->data[j]);
+ pProp = pProp->next;
+ }
+}
+#endif
+
+int
+dixLookupProperty(PropertyPtr *result, WindowPtr pWin, Atom propertyName,
+ ClientPtr client, Mask access_mode)
+{
+ PropertyPtr pProp;
+ int rc = BadMatch;
+ client->errorValue = propertyName;
+
+ for (pProp = wUserProps(pWin); pProp; pProp = pProp->next)
+ if (pProp->propertyName == propertyName)
+ break;
+
+ if (pProp)
+ rc = XaceHookPropertyAccess(client, pWin, &pProp, access_mode);
+ *result = pProp;
+ return rc;
+}
+
+static void
+deliverPropertyNotifyEvent(WindowPtr pWin, int state, Atom atom)
+{
+ xEvent event;
+
+ memset(&event, 0, sizeof(xEvent));
+ event.u.u.type = PropertyNotify;
+ event.u.property.window = pWin->drawable.id;
+ event.u.property.state = state;
+ event.u.property.atom = atom;
+ event.u.property.time = currentTime.milliseconds;
+ DeliverEvents(pWin, &event, 1, (WindowPtr)NULL);
+}
+
+int
+ProcRotateProperties(ClientPtr client)
+{
+ int i, j, delta, rc;
+ REQUEST(xRotatePropertiesReq);
+ WindowPtr pWin;
+ Atom * atoms;
+ PropertyPtr * props; /* array of pointer */
+ PropertyPtr pProp, saved;
+
+ REQUEST_FIXED_SIZE(xRotatePropertiesReq, stuff->nAtoms << 2);
+ UpdateCurrentTime();
+ rc = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess);
+ if (rc != Success || stuff->nAtoms <= 0)
+ return rc;
+
+ atoms = (Atom *) & stuff[1];
+ props = malloc(stuff->nAtoms * sizeof(PropertyPtr));
+ saved = malloc(stuff->nAtoms * sizeof(PropertyRec));
+ if (!props || !saved) {
+ rc = BadAlloc;
+ goto out;
+ }
+
+ for (i = 0; i < stuff->nAtoms; i++)
+ {
+ if (!ValidAtom(atoms[i])) {
+ rc = BadAtom;
+ client->errorValue = atoms[i];
+ goto out;
+ }
+ for (j = i + 1; j < stuff->nAtoms; j++)
+ if (atoms[j] == atoms[i])
+ {
+ rc = BadMatch;
+ goto out;
+ }
+
+ rc = dixLookupProperty(&pProp, pWin, atoms[i], client,
+ DixReadAccess|DixWriteAccess);
+ if (rc != Success)
+ goto out;
+
+ props[i] = pProp;
+ saved[i] = *pProp;
+ }
+ delta = stuff->nPositions;
+
+ /* If the rotation is a complete 360 degrees, then moving the properties
+ around and generating PropertyNotify events should be skipped. */
+
+ if (abs(delta) % stuff->nAtoms)
+ {
+ while (delta < 0) /* faster if abs value is small */
+ delta += stuff->nAtoms;
+ for (i = 0; i < stuff->nAtoms; i++)
+ {
+ j = (i + delta) % stuff->nAtoms;
+ deliverPropertyNotifyEvent(pWin, PropertyNewValue, atoms[i]);
+
+ /* Preserve name and devPrivates */
+ props[j]->type = saved[i].type;
+ props[j]->format = saved[i].format;
+ props[j]->size = saved[i].size;
+ props[j]->data = saved[i].data;
+ }
+ }
+out:
+ free(saved);
+ free(props);
+ return rc;
+}
+
+int
+ProcChangeProperty(ClientPtr client)
+{
+ WindowPtr pWin;
+ char format, mode;
+ unsigned long len;
+ int sizeInBytes, totalSize, err;
+ REQUEST(xChangePropertyReq);
+
+ REQUEST_AT_LEAST_SIZE(xChangePropertyReq);
+ UpdateCurrentTime();
+ format = stuff->format;
+ mode = stuff->mode;
+ if ((mode != PropModeReplace) && (mode != PropModeAppend) &&
+ (mode != PropModePrepend))
+ {
+ client->errorValue = mode;
+ return BadValue;
+ }
+ if ((format != 8) && (format != 16) && (format != 32))
+ {
+ client->errorValue = format;
+ return BadValue;
+ }
+ len = stuff->nUnits;
+ if (len > bytes_to_int32(0xffffffff - sizeof(xChangePropertyReq)))
+ return BadLength;
+ sizeInBytes = format>>3;
+ totalSize = len * sizeInBytes;
+ REQUEST_FIXED_SIZE(xChangePropertyReq, totalSize);
+
+ err = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess);
+ if (err != Success)
+ return err;
+ if (!ValidAtom(stuff->property))
+ {
+ client->errorValue = stuff->property;
+ return BadAtom;
+ }
+ if (!ValidAtom(stuff->type))
+ {
+ client->errorValue = stuff->type;
+ return BadAtom;
+ }
+
+ err = dixChangeWindowProperty(client, pWin, stuff->property, stuff->type,
+ (int)format, (int)mode, len, &stuff[1],
+ TRUE);
+ if (err != Success)
+ return err;
+ else
+ return Success;
+}
+
+int
+dixChangeWindowProperty(ClientPtr pClient, WindowPtr pWin, Atom property,
+ Atom type, int format, int mode, unsigned long len,
+ pointer value, Bool sendevent)
+{
+ PropertyPtr pProp;
+ PropertyRec savedProp;
+ int sizeInBytes, totalSize, rc;
+ unsigned char *data;
+ Mask access_mode;
+
+ sizeInBytes = format>>3;
+ totalSize = len * sizeInBytes;
+ access_mode = (mode == PropModeReplace) ? DixWriteAccess : DixBlendAccess;
+
+ /* first see if property already exists */
+ rc = dixLookupProperty(&pProp, pWin, property, pClient, access_mode);
+
+ if (rc == BadMatch) /* just add to list */
+ {
+ if (!pWin->optional && !MakeWindowOptional (pWin))
+ return BadAlloc;
+ pProp = dixAllocateObjectWithPrivates(PropertyRec, PRIVATE_PROPERTY);
+ if (!pProp)
+ return BadAlloc;
+ data = malloc(totalSize);
+ if (!data && len)
+ {
+ dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
+ return BadAlloc;
+ }
+ memcpy(data, value, totalSize);
+ pProp->propertyName = property;
+ pProp->type = type;
+ pProp->format = format;
+ pProp->data = data;
+ pProp->size = len;
+ rc = XaceHookPropertyAccess(pClient, pWin, &pProp,
+ DixCreateAccess|DixWriteAccess);
+ if (rc != Success) {
+ free(data);
+ dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
+ pClient->errorValue = property;
+ return rc;
+ }
+ pProp->next = pWin->optional->userProps;
+ pWin->optional->userProps = pProp;
+ }
+ else if (rc == Success)
+ {
+ /* To append or prepend to a property the request format and type
+ must match those of the already defined property. The
+ existing format and type are irrelevant when using the mode
+ "PropModeReplace" since they will be written over. */
+
+ if ((format != pProp->format) && (mode != PropModeReplace))
+ return BadMatch;
+ if ((pProp->type != type) && (mode != PropModeReplace))
+ return BadMatch;
+
+ /* save the old values for later */
+ savedProp = *pProp;
+
+ if (mode == PropModeReplace)
+ {
+ data = malloc(totalSize);
+ if (!data && len)
+ return BadAlloc;
+ memcpy(data, value, totalSize);
+ pProp->data = data;
+ pProp->size = len;
+ pProp->type = type;
+ pProp->format = format;
+ }
+ else if (len == 0)
+ {
+ /* do nothing */
+ }
+ else if (mode == PropModeAppend)
+ {
+ data = malloc((pProp->size + len) * sizeInBytes);
+ if (!data)
+ return BadAlloc;
+ memcpy(data, pProp->data, pProp->size * sizeInBytes);
+ memcpy(data + pProp->size * sizeInBytes, value, totalSize);
+ pProp->data = data;
+ pProp->size += len;
+ }
+ else if (mode == PropModePrepend)
+ {
+ data = malloc(sizeInBytes * (len + pProp->size));
+ if (!data)
+ return BadAlloc;
+ memcpy(data + totalSize, pProp->data, pProp->size * sizeInBytes);
+ memcpy(data, value, totalSize);
+ pProp->data = data;
+ pProp->size += len;
+ }
+
+ /* Allow security modules to check the new content */
+ access_mode |= DixPostAccess;
+ rc = XaceHookPropertyAccess(pClient, pWin, &pProp, access_mode);
+ if (rc == Success)
+ {
+ if (savedProp.data != pProp->data)
+ free(savedProp.data);
+ }
+ else
+ {
+ if (savedProp.data != pProp->data)
+ free(pProp->data);
+ *pProp = savedProp;
+ return rc;
+ }
+ }
+ else
+ return rc;
+
+ if (sendevent)
+ deliverPropertyNotifyEvent(pWin, PropertyNewValue, pProp->propertyName);
+
+ return Success;
+}
+
+int
+ChangeWindowProperty(WindowPtr pWin, Atom property, Atom type, int format,
+ int mode, unsigned long len, pointer value,
+ Bool sendevent)
+{
+ return dixChangeWindowProperty(serverClient, pWin, property, type, format,
+ mode, len, value, sendevent);
+}
+
+int
+DeleteProperty(ClientPtr client, WindowPtr pWin, Atom propName)
+{
+ PropertyPtr pProp, prevProp;
+ int rc;
+
+ rc = dixLookupProperty(&pProp, pWin, propName, client, DixDestroyAccess);
+ if (rc == BadMatch)
+ return Success; /* Succeed if property does not exist */
+
+ if (rc == Success) {
+ if (pWin->optional->userProps == pProp) {
+ /* Takes care of head */
+ if (!(pWin->optional->userProps = pProp->next))
+ CheckWindowOptionalNeed (pWin);
+ } else {
+ /* Need to traverse to find the previous element */
+ prevProp = pWin->optional->userProps;
+ while (prevProp->next != pProp)
+ prevProp = prevProp->next;
+ prevProp->next = pProp->next;
+ }
+
+ deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName);
+ free(pProp->data);
+ dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
+ }
+ return rc;
+}
+
+void
+DeleteAllWindowProperties(WindowPtr pWin)
+{
+ PropertyPtr pProp, pNextProp;
+
+ pProp = wUserProps (pWin);
+ while (pProp)
+ {
+ deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName);
+ pNextProp = pProp->next;
+ free(pProp->data);
+ dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
+ pProp = pNextProp;
+ }
+
+ if (pWin->optional)
+ pWin->optional->userProps = NULL;
+}
+
+static int
+NullPropertyReply(
+ ClientPtr client,
+ ATOM propertyType,
+ int format,
+ xGetPropertyReply *reply)
+{
+ reply->nItems = 0;
+ reply->length = 0;
+ reply->bytesAfter = 0;
+ reply->propertyType = propertyType;
+ reply->format = format;
+ WriteReplyToClient(client, sizeof(xGenericReply), reply);
+ return Success;
+}
+
+/*****************
+ * GetProperty
+ * If type Any is specified, returns the property from the specified
+ * window regardless of its type. If a type is specified, returns the
+ * property only if its type equals the specified type.
+ * If delete is True and a property is returned, the property is also
+ * deleted from the window and a PropertyNotify event is generated on the
+ * window.
+ *****************/
+
+int
+ProcGetProperty(ClientPtr client)
+{
+ PropertyPtr pProp, prevProp;
+ unsigned long n, len, ind;
+ int rc;
+ WindowPtr pWin;
+ xGetPropertyReply reply;
+ Mask win_mode = DixGetPropAccess, prop_mode = DixReadAccess;
+ REQUEST(xGetPropertyReq);
+
+ REQUEST_SIZE_MATCH(xGetPropertyReq);
+ if (stuff->delete) {
+ UpdateCurrentTime();
+ win_mode |= DixSetPropAccess;
+ prop_mode |= DixDestroyAccess;
+ }
+ rc = dixLookupWindow(&pWin, stuff->window, client, win_mode);
+ if (rc != Success)
+ return (rc == BadMatch) ? BadWindow : rc;
+
+ if (!ValidAtom(stuff->property))
+ {
+ client->errorValue = stuff->property;
+ return BadAtom;
+ }
+ if ((stuff->delete != xTrue) && (stuff->delete != xFalse))
+ {
+ client->errorValue = stuff->delete;
+ return BadValue;
+ }
+ if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type))
+ {
+ client->errorValue = stuff->type;
+ return BadAtom;
+ }
+
+ memset(&reply, 0, sizeof(xGetPropertyReply));
+ reply.type = X_Reply;
+ reply.sequenceNumber = client->sequence;
+
+ rc = dixLookupProperty(&pProp, pWin, stuff->property, client, prop_mode);
+ if (rc == BadMatch)
+ return NullPropertyReply(client, None, 0, &reply);
+ else if (rc != Success)
+ return rc;
+
+ /* If the request type and actual type don't match. Return the
+ property information, but not the data. */
+
+ if (((stuff->type != pProp->type) &&
+ (stuff->type != AnyPropertyType))
+ )
+ {
+ reply.bytesAfter = pProp->size;
+ reply.format = pProp->format;
+ reply.length = 0;
+ reply.nItems = 0;
+ reply.propertyType = pProp->type;
+ WriteReplyToClient(client, sizeof(xGenericReply), &reply);
+ return Success;
+ }
+
+/*
+ * Return type, format, value to client
+ */
+ n = (pProp->format/8) * pProp->size; /* size (bytes) of prop */
+ ind = stuff->longOffset << 2;
+
+ /* If longOffset is invalid such that it causes "len" to
+ be negative, it's a value error. */
+
+ if (n < ind)
+ {
+ client->errorValue = stuff->longOffset;
+ return BadValue;
+ }
+
+ len = min(n - ind, 4 * stuff->longLength);
+
+ reply.bytesAfter = n - (ind + len);
+ reply.format = pProp->format;
+ reply.length = bytes_to_int32(len);
+ reply.nItems = len / (pProp->format / 8 );
+ reply.propertyType = pProp->type;
+
+ if (stuff->delete && (reply.bytesAfter == 0))
+ deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName);
+
+ WriteReplyToClient(client, sizeof(xGenericReply), &reply);
+ if (len)
+ {
+ switch (reply.format) {
+ case 32: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap32Write; break;
+ case 16: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; break;
+ default: client->pSwapReplyFunc = (ReplySwapPtr)WriteToClient; break;
+ }
+ WriteSwappedDataToClient(client, len,
+ (char *)pProp->data + ind);
+ }
+
+ if (stuff->delete && (reply.bytesAfter == 0)) {
+ /* Delete the Property */
+ if (pWin->optional->userProps == pProp) {
+ /* Takes care of head */
+ if (!(pWin->optional->userProps = pProp->next))
+ CheckWindowOptionalNeed (pWin);
+ } else {
+ /* Need to traverse to find the previous element */
+ prevProp = pWin->optional->userProps;
+ while (prevProp->next != pProp)
+ prevProp = prevProp->next;
+ prevProp->next = pProp->next;
+ }
+
+ free(pProp->data);
+ dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
+ }
+ return Success;
+}
+
+int
+ProcListProperties(ClientPtr client)
+{
+ Atom *pAtoms = NULL, *temppAtoms;
+ xListPropertiesReply xlpr;
+ int rc, numProps = 0;
+ WindowPtr pWin;
+ PropertyPtr pProp, realProp;
+ REQUEST(xResourceReq);
+
+ REQUEST_SIZE_MATCH(xResourceReq);
+ rc = dixLookupWindow(&pWin, stuff->id, client, DixListPropAccess);
+ if (rc != Success)
+ return rc;
+
+ for (pProp = wUserProps(pWin); pProp; pProp = pProp->next)
+ numProps++;
+
+ if (numProps && !(pAtoms = malloc(numProps * sizeof(Atom))))
+ return BadAlloc;
+
+ numProps = 0;
+ temppAtoms = pAtoms;
+ for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) {
+ realProp = pProp;
+ rc = XaceHookPropertyAccess(client, pWin, &realProp, DixGetAttrAccess);
+ if (rc == Success && realProp == pProp) {
+ *temppAtoms++ = pProp->propertyName;
+ numProps++;
+ }
+ }
+
+ xlpr.type = X_Reply;
+ xlpr.nProperties = numProps;
+ xlpr.length = bytes_to_int32(numProps * sizeof(Atom));
+ xlpr.sequenceNumber = client->sequence;
+ WriteReplyToClient(client, sizeof(xGenericReply), &xlpr);
+ if (numProps)
+ {
+ client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write;
+ WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms);
+ }
+ free(pAtoms);
+ return Success;
+}
+
+int
+ProcDeleteProperty(ClientPtr client)
+{
+ WindowPtr pWin;
+ REQUEST(xDeletePropertyReq);
+ int result;
+
+ REQUEST_SIZE_MATCH(xDeletePropertyReq);
+ UpdateCurrentTime();
+ result = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess);
+ if (result != Success)
+ return result;
+ if (!ValidAtom(stuff->property))
+ {
+ client->errorValue = stuff->property;
+ return BadAtom;
+ }
+
+ return DeleteProperty(client, pWin, stuff->property);
+}
diff --git a/dix/protocol.txt b/dix/protocol.txt
new file mode 100644
index 0000000..8e152ed
--- /dev/null
+++ b/dix/protocol.txt
@@ -0,0 +1,1103 @@
+# Registry of protocol names used by X Server
+# This will eventually be replaced by server-side XCB
+#
+# Format is Xnnn <extension-name>:<object-name>
+# R=Request, V=Event, E=Error
+#
+# This is a security-sensitive file, please set permissions as appropriate.
+#
+R001 Adobe-DPS-Extension:Init
+R002 Adobe-DPS-Extension:CreateContext
+R003 Adobe-DPS-Extension:CreateSpace
+R004 Adobe-DPS-Extension:GiveInput
+R005 Adobe-DPS-Extension:GetStatus
+R006 Adobe-DPS-Extension:DestroySpace
+R007 Adobe-DPS-Extension:Reset
+R008 Adobe-DPS-Extension:NotifyContext
+R009 Adobe-DPS-Extension:CreateContextFromID
+R010 Adobe-DPS-Extension:XIDFromContext
+R011 Adobe-DPS-Extension:ContextFromXID
+R012 Adobe-DPS-Extension:SetStatusMask
+R013 Adobe-DPS-Extension:CreateSecureContext
+R014 Adobe-DPS-Extension:NotifyWhenReady
+R000 Apple-DRI:QueryVersion
+R001 Apple-DRI:QueryDirectRenderingCapable
+R002 Apple-DRI:CreateSurface
+R003 Apple-DRI:DestroySurface
+R004 Apple-DRI:AuthConnection
+V000 Apple-DRI:ObsoleteEvent1
+V001 Apple-DRI:ObsoleteEvent2
+V002 Apple-DRI:ObsoleteEvent3
+V003 Apple-DRI:SurfaceNotify
+E000 Apple-DRI:ClientNotLocal
+E001 Apple-DRI:OperationNotSupported
+R000 Apple-WM:QueryVersion
+R001 Apple-WM:FrameGetRect
+R002 Apple-WM:FrameHitTest
+R003 Apple-WM:FrameDraw
+R004 Apple-WM:DisableUpdate
+R005 Apple-WM:ReenableUpdate
+R006 Apple-WM:SelectInput
+R007 Apple-WM:SetWindowMenuCheck
+R008 Apple-WM:SetFrontProcess
+R009 Apple-WM:SetWindowLevel
+R010 Apple-WM:SetCanQuit
+R011 Apple-WM:SetWindowMenu
+V000 Apple-WM:ControllerNotify
+V001 Apple-WM:ActivationNotify
+V002 Apple-WM:PasteboardNotify
+E000 Apple-WM:ClientNotLocal
+E001 Apple-WM:OperationNotSupported
+R000 BIG-REQUESTS:Enable
+R000 Composite:CompositeQueryVersion
+R001 Composite:CompositeRedirectWindow
+R002 Composite:CompositeRedirectSubwindows
+R003 Composite:CompositeUnredirectWindow
+R004 Composite:CompositeUnredirectSubwindows
+R005 Composite:CompositeCreateRegionFromBorderClip
+R006 Composite:CompositeNameWindowPixmap
+R007 Composite:CompositeGetOverlayWindow
+R008 Composite:CompositeReleaseOverlayWindow
+R000 DAMAGE:QueryVersion
+R001 DAMAGE:Create
+R002 DAMAGE:Destroy
+R003 DAMAGE:Subtract
+R004 DAMAGE:Add
+V000 DAMAGE:Notify
+E000 DAMAGE:BadDamage
+R000 DEC-XTRAP:Reset
+R001 DEC-XTRAP:GetAvailable
+R002 DEC-XTRAP:Config
+R003 DEC-XTRAP:StartTrap
+R004 DEC-XTRAP:StopTrap
+R005 DEC-XTRAP:GetCurrent
+R006 DEC-XTRAP:GetStatistics
+R007 DEC-XTRAP:SimulateXEvent
+R008 DEC-XTRAP:GetVersion
+R009 DEC-XTRAP:GetLastInpTime
+V000 DEC-XTRAP:Event
+E002 DEC-XTRAP:BadIO
+E004 DEC-XTRAP:BadStatistics
+E005 DEC-XTRAP:BadDevices
+E007 DEC-XTRAP:BadScreen
+E008 DEC-XTRAP:BadSwapReq
+R000 DMX:DMXQueryVersion
+R001 DMX:DMXGetScreenCount
+R002 DMX:DMXGetScreenInfoDEPRECATED
+R003 DMX:DMXGetWindowAttributes
+R004 DMX:DMXGetInputCount
+R005 DMX:DMXGetInputAttributes
+R006 DMX:DMXForceWindowCreationDEPRECATED
+R007 DMX:DMXReconfigureScreenDEPRECATED
+R008 DMX:DMXSync
+R009 DMX:DMXForceWindowCreation
+R010 DMX:DMXGetScreenAttributes
+R011 DMX:DMXChangeScreensAttributes
+R012 DMX:DMXAddScreen
+R013 DMX:DMXRemoveScreen
+R014 DMX:DMXGetDesktopAttributes
+R015 DMX:DMXChangeDesktopAttributes
+R016 DMX:DMXAddInput
+R017 DMX:DMXRemoveInput
+R000 DOUBLE-BUFFER:GetVersion
+R001 DOUBLE-BUFFER:AllocateBackBufferName
+R002 DOUBLE-BUFFER:DeallocateBackBufferName
+R003 DOUBLE-BUFFER:SwapBuffers
+R004 DOUBLE-BUFFER:BeginIdiom
+R005 DOUBLE-BUFFER:EndIdiom
+R006 DOUBLE-BUFFER:GetVisualInfo
+R007 DOUBLE-BUFFER:GetBackBufferAttributes
+E000 DOUBLE-BUFFER:BadBuffer
+R000 DPMS:GetVersion
+R001 DPMS:Capable
+R002 DPMS:GetTimeouts
+R003 DPMS:SetTimeouts
+R004 DPMS:Enable
+R005 DPMS:Disable
+R006 DPMS:ForceLevel
+R007 DPMS:Info
+R000 DRI2:QueryVersion
+R001 DRI2:Connect
+R002 DRI2:Authenticate
+R003 DRI2:CreateDrawable
+R004 DRI2:DestroyDrawable
+R005 DRI2:GetBuffers
+R006 DRI2:CopyRegion
+R007 DRI2:GetBuffersWithFormat
+R000 Extended-Visual-Information:QueryVersion
+R001 Extended-Visual-Information:GetVisualInfo
+R000 FontCache:QueryVersion
+R001 FontCache:GetCacheSettings
+R002 FontCache:ChangeCacheSettings
+R003 FontCache:GetCacheStatistics
+E000 FontCache:BadProtocol
+E001 FontCache:CannotAllocMemory
+R001 GLX:
+R002 GLX:Large
+R003 GLX:CreateContext
+R004 GLX:DestroyContext
+R005 GLX:MakeCurrent
+R006 GLX:IsDirect
+R007 GLX:QueryVersion
+R008 GLX:WaitGL
+R009 GLX:WaitX
+R010 GLX:CopyContext
+R011 GLX:SwapBuffers
+R012 GLX:UseXFont
+R013 GLX:CreateGLXPixmap
+R014 GLX:GetVisualConfigs
+R015 GLX:DestroyGLXPixmap
+R016 GLX:VendorPrivate
+R017 GLX:VendorPrivateWithReply
+R018 GLX:QueryExtensionsString
+R019 GLX:QueryServerString
+R020 GLX:ClientInfo
+R101 GLX:NewList
+R102 GLX:EndList
+R103 GLX:DeleteLists
+R104 GLX:GenLists
+R105 GLX:FeedbackBuffer
+R106 GLX:SelectBuffer
+R107 GLX:Mode
+R108 GLX:Finish
+R109 GLX:PixelStoref
+R110 GLX:PixelStorei
+R111 GLX:ReadPixels
+R112 GLX:GetBooleanv
+R113 GLX:GetClipPlane
+R114 GLX:GetDoublev
+R115 GLX:GetError
+R116 GLX:GetFloatv
+R117 GLX:GetIntegerv
+R118 GLX:GetLightfv
+R119 GLX:GetLightiv
+R120 GLX:GetMapdv
+R121 GLX:GetMapfv
+R122 GLX:GetMapiv
+R123 GLX:GetMaterialfv
+R124 GLX:GetMaterialiv
+R125 GLX:GetPixelfv
+R126 GLX:GetPixelMapuiv
+R127 GLX:GetPixelMapusv
+R128 GLX:GetPolygonStipple
+R129 GLX:GetString
+R130 GLX:GetTexEnvfv
+R131 GLX:GetTexEnviv
+R132 GLX:GetTexGendv
+R133 GLX:GetTexGenfv
+R134 GLX:GetTexGeniv
+R135 GLX:GetTexImage
+R136 GLX:GetTexParameterfv
+R137 GLX:GetTexParameteriv
+R138 GLX:GetTexLevelParameterfv
+R139 GLX:GetTexLevelParameteriv
+R140 GLX:IsEnabled
+R141 GLX:IsList
+R142 GLX:Flush
+E000 GLX:BadContext
+E001 GLX:BadContextState
+E002 GLX:BadDrawable
+E003 GLX:BadPixmap
+E004 GLX:BadContextTag
+E005 GLX:BadCurrentWindow
+E006 GLX:BadRenderRequest
+E007 GLX:BadLargeRequest
+E008 GLX:UnsupportedPrivateRequest
+R000 LBX:QueryVersion
+R001 LBX:StartProxy
+R002 LBX:StopProxy
+R003 LBX:Switch
+R004 LBX:NewClient
+R005 LBX:CloseClient
+R006 LBX:ModifySequence
+R007 LBX:AllowMotion
+R008 LBX:IncrementPixel
+R009 LBX:Delta
+R010 LBX:GetModifierMapping
+R011 LBX:QueryTag
+R012 LBX:InvalidateTag
+R013 LBX:PolyPoint
+R014 LBX:PolyLine
+R015 LBX:PolySegment
+R016 LBX:PolyRectangle
+R017 LBX:PolyArc
+R018 LBX:FillPoly
+R019 LBX:PolyFillRectangle
+R020 LBX:PolyFillArc
+R021 LBX:GetKeyboardMapping
+R022 LBX:QueryFont
+R023 LBX:ChangeProperty
+R024 LBX:GetProperty
+R025 LBX:TagData
+R026 LBX:CopyArea
+R027 LBX:CopyPlane
+R028 LBX:PolyText8
+R029 LBX:PolyText16
+R030 LBX:ImageText8
+R031 LBX:ImageText16
+R032 LBX:QueryExtension
+R033 LBX:PutImage
+R034 LBX:GetImage
+R035 LBX:BeginLargeRequest
+R036 LBX:LargeRequestData
+R037 LBX:EndLargeRequest
+R038 LBX:InternAtoms
+R039 LBX:GetWinAttrAndGeom
+R040 LBX:GrabCmap
+R041 LBX:ReleaseCmap
+R042 LBX:AllocColor
+R043 LBX:Sync
+E000 LBX:BadLbxClient
+R000 MIT-SCREEN-SAVER:QueryVersion
+R001 MIT-SCREEN-SAVER:QueryInfo
+R002 MIT-SCREEN-SAVER:SelectInput
+R003 MIT-SCREEN-SAVER:SetAttributes
+R004 MIT-SCREEN-SAVER:UnsetAttributes
+R005 MIT-SCREEN-SAVER:Suspend
+V000 MIT-SCREEN-SAVER:Notify
+R000 MIT-SHM:QueryVersion
+R001 MIT-SHM:Attach
+R002 MIT-SHM:Detach
+R003 MIT-SHM:PutImage
+R004 MIT-SHM:GetImage
+R005 MIT-SHM:CreatePixmap
+V000 MIT-SHM:Completion
+E000 MIT-SHM:BadShmSeg
+R000 MIT-SUNDRY-NONSTANDARD:SetBugMode
+R001 MIT-SUNDRY-NONSTANDARD:GetBugMode
+R000 Multi-Buffering:GetBufferVersion
+R001 Multi-Buffering:CreateImageBuffers
+R002 Multi-Buffering:DestroyImageBuffers
+R003 Multi-Buffering:DisplayImageBuffers
+R004 Multi-Buffering:SetMBufferAttributes
+R005 Multi-Buffering:GetMBufferAttributes
+R006 Multi-Buffering:SetBufferAttributes
+R007 Multi-Buffering:GetBufferAttributes
+R008 Multi-Buffering:GetBufferInfo
+R009 Multi-Buffering:CreateStereoWindow
+R010 Multi-Buffering:ClearImageBufferArea
+V000 Multi-Buffering:ClobberNotify
+V001 Multi-Buffering:UpdateNotify
+E000 Multi-Buffering:BadBuffer
+R000 RANDR:QueryVersion
+R001 RANDR:OldGetScreenInfo
+R002 RANDR:SetScreenConfig
+R003 RANDR:OldScreenChangeSelectInput
+R004 RANDR:SelectInput
+R005 RANDR:GetScreenInfo
+R006 RANDR:GetScreenSizeRange
+R007 RANDR:SetScreenSize
+R008 RANDR:GetScreenResources
+R009 RANDR:GetOutputInfo
+R010 RANDR:ListOutputProperties
+R011 RANDR:QueryOutputProperty
+R012 RANDR:ConfigureOutputProperty
+R013 RANDR:ChangeOutputProperty
+R014 RANDR:DeleteOutputProperty
+R015 RANDR:GetOutputProperty
+R016 RANDR:CreateMode
+R017 RANDR:DestroyMode
+R018 RANDR:AddOutputMode
+R019 RANDR:DeleteOutputMode
+R020 RANDR:GetCrtcInfo
+R021 RANDR:SetCrtcConfig
+R022 RANDR:GetCrtcGammaSize
+R023 RANDR:GetCrtcGamma
+R024 RANDR:SetCrtcGamma
+R025 RANDR:GetScreenResourcesCurrent
+R026 RANDR:SetCrtcTransform
+R027 RANDR:GetCrtcTransform
+R028 RANDR:GetPanning
+R029 RANDR:SetPanning
+R030 RANDR:SetOutputPrimary
+R031 RANDR:GetOutputPrimary
+V000 RANDR:ScreenChangeNotify
+V001 RANDR:Notify
+E000 RANDR:BadRROutput
+E001 RANDR:BadRRCrtc
+E002 RANDR:BadRRMode
+R000 RECORD:QueryVersion
+R001 RECORD:CreateContext
+R002 RECORD:RegisterClients
+R003 RECORD:UnregisterClients
+R004 RECORD:GetContext
+R005 RECORD:EnableContext
+R006 RECORD:DisableContext
+R007 RECORD:FreeContext
+E000 RECORD:BadContext
+R000 RENDER:QueryVersion
+R001 RENDER:QueryPictFormats
+R002 RENDER:QueryPictIndexValues
+R003 RENDER:QueryDithers
+R004 RENDER:CreatePicture
+R005 RENDER:ChangePicture
+R006 RENDER:SetPictureClipRectangles
+R007 RENDER:FreePicture
+R008 RENDER:Composite
+R009 RENDER:Scale
+R010 RENDER:Trapezoids
+R011 RENDER:Triangles
+R012 RENDER:TriStrip
+R013 RENDER:TriFan
+R014 RENDER:ColorTrapezoids
+R015 RENDER:ColorTriangles
+R016 RENDER:Transform
+R017 RENDER:CreateGlyphSet
+R018 RENDER:ReferenceGlyphSet
+R019 RENDER:FreeGlyphSet
+R020 RENDER:AddGlyphs
+R021 RENDER:AddGlyphsFromPicture
+R022 RENDER:FreeGlyphs
+R023 RENDER:CompositeGlyphs8
+R024 RENDER:CompositeGlyphs16
+R025 RENDER:CompositeGlyphs32
+R026 RENDER:FillRectangles
+R027 RENDER:CreateCursor
+R028 RENDER:SetPictureTransform
+R029 RENDER:QueryFilters
+R030 RENDER:SetPictureFilter
+R031 RENDER:CreateAnimCursor
+R032 RENDER:AddTraps
+R033 RENDER:CreateSolidFill
+R034 RENDER:CreateLinearGradient
+R035 RENDER:CreateRadialGradient
+R036 RENDER:CreateConicalGradient
+E000 RENDER:BadPictFormat
+E001 RENDER:BadPicture
+E002 RENDER:BadPictOp
+E003 RENDER:BadGlyphSet
+E004 RENDER:BadGlyph
+R000 SECURITY:QueryVersion
+R001 SECURITY:GenerateAuthorization
+R002 SECURITY:RevokeAuthorization
+V000 SECURITY:AuthorizationRevoked
+E000 SECURITY:BadAuthorization
+E001 SECURITY:BadAuthorizationProtocol
+R000 SELinux:SELinuxQueryVersion
+R001 SELinux:SELinuxSetDeviceCreateContext
+R002 SELinux:SELinuxGetDeviceCreateContext
+R003 SELinux:SELinuxSetDeviceContext
+R004 SELinux:SELinuxGetDeviceContext
+R005 SELinux:SELinuxSetWindowCreateContext
+R006 SELinux:SELinuxGetWindowCreateContext
+R007 SELinux:SELinuxGetWindowContext
+R008 SELinux:SELinuxSetPropertyCreateContext
+R009 SELinux:SELinuxGetPropertyCreateContext
+R010 SELinux:SELinuxSetPropertyUseContext
+R011 SELinux:SELinuxGetPropertyUseContext
+R012 SELinux:SELinuxGetPropertyContext
+R013 SELinux:SELinuxGetPropertyDataContext
+R014 SELinux:SELinuxListProperties
+R015 SELinux:SELinuxSetSelectionCreateContext
+R016 SELinux:SELinuxGetSelectionCreateContext
+R017 SELinux:SELinuxSetSelectionUseContext
+R018 SELinux:SELinuxGetSelectionUseContext
+R019 SELinux:SELinuxGetSelectionContext
+R020 SELinux:SELinuxGetSelectionDataContext
+R021 SELinux:SELinuxListSelections
+R022 SELinux:SELinuxGetClientContext
+R000 SHAPE:QueryVersion
+R001 SHAPE:Rectangles
+R002 SHAPE:Mask
+R003 SHAPE:Combine
+R004 SHAPE:Offset
+R005 SHAPE:QueryExtents
+R006 SHAPE:SelectInput
+R007 SHAPE:InputSelected
+R008 SHAPE:GetRectangles
+V000 SHAPE:Notify
+R000 SYNC:Initialize
+R001 SYNC:ListSystemCounters
+R002 SYNC:CreateCounter
+R003 SYNC:SetCounter
+R004 SYNC:ChangeCounter
+R005 SYNC:QueryCounter
+R006 SYNC:DestroyCounter
+R007 SYNC:Await
+R008 SYNC:CreateAlarm
+R009 SYNC:ChangeAlarm
+R010 SYNC:QueryAlarm
+R011 SYNC:DestroyAlarm
+R012 SYNC:SetPriority
+R013 SYNC:GetPriority
+V000 SYNC:CounterNotify
+V001 SYNC:AlarmNotify
+E000 SYNC:BadCounter
+E001 SYNC:BadAlarm
+R000 TOG-CUP:QueryVersion
+R001 TOG-CUP:GetReservedColormapEntries
+R002 TOG-CUP:StoreColors
+R000 Windows-WM:QueryVersion
+R001 Windows-WM:FrameGetRect
+R002 Windows-WM:FrameDraw
+R003 Windows-WM:FrameSetTitle
+R004 Windows-WM:DisableUpdate
+R005 Windows-WM:ReenableUpdate
+R006 Windows-WM:SelectInput
+R007 Windows-WM:SetFrontProcess
+V000 Windows-WM:ControllerNotify
+V001 Windows-WM:ActivationNotify
+E000 Windows-WM:ClientNotLocal
+E001 Windows-WM:OperationNotSupported
+R000 X-Resource:QueryVersion
+R001 X-Resource:QueryClients
+R002 X-Resource:QueryClientResources
+R003 X-Resource:QueryClientPixmapBytes
+R001 X11:CreateWindow
+R002 X11:ChangeWindowAttributes
+R003 X11:GetWindowAttributes
+R004 X11:DestroyWindow
+R005 X11:DestroySubwindows
+R006 X11:ChangeSaveSet
+R007 X11:ReparentWindow
+R008 X11:MapWindow
+R009 X11:MapSubwindows
+R010 X11:UnmapWindow
+R011 X11:UnmapSubwindows
+R012 X11:ConfigureWindow
+R013 X11:CirculateWindow
+R014 X11:GetGeometry
+R015 X11:QueryTree
+R016 X11:InternAtom
+R017 X11:GetAtomName
+R018 X11:ChangeProperty
+R019 X11:DeleteProperty
+R020 X11:GetProperty
+R021 X11:ListProperties
+R022 X11:SetSelectionOwner
+R023 X11:GetSelectionOwner
+R024 X11:ConvertSelection
+R025 X11:SendEvent
+R026 X11:GrabPointer
+R027 X11:UngrabPointer
+R028 X11:GrabButton
+R029 X11:UngrabButton
+R030 X11:ChangeActivePointerGrab
+R031 X11:GrabKeyboard
+R032 X11:UngrabKeyboard
+R033 X11:GrabKey
+R034 X11:UngrabKey
+R035 X11:AllowEvents
+R036 X11:GrabServer
+R037 X11:UngrabServer
+R038 X11:QueryPointer
+R039 X11:GetMotionEvents
+R040 X11:TranslateCoords
+R041 X11:WarpPointer
+R042 X11:SetInputFocus
+R043 X11:GetInputFocus
+R044 X11:QueryKeymap
+R045 X11:OpenFont
+R046 X11:CloseFont
+R047 X11:QueryFont
+R048 X11:QueryTextExtents
+R049 X11:ListFonts
+R050 X11:ListFontsWithInfo
+R051 X11:SetFontPath
+R052 X11:GetFontPath
+R053 X11:CreatePixmap
+R054 X11:FreePixmap
+R055 X11:CreateGC
+R056 X11:ChangeGC
+R057 X11:CopyGC
+R058 X11:SetDashes
+R059 X11:SetClipRectangles
+R060 X11:FreeGC
+R061 X11:ClearArea
+R062 X11:CopyArea
+R063 X11:CopyPlane
+R064 X11:PolyPoint
+R065 X11:PolyLine
+R066 X11:PolySegment
+R067 X11:PolyRectangle
+R068 X11:PolyArc
+R069 X11:FillPoly
+R070 X11:PolyFillRectangle
+R071 X11:PolyFillArc
+R072 X11:PutImage
+R073 X11:GetImage
+R074 X11:PolyText8
+R075 X11:PolyText16
+R076 X11:ImageText8
+R077 X11:ImageText16
+R078 X11:CreateColormap
+R079 X11:FreeColormap
+R080 X11:CopyColormapAndFree
+R081 X11:InstallColormap
+R082 X11:UninstallColormap
+R083 X11:ListInstalledColormaps
+R084 X11:AllocColor
+R085 X11:AllocNamedColor
+R086 X11:AllocColorCells
+R087 X11:AllocColorPlanes
+R088 X11:FreeColors
+R089 X11:StoreColors
+R090 X11:StoreNamedColor
+R091 X11:QueryColors
+R092 X11:LookupColor
+R093 X11:CreateCursor
+R094 X11:CreateGlyphCursor
+R095 X11:FreeCursor
+R096 X11:RecolorCursor
+R097 X11:QueryBestSize
+R098 X11:QueryExtension
+R099 X11:ListExtensions
+R100 X11:ChangeKeyboardMapping
+R101 X11:GetKeyboardMapping
+R102 X11:ChangeKeyboardControl
+R103 X11:GetKeyboardControl
+R104 X11:Bell
+R105 X11:ChangePointerControl
+R106 X11:GetPointerControl
+R107 X11:SetScreenSaver
+R108 X11:GetScreenSaver
+R109 X11:ChangeHosts
+R110 X11:ListHosts
+R111 X11:SetAccessControl
+R112 X11:SetCloseDownMode
+R113 X11:KillClient
+R114 X11:RotateProperties
+R115 X11:ForceScreenSaver
+R116 X11:SetPointerMapping
+R117 X11:GetPointerMapping
+R118 X11:SetModifierMapping
+R119 X11:GetModifierMapping
+R127 X11:NoOperation
+V000 X11:X_Error
+V001 X11:X_Reply
+V002 X11:KeyPress
+V003 X11:KeyRelease
+V004 X11:ButtonPress
+V005 X11:ButtonRelease
+V006 X11:MotionNotify
+V007 X11:EnterNotify
+V008 X11:LeaveNotify
+V009 X11:FocusIn
+V010 X11:FocusOut
+V011 X11:KeymapNotify
+V012 X11:Expose
+V013 X11:GraphicsExpose
+V014 X11:NoExpose
+V015 X11:VisibilityNotify
+V016 X11:CreateNotify
+V017 X11:DestroyNotify
+V018 X11:UnmapNotify
+V019 X11:MapNotify
+V020 X11:MapRequest
+V021 X11:ReparentNotify
+V022 X11:ConfigureNotify
+V023 X11:ConfigureRequest
+V024 X11:GravityNotify
+V025 X11:ResizeRequest
+V026 X11:CirculateNotify
+V027 X11:CirculateRequest
+V028 X11:PropertyNotify
+V029 X11:SelectionClear
+V030 X11:SelectionRequest
+V031 X11:SelectionNotify
+V032 X11:ColormapNotify
+V033 X11:ClientMessage
+V034 X11:MappingNotify
+V035 X11:GenericEvent
+E000 X11:Success
+E001 X11:BadRequest
+E002 X11:BadValue
+E003 X11:BadWindow
+E004 X11:BadPixmap
+E005 X11:BadAtom
+E006 X11:BadCursor
+E007 X11:BadFont
+E008 X11:BadMatch
+E009 X11:BadDrawable
+E010 X11:BadAccess
+E011 X11:BadAlloc
+E012 X11:BadColor
+E013 X11:BadGC
+E014 X11:BadIDChoice
+E015 X11:BadName
+E016 X11:BadLength
+E017 X11:BadImplementation
+R001 X3D-PEX:GetExtensionInfo
+R002 X3D-PEX:GetEnumeratedTypeInfo
+R003 X3D-PEX:GetImpDepConstants
+R004 X3D-PEX:CreateLookupTable
+R005 X3D-PEX:CopyLookupTable
+R006 X3D-PEX:FreeLookupTable
+R007 X3D-PEX:GetTableInfo
+R008 X3D-PEX:GetPredefinedEntries
+R009 X3D-PEX:GetDefinedIndices
+R010 X3D-PEX:GetTableEntry
+R011 X3D-PEX:GetTableEntries
+R012 X3D-PEX:SetTableEntries
+R013 X3D-PEX:DeleteTableEntries
+R014 X3D-PEX:CreatePipelineContext
+R015 X3D-PEX:CopyPipelineContext
+R016 X3D-PEX:FreePipelineContext
+R017 X3D-PEX:GetPipelineContext
+R018 X3D-PEX:ChangePipelineContext
+R019 X3D-PEX:CreateRenderer
+R020 X3D-PEX:FreeRenderer
+R021 X3D-PEX:ChangeRenderer
+R022 X3D-PEX:GetRendererAttributes
+R023 X3D-PEX:GetRendererDynamics
+R024 X3D-PEX:BeginRendering
+R025 X3D-PEX:EndRendering
+R026 X3D-PEX:BeginStructure
+R027 X3D-PEX:EndStructure
+R028 X3D-PEX:OutputCommands
+R029 X3D-PEX:Network
+R030 X3D-PEX:CreateStructure
+R031 X3D-PEX:CopyStructure
+R032 X3D-PEX:DestroyStructures
+R033 X3D-PEX:GetStructureInfo
+R034 X3D-PEX:GetElementInfo
+R035 X3D-PEX:GetStructuresInNetwork
+R036 X3D-PEX:GetAncestors
+R037 X3D-PEX:GetDescendants
+R038 X3D-PEX:FetchElements
+R039 X3D-PEX:SetEditingMode
+R040 X3D-PEX:SetElementPointer
+R041 X3D-PEX:SetElementPointerAtLabel
+R042 X3D-PEX:ElementSearch
+R043 X3D-PEX:StoreElements
+R044 X3D-PEX:DeleteElements
+R045 X3D-PEX:DeleteElementsToLabel
+R046 X3D-PEX:DeleteBetweenLabels
+R047 X3D-PEX:CopyElements
+R048 X3D-PEX:ChangeStructureRefs
+R049 X3D-PEX:CreateNameSet
+R050 X3D-PEX:CopyNameSet
+R051 X3D-PEX:FreeNameSet
+R052 X3D-PEX:GetNameSet
+R053 X3D-PEX:ChangeNameSet
+R054 X3D-PEX:CreateSearchContext
+R055 X3D-PEX:CopySearchContext
+R056 X3D-PEX:FreeSearchContext
+R057 X3D-PEX:GetSearchContext
+R058 X3D-PEX:ChangeSearchContext
+R059 X3D-PEX:SearchNetwork
+R060 X3D-PEX:CreatePhigsWks
+R061 X3D-PEX:FreePhigsWks
+R062 X3D-PEX:GetWksInfo
+R063 X3D-PEX:GetDynamics
+R064 X3D-PEX:GetViewRep
+R065 X3D-PEX:RedrawAllStructures
+R066 X3D-PEX:UpdateWorkstation
+R067 X3D-PEX:RedrawClipRegion
+R068 X3D-PEX:ExecuteDeferredActions
+R069 X3D-PEX:SetViewPriority
+R070 X3D-PEX:SetDisplayUpdateMode
+R071 X3D-PEX:MapDCtoWC
+R072 X3D-PEX:MapWCtoDC
+R073 X3D-PEX:SetViewRep
+R074 X3D-PEX:SetWksWindow
+R075 X3D-PEX:SetWksViewport
+R076 X3D-PEX:SetHlhsrMode
+R077 X3D-PEX:SetWksBufferMode
+R078 X3D-PEX:PostStructure
+R079 X3D-PEX:UnpostStructure
+R080 X3D-PEX:UnpostAllStructures
+R081 X3D-PEX:GetWksPostings
+R082 X3D-PEX:GetPickDevice
+R083 X3D-PEX:ChangePickDevice
+R084 X3D-PEX:CreatePickMeasure
+R085 X3D-PEX:FreePickMeasure
+R086 X3D-PEX:GetPickMeasure
+R087 X3D-PEX:UpdatePickMeasure
+R088 X3D-PEX:OpenFont
+R089 X3D-PEX:CloseFont
+R090 X3D-PEX:QueryFont
+R091 X3D-PEX:ListFonts
+R092 X3D-PEX:ListFontsWithInfo
+R093 X3D-PEX:QueryTextExtents
+R094 X3D-PEX:MatchRenderingTargets
+R095 X3D-PEX:Escape
+R096 X3D-PEX:EscapeWithReply
+R097 X3D-PEX:Elements
+R098 X3D-PEX:AccumulateState
+R099 X3D-PEX:BeginPickOne
+R100 X3D-PEX:EndPickOne
+R101 X3D-PEX:PickOne
+R102 X3D-PEX:BeginPickAll
+R103 X3D-PEX:EndPickAll
+R104 X3D-PEX:PickAll
+E000 X3D-PEX:ColorTypeError
+E001 X3D-PEX:erStateError
+E002 X3D-PEX:FloatingPointFormatError
+E003 X3D-PEX:LabelError
+E004 X3D-PEX:LookupTableError
+E005 X3D-PEX:NameSetError
+E006 X3D-PEX:PathError
+E007 X3D-PEX:FontError
+E008 X3D-PEX:PhigsWksError
+E009 X3D-PEX:PickMeasureError
+E010 X3D-PEX:PipelineContextError
+E011 X3D-PEX:erError
+E012 X3D-PEX:SearchContextError
+E013 X3D-PEX:StructureError
+E014 X3D-PEX:OutputCommandError
+R000 XC-APPGROUP:QueryVersion
+R001 XC-APPGROUP:Create
+R002 XC-APPGROUP:Destroy
+R003 XC-APPGROUP:GetAttr
+R004 XC-APPGROUP:Query
+R005 XC-APPGROUP:CreateAssoc
+R006 XC-APPGROUP:DestroyAssoc
+E000 XC-APPGROUP:BadAppGroup
+R000 XC-MISC:GetVersion
+R001 XC-MISC:GetXIDRange
+R002 XC-MISC:GetXIDList
+R000 XFIXES:QueryVersion
+R001 XFIXES:ChangeSaveSet
+R002 XFIXES:SelectSelectionInput
+R003 XFIXES:SelectCursorInput
+R004 XFIXES:GetCursorImage
+R005 XFIXES:CreateRegion
+R006 XFIXES:CreateRegionFromBitmap
+R007 XFIXES:CreateRegionFromWindow
+R008 XFIXES:CreateRegionFromGC
+R009 XFIXES:CreateRegionFromPicture
+R010 XFIXES:DestroyRegion
+R011 XFIXES:SetRegion
+R012 XFIXES:CopyRegion
+R013 XFIXES:UnionRegion
+R014 XFIXES:IntersectRegion
+R015 XFIXES:SubtractRegion
+R016 XFIXES:InvertRegion
+R017 XFIXES:TranslateRegion
+R018 XFIXES:RegionExtents
+R019 XFIXES:FetchRegion
+R020 XFIXES:SetGCClipRegion
+R021 XFIXES:SetWindowShapeRegion
+R022 XFIXES:SetPictureClipRegion
+R023 XFIXES:SetCursorName
+R024 XFIXES:GetCursorName
+R025 XFIXES:GetCursorImageAndName
+R026 XFIXES:ChangeCursor
+R027 XFIXES:ChangeCursorByName
+R028 XFIXES:ExpandRegion
+R029 XFIXES:HideCursor
+R030 XFIXES:ShowCursor
+V000 XFIXES:SelectionNotify
+V001 XFIXES:CursorNotify
+E000 XFIXES:BadRegion
+R000 XFree86-Bigfont:QueryVersion
+R001 XFree86-Bigfont:QueryFont
+R000 XFree86-DGA:QueryVersion
+R001 XFree86-DGA:GetVideoLL
+R002 XFree86-DGA:DirectVideo
+R003 XFree86-DGA:GetViewPortSize
+R004 XFree86-DGA:SetViewPort
+R005 XFree86-DGA:GetVidPage
+R006 XFree86-DGA:SetVidPage
+R007 XFree86-DGA:InstallColormap
+R008 XFree86-DGA:QueryDirectVideo
+R009 XFree86-DGA:ViewPortChanged
+R010 XFree86-DGA:Obsolete1
+R011 XFree86-DGA:Obsolete2
+R012 XFree86-DGA:QueryModes
+R013 XFree86-DGA:SetMode
+R014 XFree86-DGA:SetViewport
+R015 XFree86-DGA:InstallColormap
+R016 XFree86-DGA:SelectInput
+R017 XFree86-DGA:FillRectangle
+R018 XFree86-DGA:CopyArea
+R019 XFree86-DGA:CopyTransparentArea
+R020 XFree86-DGA:GetViewportStatus
+R021 XFree86-DGA:Sync
+R022 XFree86-DGA:OpenFramebuffer
+R023 XFree86-DGA:CloseFramebuffer
+R024 XFree86-DGA:SetClientVersion
+R025 XFree86-DGA:ChangePixmapMode
+R026 XFree86-DGA:CreateColormap
+E000 XFree86-DGA:ClientNotLocal
+E001 XFree86-DGA:NoDirectVideoMode
+E002 XFree86-DGA:ScreenNotActive
+E003 XFree86-DGA:DirectNotActivated
+E004 XFree86-DGA:OperationNotSupported
+R000 XFree86-DRI:QueryVersion
+R001 XFree86-DRI:QueryDirectRenderingCapable
+R002 XFree86-DRI:OpenConnection
+R003 XFree86-DRI:CloseConnection
+R004 XFree86-DRI:GetClientDriverName
+R005 XFree86-DRI:CreateContext
+R006 XFree86-DRI:DestroyContext
+R007 XFree86-DRI:CreateDrawable
+R008 XFree86-DRI:DestroyDrawable
+R009 XFree86-DRI:GetDrawableInfo
+R010 XFree86-DRI:GetDeviceInfo
+R011 XFree86-DRI:AuthConnection
+R012 XFree86-DRI:OpenFullScreen
+R013 XFree86-DRI:CloseFullScreen
+E000 XFree86-DRI:ClientNotLocal
+E001 XFree86-DRI:OperationNotSupported
+R000 XFree86-Misc:QueryVersion
+R001 XFree86-Misc:GetSaver
+R002 XFree86-Misc:SetSaver
+R003 XFree86-Misc:GetMouseSettings
+R004 XFree86-Misc:GetKbdSettings
+R005 XFree86-Misc:SetMouseSettings
+R006 XFree86-Misc:SetKbdSettings
+R007 XFree86-Misc:SetGrabKeysState
+R008 XFree86-Misc:SetClientVersion
+R009 XFree86-Misc:GetFilePaths
+R010 XFree86-Misc:PassMessage
+E000 XFree86-Misc:BadMouseProtocol
+E001 XFree86-Misc:BadMouseBaudRate
+E002 XFree86-Misc:BadMouseFlags
+E003 XFree86-Misc:BadMouseCombo
+E004 XFree86-Misc:BadKbdType
+E005 XFree86-Misc:ModInDevDisabled
+E006 XFree86-Misc:ModInDevClientNotLocal
+E007 XFree86-Misc:NoModule
+R000 XFree86-VidModeExtension:QueryVersion
+R001 XFree86-VidModeExtension:GetModeLine
+R002 XFree86-VidModeExtension:ModModeLine
+R003 XFree86-VidModeExtension:SwitchMode
+R004 XFree86-VidModeExtension:GetMonitor
+R005 XFree86-VidModeExtension:LockModeSwitch
+R006 XFree86-VidModeExtension:GetAllModeLines
+R007 XFree86-VidModeExtension:AddModeLine
+R008 XFree86-VidModeExtension:DeleteModeLine
+R009 XFree86-VidModeExtension:ValidateModeLine
+R010 XFree86-VidModeExtension:SwitchToMode
+R011 XFree86-VidModeExtension:GetViewPort
+R012 XFree86-VidModeExtension:SetViewPort
+R013 XFree86-VidModeExtension:GetDotClocks
+R014 XFree86-VidModeExtension:SetClientVersion
+R015 XFree86-VidModeExtension:SetGamma
+R016 XFree86-VidModeExtension:GetGamma
+R017 XFree86-VidModeExtension:GetGammaRamp
+R018 XFree86-VidModeExtension:SetGammaRamp
+R019 XFree86-VidModeExtension:GetGammaRampSize
+R020 XFree86-VidModeExtension:GetPermissions
+V000 XFree86-VidModeExtension:Notify
+E000 XFree86-VidModeExtension:BadClock
+E001 XFree86-VidModeExtension:BadHTimings
+E002 XFree86-VidModeExtension:BadVTimings
+E003 XFree86-VidModeExtension:ModeUnsuitable
+E004 XFree86-VidModeExtension:ExtensionDisabled
+E005 XFree86-VidModeExtension:ClientNotLocal
+E006 XFree86-VidModeExtension:ZoomLocked
+R001 XIE:QueryImageExtension
+R002 XIE:QueryTechniques
+R003 XIE:CreateColorList
+R004 XIE:DestroyColorList
+R005 XIE:PurgeColorList
+R006 XIE:QueryColorList
+R007 XIE:CreateLUT
+R008 XIE:DestroyLUT
+R009 XIE:CreatePhotomap
+R010 XIE:DestroyPhotomap
+R011 XIE:QueryPhotomap
+R012 XIE:CreateROI
+R013 XIE:DestroyROI
+R014 XIE:CreatePhotospace
+R015 XIE:DestroyPhotospace
+R016 XIE:ExecuteImmediate
+R017 XIE:CreatePhotoflo
+R018 XIE:DestroyPhotoflo
+R019 XIE:ExecutePhotoflo
+R020 XIE:ModifyPhotoflo
+R021 XIE:RedefinePhotoflo
+R022 XIE:PutClientData
+R023 XIE:GetClientData
+R024 XIE:QueryPhotoflo
+R025 XIE:Await
+R026 XIE:Abort
+E000 XIE:ColorListError
+E001 XIE:LUTError
+E002 XIE:PhotofloError
+E003 XIE:PhotomapError
+E004 XIE:PhotospaceError
+E005 XIE:ROIError
+E006 XIE:FloError
+R000 XINERAMA:QueryVersion
+R001 XINERAMA:GetState
+R002 XINERAMA:GetScreenCount
+R003 XINERAMA:GetScreenSize
+R004 XINERAMA:IsActive
+R005 XINERAMA:QueryScreens
+R001 XInputExtension:GetExtensionVersion
+R002 XInputExtension:ListInputDevices
+R003 XInputExtension:OpenDevice
+R004 XInputExtension:CloseDevice
+R005 XInputExtension:SetDeviceMode
+R006 XInputExtension:SelectExtensionEvent
+R007 XInputExtension:GetSelectedExtensionEvents
+R008 XInputExtension:ChangeDeviceDontPropagateList
+R009 XInputExtension:GetDeviceDontPropagageList
+R010 XInputExtension:GetDeviceMotionEvents
+R011 XInputExtension:ChangeKeyboardDevice
+R012 XInputExtension:ChangePointerDevice
+R013 XInputExtension:GrabDevice
+R014 XInputExtension:UngrabDevice
+R015 XInputExtension:GrabDeviceKey
+R016 XInputExtension:UngrabDeviceKey
+R017 XInputExtension:GrabDeviceButton
+R018 XInputExtension:UngrabDeviceButton
+R019 XInputExtension:AllowDeviceEvents
+R020 XInputExtension:GetDeviceFocus
+R021 XInputExtension:SetDeviceFocus
+R022 XInputExtension:GetFeedbackControl
+R023 XInputExtension:ChangeFeedbackControl
+R024 XInputExtension:GetDeviceKeyMapping
+R025 XInputExtension:ChangeDeviceKeyMapping
+R026 XInputExtension:GetDeviceModifierMapping
+R027 XInputExtension:SetDeviceModifierMapping
+R028 XInputExtension:GetDeviceButtonMapping
+R029 XInputExtension:SetDeviceButtonMapping
+R030 XInputExtension:QueryDeviceState
+R031 XInputExtension:SendExtensionEvent
+R032 XInputExtension:DeviceBell
+R033 XInputExtension:SetDeviceValuators
+R034 XInputExtension:GetDeviceControl
+R035 XInputExtension:ChangeDeviceControl
+R036 XInputExtension:ListDeviceProperties
+R037 XInputExtension:ChangeDeviceProperty
+R038 XInputExtension:DeleteDeviceProperty
+R039 XInputExtension:GetDeviceProperty
+R040 XInputExtension:QueryPointer
+R041 XInputExtension:WarpPointer
+R042 XInputExtension:ChangeCursor
+R043 XInputExtension:ChangeHierarchy
+R044 XInputExtension:SetClientPointer
+R045 XInputExtension:GetClientPointer
+R046 XInputExtension:SelectEvents
+R047 XInputExtension:QueryVersion
+R048 XInputExtension:QueryDevice
+R049 XInputExtension:SetFocus
+R050 XInputExtension:GetFocus
+R051 XInputExtension:GrabDevice
+R052 XInputExtension:UngrabDevice
+R053 XInputExtension:AllowEvents
+R054 XInputExtension:PassiveGrabDevice
+R055 XInputExtension:PassiveUngrabDevice
+R056 XInputExtension:ListProperties
+R057 XInputExtension:ChangeProperty
+R058 XInputExtension:DeleteProperty
+R059 XInputExtension:GetProperty
+R060 XInputExtension:GetSelectedEvents
+V000 XInputExtension:DeviceValuator
+V001 XInputExtension:DeviceKeyPress
+V002 XInputExtension:DeviceKeyRelease
+V003 XInputExtension:DeviceButtonPress
+V004 XInputExtension:DeviceButtonRelease
+V005 XInputExtension:DeviceMotionNotify
+V006 XInputExtension:DeviceFocusIn
+V007 XInputExtension:DeviceFocusOut
+V008 XInputExtension:ProximityIn
+V009 XInputExtension:ProximityOut
+V010 XInputExtension:DeviceStateNotify
+V011 XInputExtension:DeviceMappingNotify
+V012 XInputExtension:ChangeDeviceNotify
+V013 XInputExtension:DeviceKeystateNotify
+V014 XInputExtension:DeviceButtonstateNotify
+V015 XInputExtension:DevicePresenceNotify
+V016 XInputExtension:DevicePropertyNotify
+E000 XInputExtension:BadDevice
+E001 XInputExtension:BadEvent
+E002 XInputExtension:BadMode
+E003 XInputExtension:DeviceBusy
+E004 XInputExtension:BadClass
+R000 XKEYBOARD:UseExtension
+R001 XKEYBOARD:SelectEvents
+R002 XKEYBOARD:Obsolete
+R003 XKEYBOARD:Bell
+R004 XKEYBOARD:GetState
+R005 XKEYBOARD:LatchLockState
+R006 XKEYBOARD:GetControls
+R007 XKEYBOARD:SetControls
+R008 XKEYBOARD:GetMap
+R009 XKEYBOARD:SetMap
+R010 XKEYBOARD:GetCompatMap
+R011 XKEYBOARD:SetCompatMap
+R012 XKEYBOARD:GetIndicatorState
+R013 XKEYBOARD:GetIndicatorMap
+R014 XKEYBOARD:SetIndicatorMap
+R015 XKEYBOARD:GetNamedIndicator
+R016 XKEYBOARD:SetNamedIndicator
+R017 XKEYBOARD:GetNames
+R018 XKEYBOARD:SetNames
+R019 XKEYBOARD:GetGeometry
+R020 XKEYBOARD:SetGeometry
+R021 XKEYBOARD:PerClientFlags
+R022 XKEYBOARD:ListComponents
+R023 XKEYBOARD:GetKbdByName
+R024 XKEYBOARD:GetDeviceInfo
+R025 XKEYBOARD:SetDeviceInfo
+R101 XKEYBOARD:SetDebuggingFlags
+V000 XKEYBOARD:EventCode
+E000 XKEYBOARD:BadKeyboard
+R000 XTEST:GetVersion
+R001 XTEST:CompareCursor
+R002 XTEST:FakeInput
+R003 XTEST:GrabControl
+R000 XVideo:QueryExtension
+R001 XVideo:QueryAdaptors
+R002 XVideo:QueryEncodings
+R003 XVideo:GrabPort
+R004 XVideo:UngrabPort
+R005 XVideo:PutVideo
+R006 XVideo:PutStill
+R007 XVideo:GetVideo
+R008 XVideo:GetStill
+R009 XVideo:StopVideo
+R010 XVideo:SelectVideoNotify
+R011 XVideo:SelectPortNotify
+R012 XVideo:QueryBestSize
+R013 XVideo:SetPortAttribute
+R014 XVideo:GetPortAttribute
+R015 XVideo:QueryPortAttributes
+R016 XVideo:ListImageFormats
+R017 XVideo:QueryImageAttributes
+R018 XVideo:PutImage
+R019 XVideo:ShmPutImage
+V000 XVideo:VideoNotify
+V001 XVideo:PortNotify
+E000 XVideo:BadPort
+E001 XVideo:BadEncoding
+E002 XVideo:BadControl
+R000 XVideo-MotionCompensation:QueryVersion
+R001 XVideo-MotionCompensation:ListSurfaceTypes
+R002 XVideo-MotionCompensation:CreateContext
+R003 XVideo-MotionCompensation:DestroyContext
+R004 XVideo-MotionCompensation:CreateSurface
+R005 XVideo-MotionCompensation:DestroySurface
+R006 XVideo-MotionCompensation:CreateSubpicture
+R007 XVideo-MotionCompensation:DestroySubpicture
+R008 XVideo-MotionCompensation:ListSubpictureTypes
+R009 XVideo-MotionCompensation:GetDRInfo
+E000 XVideo-MotionCompensation:BadContext
+E001 XVideo-MotionCompensation:BadSurface
+E002 XVideo-MotionCompensation:BadSubpicture
+R000 XpExtension:QueryVersion
+R001 XpExtension:GetPrinterList
+R002 XpExtension:CreateContext
+R003 XpExtension:SetContext
+R004 XpExtension:GetContext
+R005 XpExtension:DestroyContext
+R006 XpExtension:GetContextScreen
+R007 XpExtension:StartJob
+R008 XpExtension:EndJob
+R009 XpExtension:StartDoc
+R010 XpExtension:EndDoc
+R011 XpExtension:PutDocumentData
+R012 XpExtension:GetDocumentData
+R013 XpExtension:StartPage
+R014 XpExtension:EndPage
+R015 XpExtension:SelectInput
+R016 XpExtension:InputSelected
+R017 XpExtension:GetAttributes
+R018 XpExtension:SetAttributes
+R019 XpExtension:GetOneAttribute
+R020 XpExtension:RehashPrinterList
+R021 XpExtension:GetPageDimensions
+R022 XpExtension:QueryScreens
+R023 XpExtension:SetImageResolution
+R024 XpExtension:GetImageResolution
+V000 XpExtension:PrintNotify
+V001 XpExtension:AttributeNotify
+E000 XpExtension:BadContext
+E001 XpExtension:BadSequence
+E002 XpExtension:BadResourceID
diff --git a/dix/ptrveloc.c b/dix/ptrveloc.c
new file mode 100644
index 0000000..4d5dad7
--- /dev/null
+++ b/dix/ptrveloc.c
@@ -0,0 +1,1175 @@
+/*
+ *
+ * Copyright © 2006-2009 Simon Thum simon dot thum at gmx dot de
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <math.h>
+#include <ptrveloc.h>
+#include <exevents.h>
+#include <X11/Xatom.h>
+
+#include <xserver-properties.h>
+
+/*****************************************************************************
+ * Predictable pointer acceleration
+ *
+ * 2006-2009 by Simon Thum (simon [dot] thum [at] gmx de)
+ *
+ * Serves 3 complementary functions:
+ * 1) provide a sophisticated ballistic velocity estimate to improve
+ * the relation between velocity (of the device) and acceleration
+ * 2) make arbitrary acceleration profiles possible
+ * 3) decelerate by two means (constant and adaptive) if enabled
+ *
+ * Important concepts are the
+ *
+ * - Scheme
+ * which selects the basic algorithm
+ * (see devices.c/InitPointerAccelerationScheme)
+ * - Profile
+ * which returns an acceleration
+ * for a given velocity
+ *
+ * The profile can be selected by the user at runtime.
+ * The classic profile is intended to cleanly perform old-style
+ * function selection (threshold =/!= 0)
+ *
+ ****************************************************************************/
+
+/* fwds */
+int
+SetAccelerationProfile(DeviceVelocityPtr vel, int profile_num);
+static float
+SimpleSmoothProfile(DeviceIntPtr dev, DeviceVelocityPtr vel, float velocity,
+ float threshold, float acc);
+static PointerAccelerationProfileFunc
+GetAccelerationProfile(DeviceVelocityPtr vel, int profile_num);
+
+/*#define PTRACCEL_DEBUGGING*/
+
+#ifdef PTRACCEL_DEBUGGING
+#define DebugAccelF ErrorF
+#else
+#define DebugAccelF(...) /* */
+#endif
+
+/********************************
+ * Init/Uninit
+ *******************************/
+
+/* some int which is not a profile number */
+#define PROFILE_UNINITIALIZE (-100)
+
+
+/**
+ * Init struct so it should match the average case
+ */
+void
+InitVelocityData(DeviceVelocityPtr vel)
+{
+ memset(vel, 0, sizeof(DeviceVelocityRec));
+
+ vel->corr_mul = 10.0; /* dots per 10 milisecond should be usable */
+ vel->const_acceleration = 1.0; /* no acceleration/deceleration */
+ vel->reset_time = 300;
+ vel->use_softening = 1;
+ vel->min_acceleration = 1.0; /* don't decelerate */
+ vel->max_rel_diff = 0.2;
+ vel->max_diff = 1.0;
+ vel->initial_range = 2;
+ vel->average_accel = TRUE;
+ SetAccelerationProfile(vel, AccelProfileClassic);
+ InitTrackers(vel, 16);
+}
+
+
+/**
+ * Clean up
+ */
+void
+FreeVelocityData(DeviceVelocityPtr vel){
+ free(vel->tracker);
+ SetAccelerationProfile(vel, PROFILE_UNINITIALIZE);
+}
+
+
+/*
+ * dix uninit helper, called through scheme
+ */
+void
+AccelerationDefaultCleanup(DeviceIntPtr dev)
+{
+ /*sanity check*/
+ if( dev->valuator->accelScheme.AccelSchemeProc == acceleratePointerPredictable
+ && dev->valuator->accelScheme.accelData != NULL){
+ dev->valuator->accelScheme.AccelSchemeProc = NULL;
+ FreeVelocityData(dev->valuator->accelScheme.accelData);
+ free(dev->valuator->accelScheme.accelData);
+ dev->valuator->accelScheme.accelData = NULL;
+ DeletePredictableAccelerationProperties(dev);
+ }
+}
+
+
+/*************************
+ * Input property support
+ ************************/
+
+/**
+ * choose profile
+ */
+static int
+AccelSetProfileProperty(DeviceIntPtr dev, Atom atom,
+ XIPropertyValuePtr val, BOOL checkOnly)
+{
+ DeviceVelocityPtr vel;
+ int profile, *ptr = &profile;
+ int rc;
+ int nelem = 1;
+
+ if (atom != XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER))
+ return Success;
+
+ vel = GetDevicePredictableAccelData(dev);
+ if (!vel)
+ return BadValue;
+ rc = XIPropToInt(val, &nelem, &ptr);
+
+ if(checkOnly)
+ {
+ if (rc)
+ return rc;
+
+ if (GetAccelerationProfile(vel, profile) == NULL)
+ return BadValue;
+ } else
+ SetAccelerationProfile(vel, profile);
+
+ return Success;
+}
+
+static long
+AccelInitProfileProperty(DeviceIntPtr dev, DeviceVelocityPtr vel)
+{
+ int profile = vel->statistics.profile_number;
+ Atom prop_profile_number = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER);
+
+ XIChangeDeviceProperty(dev, prop_profile_number, XA_INTEGER, 32,
+ PropModeReplace, 1, &profile, FALSE);
+ XISetDevicePropertyDeletable(dev, prop_profile_number, FALSE);
+ return XIRegisterPropertyHandler(dev, AccelSetProfileProperty, NULL, NULL);
+}
+
+/**
+ * constant deceleration
+ */
+static int
+AccelSetDecelProperty(DeviceIntPtr dev, Atom atom,
+ XIPropertyValuePtr val, BOOL checkOnly)
+{
+ DeviceVelocityPtr vel;
+ float v, *ptr = &v;
+ int rc;
+ int nelem = 1;
+
+ if (atom != XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION))
+ return Success;
+
+ vel = GetDevicePredictableAccelData(dev);
+ if (!vel)
+ return BadValue;
+ rc = XIPropToFloat(val, &nelem, &ptr);
+
+ if(checkOnly)
+ {
+ if (rc)
+ return rc;
+ return (v >= 1.0f) ? Success : BadValue;
+ }
+
+ if(v >= 1.0f)
+ vel->const_acceleration = 1/v;
+
+ return Success;
+}
+
+static long
+AccelInitDecelProperty(DeviceIntPtr dev, DeviceVelocityPtr vel)
+{
+ float fval = 1.0/vel->const_acceleration;
+ Atom prop_const_decel = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION);
+ XIChangeDeviceProperty(dev, prop_const_decel,
+ XIGetKnownProperty(XATOM_FLOAT), 32,
+ PropModeReplace, 1, &fval, FALSE);
+ XISetDevicePropertyDeletable(dev, prop_const_decel, FALSE);
+ return XIRegisterPropertyHandler(dev, AccelSetDecelProperty, NULL, NULL);
+}
+
+
+/**
+ * adaptive deceleration
+ */
+static int
+AccelSetAdaptDecelProperty(DeviceIntPtr dev, Atom atom,
+ XIPropertyValuePtr val, BOOL checkOnly)
+{
+ DeviceVelocityPtr veloc;
+ float v, *ptr = &v;
+ int rc;
+ int nelem = 1;
+
+ if (atom != XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION))
+ return Success;
+
+ veloc = GetDevicePredictableAccelData(dev);
+ if (!veloc)
+ return BadValue;
+ rc = XIPropToFloat(val, &nelem, &ptr);
+
+ if(checkOnly)
+ {
+ if (rc)
+ return rc;
+ return (v >= 1.0f) ? Success : BadValue;
+ }
+
+ if(v >= 1.0f)
+ veloc->min_acceleration = 1/v;
+
+ return Success;
+}
+
+static long
+AccelInitAdaptDecelProperty(DeviceIntPtr dev, DeviceVelocityPtr vel)
+{
+ float fval = 1.0/vel->min_acceleration;
+ Atom prop_adapt_decel = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION);
+
+ XIChangeDeviceProperty(dev, prop_adapt_decel, XIGetKnownProperty(XATOM_FLOAT), 32,
+ PropModeReplace, 1, &fval, FALSE);
+ XISetDevicePropertyDeletable(dev, prop_adapt_decel, FALSE);
+ return XIRegisterPropertyHandler(dev, AccelSetAdaptDecelProperty, NULL, NULL);
+}
+
+
+/**
+ * velocity scaling
+ */
+static int
+AccelSetScaleProperty(DeviceIntPtr dev, Atom atom,
+ XIPropertyValuePtr val, BOOL checkOnly)
+{
+ DeviceVelocityPtr vel;
+ float v, *ptr = &v;
+ int rc;
+ int nelem = 1;
+
+ if (atom != XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING))
+ return Success;
+
+ vel = GetDevicePredictableAccelData(dev);
+ if (!vel)
+ return BadValue;
+ rc = XIPropToFloat(val, &nelem, &ptr);
+
+ if (checkOnly)
+ {
+ if (rc)
+ return rc;
+
+ return (v > 0) ? Success : BadValue;
+ }
+
+ if(v > 0)
+ vel->corr_mul = v;
+
+ return Success;
+}
+
+static long
+AccelInitScaleProperty(DeviceIntPtr dev, DeviceVelocityPtr vel)
+{
+ float fval = vel->corr_mul;
+ Atom prop_velo_scale = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING);
+
+ XIChangeDeviceProperty(dev, prop_velo_scale, XIGetKnownProperty(XATOM_FLOAT), 32,
+ PropModeReplace, 1, &fval, FALSE);
+ XISetDevicePropertyDeletable(dev, prop_velo_scale, FALSE);
+ return XIRegisterPropertyHandler(dev, AccelSetScaleProperty, NULL, NULL);
+}
+
+BOOL
+InitializePredictableAccelerationProperties(DeviceIntPtr dev)
+{
+ DeviceVelocityPtr vel = GetDevicePredictableAccelData(dev);
+
+ if(!vel)
+ return FALSE;
+
+ vel->prop_handlers[0] = AccelInitProfileProperty(dev, vel);
+ vel->prop_handlers[1] = AccelInitDecelProperty(dev, vel);
+ vel->prop_handlers[2] = AccelInitAdaptDecelProperty(dev, vel);
+ vel->prop_handlers[3] = AccelInitScaleProperty(dev, vel);
+
+ return TRUE;
+}
+
+BOOL
+DeletePredictableAccelerationProperties(DeviceIntPtr dev)
+{
+ DeviceVelocityPtr vel;
+ Atom prop;
+ int i;
+
+ prop = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING);
+ XIDeleteDeviceProperty(dev, prop, FALSE);
+ prop = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION);
+ XIDeleteDeviceProperty(dev, prop, FALSE);
+ prop = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION);
+ XIDeleteDeviceProperty(dev, prop, FALSE);
+ prop = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER);
+ XIDeleteDeviceProperty(dev, prop, FALSE);
+
+ vel = GetDevicePredictableAccelData(dev);
+ for (i = 0; vel && i < NPROPS_PREDICTABLE_ACCEL; i++)
+ if (vel->prop_handlers[i])
+ XIUnregisterPropertyHandler(dev, vel->prop_handlers[i]);
+
+ return TRUE;
+}
+
+/*********************
+ * Tracking logic
+ ********************/
+
+void
+InitTrackers(DeviceVelocityPtr vel, int ntracker)
+{
+ if(ntracker < 1){
+ ErrorF("(dix ptracc) invalid number of trackers\n");
+ return;
+ }
+ free(vel->tracker);
+ vel->tracker = (MotionTrackerPtr)malloc(ntracker * sizeof(MotionTracker));
+ memset(vel->tracker, 0, ntracker * sizeof(MotionTracker));
+ vel->num_tracker = ntracker;
+}
+
+/**
+ * return a bit field of possible directions.
+ * 0 = N, 2 = E, 4 = S, 6 = W, in-between is as you guess.
+ * There's no reason against widening to more precise directions (<45 degrees),
+ * should it not perform well. All this is needed for is sort out non-linear
+ * motion, so precision isn't paramount. However, one should not flag direction
+ * too narrow, since it would then cut the linear segment to zero size way too
+ * often.
+ */
+static int
+DoGetDirection(int dx, int dy){
+ float r;
+ int i1, i2;
+ /* on insignificant mickeys, flag 135 degrees */
+ if(abs(dx) < 2 && abs(dy) < 2){
+ /* first check diagonal cases */
+ if(dx > 0 && dy > 0)
+ return 4+8+16;
+ if(dx > 0 && dy < 0)
+ return 1+2+4;
+ if(dx < 0 && dy < 0)
+ return 1+128+64;
+ if(dx < 0 && dy > 0)
+ return 16+32+64;
+ /* check axis-aligned directions */
+ if(dx > 0)
+ return 2+4+8; /*E*/
+ if(dx < 0)
+ return 128+64+32; /*W*/
+ if(dy > 0)
+ return 32+16+8; /*S*/
+ if(dy < 0)
+ return 128+1+2; /*N*/
+ return 255; /* shouldn't happen */
+ }
+ /* else, compute angle and set appropriate flags */
+#ifdef _ISOC99_SOURCE
+ r = atan2f(dy, dx);
+#else
+ r = atan2(dy, dx);
+#endif
+ /* find direction. We avoid r to become negative,
+ * since C has no well-defined modulo for such cases. */
+ r = (r+(M_PI*2.5))/(M_PI/4);
+ /* this intends to flag 2 directions (90 degrees),
+ * except on very well-aligned mickeys. */
+ i1 = (int)(r+0.1) % 8;
+ i2 = (int)(r+0.9) % 8;
+ if(i1 < 0 || i1 > 7 || i2 < 0 || i2 > 7)
+ return 255; /* shouldn't happen */
+ return 1 << i1 | 1 << i2;
+}
+
+#define DIRECTION_CACHE_RANGE 5
+#define DIRECTION_CACHE_SIZE (DIRECTION_CACHE_RANGE*2+1)
+
+/* cache DoGetDirection(). */
+static int
+GetDirection(int dx, int dy){
+ static int cache[DIRECTION_CACHE_SIZE][DIRECTION_CACHE_SIZE];
+ int i;
+ if (abs(dx) <= DIRECTION_CACHE_RANGE &&
+ abs(dy) <= DIRECTION_CACHE_RANGE) {
+ /* cacheable */
+ i = cache[DIRECTION_CACHE_RANGE+dx][DIRECTION_CACHE_RANGE+dy];
+ if(i != 0){
+ return i;
+ }else{
+ i = DoGetDirection(dx, dy);
+ cache[DIRECTION_CACHE_RANGE+dx][DIRECTION_CACHE_RANGE+dy] = i;
+ return i;
+ }
+ }else{
+ /* non-cacheable */
+ return DoGetDirection(dx, dy);
+ }
+}
+
+#undef DIRECTION_CACHE_RANGE
+#undef DIRECTION_CACHE_SIZE
+
+
+/* convert offset (age) to array index */
+#define TRACKER_INDEX(s, d) (((s)->num_tracker + (s)->cur_tracker - (d)) % (s)->num_tracker)
+
+static inline void
+FeedTrackers(DeviceVelocityPtr vel, int dx, int dy, int cur_t)
+{
+ int n;
+ for(n = 0; n < vel->num_tracker; n++){
+ vel->tracker[n].dx += dx;
+ vel->tracker[n].dy += dy;
+ }
+ n = (vel->cur_tracker + 1) % vel->num_tracker;
+ vel->tracker[n].dx = 0;
+ vel->tracker[n].dy = 0;
+ vel->tracker[n].time = cur_t;
+ vel->tracker[n].dir = GetDirection(dx, dy);
+ DebugAccelF("(dix prtacc) motion [dx: %i dy: %i dir:%i diff: %i]\n",
+ dx, dy, vel->tracker[n].dir,
+ cur_t - vel->tracker[vel->cur_tracker].time);
+ vel->cur_tracker = n;
+}
+
+/**
+ * calc velocity for given tracker, with
+ * velocity scaling.
+ * This assumes linear motion.
+ */
+static float
+CalcTracker(DeviceVelocityPtr vel, int offset, int cur_t){
+ int index = TRACKER_INDEX(vel, offset);
+ float dist = sqrt( vel->tracker[index].dx * vel->tracker[index].dx
+ + vel->tracker[index].dy * vel->tracker[index].dy);
+ int dtime = cur_t - vel->tracker[index].time;
+ if(dtime > 0)
+ return dist / dtime;
+ else
+ return 0;/* synonymous for NaN, since we're not C99 */
+}
+
+/* find the most plausible velocity. That is, the most distant
+ * (in time) tracker which isn't too old, beyond a linear partition,
+ * or simply too much off initial velocity.
+ *
+ * May return 0.
+ */
+static float
+QueryTrackers(DeviceVelocityPtr vel, int cur_t){
+ int n, offset, dir = 255, i = -1, age_ms;
+ /* initial velocity: a low-offset, valid velocity */
+ float iveloc = 0, res = 0, tmp, vdiff;
+ float vfac = vel->corr_mul * vel->const_acceleration; /* premultiply */
+ /* loop from current to older data */
+ for(offset = 1; offset < vel->num_tracker; offset++){
+ n = TRACKER_INDEX(vel, offset);
+
+ age_ms = cur_t - vel->tracker[n].time;
+
+ /* bail out if data is too old and protect from overrun */
+ if (age_ms >= vel->reset_time || age_ms < 0) {
+ DebugAccelF("(dix prtacc) query: tracker too old\n");
+ break;
+ }
+
+ /*
+ * this heuristic avoids using the linear-motion velocity formula
+ * in CalcTracker() on motion that isn't exactly linear. So to get
+ * even more precision we could subdivide as a final step, so possible
+ * non-linearities are accounted for.
+ */
+ dir &= vel->tracker[n].dir;
+ if(dir == 0){
+ DebugAccelF("(dix prtacc) query: no longer linear\n");
+ /* instead of breaking it we might also inspect the partition after,
+ * but actual improvement with this is probably rare. */
+ break;
+ }
+
+ tmp = CalcTracker(vel, offset, cur_t) * vfac;
+
+ if ((iveloc == 0 || offset <= vel->initial_range) && tmp != 0) {
+ /* set initial velocity and result */
+ res = iveloc = tmp;
+ i = offset;
+ } else if (iveloc != 0 && tmp != 0) {
+ vdiff = fabs(iveloc - tmp);
+ if (vdiff <= vel->max_diff ||
+ vdiff/(iveloc + tmp) < vel->max_rel_diff) {
+ /* we're in range with the initial velocity,
+ * so this result is likely better
+ * (it contains more information). */
+ res = tmp;
+ i = offset;
+ }else{
+ /* we're not in range, quit - it won't get better. */
+ DebugAccelF("(dix prtacc) query: tracker too different:"
+ " old %2.2f initial %2.2f diff: %2.2f\n",
+ tmp, iveloc, vdiff);
+ break;
+ }
+ }
+ }
+ if(offset == vel->num_tracker){
+ DebugAccelF("(dix prtacc) query: last tracker in effect\n");
+ i = vel->num_tracker-1;
+ }
+ if(i>=0){
+ n = TRACKER_INDEX(vel, i);
+ DebugAccelF("(dix prtacc) result: offset %i [dx: %i dy: %i diff: %i]\n",
+ i,
+ vel->tracker[n].dx,
+ vel->tracker[n].dy,
+ cur_t - vel->tracker[n].time);
+ }
+ return res;
+}
+
+#undef TRACKER_INDEX
+
+/**
+ * Perform velocity approximation based on 2D 'mickeys' (mouse motion delta).
+ * return true if non-visible state reset is suggested
+ */
+short
+ProcessVelocityData2D(
+ DeviceVelocityPtr vel,
+ int dx,
+ int dy,
+ int time)
+{
+ float velocity;
+
+ vel->last_velocity = vel->velocity;
+
+ FeedTrackers(vel, dx, dy, time);
+
+ velocity = QueryTrackers(vel, time);
+
+ vel->velocity = velocity;
+ return velocity == 0;
+}
+
+/**
+ * this flattens significant ( > 1) mickeys a little bit for more steady
+ * constant-velocity response
+ */
+static inline float
+ApplySimpleSoftening(int od, int d)
+{
+ float res = d;
+ if (d <= 1 && d >= -1)
+ return res;
+ if (d > od)
+ res -= 0.5;
+ else if (d < od)
+ res += 0.5;
+ return res;
+}
+
+
+static void
+ApplySofteningAndConstantDeceleration(
+ DeviceVelocityPtr vel,
+ int dx,
+ int dy,
+ float* fdx,
+ float* fdy,
+ short do_soften)
+{
+ if (do_soften && vel->use_softening) {
+ *fdx = ApplySimpleSoftening(vel->last_dx, dx);
+ *fdy = ApplySimpleSoftening(vel->last_dy, dy);
+ } else {
+ *fdx = dx;
+ *fdy = dy;
+ }
+
+ *fdx *= vel->const_acceleration;
+ *fdy *= vel->const_acceleration;
+}
+
+/*
+ * compute the acceleration for given velocity and enforce min_acceleartion
+ */
+float
+BasicComputeAcceleration(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float velocity,
+ float threshold,
+ float acc){
+
+ float result;
+ result = vel->Profile(dev, vel, velocity, threshold, acc);
+
+ /* enforce min_acceleration */
+ if (result < vel->min_acceleration)
+ result = vel->min_acceleration;
+ return result;
+}
+
+/**
+ * Compute acceleration. Takes into account averaging, nv-reset, etc.
+ */
+static float
+ComputeAcceleration(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float threshold,
+ float acc){
+ float res;
+
+ if(vel->velocity <= 0){
+ DebugAccelF("(dix ptracc) profile skipped\n");
+ /*
+ * If we have no idea about device velocity, don't pretend it.
+ */
+ return 1;
+ }
+
+ if(vel->average_accel && vel->velocity != vel->last_velocity){
+ /* use simpson's rule to average acceleration between
+ * current and previous velocity.
+ * Though being the more natural choice, it causes a minor delay
+ * in comparison, so it can be disabled. */
+ res = BasicComputeAcceleration(
+ dev, vel, vel->velocity, threshold, acc);
+ res += BasicComputeAcceleration(
+ dev, vel, vel->last_velocity, threshold, acc);
+ res += 4.0f * BasicComputeAcceleration(dev, vel,
+ (vel->last_velocity + vel->velocity) / 2,
+ threshold, acc);
+ res /= 6.0f;
+ DebugAccelF("(dix ptracc) profile average [%.2f ... %.2f] is %.3f\n",
+ vel->velocity, vel->last_velocity, res);
+ return res;
+ }else{
+ res = BasicComputeAcceleration(dev, vel,
+ vel->velocity, threshold, acc);
+ DebugAccelF("(dix ptracc) profile sample [%.2f] is %.3f\n",
+ vel->velocity, res);
+ return res;
+ }
+}
+
+
+/*****************************************
+ * Acceleration functions and profiles
+ ****************************************/
+
+/**
+ * Polynomial function similar previous one, but with f(1) = 1
+ */
+static float
+PolynomialAccelerationProfile(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float velocity,
+ float ignored,
+ float acc)
+{
+ return pow(velocity, (acc - 1.0) * 0.5);
+}
+
+
+/**
+ * returns acceleration for velocity.
+ * This profile selects the two functions like the old scheme did
+ */
+static float
+ClassicProfile(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float velocity,
+ float threshold,
+ float acc)
+{
+ if (threshold > 0) {
+ return SimpleSmoothProfile (dev,
+ vel,
+ velocity,
+ threshold,
+ acc);
+ } else {
+ return PolynomialAccelerationProfile (dev,
+ vel,
+ velocity,
+ 0,
+ acc);
+ }
+}
+
+
+/**
+ * Power profile
+ * This has a completely smooth transition curve, i.e. no jumps in the
+ * derivatives.
+ *
+ * This has the expense of overall response dependency on min-acceleration.
+ * In effect, min_acceleration mimics const_acceleration in this profile.
+ */
+static float
+PowerProfile(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float velocity,
+ float threshold,
+ float acc)
+{
+ float vel_dist;
+
+ acc = (acc-1.0) * 0.1f + 1.0; /* without this, acc of 2 is unuseable */
+
+ if (velocity <= threshold)
+ return vel->min_acceleration;
+ vel_dist = velocity - threshold;
+ return (pow(acc, vel_dist)) * vel->min_acceleration;
+}
+
+
+/**
+ * just a smooth function in [0..1] -> [0..1]
+ * - point symmetry at 0.5
+ * - f'(0) = f'(1) = 0
+ * - starts faster than a sinoid
+ * - smoothness C1 (Cinf if you dare to ignore endpoints)
+ */
+static inline float
+CalcPenumbralGradient(float x){
+ x *= 2.0f;
+ x -= 1.0f;
+ return 0.5f + (x * sqrt(1.0f - x*x) + asin(x))/M_PI;
+}
+
+
+/**
+ * acceleration function similar to classic accelerated/unaccelerated,
+ * but with smooth transition in between (and towards zero for adaptive dec.).
+ */
+static float
+SimpleSmoothProfile(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float velocity,
+ float threshold,
+ float acc)
+{
+ if(velocity < 1.0f)
+ return CalcPenumbralGradient(0.5 + velocity*0.5) * 2.0f - 1.0f;
+ if(threshold < 1.0f)
+ threshold = 1.0f;
+ if (velocity <= threshold)
+ return 1;
+ velocity /= threshold;
+ if (velocity >= acc)
+ return acc;
+ else
+ return 1.0f + (CalcPenumbralGradient(velocity/acc) * (acc - 1.0f));
+}
+
+
+/**
+ * This profile uses the first half of the penumbral gradient as a start
+ * and then scales linearly.
+ */
+static float
+SmoothLinearProfile(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float velocity,
+ float threshold,
+ float acc)
+{
+ float res, nv;
+
+ if(acc > 1.0f)
+ acc -= 1.0f; /*this is so acc = 1 is no acceleration */
+ else
+ return 1.0f;
+
+ nv = (velocity - threshold) * acc * 0.5f;
+
+ if(nv < 0){
+ res = 0;
+ }else if(nv < 2){
+ res = CalcPenumbralGradient(nv*0.25f)*2.0f;
+ }else{
+ nv -= 2.0f;
+ res = nv * 2.0f / M_PI /* steepness of gradient at 0.5 */
+ + 1.0f; /* gradient crosses 2|1 */
+ }
+ res += vel->min_acceleration;
+ return res;
+}
+
+
+/**
+ * From 0 to threshold, the response graduates smoothly from min_accel to
+ * acceleration. Beyond threshold it is exactly the specified acceleration.
+ */
+static float
+SmoothLimitedProfile(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float velocity,
+ float threshold,
+ float acc)
+{
+ float res;
+
+ if(velocity >= threshold || threshold == 0.0f)
+ return acc;
+
+ velocity /= threshold; /* should be [0..1[ now */
+
+ res = CalcPenumbralGradient(velocity) * (acc - vel->min_acceleration);
+
+ return vel->min_acceleration + res;
+}
+
+
+static float
+LinearProfile(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float velocity,
+ float threshold,
+ float acc)
+{
+ return acc * velocity;
+}
+
+static float
+NoProfile(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float velocity,
+ float threshold,
+ float acc)
+{
+ return 1.0f;
+}
+
+static PointerAccelerationProfileFunc
+GetAccelerationProfile(
+ DeviceVelocityPtr vel,
+ int profile_num)
+{
+ switch(profile_num){
+ case AccelProfileClassic:
+ return ClassicProfile;
+ case AccelProfileDeviceSpecific:
+ return vel->deviceSpecificProfile;
+ case AccelProfilePolynomial:
+ return PolynomialAccelerationProfile;
+ case AccelProfileSmoothLinear:
+ return SmoothLinearProfile;
+ case AccelProfileSimple:
+ return SimpleSmoothProfile;
+ case AccelProfilePower:
+ return PowerProfile;
+ case AccelProfileLinear:
+ return LinearProfile;
+ case AccelProfileSmoothLimited:
+ return SmoothLimitedProfile;
+ case AccelProfileNone:
+ return NoProfile;
+ default:
+ return NULL;
+ }
+}
+
+/**
+ * Set the profile by number.
+ * Intended to make profiles exchangeable at runtime.
+ * If you created a profile, give it a number here and in the header to
+ * make it selectable. In case some profile-specific init is needed, here
+ * would be a good place, since FreeVelocityData() also calls this with
+ * PROFILE_UNINITIALIZE.
+ *
+ * returns FALSE if profile number is unavailable, TRUE otherwise.
+ */
+int
+SetAccelerationProfile(
+ DeviceVelocityPtr vel,
+ int profile_num)
+{
+ PointerAccelerationProfileFunc profile;
+ profile = GetAccelerationProfile(vel, profile_num);
+
+ if(profile == NULL && profile_num != PROFILE_UNINITIALIZE)
+ return FALSE;
+
+ /* Here one could free old profile-private data */
+ free(vel->profile_private);
+ vel->profile_private = NULL;
+ /* Here one could init profile-private data */
+ vel->Profile = profile;
+ vel->statistics.profile_number = profile_num;
+ return TRUE;
+}
+
+/**********************************************
+ * driver interaction
+ **********************************************/
+
+
+/**
+ * device-specific profile
+ *
+ * The device-specific profile is intended as a hook for a driver
+ * which may want to provide an own acceleration profile.
+ * It should not rely on profile-private data, instead
+ * it should do init/uninit in the driver (ie. with DEVICE_INIT and friends).
+ * Users may override or choose it.
+ */
+void
+SetDeviceSpecificAccelerationProfile(
+ DeviceVelocityPtr vel,
+ PointerAccelerationProfileFunc profile)
+{
+ if(vel)
+ vel->deviceSpecificProfile = profile;
+}
+
+/**
+ * Use this function to obtain a DeviceVelocityPtr for a device. Will return NULL if
+ * the predictable acceleration scheme is not in effect.
+ */
+DeviceVelocityPtr
+GetDevicePredictableAccelData(
+ DeviceIntPtr dev)
+{
+ /*sanity check*/
+ if(!dev){
+ ErrorF("[dix] accel: DeviceIntPtr was NULL");
+ return NULL;
+ }
+ if( dev->valuator &&
+ dev->valuator->accelScheme.AccelSchemeProc ==
+ acceleratePointerPredictable &&
+ dev->valuator->accelScheme.accelData != NULL){
+
+ return (DeviceVelocityPtr)dev->valuator->accelScheme.accelData;
+ }
+ return NULL;
+}
+
+/********************************
+ * acceleration schemes
+ *******************************/
+
+/**
+ * Modifies valuators in-place.
+ * This version employs a velocity approximation algorithm to
+ * enable fine-grained predictable acceleration profiles.
+ */
+void
+acceleratePointerPredictable(
+ DeviceIntPtr dev,
+ int first_valuator,
+ int num_valuators,
+ int *valuators,
+ int evtime)
+{
+ float mult = 0.0;
+ int dx = 0, dy = 0;
+ int *px = NULL, *py = NULL;
+ DeviceVelocityPtr velocitydata =
+ (DeviceVelocityPtr) dev->valuator->accelScheme.accelData;
+ float fdx, fdy, tmp; /* no need to init */
+ Bool soften = TRUE;
+
+ if (!num_valuators || !valuators || !velocitydata)
+ return;
+
+ if (velocitydata->statistics.profile_number == AccelProfileNone &&
+ velocitydata->const_acceleration == 1.0f) {
+ return; /*we're inactive anyway, so skip the whole thing.*/
+ }
+
+ if (first_valuator == 0) {
+ dx = valuators[0];
+ px = &valuators[0];
+ }
+ if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) {
+ dy = valuators[1 - first_valuator];
+ py = &valuators[1 - first_valuator];
+ }
+
+ if (dx || dy){
+ /* reset non-visible state? */
+ if (ProcessVelocityData2D(velocitydata, dx , dy, evtime)) {
+ soften = FALSE;
+ }
+
+ if (dev->ptrfeed && dev->ptrfeed->ctrl.num) {
+ /* invoke acceleration profile to determine acceleration */
+ mult = ComputeAcceleration (dev, velocitydata,
+ dev->ptrfeed->ctrl.threshold,
+ (float)dev->ptrfeed->ctrl.num /
+ (float)dev->ptrfeed->ctrl.den);
+
+ if(mult != 1.0 || velocitydata->const_acceleration != 1.0) {
+ ApplySofteningAndConstantDeceleration( velocitydata,
+ dx, dy,
+ &fdx, &fdy,
+ (mult > 1.0) && soften);
+
+ if (dx) {
+ tmp = mult * fdx + dev->last.remainder[0];
+ /* Since it may not be apparent: lrintf() does not offer
+ * strong statements about rounding; however because we
+ * process each axis conditionally, there's no danger
+ * of a toggling remainder. Its lack of guarantees likely
+ * makes it faster on the average target. */
+ *px = lrintf(tmp);
+ dev->last.remainder[0] = tmp - (float)*px;
+ }
+ if (dy) {
+ tmp = mult * fdy + dev->last.remainder[1];
+ *py = lrintf(tmp);
+ dev->last.remainder[1] = tmp - (float)*py;
+ }
+ DebugAccelF("pos (%i | %i) remainders x: %.3f y: %.3f delta x:%.3f y:%.3f\n",
+ *px, *py, dev->last.remainder[0], dev->last.remainder[1], fdx, fdy);
+ }
+ }
+ }
+ /* remember last motion delta (for softening/slow movement treatment) */
+ velocitydata->last_dx = dx;
+ velocitydata->last_dy = dy;
+}
+
+
+
+/**
+ * Originally a part of xf86PostMotionEvent; modifies valuators
+ * in-place. Retained mostly for embedded scenarios.
+ */
+void
+acceleratePointerLightweight(
+ DeviceIntPtr dev,
+ int first_valuator,
+ int num_valuators,
+ int *valuators,
+ int ignored)
+{
+ float mult = 0.0;
+ int dx = 0, dy = 0;
+ int *px = NULL, *py = NULL;
+
+ if (!num_valuators || !valuators)
+ return;
+
+ if (first_valuator == 0) {
+ dx = valuators[0];
+ px = &valuators[0];
+ }
+ if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) {
+ dy = valuators[1 - first_valuator];
+ py = &valuators[1 - first_valuator];
+ }
+
+ if (!dx && !dy)
+ return;
+
+ if (dev->ptrfeed && dev->ptrfeed->ctrl.num) {
+ /* modeled from xf86Events.c */
+ if (dev->ptrfeed->ctrl.threshold) {
+ if ((abs(dx) + abs(dy)) >= dev->ptrfeed->ctrl.threshold) {
+ dev->last.remainder[0] = ((float)dx *
+ (float)(dev->ptrfeed->ctrl.num)) /
+ (float)(dev->ptrfeed->ctrl.den) +
+ dev->last.remainder[0];
+ if (px) {
+ *px = (int)dev->last.remainder[0];
+ dev->last.remainder[0] = dev->last.remainder[0] -
+ (float)(*px);
+ }
+
+ dev->last.remainder[1] = ((float)dy *
+ (float)(dev->ptrfeed->ctrl.num)) /
+ (float)(dev->ptrfeed->ctrl.den) +
+ dev->last.remainder[1];
+ if (py) {
+ *py = (int)dev->last.remainder[1];
+ dev->last.remainder[1] = dev->last.remainder[1] -
+ (float)(*py);
+ }
+ }
+ }
+ else {
+ mult = pow((float)dx * (float)dx + (float)dy * (float)dy,
+ ((float)(dev->ptrfeed->ctrl.num) /
+ (float)(dev->ptrfeed->ctrl.den) - 1.0) /
+ 2.0) / 2.0;
+ if (dx) {
+ dev->last.remainder[0] = mult * (float)dx +
+ dev->last.remainder[0];
+ *px = (int)dev->last.remainder[0];
+ dev->last.remainder[0] = dev->last.remainder[0] -
+ (float)(*px);
+ }
+ if (dy) {
+ dev->last.remainder[1] = mult * (float)dy +
+ dev->last.remainder[1];
+ *py = (int)dev->last.remainder[1];
+ dev->last.remainder[1] = dev->last.remainder[1] -
+ (float)(*py);
+ }
+ }
+ }
+}
diff --git a/dix/region.c b/dix/region.c
new file mode 100644
index 0000000..5ba3457
--- /dev/null
+++ b/dix/region.c
@@ -0,0 +1,1659 @@
+/***********************************************************
+
+Copyright 1987, 1988, 1989, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987, 1988, 1989 by
+Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+******************************************************************/
+
+/* The panoramix components contained the following notice */
+/*****************************************************************
+
+Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
+BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of Digital Equipment Corporation
+shall not be used in advertising or otherwise to promote the sale, use or other
+dealings in this Software without prior written authorization from Digital
+Equipment Corporation.
+
+******************************************************************/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "regionstr.h"
+#include <X11/Xprotostr.h>
+#include <X11/Xfuncproto.h>
+#include "gc.h"
+#include <pixman.h>
+
+#undef assert
+#ifdef REGION_DEBUG
+#define assert(expr) { \
+ CARD32 *foo = NULL; \
+ if (!(expr)) { \
+ ErrorF("Assertion failed file %s, line %d: %s\n", \
+ __FILE__, __LINE__, #expr); \
+ *foo = 0xdeadbeef; /* to get a backtrace */ \
+ } \
+ }
+#else
+#define assert(expr)
+#endif
+
+#define good(reg) assert(RegionIsValid(reg))
+
+/*
+ * The functions in this file implement the Region abstraction used extensively
+ * throughout the X11 sample server. A Region is simply a set of disjoint
+ * (non-overlapping) rectangles, plus an "extent" rectangle which is the
+ * smallest single rectangle that contains all the non-overlapping rectangles.
+ *
+ * A Region is implemented as a "y-x-banded" array of rectangles. This array
+ * imposes two degrees of order. First, all rectangles are sorted by top side
+ * y coordinate first (y1), and then by left side x coordinate (x1).
+ *
+ * Furthermore, the rectangles are grouped into "bands". Each rectangle in a
+ * band has the same top y coordinate (y1), and each has the same bottom y
+ * coordinate (y2). Thus all rectangles in a band differ only in their left
+ * and right side (x1 and x2). Bands are implicit in the array of rectangles:
+ * there is no separate list of band start pointers.
+ *
+ * The y-x band representation does not minimize rectangles. In particular,
+ * if a rectangle vertically crosses a band (the rectangle has scanlines in
+ * the y1 to y2 area spanned by the band), then the rectangle may be broken
+ * down into two or more smaller rectangles stacked one atop the other.
+ *
+ * ----------- -----------
+ * | | | | band 0
+ * | | -------- ----------- --------
+ * | | | | in y-x banded | | | | band 1
+ * | | | | form is | | | |
+ * ----------- | | ----------- --------
+ * | | | | band 2
+ * -------- --------
+ *
+ * An added constraint on the rectangles is that they must cover as much
+ * horizontal area as possible: no two rectangles within a band are allowed
+ * to touch.
+ *
+ * Whenever possible, bands will be merged together to cover a greater vertical
+ * distance (and thus reduce the number of rectangles). Two bands can be merged
+ * only if the bottom of one touches the top of the other and they have
+ * rectangles in the same places (of the same width, of course).
+ *
+ * Adam de Boor wrote most of the original region code. Joel McCormack
+ * substantially modified or rewrote most of the core arithmetic routines,
+ * and added RegionValidate in order to support several speed improvements
+ * to miValidateTree. Bob Scheifler changed the representation to be more
+ * compact when empty or a single rectangle, and did a bunch of gratuitous
+ * reformatting.
+ */
+
+/* true iff two Boxes overlap */
+#define EXTENTCHECK(r1,r2) \
+ (!( ((r1)->x2 <= (r2)->x1) || \
+ ((r1)->x1 >= (r2)->x2) || \
+ ((r1)->y2 <= (r2)->y1) || \
+ ((r1)->y1 >= (r2)->y2) ) )
+
+/* true iff (x,y) is in Box */
+#define INBOX(r,x,y) \
+ ( ((r)->x2 > x) && \
+ ((r)->x1 <= x) && \
+ ((r)->y2 > y) && \
+ ((r)->y1 <= y) )
+
+/* true iff Box r1 contains Box r2 */
+#define SUBSUMES(r1,r2) \
+ ( ((r1)->x1 <= (r2)->x1) && \
+ ((r1)->x2 >= (r2)->x2) && \
+ ((r1)->y1 <= (r2)->y1) && \
+ ((r1)->y2 >= (r2)->y2) )
+
+#define xallocData(n) malloc(RegionSizeof(n))
+#define xfreeData(reg) if ((reg)->data && (reg)->data->size) free((reg)->data)
+
+#define RECTALLOC_BAIL(pReg,n,bail) \
+if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
+ if (!RegionRectAlloc(pReg, n)) { goto bail; }
+
+#define RECTALLOC(pReg,n) \
+if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
+ if (!RegionRectAlloc(pReg, n)) { return FALSE; }
+
+#define ADDRECT(pNextRect,nx1,ny1,nx2,ny2) \
+{ \
+ pNextRect->x1 = nx1; \
+ pNextRect->y1 = ny1; \
+ pNextRect->x2 = nx2; \
+ pNextRect->y2 = ny2; \
+ pNextRect++; \
+}
+
+#define NEWRECT(pReg,pNextRect,nx1,ny1,nx2,ny2) \
+{ \
+ if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\
+ { \
+ if (!RegionRectAlloc(pReg, 1)) \
+ return FALSE; \
+ pNextRect = RegionTop(pReg); \
+ } \
+ ADDRECT(pNextRect,nx1,ny1,nx2,ny2); \
+ pReg->data->numRects++; \
+ assert(pReg->data->numRects<=pReg->data->size); \
+}
+
+
+#define DOWNSIZE(reg,numRects) \
+if (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \
+{ \
+ RegDataPtr NewData; \
+ NewData = (RegDataPtr)realloc((reg)->data, RegionSizeof(numRects)); \
+ if (NewData) \
+ { \
+ NewData->size = (numRects); \
+ (reg)->data = NewData; \
+ } \
+}
+
+
+BoxRec RegionEmptyBox = {0, 0, 0, 0};
+RegDataRec RegionEmptyData = {0, 0};
+
+RegDataRec RegionBrokenData = {0, 0};
+static RegionRec RegionBrokenRegion = { { 0, 0, 0, 0 }, &RegionBrokenData };
+
+void
+InitRegions (void)
+{
+ pixman_region_set_static_pointers (&RegionEmptyBox, &RegionEmptyData, &RegionBrokenData);
+}
+
+/*****************************************************************
+ * RegionCreate(rect, size)
+ * This routine does a simple malloc to make a structure of
+ * REGION of "size" number of rectangles.
+ *****************************************************************/
+
+RegionPtr
+RegionCreate(BoxPtr rect, int size)
+{
+ RegionPtr pReg;
+
+ pReg = (RegionPtr)malloc(sizeof(RegionRec));
+ if (!pReg)
+ return &RegionBrokenRegion;
+
+ RegionInit (pReg, rect, size);
+
+ return pReg;
+}
+
+void
+RegionDestroy(RegionPtr pReg)
+{
+ pixman_region_fini (pReg);
+ if (pReg != &RegionBrokenRegion)
+ free(pReg);
+}
+
+void
+RegionPrint(RegionPtr rgn)
+{
+ int num, size;
+ int i;
+ BoxPtr rects;
+
+ num = RegionNumRects(rgn);
+ size = RegionSize(rgn);
+ rects = RegionRects(rgn);
+ ErrorF("[mi] num: %d size: %d\n", num, size);
+ ErrorF("[mi] extents: %d %d %d %d\n",
+ rgn->extents.x1, rgn->extents.y1, rgn->extents.x2, rgn->extents.y2);
+ for (i = 0; i < num; i++)
+ ErrorF("[mi] %d %d %d %d \n",
+ rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2);
+ ErrorF("[mi] \n");
+}
+
+#ifdef DEBUG
+Bool
+RegionIsValid(RegionPtr reg)
+{
+ int i, numRects;
+
+ if ((reg->extents.x1 > reg->extents.x2) ||
+ (reg->extents.y1 > reg->extents.y2))
+ return FALSE;
+ numRects = RegionNumRects(reg);
+ if (!numRects)
+ return ((reg->extents.x1 == reg->extents.x2) &&
+ (reg->extents.y1 == reg->extents.y2) &&
+ (reg->data->size || (reg->data == &RegionEmptyData)));
+ else if (numRects == 1)
+ return !reg->data;
+ else
+ {
+ BoxPtr pboxP, pboxN;
+ BoxRec box;
+
+ pboxP = RegionRects(reg);
+ box = *pboxP;
+ box.y2 = pboxP[numRects-1].y2;
+ pboxN = pboxP + 1;
+ for (i = numRects; --i > 0; pboxP++, pboxN++)
+ {
+ if ((pboxN->x1 >= pboxN->x2) ||
+ (pboxN->y1 >= pboxN->y2))
+ return FALSE;
+ if (pboxN->x1 < box.x1)
+ box.x1 = pboxN->x1;
+ if (pboxN->x2 > box.x2)
+ box.x2 = pboxN->x2;
+ if ((pboxN->y1 < pboxP->y1) ||
+ ((pboxN->y1 == pboxP->y1) &&
+ ((pboxN->x1 < pboxP->x2) || (pboxN->y2 != pboxP->y2))))
+ return FALSE;
+ }
+ return ((box.x1 == reg->extents.x1) &&
+ (box.x2 == reg->extents.x2) &&
+ (box.y1 == reg->extents.y1) &&
+ (box.y2 == reg->extents.y2));
+ }
+}
+#endif /* DEBUG */
+
+Bool
+RegionBreak (RegionPtr pReg)
+{
+ xfreeData (pReg);
+ pReg->extents = RegionEmptyBox;
+ pReg->data = &RegionBrokenData;
+ return FALSE;
+}
+
+Bool
+RegionRectAlloc(RegionPtr pRgn, int n)
+{
+ RegDataPtr data;
+
+ if (!pRgn->data)
+ {
+ n++;
+ pRgn->data = xallocData(n);
+ if (!pRgn->data)
+ return RegionBreak (pRgn);
+ pRgn->data->numRects = 1;
+ *RegionBoxptr(pRgn) = pRgn->extents;
+ }
+ else if (!pRgn->data->size)
+ {
+ pRgn->data = xallocData(n);
+ if (!pRgn->data)
+ return RegionBreak (pRgn);
+ pRgn->data->numRects = 0;
+ }
+ else
+ {
+ if (n == 1)
+ {
+ n = pRgn->data->numRects;
+ if (n > 500) /* XXX pick numbers out of a hat */
+ n = 250;
+ }
+ n += pRgn->data->numRects;
+ data = (RegDataPtr)realloc(pRgn->data, RegionSizeof(n));
+ if (!data)
+ return RegionBreak (pRgn);
+ pRgn->data = data;
+ }
+ pRgn->data->size = n;
+ return TRUE;
+}
+
+/*======================================================================
+ * Generic Region Operator
+ *====================================================================*/
+
+/*-
+ *-----------------------------------------------------------------------
+ * RegionCoalesce --
+ * Attempt to merge the boxes in the current band with those in the
+ * previous one. We are guaranteed that the current band extends to
+ * the end of the rects array. Used only by RegionOp.
+ *
+ * Results:
+ * The new index for the previous band.
+ *
+ * Side Effects:
+ * If coalescing takes place:
+ * - rectangles in the previous band will have their y2 fields
+ * altered.
+ * - pReg->data->numRects will be decreased.
+ *
+ *-----------------------------------------------------------------------
+ */
+_X_INLINE static int
+RegionCoalesce (
+ RegionPtr pReg, /* Region to coalesce */
+ int prevStart, /* Index of start of previous band */
+ int curStart) /* Index of start of current band */
+{
+ BoxPtr pPrevBox; /* Current box in previous band */
+ BoxPtr pCurBox; /* Current box in current band */
+ int numRects; /* Number rectangles in both bands */
+ int y2; /* Bottom of current band */
+ /*
+ * Figure out how many rectangles are in the band.
+ */
+ numRects = curStart - prevStart;
+ assert(numRects == pReg->data->numRects - curStart);
+
+ if (!numRects) return curStart;
+
+ /*
+ * The bands may only be coalesced if the bottom of the previous
+ * matches the top scanline of the current.
+ */
+ pPrevBox = RegionBox(pReg, prevStart);
+ pCurBox = RegionBox(pReg, curStart);
+ if (pPrevBox->y2 != pCurBox->y1) return curStart;
+
+ /*
+ * Make sure the bands have boxes in the same places. This
+ * assumes that boxes have been added in such a way that they
+ * cover the most area possible. I.e. two boxes in a band must
+ * have some horizontal space between them.
+ */
+ y2 = pCurBox->y2;
+
+ do {
+ if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) {
+ return curStart;
+ }
+ pPrevBox++;
+ pCurBox++;
+ numRects--;
+ } while (numRects);
+
+ /*
+ * The bands may be merged, so set the bottom y of each box
+ * in the previous band to the bottom y of the current band.
+ */
+ numRects = curStart - prevStart;
+ pReg->data->numRects -= numRects;
+ do {
+ pPrevBox--;
+ pPrevBox->y2 = y2;
+ numRects--;
+ } while (numRects);
+ return prevStart;
+}
+
+
+/* Quicky macro to avoid trivial reject procedure calls to RegionCoalesce */
+
+#define Coalesce(newReg, prevBand, curBand) \
+ if (curBand - prevBand == newReg->data->numRects - curBand) { \
+ prevBand = RegionCoalesce(newReg, prevBand, curBand); \
+ } else { \
+ prevBand = curBand; \
+ }
+
+/*-
+ *-----------------------------------------------------------------------
+ * RegionAppendNonO --
+ * Handle a non-overlapping band for the union and subtract operations.
+ * Just adds the (top/bottom-clipped) rectangles into the region.
+ * Doesn't have to check for subsumption or anything.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * pReg->data->numRects is incremented and the rectangles overwritten
+ * with the rectangles we're passed.
+ *
+ *-----------------------------------------------------------------------
+ */
+
+_X_INLINE static Bool
+RegionAppendNonO (
+ RegionPtr pReg,
+ BoxPtr r,
+ BoxPtr rEnd,
+ int y1,
+ int y2)
+{
+ BoxPtr pNextRect;
+ int newRects;
+
+ newRects = rEnd - r;
+
+ assert(y1 < y2);
+ assert(newRects != 0);
+
+ /* Make sure we have enough space for all rectangles to be added */
+ RECTALLOC(pReg, newRects);
+ pNextRect = RegionTop(pReg);
+ pReg->data->numRects += newRects;
+ do {
+ assert(r->x1 < r->x2);
+ ADDRECT(pNextRect, r->x1, y1, r->x2, y2);
+ r++;
+ } while (r != rEnd);
+
+ return TRUE;
+}
+
+#define FindBand(r, rBandEnd, rEnd, ry1) \
+{ \
+ ry1 = r->y1; \
+ rBandEnd = r+1; \
+ while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) { \
+ rBandEnd++; \
+ } \
+}
+
+#define AppendRegions(newReg, r, rEnd) \
+{ \
+ int newRects; \
+ if ((newRects = rEnd - r)) { \
+ RECTALLOC(newReg, newRects); \
+ memmove((char *)RegionTop(newReg),(char *)r, \
+ newRects * sizeof(BoxRec)); \
+ newReg->data->numRects += newRects; \
+ } \
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * RegionOp --
+ * Apply an operation to two regions. Called by RegionUnion, RegionInverse,
+ * RegionSubtract, RegionIntersect.... Both regions MUST have at least one
+ * rectangle, and cannot be the same object.
+ *
+ * Results:
+ * TRUE if successful.
+ *
+ * Side Effects:
+ * The new region is overwritten.
+ * pOverlap set to TRUE if overlapFunc ever returns TRUE.
+ *
+ * Notes:
+ * The idea behind this function is to view the two regions as sets.
+ * Together they cover a rectangle of area that this function divides
+ * into horizontal bands where points are covered only by one region
+ * or by both. For the first case, the nonOverlapFunc is called with
+ * each the band and the band's upper and lower extents. For the
+ * second, the overlapFunc is called to process the entire band. It
+ * is responsible for clipping the rectangles in the band, though
+ * this function provides the boundaries.
+ * At the end of each band, the new region is coalesced, if possible,
+ * to reduce the number of rectangles in the region.
+ *
+ *-----------------------------------------------------------------------
+ */
+
+typedef Bool (*OverlapProcPtr)(
+ RegionPtr pReg,
+ BoxPtr r1,
+ BoxPtr r1End,
+ BoxPtr r2,
+ BoxPtr r2End,
+ short y1,
+ short y2,
+ Bool *pOverlap);
+
+static Bool
+RegionOp(
+ RegionPtr newReg, /* Place to store result */
+ RegionPtr reg1, /* First region in operation */
+ RegionPtr reg2, /* 2d region in operation */
+ OverlapProcPtr overlapFunc, /* Function to call for over-
+ * lapping bands */
+ Bool appendNon1, /* Append non-overlapping bands */
+ /* in region 1 ? */
+ Bool appendNon2, /* Append non-overlapping bands */
+ /* in region 2 ? */
+ Bool *pOverlap)
+{
+ BoxPtr r1; /* Pointer into first region */
+ BoxPtr r2; /* Pointer into 2d region */
+ BoxPtr r1End; /* End of 1st region */
+ BoxPtr r2End; /* End of 2d region */
+ short ybot; /* Bottom of intersection */
+ short ytop; /* Top of intersection */
+ RegDataPtr oldData; /* Old data for newReg */
+ int prevBand; /* Index of start of
+ * previous band in newReg */
+ int curBand; /* Index of start of current
+ * band in newReg */
+ BoxPtr r1BandEnd; /* End of current band in r1 */
+ BoxPtr r2BandEnd; /* End of current band in r2 */
+ short top; /* Top of non-overlapping band */
+ short bot; /* Bottom of non-overlapping band*/
+ int r1y1; /* Temps for r1->y1 and r2->y1 */
+ int r2y1;
+ int newSize;
+ int numRects;
+
+ /*
+ * Break any region computed from a broken region
+ */
+ if (RegionNar (reg1) || RegionNar(reg2))
+ return RegionBreak (newReg);
+
+ /*
+ * Initialization:
+ * set r1, r2, r1End and r2End appropriately, save the rectangles
+ * of the destination region until the end in case it's one of
+ * the two source regions, then mark the "new" region empty, allocating
+ * another array of rectangles for it to use.
+ */
+
+ r1 = RegionRects(reg1);
+ newSize = RegionNumRects(reg1);
+ r1End = r1 + newSize;
+ numRects = RegionNumRects(reg2);
+ r2 = RegionRects(reg2);
+ r2End = r2 + numRects;
+ assert(r1 != r1End);
+ assert(r2 != r2End);
+
+ oldData = NULL;
+ if (((newReg == reg1) && (newSize > 1)) ||
+ ((newReg == reg2) && (numRects > 1)))
+ {
+ oldData = newReg->data;
+ newReg->data = &RegionEmptyData;
+ }
+ /* guess at new size */
+ if (numRects > newSize)
+ newSize = numRects;
+ newSize <<= 1;
+ if (!newReg->data)
+ newReg->data = &RegionEmptyData;
+ else if (newReg->data->size)
+ newReg->data->numRects = 0;
+ if (newSize > newReg->data->size)
+ if (!RegionRectAlloc(newReg, newSize))
+ return FALSE;
+
+ /*
+ * Initialize ybot.
+ * In the upcoming loop, ybot and ytop serve different functions depending
+ * on whether the band being handled is an overlapping or non-overlapping
+ * band.
+ * In the case of a non-overlapping band (only one of the regions
+ * has points in the band), ybot is the bottom of the most recent
+ * intersection and thus clips the top of the rectangles in that band.
+ * ytop is the top of the next intersection between the two regions and
+ * serves to clip the bottom of the rectangles in the current band.
+ * For an overlapping band (where the two regions intersect), ytop clips
+ * the top of the rectangles of both regions and ybot clips the bottoms.
+ */
+
+ ybot = min(r1->y1, r2->y1);
+
+ /*
+ * prevBand serves to mark the start of the previous band so rectangles
+ * can be coalesced into larger rectangles. qv. RegionCoalesce, above.
+ * In the beginning, there is no previous band, so prevBand == curBand
+ * (curBand is set later on, of course, but the first band will always
+ * start at index 0). prevBand and curBand must be indices because of
+ * the possible expansion, and resultant moving, of the new region's
+ * array of rectangles.
+ */
+ prevBand = 0;
+
+ do {
+ /*
+ * This algorithm proceeds one source-band (as opposed to a
+ * destination band, which is determined by where the two regions
+ * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
+ * rectangle after the last one in the current band for their
+ * respective regions.
+ */
+ assert(r1 != r1End);
+ assert(r2 != r2End);
+
+ FindBand(r1, r1BandEnd, r1End, r1y1);
+ FindBand(r2, r2BandEnd, r2End, r2y1);
+
+ /*
+ * First handle the band that doesn't intersect, if any.
+ *
+ * Note that attention is restricted to one band in the
+ * non-intersecting region at once, so if a region has n
+ * bands between the current position and the next place it overlaps
+ * the other, this entire loop will be passed through n times.
+ */
+ if (r1y1 < r2y1) {
+ if (appendNon1) {
+ top = max(r1y1, ybot);
+ bot = min(r1->y2, r2y1);
+ if (top != bot) {
+ curBand = newReg->data->numRects;
+ RegionAppendNonO(newReg, r1, r1BandEnd, top, bot);
+ Coalesce(newReg, prevBand, curBand);
+ }
+ }
+ ytop = r2y1;
+ } else if (r2y1 < r1y1) {
+ if (appendNon2) {
+ top = max(r2y1, ybot);
+ bot = min(r2->y2, r1y1);
+ if (top != bot) {
+ curBand = newReg->data->numRects;
+ RegionAppendNonO(newReg, r2, r2BandEnd, top, bot);
+ Coalesce(newReg, prevBand, curBand);
+ }
+ }
+ ytop = r1y1;
+ } else {
+ ytop = r1y1;
+ }
+
+ /*
+ * Now see if we've hit an intersecting band. The two bands only
+ * intersect if ybot > ytop
+ */
+ ybot = min(r1->y2, r2->y2);
+ if (ybot > ytop) {
+ curBand = newReg->data->numRects;
+ (* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot,
+ pOverlap);
+ Coalesce(newReg, prevBand, curBand);
+ }
+
+ /*
+ * If we've finished with a band (y2 == ybot) we skip forward
+ * in the region to the next band.
+ */
+ if (r1->y2 == ybot) r1 = r1BandEnd;
+ if (r2->y2 == ybot) r2 = r2BandEnd;
+
+ } while (r1 != r1End && r2 != r2End);
+
+ /*
+ * Deal with whichever region (if any) still has rectangles left.
+ *
+ * We only need to worry about banding and coalescing for the very first
+ * band left. After that, we can just group all remaining boxes,
+ * regardless of how many bands, into one final append to the list.
+ */
+
+ if ((r1 != r1End) && appendNon1) {
+ /* Do first nonOverlap1Func call, which may be able to coalesce */
+ FindBand(r1, r1BandEnd, r1End, r1y1);
+ curBand = newReg->data->numRects;
+ RegionAppendNonO(newReg, r1, r1BandEnd, max(r1y1, ybot), r1->y2);
+ Coalesce(newReg, prevBand, curBand);
+ /* Just append the rest of the boxes */
+ AppendRegions(newReg, r1BandEnd, r1End);
+
+ } else if ((r2 != r2End) && appendNon2) {
+ /* Do first nonOverlap2Func call, which may be able to coalesce */
+ FindBand(r2, r2BandEnd, r2End, r2y1);
+ curBand = newReg->data->numRects;
+ RegionAppendNonO(newReg, r2, r2BandEnd, max(r2y1, ybot), r2->y2);
+ Coalesce(newReg, prevBand, curBand);
+ /* Append rest of boxes */
+ AppendRegions(newReg, r2BandEnd, r2End);
+ }
+
+ free(oldData);
+
+ if (!(numRects = newReg->data->numRects))
+ {
+ xfreeData(newReg);
+ newReg->data = &RegionEmptyData;
+ }
+ else if (numRects == 1)
+ {
+ newReg->extents = *RegionBoxptr(newReg);
+ xfreeData(newReg);
+ newReg->data = NULL;
+ }
+ else
+ {
+ DOWNSIZE(newReg, numRects);
+ }
+
+ return TRUE;
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * RegionSetExtents --
+ * Reset the extents of a region to what they should be. Called by
+ * Subtract and Intersect as they can't figure it out along the
+ * way or do so easily, as Union can.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * The region's 'extents' structure is overwritten.
+ *
+ *-----------------------------------------------------------------------
+ */
+static void
+RegionSetExtents (RegionPtr pReg)
+{
+ BoxPtr pBox, pBoxEnd;
+
+ if (!pReg->data)
+ return;
+ if (!pReg->data->size)
+ {
+ pReg->extents.x2 = pReg->extents.x1;
+ pReg->extents.y2 = pReg->extents.y1;
+ return;
+ }
+
+ pBox = RegionBoxptr(pReg);
+ pBoxEnd = RegionEnd(pReg);
+
+ /*
+ * Since pBox is the first rectangle in the region, it must have the
+ * smallest y1 and since pBoxEnd is the last rectangle in the region,
+ * it must have the largest y2, because of banding. Initialize x1 and
+ * x2 from pBox and pBoxEnd, resp., as good things to initialize them
+ * to...
+ */
+ pReg->extents.x1 = pBox->x1;
+ pReg->extents.y1 = pBox->y1;
+ pReg->extents.x2 = pBoxEnd->x2;
+ pReg->extents.y2 = pBoxEnd->y2;
+
+ assert(pReg->extents.y1 < pReg->extents.y2);
+ while (pBox <= pBoxEnd) {
+ if (pBox->x1 < pReg->extents.x1)
+ pReg->extents.x1 = pBox->x1;
+ if (pBox->x2 > pReg->extents.x2)
+ pReg->extents.x2 = pBox->x2;
+ pBox++;
+ };
+
+ assert(pReg->extents.x1 < pReg->extents.x2);
+}
+
+/*======================================================================
+ * Region Intersection
+ *====================================================================*/
+/*-
+ *-----------------------------------------------------------------------
+ * RegionIntersectO --
+ * Handle an overlapping band for RegionIntersect.
+ *
+ * Results:
+ * TRUE if successful.
+ *
+ * Side Effects:
+ * Rectangles may be added to the region.
+ *
+ *-----------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+
+#define MERGERECT(r) \
+{ \
+ if (r->x1 <= x2) { \
+ /* Merge with current rectangle */ \
+ if (r->x1 < x2) *pOverlap = TRUE; \
+ if (x2 < r->x2) x2 = r->x2; \
+ } else { \
+ /* Add current rectangle, start new one */ \
+ NEWRECT(pReg, pNextRect, x1, y1, x2, y2); \
+ x1 = r->x1; \
+ x2 = r->x2; \
+ } \
+ r++; \
+}
+
+/*======================================================================
+ * Region Union
+ *====================================================================*/
+
+/*-
+ *-----------------------------------------------------------------------
+ * RegionUnionO --
+ * Handle an overlapping band for the union operation. Picks the
+ * left-most rectangle each time and merges it into the region.
+ *
+ * Results:
+ * TRUE if successful.
+ *
+ * Side Effects:
+ * pReg is overwritten.
+ * pOverlap is set to TRUE if any boxes overlap.
+ *
+ *-----------------------------------------------------------------------
+ */
+static Bool
+RegionUnionO (
+ RegionPtr pReg,
+ BoxPtr r1,
+ BoxPtr r1End,
+ BoxPtr r2,
+ BoxPtr r2End,
+ short y1,
+ short y2,
+ Bool *pOverlap)
+{
+ BoxPtr pNextRect;
+ int x1; /* left and right side of current union */
+ int x2;
+
+ assert (y1 < y2);
+ assert(r1 != r1End && r2 != r2End);
+
+ pNextRect = RegionTop(pReg);
+
+ /* Start off current rectangle */
+ if (r1->x1 < r2->x1)
+ {
+ x1 = r1->x1;
+ x2 = r1->x2;
+ r1++;
+ }
+ else
+ {
+ x1 = r2->x1;
+ x2 = r2->x2;
+ r2++;
+ }
+ while (r1 != r1End && r2 != r2End)
+ {
+ if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2);
+ }
+
+ /* Finish off whoever (if any) is left */
+ if (r1 != r1End)
+ {
+ do
+ {
+ MERGERECT(r1);
+ } while (r1 != r1End);
+ }
+ else if (r2 != r2End)
+ {
+ do
+ {
+ MERGERECT(r2);
+ } while (r2 != r2End);
+ }
+
+ /* Add current rectangle */
+ NEWRECT(pReg, pNextRect, x1, y1, x2, y2);
+
+ return TRUE;
+}
+
+/*======================================================================
+ * Batch Rectangle Union
+ *====================================================================*/
+
+/*-
+ *-----------------------------------------------------------------------
+ * RegionAppend --
+ *
+ * "Append" the rgn rectangles onto the end of dstrgn, maintaining
+ * knowledge of YX-banding when it's easy. Otherwise, dstrgn just
+ * becomes a non-y-x-banded random collection of rectangles, and not
+ * yet a true region. After a sequence of appends, the caller must
+ * call RegionValidate to ensure that a valid region is constructed.
+ *
+ * Results:
+ * TRUE if successful.
+ *
+ * Side Effects:
+ * dstrgn is modified if rgn has rectangles.
+ *
+ */
+Bool
+RegionAppend(RegionPtr dstrgn, RegionPtr rgn)
+{
+ int numRects, dnumRects, size;
+ BoxPtr new, old;
+ Bool prepend;
+
+ if (RegionNar(rgn))
+ return RegionBreak (dstrgn);
+
+ if (!rgn->data && (dstrgn->data == &RegionEmptyData))
+ {
+ dstrgn->extents = rgn->extents;
+ dstrgn->data = NULL;
+ return TRUE;
+ }
+
+ numRects = RegionNumRects(rgn);
+ if (!numRects)
+ return TRUE;
+ prepend = FALSE;
+ size = numRects;
+ dnumRects = RegionNumRects(dstrgn);
+ if (!dnumRects && (size < 200))
+ size = 200; /* XXX pick numbers out of a hat */
+ RECTALLOC(dstrgn, size);
+ old = RegionRects(rgn);
+ if (!dnumRects)
+ dstrgn->extents = rgn->extents;
+ else if (dstrgn->extents.x2 > dstrgn->extents.x1)
+ {
+ BoxPtr first, last;
+
+ first = old;
+ last = RegionBoxptr(dstrgn) + (dnumRects - 1);
+ if ((first->y1 > last->y2) ||
+ ((first->y1 == last->y1) && (first->y2 == last->y2) &&
+ (first->x1 > last->x2)))
+ {
+ if (rgn->extents.x1 < dstrgn->extents.x1)
+ dstrgn->extents.x1 = rgn->extents.x1;
+ if (rgn->extents.x2 > dstrgn->extents.x2)
+ dstrgn->extents.x2 = rgn->extents.x2;
+ dstrgn->extents.y2 = rgn->extents.y2;
+ }
+ else
+ {
+ first = RegionBoxptr(dstrgn);
+ last = old + (numRects - 1);
+ if ((first->y1 > last->y2) ||
+ ((first->y1 == last->y1) && (first->y2 == last->y2) &&
+ (first->x1 > last->x2)))
+ {
+ prepend = TRUE;
+ if (rgn->extents.x1 < dstrgn->extents.x1)
+ dstrgn->extents.x1 = rgn->extents.x1;
+ if (rgn->extents.x2 > dstrgn->extents.x2)
+ dstrgn->extents.x2 = rgn->extents.x2;
+ dstrgn->extents.y1 = rgn->extents.y1;
+ }
+ else
+ dstrgn->extents.x2 = dstrgn->extents.x1;
+ }
+ }
+ if (prepend)
+ {
+ new = RegionBox(dstrgn, numRects);
+ if (dnumRects == 1)
+ *new = *RegionBoxptr(dstrgn);
+ else
+ memmove((char *)new,(char *)RegionBoxptr(dstrgn),
+ dnumRects * sizeof(BoxRec));
+ new = RegionBoxptr(dstrgn);
+ }
+ else
+ new = RegionBoxptr(dstrgn) + dnumRects;
+ if (numRects == 1)
+ *new = *old;
+ else
+ memmove((char *)new, (char *)old, numRects * sizeof(BoxRec));
+ dstrgn->data->numRects += numRects;
+ return TRUE;
+}
+
+
+#define ExchangeRects(a, b) \
+{ \
+ BoxRec t; \
+ t = rects[a]; \
+ rects[a] = rects[b]; \
+ rects[b] = t; \
+}
+
+static void
+QuickSortRects(
+ BoxRec rects[],
+ int numRects)
+{
+ int y1;
+ int x1;
+ int i, j;
+ BoxPtr r;
+
+ /* Always called with numRects > 1 */
+
+ do
+ {
+ if (numRects == 2)
+ {
+ if (rects[0].y1 > rects[1].y1 ||
+ (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1))
+ ExchangeRects(0, 1);
+ return;
+ }
+
+ /* Choose partition element, stick in location 0 */
+ ExchangeRects(0, numRects >> 1);
+ y1 = rects[0].y1;
+ x1 = rects[0].x1;
+
+ /* Partition array */
+ i = 0;
+ j = numRects;
+ do
+ {
+ r = &(rects[i]);
+ do
+ {
+ r++;
+ i++;
+ } while (i != numRects &&
+ (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1)));
+ r = &(rects[j]);
+ do
+ {
+ r--;
+ j--;
+ } while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1));
+ if (i < j)
+ ExchangeRects(i, j);
+ } while (i < j);
+
+ /* Move partition element back to middle */
+ ExchangeRects(0, j);
+
+ /* Recurse */
+ if (numRects-j-1 > 1)
+ QuickSortRects(&rects[j+1], numRects-j-1);
+ numRects = j;
+ } while (numRects > 1);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * RegionValidate --
+ *
+ * Take a ``region'' which is a non-y-x-banded random collection of
+ * rectangles, and compute a nice region which is the union of all the
+ * rectangles.
+ *
+ * Results:
+ * TRUE if successful.
+ *
+ * Side Effects:
+ * The passed-in ``region'' may be modified.
+ * pOverlap set to TRUE if any retangles overlapped, else FALSE;
+ *
+ * Strategy:
+ * Step 1. Sort the rectangles into ascending order with primary key y1
+ * and secondary key x1.
+ *
+ * Step 2. Split the rectangles into the minimum number of proper y-x
+ * banded regions. This may require horizontally merging
+ * rectangles, and vertically coalescing bands. With any luck,
+ * this step in an identity tranformation (ala the Box widget),
+ * or a coalescing into 1 box (ala Menus).
+ *
+ * Step 3. Merge the separate regions down to a single region by calling
+ * Union. Maximize the work each Union call does by using
+ * a binary merge.
+ *
+ *-----------------------------------------------------------------------
+ */
+
+Bool
+RegionValidate(RegionPtr badreg, Bool *pOverlap)
+{
+ /* Descriptor for regions under construction in Step 2. */
+ typedef struct {
+ RegionRec reg;
+ int prevBand;
+ int curBand;
+ } RegionInfo;
+
+ int numRects; /* Original numRects for badreg */
+ RegionInfo *ri; /* Array of current regions */
+ int numRI; /* Number of entries used in ri */
+ int sizeRI; /* Number of entries available in ri */
+ int i; /* Index into rects */
+ int j; /* Index into ri */
+ RegionInfo *rit; /* &ri[j] */
+ RegionPtr reg; /* ri[j].reg */
+ BoxPtr box; /* Current box in rects */
+ BoxPtr riBox; /* Last box in ri[j].reg */
+ RegionPtr hreg; /* ri[j_half].reg */
+ Bool ret = TRUE;
+
+ *pOverlap = FALSE;
+ if (!badreg->data)
+ {
+ good(badreg);
+ return TRUE;
+ }
+ numRects = badreg->data->numRects;
+ if (!numRects)
+ {
+ if (RegionNar(badreg))
+ return FALSE;
+ good(badreg);
+ return TRUE;
+ }
+ if (badreg->extents.x1 < badreg->extents.x2)
+ {
+ if ((numRects) == 1)
+ {
+ xfreeData(badreg);
+ badreg->data = (RegDataPtr) NULL;
+ }
+ else
+ {
+ DOWNSIZE(badreg, numRects);
+ }
+ good(badreg);
+ return TRUE;
+ }
+
+ /* Step 1: Sort the rects array into ascending (y1, x1) order */
+ QuickSortRects(RegionBoxptr(badreg), numRects);
+
+ /* Step 2: Scatter the sorted array into the minimum number of regions */
+
+ /* Set up the first region to be the first rectangle in badreg */
+ /* Note that step 2 code will never overflow the ri[0].reg rects array */
+ ri = (RegionInfo *) malloc(4 * sizeof(RegionInfo));
+ if (!ri)
+ return RegionBreak (badreg);
+ sizeRI = 4;
+ numRI = 1;
+ ri[0].prevBand = 0;
+ ri[0].curBand = 0;
+ ri[0].reg = *badreg;
+ box = RegionBoxptr(&ri[0].reg);
+ ri[0].reg.extents = *box;
+ ri[0].reg.data->numRects = 1;
+
+ /* Now scatter rectangles into the minimum set of valid regions. If the
+ next rectangle to be added to a region would force an existing rectangle
+ in the region to be split up in order to maintain y-x banding, just
+ forget it. Try the next region. If it doesn't fit cleanly into any
+ region, make a new one. */
+
+ for (i = numRects; --i > 0;)
+ {
+ box++;
+ /* Look for a region to append box to */
+ for (j = numRI, rit = ri; --j >= 0; rit++)
+ {
+ reg = &rit->reg;
+ riBox = RegionEnd(reg);
+
+ if (box->y1 == riBox->y1 && box->y2 == riBox->y2)
+ {
+ /* box is in same band as riBox. Merge or append it */
+ if (box->x1 <= riBox->x2)
+ {
+ /* Merge it with riBox */
+ if (box->x1 < riBox->x2) *pOverlap = TRUE;
+ if (box->x2 > riBox->x2) riBox->x2 = box->x2;
+ }
+ else
+ {
+ RECTALLOC_BAIL(reg, 1, bail);
+ *RegionTop(reg) = *box;
+ reg->data->numRects++;
+ }
+ goto NextRect; /* So sue me */
+ }
+ else if (box->y1 >= riBox->y2)
+ {
+ /* Put box into new band */
+ if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
+ if (reg->extents.x1 > box->x1) reg->extents.x1 = box->x1;
+ Coalesce(reg, rit->prevBand, rit->curBand);
+ rit->curBand = reg->data->numRects;
+ RECTALLOC_BAIL(reg, 1, bail);
+ *RegionTop(reg) = *box;
+ reg->data->numRects++;
+ goto NextRect;
+ }
+ /* Well, this region was inappropriate. Try the next one. */
+ } /* for j */
+
+ /* Uh-oh. No regions were appropriate. Create a new one. */
+ if (sizeRI == numRI)
+ {
+ /* Oops, allocate space for new region information */
+ sizeRI <<= 1;
+ rit = (RegionInfo *) realloc(ri, sizeRI * sizeof(RegionInfo));
+ if (!rit)
+ goto bail;
+ ri = rit;
+ rit = &ri[numRI];
+ }
+ numRI++;
+ rit->prevBand = 0;
+ rit->curBand = 0;
+ rit->reg.extents = *box;
+ rit->reg.data = NULL;
+ if (!RegionRectAlloc(&rit->reg, (i+numRI) / numRI)) /* MUST force allocation */
+ goto bail;
+NextRect: ;
+ } /* for i */
+
+ /* Make a final pass over each region in order to Coalesce and set
+ extents.x2 and extents.y2 */
+
+ for (j = numRI, rit = ri; --j >= 0; rit++)
+ {
+ reg = &rit->reg;
+ riBox = RegionEnd(reg);
+ reg->extents.y2 = riBox->y2;
+ if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
+ Coalesce(reg, rit->prevBand, rit->curBand);
+ if (reg->data->numRects == 1) /* keep unions happy below */
+ {
+ xfreeData(reg);
+ reg->data = NULL;
+ }
+ }
+
+ /* Step 3: Union all regions into a single region */
+ while (numRI > 1)
+ {
+ int half = numRI/2;
+ for (j = numRI & 1; j < (half + (numRI & 1)); j++)
+ {
+ reg = &ri[j].reg;
+ hreg = &ri[j+half].reg;
+ if (!RegionOp(reg, reg, hreg, RegionUnionO, TRUE, TRUE, pOverlap))
+ ret = FALSE;
+ if (hreg->extents.x1 < reg->extents.x1)
+ reg->extents.x1 = hreg->extents.x1;
+ if (hreg->extents.y1 < reg->extents.y1)
+ reg->extents.y1 = hreg->extents.y1;
+ if (hreg->extents.x2 > reg->extents.x2)
+ reg->extents.x2 = hreg->extents.x2;
+ if (hreg->extents.y2 > reg->extents.y2)
+ reg->extents.y2 = hreg->extents.y2;
+ xfreeData(hreg);
+ }
+ numRI -= half;
+ }
+ *badreg = ri[0].reg;
+ free(ri);
+ good(badreg);
+ return ret;
+bail:
+ for (i = 0; i < numRI; i++)
+ xfreeData(&ri[i].reg);
+ free(ri);
+ return RegionBreak (badreg);
+}
+
+RegionPtr
+RegionFromRects(int nrects, xRectangle *prect, int ctype)
+{
+
+ RegionPtr pRgn;
+ RegDataPtr pData;
+ BoxPtr pBox;
+ int i;
+ int x1, y1, x2, y2;
+
+ pRgn = RegionCreate(NullBox, 0);
+ if (RegionNar (pRgn))
+ return pRgn;
+ if (!nrects)
+ return pRgn;
+ if (nrects == 1)
+ {
+ x1 = prect->x;
+ y1 = prect->y;
+ if ((x2 = x1 + (int) prect->width) > MAXSHORT)
+ x2 = MAXSHORT;
+ if ((y2 = y1 + (int) prect->height) > MAXSHORT)
+ y2 = MAXSHORT;
+ if (x1 != x2 && y1 != y2)
+ {
+ pRgn->extents.x1 = x1;
+ pRgn->extents.y1 = y1;
+ pRgn->extents.x2 = x2;
+ pRgn->extents.y2 = y2;
+ pRgn->data = NULL;
+ }
+ return pRgn;
+ }
+ pData = xallocData(nrects);
+ if (!pData)
+ {
+ RegionBreak (pRgn);
+ return pRgn;
+ }
+ pBox = (BoxPtr) (pData + 1);
+ for (i = nrects; --i >= 0; prect++)
+ {
+ x1 = prect->x;
+ y1 = prect->y;
+ if ((x2 = x1 + (int) prect->width) > MAXSHORT)
+ x2 = MAXSHORT;
+ if ((y2 = y1 + (int) prect->height) > MAXSHORT)
+ y2 = MAXSHORT;
+ if (x1 != x2 && y1 != y2)
+ {
+ pBox->x1 = x1;
+ pBox->y1 = y1;
+ pBox->x2 = x2;
+ pBox->y2 = y2;
+ pBox++;
+ }
+ }
+ if (pBox != (BoxPtr) (pData + 1))
+ {
+ pData->size = nrects;
+ pData->numRects = pBox - (BoxPtr) (pData + 1);
+ pRgn->data = pData;
+ if (ctype != CT_YXBANDED)
+ {
+ Bool overlap; /* result ignored */
+ pRgn->extents.x1 = pRgn->extents.x2 = 0;
+ RegionValidate(pRgn, &overlap);
+ }
+ else
+ RegionSetExtents(pRgn);
+ good(pRgn);
+ }
+ else
+ {
+ free(pData);
+ }
+ return pRgn;
+}
+
+#define ExchangeSpans(a, b) \
+{ \
+ DDXPointRec tpt; \
+ int tw; \
+ \
+ tpt = spans[a]; spans[a] = spans[b]; spans[b] = tpt; \
+ tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \
+}
+
+/* ||| I should apply the merge sort code to rectangle sorting above, and see
+ if mapping time can be improved. But right now I've been at work 12 hours,
+ so forget it.
+*/
+
+static void QuickSortSpans(
+ DDXPointRec spans[],
+ int widths[],
+ int numSpans)
+{
+ int y;
+ int i, j, m;
+ DDXPointPtr r;
+
+ /* Always called with numSpans > 1 */
+ /* Sorts only by y, doesn't bother to sort by x */
+
+ do
+ {
+ if (numSpans < 9)
+ {
+ /* Do insertion sort */
+ int yprev;
+
+ yprev = spans[0].y;
+ i = 1;
+ do
+ { /* while i != numSpans */
+ y = spans[i].y;
+ if (yprev > y)
+ {
+ /* spans[i] is out of order. Move into proper location. */
+ DDXPointRec tpt;
+ int tw, k;
+
+ for (j = 0; y >= spans[j].y; j++) {}
+ tpt = spans[i];
+ tw = widths[i];
+ for (k = i; k != j; k--)
+ {
+ spans[k] = spans[k-1];
+ widths[k] = widths[k-1];
+ }
+ spans[j] = tpt;
+ widths[j] = tw;
+ y = spans[i].y;
+ } /* if out of order */
+ yprev = y;
+ i++;
+ } while (i != numSpans);
+ return;
+ }
+
+ /* Choose partition element, stick in location 0 */
+ m = numSpans / 2;
+ if (spans[m].y > spans[0].y) ExchangeSpans(m, 0);
+ if (spans[m].y > spans[numSpans-1].y) ExchangeSpans(m, numSpans-1);
+ if (spans[m].y > spans[0].y) ExchangeSpans(m, 0);
+ y = spans[0].y;
+
+ /* Partition array */
+ i = 0;
+ j = numSpans;
+ do
+ {
+ r = &(spans[i]);
+ do
+ {
+ r++;
+ i++;
+ } while (i != numSpans && r->y < y);
+ r = &(spans[j]);
+ do
+ {
+ r--;
+ j--;
+ } while (y < r->y);
+ if (i < j)
+ ExchangeSpans(i, j);
+ } while (i < j);
+
+ /* Move partition element back to middle */
+ ExchangeSpans(0, j);
+
+ /* Recurse */
+ if (numSpans-j-1 > 1)
+ QuickSortSpans(&spans[j+1], &widths[j+1], numSpans-j-1);
+ numSpans = j;
+ } while (numSpans > 1);
+}
+
+#define NextBand() \
+{ \
+ clipy1 = pboxBandStart->y1; \
+ clipy2 = pboxBandStart->y2; \
+ pboxBandEnd = pboxBandStart + 1; \
+ while (pboxBandEnd != pboxLast && pboxBandEnd->y1 == clipy1) { \
+ pboxBandEnd++; \
+ } \
+ for (; ppt != pptLast && ppt->y < clipy1; ppt++, pwidth++) {} \
+}
+
+/*
+ Clip a list of scanlines to a region. The caller has allocated the
+ space. FSorted is non-zero if the scanline origins are in ascending
+ order.
+ returns the number of new, clipped scanlines.
+*/
+
+int
+RegionClipSpans(
+ RegionPtr prgnDst,
+ DDXPointPtr ppt,
+ int *pwidth,
+ int nspans,
+ DDXPointPtr pptNew,
+ int *pwidthNew,
+ int fSorted)
+{
+ DDXPointPtr pptLast;
+ int *pwidthNewStart; /* the vengeance of Xerox! */
+ int y, x1, x2;
+ int numRects;
+
+ good(prgnDst);
+ pptLast = ppt + nspans;
+ pwidthNewStart = pwidthNew;
+
+ if (!prgnDst->data)
+ {
+ /* Do special fast code with clip boundaries in registers(?) */
+ /* It doesn't pay much to make use of fSorted in this case,
+ so we lump everything together. */
+
+ int clipx1, clipx2, clipy1, clipy2;
+
+ clipx1 = prgnDst->extents.x1;
+ clipy1 = prgnDst->extents.y1;
+ clipx2 = prgnDst->extents.x2;
+ clipy2 = prgnDst->extents.y2;
+
+ for (; ppt != pptLast; ppt++, pwidth++)
+ {
+ y = ppt->y;
+ x1 = ppt->x;
+ if (clipy1 <= y && y < clipy2)
+ {
+ x2 = x1 + *pwidth;
+ if (x1 < clipx1) x1 = clipx1;
+ if (x2 > clipx2) x2 = clipx2;
+ if (x1 < x2)
+ {
+ /* part of span in clip rectangle */
+ pptNew->x = x1;
+ pptNew->y = y;
+ *pwidthNew = x2 - x1;
+ pptNew++;
+ pwidthNew++;
+ }
+ }
+ } /* end for */
+
+ }
+ else if ((numRects = prgnDst->data->numRects))
+ {
+ /* Have to clip against many boxes */
+ BoxPtr pboxBandStart, pboxBandEnd;
+ BoxPtr pbox;
+ BoxPtr pboxLast;
+ int clipy1, clipy2;
+
+ /* In this case, taking advantage of sorted spans gains more than
+ the sorting costs. */
+ if ((! fSorted) && (nspans > 1))
+ QuickSortSpans(ppt, pwidth, nspans);
+
+ pboxBandStart = RegionBoxptr(prgnDst);
+ pboxLast = pboxBandStart + numRects;
+
+ NextBand();
+
+ for (; ppt != pptLast; )
+ {
+ y = ppt->y;
+ if (y < clipy2)
+ {
+ /* span is in the current band */
+ pbox = pboxBandStart;
+ x1 = ppt->x;
+ x2 = x1 + *pwidth;
+ do
+ { /* For each box in band */
+ int newx1, newx2;
+
+ newx1 = x1;
+ newx2 = x2;
+ if (newx1 < pbox->x1) newx1 = pbox->x1;
+ if (newx2 > pbox->x2) newx2 = pbox->x2;
+ if (newx1 < newx2)
+ {
+ /* Part of span in clip rectangle */
+ pptNew->x = newx1;
+ pptNew->y = y;
+ *pwidthNew = newx2 - newx1;
+ pptNew++;
+ pwidthNew++;
+ }
+ pbox++;
+ } while (pbox != pboxBandEnd);
+ ppt++;
+ pwidth++;
+ }
+ else
+ {
+ /* Move to next band, adjust ppt as needed */
+ pboxBandStart = pboxBandEnd;
+ if (pboxBandStart == pboxLast)
+ break; /* We're completely done */
+ NextBand();
+ }
+ }
+ }
+ return pwidthNew - pwidthNewStart;
+}
diff --git a/dix/registry.c b/dix/registry.c
new file mode 100644
index 0000000..fc35dbb
--- /dev/null
+++ b/dix/registry.c
@@ -0,0 +1,336 @@
+/************************************************************
+
+Author: Eamon Walsh <ewalsh@tycho.nsa.gov>
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+this permission notice appear in supporting documentation. This permission
+notice shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+********************************************************/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#ifdef XREGISTRY
+
+#include <stdlib.h>
+#include <string.h>
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include "resource.h"
+#include "registry.h"
+
+#define BASE_SIZE 16
+#define CORE "X11"
+#define FILENAME SERVER_MISC_CONFIG_PATH "/protocol.txt"
+
+#define PROT_COMMENT '#'
+#define PROT_REQUEST 'R'
+#define PROT_EVENT 'V'
+#define PROT_ERROR 'E'
+
+static FILE *fh;
+
+static char ***requests, **events, **errors, **resources;
+static unsigned nmajor, *nminor, nevent, nerror, nresource;
+
+/*
+ * File parsing routines
+ */
+static int double_size(void *p, unsigned n, unsigned size)
+{
+ char **ptr = (char **)p;
+ unsigned s, f;
+
+ if (n) {
+ s = n * size;
+ n *= 2 * size;
+ f = n;
+ } else {
+ s = 0;
+ n = f = BASE_SIZE * size;
+ }
+
+ *ptr = realloc(*ptr, n);
+ if (!*ptr) {
+ dixResetRegistry();
+ return FALSE;
+ }
+ memset(*ptr + s, 0, f - s);
+ return TRUE;
+}
+
+static void
+RegisterRequestName(unsigned major, unsigned minor, char *name)
+{
+ while (major >= nmajor) {
+ if (!double_size(&requests, nmajor, sizeof(char **)))
+ return;
+ if (!double_size(&nminor, nmajor, sizeof(unsigned)))
+ return;
+ nmajor = nmajor ? nmajor * 2 : BASE_SIZE;
+ }
+ while (minor >= nminor[major]) {
+ if (!double_size(requests+major, nminor[major], sizeof(char *)))
+ return;
+ nminor[major] = nminor[major] ? nminor[major] * 2 : BASE_SIZE;
+ }
+
+ free(requests[major][minor]);
+ requests[major][minor] = name;
+}
+
+static void
+RegisterEventName(unsigned event, char *name) {
+ while (event >= nevent) {
+ if (!double_size(&events, nevent, sizeof(char *)))
+ return;
+ nevent = nevent ? nevent * 2 : BASE_SIZE;
+ }
+
+ free(events[event]);
+ events[event] = name;
+}
+
+static void
+RegisterErrorName(unsigned error, char *name) {
+ while (error >= nerror) {
+ if (!double_size(&errors, nerror, sizeof(char *)))
+ return;
+ nerror = nerror ? nerror * 2 : BASE_SIZE;
+ }
+
+ free(errors[error]);
+ errors[error] = name;
+}
+
+void
+RegisterExtensionNames(ExtensionEntry *extEntry)
+{
+ char buf[256], *lineobj, *ptr;
+ unsigned offset;
+
+ if (fh == NULL)
+ return;
+
+ rewind(fh);
+
+ while (fgets(buf, sizeof(buf), fh)) {
+ lineobj = NULL;
+ ptr = strchr(buf, '\n');
+ if (ptr)
+ *ptr = 0;
+
+ /* Check for comments or empty lines */
+ switch (buf[0]) {
+ case PROT_REQUEST:
+ case PROT_EVENT:
+ case PROT_ERROR:
+ break;
+ case PROT_COMMENT:
+ case '\0':
+ continue;
+ default:
+ goto invalid;
+ }
+
+ /* Check for space character in the fifth position */
+ ptr = strchr(buf, ' ');
+ if (!ptr || ptr != buf + 4)
+ goto invalid;
+
+ /* Duplicate the string after the space */
+ lineobj = strdup(ptr + 1);
+ if (!lineobj)
+ continue;
+
+ /* Check for a colon somewhere on the line */
+ ptr = strchr(buf, ':');
+ if (!ptr)
+ goto invalid;
+
+ /* Compare the part before colon with the target extension name */
+ *ptr = 0;
+ if (strcmp(buf + 5, extEntry->name))
+ goto skip;
+
+ /* Get the opcode for the request, event, or error */
+ offset = strtol(buf + 1, &ptr, 10);
+ if (offset == 0 && ptr == buf + 1)
+ goto invalid;
+
+ /* Save the strdup result in the registry */
+ switch(buf[0]) {
+ case PROT_REQUEST:
+ if (extEntry->base)
+ RegisterRequestName(extEntry->base, offset, lineobj);
+ else
+ RegisterRequestName(offset, 0, lineobj);
+ continue;
+ case PROT_EVENT:
+ RegisterEventName(extEntry->eventBase + offset, lineobj);
+ continue;
+ case PROT_ERROR:
+ RegisterErrorName(extEntry->errorBase + offset, lineobj);
+ continue;
+ }
+
+ invalid:
+ LogMessage(X_WARNING, "Invalid line in " FILENAME ", skipping\n");
+ skip:
+ free(lineobj);
+ }
+}
+
+/*
+ * Registration functions
+ */
+
+void
+RegisterResourceName(RESTYPE resource, char *name)
+{
+ resource &= TypeMask;
+
+ while (resource >= nresource) {
+ if (!double_size(&resources, nresource, sizeof(char *)))
+ return;
+ nresource = nresource ? nresource * 2 : BASE_SIZE;
+ }
+
+ resources[resource] = name;
+}
+
+/*
+ * Lookup functions
+ */
+
+const char *
+LookupRequestName(int major, int minor)
+{
+ if (major >= nmajor)
+ return XREGISTRY_UNKNOWN;
+ if (minor >= nminor[major])
+ return XREGISTRY_UNKNOWN;
+
+ return requests[major][minor] ? requests[major][minor] : XREGISTRY_UNKNOWN;
+}
+
+const char *
+LookupMajorName(int major)
+{
+ if (major < 128) {
+ const char *retval;
+
+ if (major >= nmajor)
+ return XREGISTRY_UNKNOWN;
+ if (0 >= nminor[major])
+ return XREGISTRY_UNKNOWN;
+
+ retval = requests[major][0];
+ return retval ? retval + sizeof(CORE) : XREGISTRY_UNKNOWN;
+ } else {
+ ExtensionEntry *extEntry = GetExtensionEntry(major);
+ return extEntry ? extEntry->name : XREGISTRY_UNKNOWN;
+ }
+}
+
+const char *
+LookupEventName(int event)
+{
+ event &= 127;
+ if (event >= nevent)
+ return XREGISTRY_UNKNOWN;
+
+ return events[event] ? events[event] : XREGISTRY_UNKNOWN;
+}
+
+const char *
+LookupErrorName(int error)
+{
+ if (error >= nerror)
+ return XREGISTRY_UNKNOWN;
+
+ return errors[error] ? errors[error] : XREGISTRY_UNKNOWN;
+}
+
+const char *
+LookupResourceName(RESTYPE resource)
+{
+ resource &= TypeMask;
+ if (resource >= nresource)
+ return XREGISTRY_UNKNOWN;
+
+ return resources[resource] ? resources[resource] : XREGISTRY_UNKNOWN;
+}
+
+/*
+ * Setup and teardown
+ */
+void
+dixResetRegistry(void)
+{
+ ExtensionEntry extEntry;
+
+ /* Free all memory */
+ while (nmajor--) {
+ while (nminor[nmajor])
+ free(requests[nmajor][--nminor[nmajor]]);
+ free(requests[nmajor]);
+ }
+ free(requests);
+ free(nminor);
+
+ while (nevent--)
+ free(events[nevent]);
+ free(events);
+
+ while (nerror--)
+ free(errors[nerror]);
+ free(errors);
+
+ free(resources);
+
+ requests = NULL;
+ nminor = NULL;
+ events = NULL;
+ errors = NULL;
+ resources = NULL;
+
+ nmajor = nevent = nerror = nresource = 0;
+
+ /* Open the protocol file */
+ if (fh)
+ fclose(fh);
+ fh = fopen(FILENAME, "r");
+ if (!fh)
+ LogMessage(X_WARNING, "Failed to open protocol names file " FILENAME "\n");
+
+ /* Add built-in resources */
+ RegisterResourceName(RT_NONE, "NONE");
+ RegisterResourceName(RT_WINDOW, "WINDOW");
+ RegisterResourceName(RT_PIXMAP, "PIXMAP");
+ RegisterResourceName(RT_GC, "GC");
+ RegisterResourceName(RT_FONT, "FONT");
+ RegisterResourceName(RT_CURSOR, "CURSOR");
+ RegisterResourceName(RT_COLORMAP, "COLORMAP");
+ RegisterResourceName(RT_CMAPENTRY, "COLORMAP ENTRY");
+ RegisterResourceName(RT_OTHERCLIENT, "OTHER CLIENT");
+ RegisterResourceName(RT_PASSIVEGRAB, "PASSIVE GRAB");
+
+ /* Add the core protocol */
+ memset(&extEntry, 0, sizeof(extEntry));
+ extEntry.name = CORE;
+ RegisterExtensionNames(&extEntry);
+}
+
+#endif /* XREGISTRY */
diff --git a/dix/resource.c b/dix/resource.c
new file mode 100644
index 0000000..26d2c72
--- /dev/null
+++ b/dix/resource.c
@@ -0,0 +1,965 @@
+/************************************************************
+
+Copyright 1987, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+********************************************************/
+/* The panoramix components contained the following notice */
+/*****************************************************************
+
+Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
+BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of Digital Equipment Corporation
+shall not be used in advertising or otherwise to promote the sale, use or other
+dealings in this Software without prior written authorization from Digital
+Equipment Corporation.
+
+******************************************************************/
+/* XSERVER_DTRACE additions:
+ * Copyright (c) 2005-2006, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/* Routines to manage various kinds of resources:
+ *
+ * CreateNewResourceType, CreateNewResourceClass, InitClientResources,
+ * FakeClientID, AddResource, FreeResource, FreeClientResources,
+ * FreeAllResources, LookupIDByType, LookupIDByClass, GetXIDRange
+ */
+
+/*
+ * A resource ID is a 32 bit quantity, the upper 2 bits of which are
+ * off-limits for client-visible resources. The next 8 bits are
+ * used as client ID, and the low 22 bits come from the client.
+ * A resource ID is "hashed" by extracting and xoring subfields
+ * (varying with the size of the hash table).
+ *
+ * It is sometimes necessary for the server to create an ID that looks
+ * like it belongs to a client. This ID, however, must not be one
+ * the client actually can create, or we have the potential for conflict.
+ * The 31st bit of the ID is reserved for the server's use for this
+ * purpose. By setting CLIENT_ID(id) to the client, the SERVER_BIT to
+ * 1, and an otherwise arbitrary ID in the low 22 bits, we can create a
+ * resource "owned" by the client.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include "misc.h"
+#include "os.h"
+#include "resource.h"
+#include "dixstruct.h"
+#include "opaque.h"
+#include "windowstr.h"
+#include "dixfont.h"
+#include "colormap.h"
+#include "inputstr.h"
+#include "dixevents.h"
+#include "dixgrabs.h"
+#include "cursor.h"
+#ifdef PANORAMIX
+#include "panoramiX.h"
+#include "panoramiXsrv.h"
+#endif
+#include "xace.h"
+#include <assert.h>
+#include "registry.h"
+
+#ifdef XSERVER_DTRACE
+#include <sys/types.h>
+typedef const char *string;
+#include "Xserver-dtrace.h"
+
+#define TypeNameString(t) LookupResourceName(t)
+#endif
+
+static void RebuildTable(
+ int /*client*/
+);
+
+#define SERVER_MINID 32
+
+#define INITBUCKETS 64
+#define INITHASHSIZE 6
+#define MAXHASHSIZE 11
+
+typedef struct _Resource {
+ struct _Resource *next;
+ XID id;
+ RESTYPE type;
+ pointer value;
+} ResourceRec, *ResourcePtr;
+
+typedef struct _ClientResource {
+ ResourcePtr *resources;
+ int elements;
+ int buckets;
+ int hashsize; /* log(2)(buckets) */
+ XID fakeID;
+ XID endFakeID;
+} ClientResourceRec;
+
+RESTYPE lastResourceType;
+static RESTYPE lastResourceClass;
+RESTYPE TypeMask;
+
+struct ResourceType {
+ DeleteType deleteFunc;
+ int errorValue;
+};
+
+static struct ResourceType *resourceTypes;
+static const struct ResourceType predefTypes[] = {
+ [RT_NONE & (RC_LASTPREDEF - 1)] = {
+ .deleteFunc = (DeleteType)NoopDDA,
+ .errorValue = BadValue,
+ },
+ [RT_WINDOW & (RC_LASTPREDEF - 1)] = {
+ .deleteFunc = DeleteWindow,
+ .errorValue = BadWindow,
+ },
+ [RT_PIXMAP & (RC_LASTPREDEF - 1)] = {
+ .deleteFunc = dixDestroyPixmap,
+ .errorValue = BadPixmap,
+ },
+ [RT_GC & (RC_LASTPREDEF - 1)] = {
+ .deleteFunc = FreeGC,
+ .errorValue = BadGC,
+ },
+ [RT_FONT & (RC_LASTPREDEF - 1)] = {
+ .deleteFunc = CloseFont,
+ .errorValue = BadFont,
+ },
+ [RT_CURSOR & (RC_LASTPREDEF - 1)] = {
+ .deleteFunc = FreeCursor,
+ .errorValue = BadCursor,
+ },
+ [RT_COLORMAP & (RC_LASTPREDEF - 1)] = {
+ .deleteFunc = FreeColormap,
+ .errorValue = BadColor,
+ },
+ [RT_CMAPENTRY & (RC_LASTPREDEF - 1)] = {
+ .deleteFunc = FreeClientPixels,
+ .errorValue = BadColor,
+ },
+ [RT_OTHERCLIENT & (RC_LASTPREDEF - 1)] = {
+ .deleteFunc = OtherClientGone,
+ .errorValue = BadValue,
+ },
+ [RT_PASSIVEGRAB & (RC_LASTPREDEF - 1)] = {
+ .deleteFunc = DeletePassiveGrab,
+ .errorValue = BadValue,
+ },
+};
+
+CallbackListPtr ResourceStateCallback;
+
+static _X_INLINE void
+CallResourceStateCallback(ResourceState state, ResourceRec *res)
+{
+ if (ResourceStateCallback) {
+ ResourceStateInfoRec rsi = { state, res->id, res->type, res->value };
+ CallCallbacks(&ResourceStateCallback, &rsi);
+ }
+}
+
+RESTYPE
+CreateNewResourceType(DeleteType deleteFunc, char *name)
+{
+ RESTYPE next = lastResourceType + 1;
+ struct ResourceType *types;
+
+ if (next & lastResourceClass)
+ return 0;
+ types = realloc(resourceTypes, (next + 1) * sizeof(*resourceTypes));
+ if (!types)
+ return 0;
+
+ lastResourceType = next;
+ resourceTypes = types;
+ resourceTypes[next].deleteFunc = deleteFunc;
+ resourceTypes[next].errorValue = BadValue;
+
+ /* Called even if name is NULL, to remove any previous entry */
+ RegisterResourceName(next, name);
+
+ return next;
+}
+
+void
+SetResourceTypeErrorValue(RESTYPE type, int errorValue)
+{
+ resourceTypes[type & TypeMask].errorValue = errorValue;
+}
+
+RESTYPE
+CreateNewResourceClass(void)
+{
+ RESTYPE next = lastResourceClass >> 1;
+
+ if (next & lastResourceType)
+ return 0;
+ lastResourceClass = next;
+ TypeMask = next - 1;
+ return next;
+}
+
+static ClientResourceRec clientTable[MAXCLIENTS];
+
+/*****************
+ * InitClientResources
+ * When a new client is created, call this to allocate space
+ * in resource table
+ *****************/
+
+Bool
+InitClientResources(ClientPtr client)
+{
+ int i, j;
+
+ if (client == serverClient)
+ {
+ lastResourceType = RT_LASTPREDEF;
+ lastResourceClass = RC_LASTPREDEF;
+ TypeMask = RC_LASTPREDEF - 1;
+ free(resourceTypes);
+ resourceTypes = malloc(sizeof(predefTypes));
+ if (!resourceTypes)
+ return FALSE;
+ memcpy(resourceTypes, predefTypes, sizeof(predefTypes));
+ }
+ clientTable[i = client->index].resources =
+ malloc(INITBUCKETS*sizeof(ResourcePtr));
+ if (!clientTable[i].resources)
+ return FALSE;
+ clientTable[i].buckets = INITBUCKETS;
+ clientTable[i].elements = 0;
+ clientTable[i].hashsize = INITHASHSIZE;
+ /* Many IDs allocated from the server client are visible to clients,
+ * so we don't use the SERVER_BIT for them, but we have to start
+ * past the magic value constants used in the protocol. For normal
+ * clients, we can start from zero, with SERVER_BIT set.
+ */
+ clientTable[i].fakeID = client->clientAsMask |
+ (client->index ? SERVER_BIT : SERVER_MINID);
+ clientTable[i].endFakeID = (clientTable[i].fakeID | RESOURCE_ID_MASK) + 1;
+ for (j=0; j<INITBUCKETS; j++)
+ {
+ clientTable[i].resources[j] = NULL;
+ }
+ return TRUE;
+}
+
+
+static int
+Hash(int client, XID id)
+{
+ id &= RESOURCE_ID_MASK;
+ switch (clientTable[client].hashsize)
+ {
+ case 6:
+ return ((int)(0x03F & (id ^ (id>>6) ^ (id>>12))));
+ case 7:
+ return ((int)(0x07F & (id ^ (id>>7) ^ (id>>13))));
+ case 8:
+ return ((int)(0x0FF & (id ^ (id>>8) ^ (id>>16))));
+ case 9:
+ return ((int)(0x1FF & (id ^ (id>>9))));
+ case 10:
+ return ((int)(0x3FF & (id ^ (id>>10))));
+ case 11:
+ return ((int)(0x7FF & (id ^ (id>>11))));
+ }
+ return -1;
+}
+
+static XID
+AvailableID(
+ int client,
+ XID id,
+ XID maxid,
+ XID goodid)
+{
+ ResourcePtr res;
+
+ if ((goodid >= id) && (goodid <= maxid))
+ return goodid;
+ for (; id <= maxid; id++)
+ {
+ res = clientTable[client].resources[Hash(client, id)];
+ while (res && (res->id != id))
+ res = res->next;
+ if (!res)
+ return id;
+ }
+ return 0;
+}
+
+void
+GetXIDRange(int client, Bool server, XID *minp, XID *maxp)
+{
+ XID id, maxid;
+ ResourcePtr *resp;
+ ResourcePtr res;
+ int i;
+ XID goodid;
+
+ id = (Mask)client << CLIENTOFFSET;
+ if (server)
+ id |= client ? SERVER_BIT : SERVER_MINID;
+ maxid = id | RESOURCE_ID_MASK;
+ goodid = 0;
+ for (resp = clientTable[client].resources, i = clientTable[client].buckets;
+ --i >= 0;)
+ {
+ for (res = *resp++; res; res = res->next)
+ {
+ if ((res->id < id) || (res->id > maxid))
+ continue;
+ if (((res->id - id) >= (maxid - res->id)) ?
+ (goodid = AvailableID(client, id, res->id - 1, goodid)) :
+ !(goodid = AvailableID(client, res->id + 1, maxid, goodid)))
+ maxid = res->id - 1;
+ else
+ id = res->id + 1;
+ }
+ }
+ if (id > maxid)
+ id = maxid = 0;
+ *minp = id;
+ *maxp = maxid;
+}
+
+/**
+ * GetXIDList is called by the XC-MISC extension's MiscGetXIDList function.
+ * This function tries to find count unused XIDs for the given client. It
+ * puts the IDs in the array pids and returns the number found, which should
+ * almost always be the number requested.
+ *
+ * The circumstances that lead to a call to this function are very rare.
+ * Xlib must run out of IDs while trying to generate a request that wants
+ * multiple ID's, like the Multi-buffering CreateImageBuffers request.
+ *
+ * No rocket science in the implementation; just iterate over all
+ * possible IDs for the given client and pick the first count IDs
+ * that aren't in use. A more efficient algorithm could probably be
+ * invented, but this will be used so rarely that this should suffice.
+ */
+
+unsigned int
+GetXIDList(ClientPtr pClient, unsigned count, XID *pids)
+{
+ unsigned int found = 0;
+ XID rc, id = pClient->clientAsMask;
+ XID maxid;
+ pointer val;
+
+ maxid = id | RESOURCE_ID_MASK;
+ while ( (found < count) && (id <= maxid) )
+ {
+ rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient,
+ DixGetAttrAccess);
+ if (rc == BadValue)
+ {
+ pids[found++] = id;
+ }
+ id++;
+ }
+ return found;
+}
+
+/*
+ * Return the next usable fake client ID.
+ *
+ * Normally this is just the next one in line, but if we've used the last
+ * in the range, we need to find a new range of safe IDs to avoid
+ * over-running another client.
+ */
+
+XID
+FakeClientID(int client)
+{
+ XID id, maxid;
+
+ id = clientTable[client].fakeID++;
+ if (id != clientTable[client].endFakeID)
+ return id;
+ GetXIDRange(client, TRUE, &id, &maxid);
+ if (!id) {
+ if (!client)
+ FatalError("FakeClientID: server internal ids exhausted\n");
+ MarkClientException(clients[client]);
+ id = ((Mask)client << CLIENTOFFSET) | (SERVER_BIT * 3);
+ maxid = id | RESOURCE_ID_MASK;
+ }
+ clientTable[client].fakeID = id + 1;
+ clientTable[client].endFakeID = maxid + 1;
+ return id;
+}
+
+Bool
+AddResource(XID id, RESTYPE type, pointer value)
+{
+ int client;
+ ClientResourceRec *rrec;
+ ResourcePtr res, *head;
+
+#ifdef XSERVER_DTRACE
+ XSERVER_RESOURCE_ALLOC(id, type, value, TypeNameString(type));
+#endif
+ client = CLIENT_ID(id);
+ rrec = &clientTable[client];
+ if (!rrec->buckets)
+ {
+ ErrorF("[dix] AddResource(%lx, %lx, %lx), client=%d \n",
+ (unsigned long)id, type, (unsigned long)value, client);
+ FatalError("client not in use\n");
+ }
+ if ((rrec->elements >= 4*rrec->buckets) &&
+ (rrec->hashsize < MAXHASHSIZE))
+ RebuildTable(client);
+ head = &rrec->resources[Hash(client, id)];
+ res = malloc(sizeof(ResourceRec));
+ if (!res)
+ {
+ (*resourceTypes[type & TypeMask].deleteFunc)(value, id);
+ return FALSE;
+ }
+ res->next = *head;
+ res->id = id;
+ res->type = type;
+ res->value = value;
+ *head = res;
+ rrec->elements++;
+ CallResourceStateCallback(ResourceStateAdding, res);
+ return TRUE;
+}
+
+static void
+RebuildTable(int client)
+{
+ int j;
+ ResourcePtr res, next;
+ ResourcePtr **tails, *resources;
+ ResourcePtr **tptr, *rptr;
+
+ /*
+ * For now, preserve insertion order, since some ddx layers depend
+ * on resources being free in the opposite order they are added.
+ */
+
+ j = 2 * clientTable[client].buckets;
+ tails = malloc(j * sizeof(ResourcePtr *));
+ if (!tails)
+ return;
+ resources = malloc(j * sizeof(ResourcePtr));
+ if (!resources)
+ {
+ free(tails);
+ return;
+ }
+ for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++)
+ {
+ *rptr = NULL;
+ *tptr = rptr;
+ }
+ clientTable[client].hashsize++;
+ for (j = clientTable[client].buckets,
+ rptr = clientTable[client].resources;
+ --j >= 0;
+ rptr++)
+ {
+ for (res = *rptr; res; res = next)
+ {
+ next = res->next;
+ res->next = NULL;
+ tptr = &tails[Hash(client, res->id)];
+ **tptr = res;
+ *tptr = &res->next;
+ }
+ }
+ free(tails);
+ clientTable[client].buckets *= 2;
+ free(clientTable[client].resources);
+ clientTable[client].resources = resources;
+}
+
+void
+FreeResource(XID id, RESTYPE skipDeleteFuncType)
+{
+ int cid;
+ ResourcePtr res;
+ ResourcePtr *prev, *head;
+ int *eltptr;
+ int elements;
+
+ if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
+ {
+ head = &clientTable[cid].resources[Hash(cid, id)];
+ eltptr = &clientTable[cid].elements;
+
+ prev = head;
+ while ( (res = *prev) )
+ {
+ if (res->id == id)
+ {
+ RESTYPE rtype = res->type;
+
+#ifdef XSERVER_DTRACE
+ XSERVER_RESOURCE_FREE(res->id, res->type,
+ res->value, TypeNameString(res->type));
+#endif
+ *prev = res->next;
+ elements = --*eltptr;
+
+ CallResourceStateCallback(ResourceStateFreeing, res);
+
+ if (rtype != skipDeleteFuncType)
+ (*resourceTypes[rtype & TypeMask].deleteFunc)(res->value, res->id);
+ free(res);
+ if (*eltptr != elements)
+ prev = head; /* prev may no longer be valid */
+ }
+ else
+ prev = &res->next;
+ }
+ }
+}
+
+
+void
+FreeResourceByType(XID id, RESTYPE type, Bool skipFree)
+{
+ int cid;
+ ResourcePtr res;
+ ResourcePtr *prev, *head;
+ if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
+ {
+ head = &clientTable[cid].resources[Hash(cid, id)];
+
+ prev = head;
+ while ( (res = *prev) )
+ {
+ if (res->id == id && res->type == type)
+ {
+#ifdef XSERVER_DTRACE
+ XSERVER_RESOURCE_FREE(res->id, res->type,
+ res->value, TypeNameString(res->type));
+#endif
+ *prev = res->next;
+ clientTable[cid].elements--;
+
+ CallResourceStateCallback(ResourceStateFreeing, res);
+
+ if (!skipFree)
+ (*resourceTypes[type & TypeMask].deleteFunc)(res->value, res->id);
+ free(res);
+ break;
+ }
+ else
+ prev = &res->next;
+ }
+ }
+}
+
+/*
+ * Change the value associated with a resource id. Caller
+ * is responsible for "doing the right thing" with the old
+ * data
+ */
+
+Bool
+ChangeResourceValue (XID id, RESTYPE rtype, pointer value)
+{
+ int cid;
+ ResourcePtr res;
+
+ if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
+ {
+ res = clientTable[cid].resources[Hash(cid, id)];
+
+ for (; res; res = res->next)
+ if ((res->id == id) && (res->type == rtype))
+ {
+ res->value = value;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/* Note: if func adds or deletes resources, then func can get called
+ * more than once for some resources. If func adds new resources,
+ * func might or might not get called for them. func cannot both
+ * add and delete an equal number of resources!
+ */
+
+void
+FindClientResourcesByType(
+ ClientPtr client,
+ RESTYPE type,
+ FindResType func,
+ pointer cdata
+){
+ ResourcePtr *resources;
+ ResourcePtr this, next;
+ int i, elements;
+ int *eltptr;
+
+ if (!client)
+ client = serverClient;
+
+ resources = clientTable[client->index].resources;
+ eltptr = &clientTable[client->index].elements;
+ for (i = 0; i < clientTable[client->index].buckets; i++)
+ {
+ for (this = resources[i]; this; this = next)
+ {
+ next = this->next;
+ if (!type || this->type == type) {
+ elements = *eltptr;
+ (*func)(this->value, this->id, cdata);
+ if (*eltptr != elements)
+ next = resources[i]; /* start over */
+ }
+ }
+ }
+}
+
+void
+FindAllClientResources(
+ ClientPtr client,
+ FindAllRes func,
+ pointer cdata
+){
+ ResourcePtr *resources;
+ ResourcePtr this, next;
+ int i, elements;
+ int *eltptr;
+
+ if (!client)
+ client = serverClient;
+
+ resources = clientTable[client->index].resources;
+ eltptr = &clientTable[client->index].elements;
+ for (i = 0; i < clientTable[client->index].buckets; i++)
+ {
+ for (this = resources[i]; this; this = next)
+ {
+ next = this->next;
+ elements = *eltptr;
+ (*func)(this->value, this->id, this->type, cdata);
+ if (*eltptr != elements)
+ next = resources[i]; /* start over */
+ }
+ }
+}
+
+
+pointer
+LookupClientResourceComplex(
+ ClientPtr client,
+ RESTYPE type,
+ FindComplexResType func,
+ pointer cdata
+){
+ ResourcePtr *resources;
+ ResourcePtr this, next;
+ pointer value;
+ int i;
+
+ if (!client)
+ client = serverClient;
+
+ resources = clientTable[client->index].resources;
+ for (i = 0; i < clientTable[client->index].buckets; i++) {
+ for (this = resources[i]; this; this = next) {
+ next = this->next;
+ if (!type || this->type == type) {
+ /* workaround func freeing the type as DRI1 does */
+ value = this->value;
+ if((*func)(value, this->id, cdata))
+ return value;
+ }
+ }
+ }
+ return NULL;
+}
+
+
+void
+FreeClientNeverRetainResources(ClientPtr client)
+{
+ ResourcePtr *resources;
+ ResourcePtr this;
+ ResourcePtr *prev;
+ int j, elements;
+ int *eltptr;
+
+ if (!client)
+ return;
+
+ resources = clientTable[client->index].resources;
+ eltptr = &clientTable[client->index].elements;
+ for (j=0; j < clientTable[client->index].buckets; j++)
+ {
+ prev = &resources[j];
+ while ( (this = *prev) )
+ {
+ RESTYPE rtype = this->type;
+ if (rtype & RC_NEVERRETAIN)
+ {
+#ifdef XSERVER_DTRACE
+ XSERVER_RESOURCE_FREE(this->id, this->type,
+ this->value, TypeNameString(this->type));
+#endif
+ *prev = this->next;
+ clientTable[client->index].elements--;
+
+ CallResourceStateCallback(ResourceStateFreeing, this);
+
+ elements = *eltptr;
+ (*resourceTypes[rtype & TypeMask].deleteFunc)(this->value, this->id);
+ free(this);
+ if (*eltptr != elements)
+ prev = &resources[j]; /* prev may no longer be valid */
+ }
+ else
+ prev = &this->next;
+ }
+ }
+}
+
+void
+FreeClientResources(ClientPtr client)
+{
+ ResourcePtr *resources;
+ ResourcePtr this;
+ int j;
+
+ /* This routine shouldn't be called with a null client, but just in
+ case ... */
+
+ if (!client)
+ return;
+
+ HandleSaveSet(client);
+
+ resources = clientTable[client->index].resources;
+ for (j=0; j < clientTable[client->index].buckets; j++)
+ {
+ /* It may seem silly to update the head of this resource list as
+ we delete the members, since the entire list will be deleted any way,
+ but there are some resource deletion functions "FreeClientPixels" for
+ one which do a LookupID on another resource id (a Colormap id in this
+ case), so the resource list must be kept valid up to the point that
+ it is deleted, so every time we delete a resource, we must update the
+ head, just like in FreeResource. I hope that this doesn't slow down
+ mass deletion appreciably. PRH */
+
+ ResourcePtr *head;
+
+ head = &resources[j];
+
+ for (this = *head; this; this = *head)
+ {
+ RESTYPE rtype = this->type;
+#ifdef XSERVER_DTRACE
+ XSERVER_RESOURCE_FREE(this->id, this->type,
+ this->value, TypeNameString(this->type));
+#endif
+ *head = this->next;
+ clientTable[client->index].elements--;
+
+ CallResourceStateCallback(ResourceStateFreeing, this);
+
+ (*resourceTypes[rtype & TypeMask].deleteFunc)(this->value, this->id);
+ free(this);
+ }
+ }
+ free(clientTable[client->index].resources);
+ clientTable[client->index].resources = NULL;
+ clientTable[client->index].buckets = 0;
+}
+
+void
+FreeAllResources(void)
+{
+ int i;
+
+ for (i = currentMaxClients; --i >= 0; )
+ {
+ if (clientTable[i].buckets)
+ FreeClientResources(clients[i]);
+ }
+}
+
+Bool
+LegalNewID(XID id, ClientPtr client)
+{
+ pointer val;
+ int rc;
+
+#ifdef PANORAMIX
+ XID minid, maxid;
+
+ if (!noPanoramiXExtension) {
+ minid = client->clientAsMask | (client->index ?
+ SERVER_BIT : SERVER_MINID);
+ maxid = (clientTable[client->index].fakeID | RESOURCE_ID_MASK) + 1;
+ if ((id >= minid) && (id <= maxid))
+ return TRUE;
+ }
+#endif /* PANORAMIX */
+ if (client->clientAsMask == (id & ~RESOURCE_ID_MASK))
+ {
+ rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient,
+ DixGetAttrAccess);
+ return rc == BadValue;
+ }
+ return FALSE;
+}
+
+int
+dixLookupResourceByType(pointer *result, XID id, RESTYPE rtype,
+ ClientPtr client, Mask mode)
+{
+ int cid = CLIENT_ID(id);
+ ResourcePtr res = NULL;
+
+ *result = NULL;
+ if ((rtype & TypeMask) > lastResourceType)
+ return BadImplementation;
+
+ if ((cid < MAXCLIENTS) && clientTable[cid].buckets) {
+ res = clientTable[cid].resources[Hash(cid, id)];
+
+ for (; res; res = res->next)
+ if (res->id == id && res->type == rtype)
+ break;
+ }
+ if (!res)
+ return resourceTypes[rtype & TypeMask].errorValue;
+
+ if (client) {
+ client->errorValue = id;
+ cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type,
+ res->value, RT_NONE, NULL, mode);
+ if (cid == BadValue)
+ return resourceTypes[rtype & TypeMask].errorValue;
+ if (cid != Success)
+ return cid;
+ }
+
+ *result = res->value;
+ return Success;
+}
+
+int
+dixLookupResourceByClass(pointer *result, XID id, RESTYPE rclass,
+ ClientPtr client, Mask mode)
+{
+ int cid = CLIENT_ID(id);
+ ResourcePtr res = NULL;
+
+ *result = NULL;
+
+ if ((cid < MAXCLIENTS) && clientTable[cid].buckets) {
+ res = clientTable[cid].resources[Hash(cid, id)];
+
+ for (; res; res = res->next)
+ if (res->id == id && (res->type & rclass))
+ break;
+ }
+ if (!res)
+ return BadValue;
+
+ if (client) {
+ client->errorValue = id;
+ cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type,
+ res->value, RT_NONE, NULL, mode);
+ if (cid != Success)
+ return cid;
+ }
+
+ *result = res->value;
+ return Success;
+}
diff --git a/dix/selection.c b/dix/selection.c
new file mode 100644
index 0000000..87ed1ab
--- /dev/null
+++ b/dix/selection.c
@@ -0,0 +1,311 @@
+/************************************************************
+
+Copyright 1987, 1989, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+********************************************************/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "windowstr.h"
+#include "dixstruct.h"
+#include "dispatch.h"
+#include "selection.h"
+#include "xace.h"
+
+/*****************************************************************
+ * Selection Stuff
+ *
+ * dixLookupSelection
+ *
+ * Selections are global to the server. The list of selections should
+ * not be traversed directly. Instead, use the functions listed above.
+ *
+ *****************************************************************/
+
+Selection *CurrentSelections;
+CallbackListPtr SelectionCallback;
+
+int
+dixLookupSelection(Selection **result, Atom selectionName,
+ ClientPtr client, Mask access_mode)
+{
+ Selection *pSel;
+ int rc = BadMatch;
+ client->errorValue = selectionName;
+
+ for (pSel = CurrentSelections; pSel; pSel = pSel->next)
+ if (pSel->selection == selectionName)
+ break;
+
+ if (pSel)
+ rc = XaceHookSelectionAccess(client, &pSel, access_mode);
+ *result = pSel;
+ return rc;
+}
+
+void
+InitSelections(void)
+{
+ Selection *pSel, *pNextSel;
+
+ pSel = CurrentSelections;
+ while (pSel) {
+ pNextSel = pSel->next;
+ dixFreeObjectWithPrivates(pSel, PRIVATE_SELECTION);
+ pSel = pNextSel;
+ }
+
+ CurrentSelections = NULL;
+}
+
+static _X_INLINE void
+CallSelectionCallback(Selection *pSel, ClientPtr client,
+ SelectionCallbackKind kind)
+{
+ SelectionInfoRec info = { pSel, client, kind };
+ CallCallbacks(&SelectionCallback, &info);
+}
+
+void
+DeleteWindowFromAnySelections(WindowPtr pWin)
+{
+ Selection *pSel;
+
+ for (pSel = CurrentSelections; pSel; pSel = pSel->next)
+ if (pSel->pWin == pWin) {
+ CallSelectionCallback(pSel, NULL, SelectionWindowDestroy);
+
+ pSel->pWin = (WindowPtr)NULL;
+ pSel->window = None;
+ pSel->client = NullClient;
+ }
+}
+
+void
+DeleteClientFromAnySelections(ClientPtr client)
+{
+ Selection *pSel;
+
+ for (pSel = CurrentSelections; pSel; pSel = pSel->next)
+ if (pSel->client == client) {
+ CallSelectionCallback(pSel, NULL, SelectionClientClose);
+
+ pSel->pWin = (WindowPtr)NULL;
+ pSel->window = None;
+ pSel->client = NullClient;
+ }
+}
+
+int
+ProcSetSelectionOwner(ClientPtr client)
+{
+ WindowPtr pWin = NULL;
+ TimeStamp time;
+ Selection *pSel;
+ int rc;
+
+ REQUEST(xSetSelectionOwnerReq);
+ REQUEST_SIZE_MATCH(xSetSelectionOwnerReq);
+
+ UpdateCurrentTime();
+ time = ClientTimeToServerTime(stuff->time);
+
+ /* If the client's time stamp is in the future relative to the server's
+ time stamp, do not set the selection, just return success. */
+ if (CompareTimeStamps(time, currentTime) == LATER)
+ return Success;
+
+ if (stuff->window != None) {
+ rc = dixLookupWindow(&pWin, stuff->window, client, DixSetAttrAccess);
+ if (rc != Success)
+ return rc;
+ }
+ if (!ValidAtom(stuff->selection)) {
+ client->errorValue = stuff->selection;
+ return BadAtom;
+ }
+
+ /*
+ * First, see if the selection is already set...
+ */
+ rc = dixLookupSelection(&pSel, stuff->selection, client, DixSetAttrAccess);
+
+ if (rc == Success) {
+ xEvent event;
+
+ /* If the timestamp in client's request is in the past relative
+ to the time stamp indicating the last time the owner of the
+ selection was set, do not set the selection, just return
+ success. */
+ if (CompareTimeStamps(time, pSel->lastTimeChanged) == EARLIER)
+ return Success;
+ if (pSel->client && (!pWin || (pSel->client != client)))
+ {
+ event.u.u.type = SelectionClear;
+ event.u.selectionClear.time = time.milliseconds;
+ event.u.selectionClear.window = pSel->window;
+ event.u.selectionClear.atom = pSel->selection;
+ WriteEventsToClient(pSel->client, 1, &event);
+ }
+ }
+ else if (rc == BadMatch)
+ {
+ /*
+ * It doesn't exist, so add it...
+ */
+ pSel = dixAllocateObjectWithPrivates(Selection, PRIVATE_SELECTION);
+ if (!pSel)
+ return BadAlloc;
+
+ pSel->selection = stuff->selection;
+
+ /* security creation/labeling check */
+ rc = XaceHookSelectionAccess(client, &pSel,
+ DixCreateAccess|DixSetAttrAccess);
+ if (rc != Success) {
+ free(pSel);
+ return rc;
+ }
+
+ pSel->next = CurrentSelections;
+ CurrentSelections = pSel;
+ }
+ else
+ return rc;
+
+ pSel->lastTimeChanged = time;
+ pSel->window = stuff->window;
+ pSel->pWin = pWin;
+ pSel->client = (pWin ? client : NullClient);
+
+ CallSelectionCallback(pSel, client, SelectionSetOwner);
+ return Success;
+}
+
+int
+ProcGetSelectionOwner(ClientPtr client)
+{
+ int rc;
+ Selection *pSel;
+ xGetSelectionOwnerReply reply;
+
+ REQUEST(xResourceReq);
+ REQUEST_SIZE_MATCH(xResourceReq);
+
+ if (!ValidAtom(stuff->id)) {
+ client->errorValue = stuff->id;
+ return BadAtom;
+ }
+
+ memset(&reply, 0, sizeof(xGetSelectionOwnerReply));
+ reply.type = X_Reply;
+ reply.length = 0;
+ reply.sequenceNumber = client->sequence;
+
+ rc = dixLookupSelection(&pSel, stuff->id, client, DixGetAttrAccess);
+ if (rc == Success)
+ reply.owner = pSel->window;
+ else if (rc == BadMatch)
+ reply.owner = None;
+ else
+ return rc;
+
+ WriteReplyToClient(client, sizeof(xGetSelectionOwnerReply), &reply);
+ return Success;
+}
+
+int
+ProcConvertSelection(ClientPtr client)
+{
+ Bool paramsOkay;
+ xEvent event;
+ WindowPtr pWin;
+ Selection *pSel;
+ int rc;
+
+ REQUEST(xConvertSelectionReq);
+ REQUEST_SIZE_MATCH(xConvertSelectionReq);
+
+ rc = dixLookupWindow(&pWin, stuff->requestor, client, DixSetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ paramsOkay = ValidAtom(stuff->selection) && ValidAtom(stuff->target);
+ paramsOkay &= (stuff->property == None) || ValidAtom(stuff->property);
+ if (!paramsOkay) {
+ client->errorValue = stuff->property;
+ return BadAtom;
+ }
+
+ rc = dixLookupSelection(&pSel, stuff->selection, client, DixReadAccess);
+
+ memset(&event, 0, sizeof(xEvent));
+ if (rc != Success && rc != BadMatch)
+ return rc;
+ else if (rc == Success && pSel->window != None) {
+ event.u.u.type = SelectionRequest;
+ event.u.selectionRequest.owner = pSel->window;
+ event.u.selectionRequest.time = stuff->time;
+ event.u.selectionRequest.requestor = stuff->requestor;
+ event.u.selectionRequest.selection = stuff->selection;
+ event.u.selectionRequest.target = stuff->target;
+ event.u.selectionRequest.property = stuff->property;
+ if (pSel->client && pSel->client != serverClient && !pSel->client->clientGone)
+ {
+ WriteEventsToClient(pSel->client, 1, &event);
+ return Success;
+ }
+ }
+
+ event.u.u.type = SelectionNotify;
+ event.u.selectionNotify.time = stuff->time;
+ event.u.selectionNotify.requestor = stuff->requestor;
+ event.u.selectionNotify.selection = stuff->selection;
+ event.u.selectionNotify.target = stuff->target;
+ event.u.selectionNotify.property = None;
+ WriteEventsToClient(client, 1, &event);
+ return Success;
+}
diff --git a/dix/swaprep.c b/dix/swaprep.c
new file mode 100644
index 0000000..c173411
--- /dev/null
+++ b/dix/swaprep.c
@@ -0,0 +1,1308 @@
+/************************************************************
+
+Copyright 1987, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+********************************************************/
+
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include "misc.h"
+#include "dixstruct.h"
+#include <X11/fonts/fontstruct.h>
+#include "scrnintstr.h"
+#include "swaprep.h"
+#include "globals.h"
+
+static void SwapFontInfo(xQueryFontReply *pr);
+
+static void SwapCharInfo(xCharInfo *pInfo);
+
+static void SwapFont(xQueryFontReply *pr, Bool hasGlyphs);
+
+/**
+ * Thanks to Jack Palevich for testing and subsequently rewriting all this
+ *
+ * \param size size in bytes
+ */
+void
+Swap32Write(ClientPtr pClient, int size, CARD32 *pbuf)
+{
+ int i;
+ char n;
+
+ size >>= 2;
+ for(i = 0; i < size; i++)
+ /* brackets are mandatory here, because "swapl" macro expands
+ to several statements */
+ {
+ swapl(&pbuf[i], n);
+ }
+ (void)WriteToClient(pClient, size << 2, (char *) pbuf);
+}
+
+/**
+ *
+ * \param size size in bytes
+ */
+void
+CopySwap32Write(ClientPtr pClient, int size, CARD32 *pbuf)
+{
+ int bufsize = size;
+ CARD32 *pbufT;
+ CARD32 *from, *to, *fromLast, *toLast;
+ CARD32 tmpbuf[1];
+
+ /* Allocate as big a buffer as we can... */
+ while (!(pbufT = malloc(bufsize)))
+ {
+ bufsize >>= 1;
+ if (bufsize == 4)
+ {
+ pbufT = tmpbuf;
+ break;
+ }
+ }
+
+ /* convert lengths from # of bytes to # of longs */
+ size >>= 2;
+ bufsize >>= 2;
+
+ from = pbuf;
+ fromLast = from + size;
+ while (from < fromLast) {
+ int nbytes;
+ to = pbufT;
+ toLast = to + min (bufsize, fromLast - from);
+ nbytes = (toLast - to) << 2;
+ while (to < toLast) {
+ /* can't write "cpswapl(*from++, *to++)" because cpswapl is a macro
+ that evaulates its args more than once */
+ cpswapl(*from, *to);
+ from++;
+ to++;
+ }
+ (void)WriteToClient (pClient, nbytes, (char *) pbufT);
+ }
+
+ if (pbufT != tmpbuf)
+ free(pbufT);
+}
+
+/**
+ *
+ * \param size size in bytes
+ */
+void
+CopySwap16Write(ClientPtr pClient, int size, short *pbuf)
+{
+ int bufsize = size;
+ short *pbufT;
+ short *from, *to, *fromLast, *toLast;
+ short tmpbuf[2];
+
+ /* Allocate as big a buffer as we can... */
+ while (!(pbufT = malloc(bufsize)))
+ {
+ bufsize >>= 1;
+ if (bufsize == 4)
+ {
+ pbufT = tmpbuf;
+ break;
+ }
+ }
+
+ /* convert lengths from # of bytes to # of shorts */
+ size >>= 1;
+ bufsize >>= 1;
+
+ from = pbuf;
+ fromLast = from + size;
+ while (from < fromLast) {
+ int nbytes;
+ to = pbufT;
+ toLast = to + min (bufsize, fromLast - from);
+ nbytes = (toLast - to) << 1;
+ while (to < toLast) {
+ /* can't write "cpswaps(*from++, *to++)" because cpswaps is a macro
+ that evaulates its args more than once */
+ cpswaps(*from, *to);
+ from++;
+ to++;
+ }
+ (void)WriteToClient (pClient, nbytes, (char *) pbufT);
+ }
+
+ if (pbufT != tmpbuf)
+ free(pbufT);
+}
+
+
+/* Extra-small reply */
+void
+SGenericReply(ClientPtr pClient, int size, xGenericReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+/* Extra-large reply */
+void
+SGetWindowAttributesReply(ClientPtr pClient, int size,
+ xGetWindowAttributesReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->length, n);
+ swapl(&pRep->visualID, n);
+ swaps(&pRep->class, n);
+ swapl(&pRep->backingBitPlanes, n);
+ swapl(&pRep->backingPixel, n);
+ swapl(&pRep->colormap, n);
+ swapl(&pRep->allEventMasks, n);
+ swapl(&pRep->yourEventMask, n);
+ swaps(&pRep->doNotPropagateMask, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SGetGeometryReply(ClientPtr pClient, int size, xGetGeometryReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->root, n);
+ swaps(&pRep->x, n);
+ swaps(&pRep->y, n);
+ swaps(&pRep->width, n);
+ swaps(&pRep->height, n);
+ swaps(&pRep->borderWidth, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SQueryTreeReply(ClientPtr pClient, int size, xQueryTreeReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->length, n);
+ swapl(&pRep->root, n);
+ swapl(&pRep->parent, n);
+ swaps(&pRep->nChildren, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SInternAtomReply(ClientPtr pClient, int size, xInternAtomReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->atom, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SGetAtomNameReply(ClientPtr pClient, int size, xGetAtomNameReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->length, n);
+ swaps(&pRep->nameLength, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+
+void
+SGetPropertyReply(ClientPtr pClient, int size, xGetPropertyReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->length, n);
+ swapl(&pRep->propertyType, n);
+ swapl(&pRep->bytesAfter, n);
+ swapl(&pRep->nItems, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SListPropertiesReply(ClientPtr pClient, int size, xListPropertiesReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->length, n);
+ swaps(&pRep->nProperties, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SGetSelectionOwnerReply(ClientPtr pClient, int size,
+ xGetSelectionOwnerReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->owner, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+
+void
+SQueryPointerReply(ClientPtr pClient, int size, xQueryPointerReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->root, n);
+ swapl(&pRep->child, n);
+ swaps(&pRep->rootX, n);
+ swaps(&pRep->rootY, n);
+ swaps(&pRep->winX, n);
+ swaps(&pRep->winY, n);
+ swaps(&pRep->mask, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+static void
+SwapTimecoord(xTimecoord* pCoord)
+{
+ char n;
+
+ swapl(&pCoord->time, n);
+ swaps(&pCoord->x, n);
+ swaps(&pCoord->y, n);
+}
+
+void
+SwapTimeCoordWrite(ClientPtr pClient, int size, xTimecoord *pRep)
+{
+ int i, n;
+ xTimecoord *pRepT;
+
+ n = size / sizeof(xTimecoord);
+ pRepT = pRep;
+ for(i = 0; i < n; i++)
+ {
+ SwapTimecoord(pRepT);
+ pRepT++;
+ }
+ (void)WriteToClient(pClient, size, (char *) pRep);
+
+}
+void
+SGetMotionEventsReply(ClientPtr pClient, int size, xGetMotionEventsReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->length, n);
+ swapl(&pRep->nEvents, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+STranslateCoordsReply(ClientPtr pClient, int size, xTranslateCoordsReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->child, n);
+ swaps(&pRep->dstX, n);
+ swaps(&pRep->dstY, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SGetInputFocusReply(ClientPtr pClient, int size, xGetInputFocusReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->focus, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+/* extra long reply */
+void
+SQueryKeymapReply(ClientPtr pClient, int size, xQueryKeymapReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->length, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+static void
+SwapCharInfo(xCharInfo *pInfo)
+{
+ char n;
+
+ swaps(&pInfo->leftSideBearing, n);
+ swaps(&pInfo->rightSideBearing, n);
+ swaps(&pInfo->characterWidth, n);
+ swaps(&pInfo->ascent, n);
+ swaps(&pInfo->descent, n);
+ swaps(&pInfo->attributes, n);
+}
+
+static void
+SwapFontInfo(xQueryFontReply *pr)
+{
+ char n;
+
+ swaps(&pr->minCharOrByte2, n);
+ swaps(&pr->maxCharOrByte2, n);
+ swaps(&pr->defaultChar, n);
+ swaps(&pr->nFontProps, n);
+ swaps(&pr->fontAscent, n);
+ swaps(&pr->fontDescent, n);
+ SwapCharInfo( &pr->minBounds);
+ SwapCharInfo( &pr->maxBounds);
+ swapl(&pr->nCharInfos, n);
+}
+
+static void
+SwapFont(xQueryFontReply *pr, Bool hasGlyphs)
+{
+ unsigned i;
+ xCharInfo * pxci;
+ unsigned nchars, nprops;
+ char *pby;
+ char n;
+
+ swaps(&pr->sequenceNumber, n);
+ swapl(&pr->length, n);
+ nchars = pr->nCharInfos;
+ nprops = pr->nFontProps;
+ SwapFontInfo(pr);
+ pby = (char *) &pr[1];
+ /* Font properties are an atom and either an int32 or a CARD32, so
+ * they are always 2 4 byte values */
+ for(i = 0; i < nprops; i++)
+ {
+ swapl(pby, n);
+ pby += 4;
+ swapl(pby, n);
+ pby += 4;
+ }
+ if (hasGlyphs)
+ {
+ pxci = (xCharInfo *)pby;
+ for(i = 0; i< nchars; i++, pxci++)
+ SwapCharInfo(pxci);
+ }
+}
+
+void
+SQueryFontReply(ClientPtr pClient, int size, xQueryFontReply *pRep)
+{
+ SwapFont(pRep, TRUE);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SQueryTextExtentsReply(ClientPtr pClient, int size, xQueryTextExtentsReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swaps(&pRep->fontAscent, n);
+ swaps(&pRep->fontDescent, n);
+ swaps(&pRep->overallAscent, n);
+ swaps(&pRep->overallDescent, n);
+ swapl(&pRep->overallWidth, n);
+ swapl(&pRep->overallLeft, n);
+ swapl(&pRep->overallRight, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SListFontsReply(ClientPtr pClient, int size, xListFontsReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->length, n);
+ swaps(&pRep->nFonts, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SListFontsWithInfoReply(ClientPtr pClient, int size,
+ xListFontsWithInfoReply *pRep)
+{
+ SwapFont((xQueryFontReply *)pRep, FALSE);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SGetFontPathReply(ClientPtr pClient, int size, xGetFontPathReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->length, n);
+ swaps(&pRep->nPaths, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SGetImageReply(ClientPtr pClient, int size, xGetImageReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->length, n);
+ swapl(&pRep->visual, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+ /* Fortunately, image doesn't need swapping */
+}
+
+void
+SListInstalledColormapsReply(ClientPtr pClient, int size,
+ xListInstalledColormapsReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->length, n);
+ swaps(&pRep->nColormaps, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SAllocColorReply(ClientPtr pClient, int size, xAllocColorReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swaps(&pRep->red, n);
+ swaps(&pRep->green, n);
+ swaps(&pRep->blue, n);
+ swapl(&pRep->pixel, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SAllocNamedColorReply(ClientPtr pClient, int size, xAllocNamedColorReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->pixel, n);
+ swaps(&pRep->exactRed, n);
+ swaps(&pRep->exactGreen, n);
+ swaps(&pRep->exactBlue, n);
+ swaps(&pRep->screenRed, n);
+ swaps(&pRep->screenGreen, n);
+ swaps(&pRep->screenBlue, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SAllocColorCellsReply(ClientPtr pClient, int size, xAllocColorCellsReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->length, n);
+ swaps(&pRep->nPixels, n);
+ swaps(&pRep->nMasks, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+
+void
+SAllocColorPlanesReply(ClientPtr pClient, int size, xAllocColorPlanesReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->length, n);
+ swaps(&pRep->nPixels, n);
+ swapl(&pRep->redMask, n);
+ swapl(&pRep->greenMask, n);
+ swapl(&pRep->blueMask, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+static void
+SwapRGB(xrgb *prgb)
+{
+ char n;
+
+ swaps(&prgb->red, n);
+ swaps(&prgb->green, n);
+ swaps(&prgb->blue, n);
+}
+
+void
+SQColorsExtend(ClientPtr pClient, int size, xrgb *prgb)
+{
+ int i, n;
+ xrgb *prgbT;
+
+ n = size / sizeof(xrgb);
+ prgbT = prgb;
+ for(i = 0; i < n; i++)
+ {
+ SwapRGB(prgbT);
+ prgbT++;
+ }
+ (void)WriteToClient(pClient, size, (char *) prgb);
+}
+
+void
+SQueryColorsReply(ClientPtr pClient, int size, xQueryColorsReply* pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->length, n);
+ swaps(&pRep->nColors, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SLookupColorReply(ClientPtr pClient, int size, xLookupColorReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swaps(&pRep->exactRed, n);
+ swaps(&pRep->exactGreen, n);
+ swaps(&pRep->exactBlue, n);
+ swaps(&pRep->screenRed, n);
+ swaps(&pRep->screenGreen, n);
+ swaps(&pRep->screenBlue, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SQueryBestSizeReply(ClientPtr pClient, int size, xQueryBestSizeReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swaps(&pRep->width, n);
+ swaps(&pRep->height, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SListExtensionsReply(ClientPtr pClient, int size, xListExtensionsReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->length, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SGetKeyboardMappingReply(ClientPtr pClient, int size,
+ xGetKeyboardMappingReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->length, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SGetPointerMappingReply(ClientPtr pClient, int size,
+ xGetPointerMappingReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->length, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SGetModifierMappingReply(ClientPtr pClient, int size,
+ xGetModifierMappingReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->length, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SGetKeyboardControlReply(ClientPtr pClient, int size, xGetKeyboardControlReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->length, n);
+ swapl(&pRep->ledMask, n);
+ swaps(&pRep->bellPitch, n);
+ swaps(&pRep->bellDuration, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SGetPointerControlReply(ClientPtr pClient, int size, xGetPointerControlReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swaps(&pRep->accelNumerator, n);
+ swaps(&pRep->accelDenominator, n);
+ swaps(&pRep->threshold, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SGetScreenSaverReply(ClientPtr pClient, int size, xGetScreenSaverReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swaps(&pRep->timeout, n);
+ swaps(&pRep->interval, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+void
+SLHostsExtend(ClientPtr pClient, int size, char *buf)
+{
+ char *bufT = buf;
+ char *endbuf = buf + size;
+ while (bufT < endbuf) {
+ xHostEntry *host = (xHostEntry *) bufT;
+ int len = host->length;
+ char n;
+ swaps (&host->length, n);
+ bufT += sizeof (xHostEntry) + pad_to_int32(len);
+ }
+ (void)WriteToClient (pClient, size, buf);
+}
+
+void
+SListHostsReply(ClientPtr pClient, int size, xListHostsReply *pRep)
+{
+ char n;
+
+ swaps(&pRep->sequenceNumber, n);
+ swapl(&pRep->length, n);
+ swaps(&pRep->nHosts, n);
+ (void)WriteToClient(pClient, size, (char *) pRep);
+}
+
+
+
+void
+SErrorEvent(xError *from, xError *to)
+{
+ to->type = X_Error;
+ to->errorCode = from->errorCode;
+ cpswaps(from->sequenceNumber, to->sequenceNumber);
+ cpswapl(from->resourceID, to->resourceID);
+ cpswaps(from->minorCode, to->minorCode);
+ to->majorCode = from->majorCode;
+}
+
+void
+SKeyButtonPtrEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ to->u.u.detail = from->u.u.detail;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.keyButtonPointer.time,
+ to->u.keyButtonPointer.time);
+ cpswapl(from->u.keyButtonPointer.root,
+ to->u.keyButtonPointer.root);
+ cpswapl(from->u.keyButtonPointer.event,
+ to->u.keyButtonPointer.event);
+ cpswapl(from->u.keyButtonPointer.child,
+ to->u.keyButtonPointer.child);
+ cpswaps(from->u.keyButtonPointer.rootX,
+ to->u.keyButtonPointer.rootX);
+ cpswaps(from->u.keyButtonPointer.rootY,
+ to->u.keyButtonPointer.rootY);
+ cpswaps(from->u.keyButtonPointer.eventX,
+ to->u.keyButtonPointer.eventX);
+ cpswaps(from->u.keyButtonPointer.eventY,
+ to->u.keyButtonPointer.eventY);
+ cpswaps(from->u.keyButtonPointer.state,
+ to->u.keyButtonPointer.state);
+ to->u.keyButtonPointer.sameScreen =
+ from->u.keyButtonPointer.sameScreen;
+}
+
+void
+SEnterLeaveEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ to->u.u.detail = from->u.u.detail;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.enterLeave.time, to->u.enterLeave.time);
+ cpswapl(from->u.enterLeave.root, to->u.enterLeave.root);
+ cpswapl(from->u.enterLeave.event, to->u.enterLeave.event);
+ cpswapl(from->u.enterLeave.child, to->u.enterLeave.child);
+ cpswaps(from->u.enterLeave.rootX, to->u.enterLeave.rootX);
+ cpswaps(from->u.enterLeave.rootY, to->u.enterLeave.rootY);
+ cpswaps(from->u.enterLeave.eventX, to->u.enterLeave.eventX);
+ cpswaps(from->u.enterLeave.eventY, to->u.enterLeave.eventY);
+ cpswaps(from->u.enterLeave.state, to->u.enterLeave.state);
+ to->u.enterLeave.mode = from->u.enterLeave.mode;
+ to->u.enterLeave.flags = from->u.enterLeave.flags;
+}
+
+void
+SFocusEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ to->u.u.detail = from->u.u.detail;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.focus.window, to->u.focus.window);
+ to->u.focus.mode = from->u.focus.mode;
+}
+
+void
+SExposeEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.expose.window, to->u.expose.window);
+ cpswaps(from->u.expose.x, to->u.expose.x);
+ cpswaps(from->u.expose.y, to->u.expose.y);
+ cpswaps(from->u.expose.width, to->u.expose.width);
+ cpswaps(from->u.expose.height, to->u.expose.height);
+ cpswaps(from->u.expose.count, to->u.expose.count);
+}
+
+void
+SGraphicsExposureEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.graphicsExposure.drawable,
+ to->u.graphicsExposure.drawable);
+ cpswaps(from->u.graphicsExposure.x,
+ to->u.graphicsExposure.x);
+ cpswaps(from->u.graphicsExposure.y,
+ to->u.graphicsExposure.y);
+ cpswaps(from->u.graphicsExposure.width,
+ to->u.graphicsExposure.width);
+ cpswaps(from->u.graphicsExposure.height,
+ to->u.graphicsExposure.height);
+ cpswaps(from->u.graphicsExposure.minorEvent,
+ to->u.graphicsExposure.minorEvent);
+ cpswaps(from->u.graphicsExposure.count,
+ to->u.graphicsExposure.count);
+ to->u.graphicsExposure.majorEvent =
+ from->u.graphicsExposure.majorEvent;
+}
+
+void
+SNoExposureEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.noExposure.drawable, to->u.noExposure.drawable);
+ cpswaps(from->u.noExposure.minorEvent, to->u.noExposure.minorEvent);
+ to->u.noExposure.majorEvent = from->u.noExposure.majorEvent;
+}
+
+void
+SVisibilityEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.visibility.window, to->u.visibility.window);
+ to->u.visibility.state = from->u.visibility.state;
+}
+
+void
+SCreateNotifyEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.createNotify.window, to->u.createNotify.window);
+ cpswapl(from->u.createNotify.parent, to->u.createNotify.parent);
+ cpswaps(from->u.createNotify.x, to->u.createNotify.x);
+ cpswaps(from->u.createNotify.y, to->u.createNotify.y);
+ cpswaps(from->u.createNotify.width, to->u.createNotify.width);
+ cpswaps(from->u.createNotify.height, to->u.createNotify.height);
+ cpswaps(from->u.createNotify.borderWidth,
+ to->u.createNotify.borderWidth);
+ to->u.createNotify.override = from->u.createNotify.override;
+}
+
+void
+SDestroyNotifyEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.destroyNotify.event, to->u.destroyNotify.event);
+ cpswapl(from->u.destroyNotify.window, to->u.destroyNotify.window);
+}
+
+void
+SUnmapNotifyEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.unmapNotify.event, to->u.unmapNotify.event);
+ cpswapl(from->u.unmapNotify.window, to->u.unmapNotify.window);
+ to->u.unmapNotify.fromConfigure = from->u.unmapNotify.fromConfigure;
+}
+
+void
+SMapNotifyEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.mapNotify.event, to->u.mapNotify.event);
+ cpswapl(from->u.mapNotify.window, to->u.mapNotify.window);
+ to->u.mapNotify.override = from->u.mapNotify.override;
+}
+
+void
+SMapRequestEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.mapRequest.parent, to->u.mapRequest.parent);
+ cpswapl(from->u.mapRequest.window, to->u.mapRequest.window);
+}
+
+void
+SReparentEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.reparent.event, to->u.reparent.event);
+ cpswapl(from->u.reparent.window, to->u.reparent.window);
+ cpswapl(from->u.reparent.parent, to->u.reparent.parent);
+ cpswaps(from->u.reparent.x, to->u.reparent.x);
+ cpswaps(from->u.reparent.y, to->u.reparent.y);
+ to->u.reparent.override = from->u.reparent.override;
+}
+
+void
+SConfigureNotifyEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.configureNotify.event,
+ to->u.configureNotify.event);
+ cpswapl(from->u.configureNotify.window,
+ to->u.configureNotify.window);
+ cpswapl(from->u.configureNotify.aboveSibling,
+ to->u.configureNotify.aboveSibling);
+ cpswaps(from->u.configureNotify.x, to->u.configureNotify.x);
+ cpswaps(from->u.configureNotify.y, to->u.configureNotify.y);
+ cpswaps(from->u.configureNotify.width, to->u.configureNotify.width);
+ cpswaps(from->u.configureNotify.height,
+ to->u.configureNotify.height);
+ cpswaps(from->u.configureNotify.borderWidth,
+ to->u.configureNotify.borderWidth);
+ to->u.configureNotify.override = from->u.configureNotify.override;
+}
+
+void
+SConfigureRequestEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ to->u.u.detail = from->u.u.detail; /* actually stack-mode */
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.configureRequest.parent,
+ to->u.configureRequest.parent);
+ cpswapl(from->u.configureRequest.window,
+ to->u.configureRequest.window);
+ cpswapl(from->u.configureRequest.sibling,
+ to->u.configureRequest.sibling);
+ cpswaps(from->u.configureRequest.x, to->u.configureRequest.x);
+ cpswaps(from->u.configureRequest.y, to->u.configureRequest.y);
+ cpswaps(from->u.configureRequest.width,
+ to->u.configureRequest.width);
+ cpswaps(from->u.configureRequest.height,
+ to->u.configureRequest.height);
+ cpswaps(from->u.configureRequest.borderWidth,
+ to->u.configureRequest.borderWidth);
+ cpswaps(from->u.configureRequest.valueMask,
+ to->u.configureRequest.valueMask);
+}
+
+
+void
+SGravityEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.gravity.event, to->u.gravity.event);
+ cpswapl(from->u.gravity.window, to->u.gravity.window);
+ cpswaps(from->u.gravity.x, to->u.gravity.x);
+ cpswaps(from->u.gravity.y, to->u.gravity.y);
+}
+
+void
+SResizeRequestEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.resizeRequest.window, to->u.resizeRequest.window);
+ cpswaps(from->u.resizeRequest.width, to->u.resizeRequest.width);
+ cpswaps(from->u.resizeRequest.height, to->u.resizeRequest.height);
+}
+
+void
+SCirculateEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ to->u.u.detail = from->u.u.detail;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.circulate.event, to->u.circulate.event);
+ cpswapl(from->u.circulate.window, to->u.circulate.window);
+ cpswapl(from->u.circulate.parent, to->u.circulate.parent);
+ to->u.circulate.place = from->u.circulate.place;
+}
+
+void
+SPropertyEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.property.window, to->u.property.window);
+ cpswapl(from->u.property.atom, to->u.property.atom);
+ cpswapl(from->u.property.time, to->u.property.time);
+ to->u.property.state = from->u.property.state;
+}
+
+void
+SSelectionClearEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.selectionClear.time, to->u.selectionClear.time);
+ cpswapl(from->u.selectionClear.window, to->u.selectionClear.window);
+ cpswapl(from->u.selectionClear.atom, to->u.selectionClear.atom);
+}
+
+void
+SSelectionRequestEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.selectionRequest.time, to->u.selectionRequest.time);
+ cpswapl(from->u.selectionRequest.owner,
+ to->u.selectionRequest.owner);
+ cpswapl(from->u.selectionRequest.requestor,
+ to->u.selectionRequest.requestor);
+ cpswapl(from->u.selectionRequest.selection,
+ to->u.selectionRequest.selection);
+ cpswapl(from->u.selectionRequest.target,
+ to->u.selectionRequest.target);
+ cpswapl(from->u.selectionRequest.property,
+ to->u.selectionRequest.property);
+}
+
+void
+SSelectionNotifyEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.selectionNotify.time, to->u.selectionNotify.time);
+ cpswapl(from->u.selectionNotify.requestor,
+ to->u.selectionNotify.requestor);
+ cpswapl(from->u.selectionNotify.selection,
+ to->u.selectionNotify.selection);
+ cpswapl(from->u.selectionNotify.target,
+ to->u.selectionNotify.target);
+ cpswapl(from->u.selectionNotify.property,
+ to->u.selectionNotify.property);
+}
+
+void
+SColormapEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.colormap.window, to->u.colormap.window);
+ cpswapl(from->u.colormap.colormap, to->u.colormap.colormap);
+ to->u.colormap.new = from->u.colormap.new;
+ to->u.colormap.state = from->u.colormap.state;
+}
+
+void
+SMappingEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ to->u.mappingNotify.request = from->u.mappingNotify.request;
+ to->u.mappingNotify.firstKeyCode =
+ from->u.mappingNotify.firstKeyCode;
+ to->u.mappingNotify.count = from->u.mappingNotify.count;
+}
+
+void
+SClientMessageEvent(xEvent *from, xEvent *to)
+{
+ to->u.u.type = from->u.u.type;
+ to->u.u.detail = from->u.u.detail; /* actually format */
+ cpswaps(from->u.u.sequenceNumber, to->u.u.sequenceNumber);
+ cpswapl(from->u.clientMessage.window, to->u.clientMessage.window);
+ cpswapl(from->u.clientMessage.u.l.type,
+ to->u.clientMessage.u.l.type);
+ switch (from->u.u.detail) {
+ case 8:
+ memmove(to->u.clientMessage.u.b.bytes,
+ from->u.clientMessage.u.b.bytes,20);
+ break;
+ case 16:
+ cpswaps(from->u.clientMessage.u.s.shorts0,
+ to->u.clientMessage.u.s.shorts0);
+ cpswaps(from->u.clientMessage.u.s.shorts1,
+ to->u.clientMessage.u.s.shorts1);
+ cpswaps(from->u.clientMessage.u.s.shorts2,
+ to->u.clientMessage.u.s.shorts2);
+ cpswaps(from->u.clientMessage.u.s.shorts3,
+ to->u.clientMessage.u.s.shorts3);
+ cpswaps(from->u.clientMessage.u.s.shorts4,
+ to->u.clientMessage.u.s.shorts4);
+ cpswaps(from->u.clientMessage.u.s.shorts5,
+ to->u.clientMessage.u.s.shorts5);
+ cpswaps(from->u.clientMessage.u.s.shorts6,
+ to->u.clientMessage.u.s.shorts6);
+ cpswaps(from->u.clientMessage.u.s.shorts7,
+ to->u.clientMessage.u.s.shorts7);
+ cpswaps(from->u.clientMessage.u.s.shorts8,
+ to->u.clientMessage.u.s.shorts8);
+ cpswaps(from->u.clientMessage.u.s.shorts9,
+ to->u.clientMessage.u.s.shorts9);
+ break;
+ case 32:
+ cpswapl(from->u.clientMessage.u.l.longs0,
+ to->u.clientMessage.u.l.longs0);
+ cpswapl(from->u.clientMessage.u.l.longs1,
+ to->u.clientMessage.u.l.longs1);
+ cpswapl(from->u.clientMessage.u.l.longs2,
+ to->u.clientMessage.u.l.longs2);
+ cpswapl(from->u.clientMessage.u.l.longs3,
+ to->u.clientMessage.u.l.longs3);
+ cpswapl(from->u.clientMessage.u.l.longs4,
+ to->u.clientMessage.u.l.longs4);
+ break;
+ }
+}
+
+void
+SKeymapNotifyEvent(xEvent *from, xEvent *to)
+{
+ /* Keymap notify events are special; they have no
+ sequence number field, and contain entirely 8-bit data */
+ *to = *from;
+}
+
+static void
+SwapConnSetup(xConnSetup *pConnSetup, xConnSetup *pConnSetupT)
+{
+ cpswapl(pConnSetup->release, pConnSetupT->release);
+ cpswapl(pConnSetup->ridBase, pConnSetupT->ridBase);
+ cpswapl(pConnSetup->ridMask, pConnSetupT->ridMask);
+ cpswapl(pConnSetup->motionBufferSize, pConnSetupT->motionBufferSize);
+ cpswaps(pConnSetup->nbytesVendor, pConnSetupT->nbytesVendor);
+ cpswaps(pConnSetup->maxRequestSize, pConnSetupT->maxRequestSize);
+ pConnSetupT->minKeyCode = pConnSetup->minKeyCode;
+ pConnSetupT->maxKeyCode = pConnSetup->maxKeyCode;
+ pConnSetupT->numRoots = pConnSetup->numRoots;
+ pConnSetupT->numFormats = pConnSetup->numFormats;
+ pConnSetupT->imageByteOrder = pConnSetup->imageByteOrder;
+ pConnSetupT->bitmapBitOrder = pConnSetup->bitmapBitOrder;
+ pConnSetupT->bitmapScanlineUnit = pConnSetup->bitmapScanlineUnit;
+ pConnSetupT->bitmapScanlinePad = pConnSetup->bitmapScanlinePad;
+}
+
+static void
+SwapWinRoot(xWindowRoot *pRoot, xWindowRoot *pRootT)
+{
+ cpswapl(pRoot->windowId, pRootT->windowId);
+ cpswapl(pRoot->defaultColormap, pRootT->defaultColormap);
+ cpswapl(pRoot->whitePixel, pRootT->whitePixel);
+ cpswapl(pRoot->blackPixel, pRootT->blackPixel);
+ cpswapl(pRoot->currentInputMask, pRootT->currentInputMask);
+ cpswaps(pRoot->pixWidth, pRootT->pixWidth);
+ cpswaps(pRoot->pixHeight, pRootT->pixHeight);
+ cpswaps(pRoot->mmWidth, pRootT->mmWidth);
+ cpswaps(pRoot->mmHeight, pRootT->mmHeight);
+ cpswaps(pRoot->minInstalledMaps, pRootT->minInstalledMaps);
+ cpswaps(pRoot->maxInstalledMaps, pRootT->maxInstalledMaps);
+ cpswapl(pRoot->rootVisualID, pRootT->rootVisualID);
+ pRootT->backingStore = pRoot->backingStore;
+ pRootT->saveUnders = pRoot->saveUnders;
+ pRootT->rootDepth = pRoot->rootDepth;
+ pRootT->nDepths = pRoot->nDepths;
+}
+
+static void
+SwapVisual(xVisualType *pVis, xVisualType *pVisT)
+{
+ cpswapl(pVis->visualID, pVisT->visualID);
+ pVisT->class = pVis->class;
+ pVisT->bitsPerRGB = pVis->bitsPerRGB;
+ cpswaps(pVis->colormapEntries, pVisT->colormapEntries);
+ cpswapl(pVis->redMask, pVisT->redMask);
+ cpswapl(pVis->greenMask, pVisT->greenMask);
+ cpswapl(pVis->blueMask, pVisT->blueMask);
+}
+
+void
+SwapConnSetupInfo(
+ char *pInfo,
+ char *pInfoT
+)
+{
+ int i, j, k;
+ xConnSetup *pConnSetup = (xConnSetup *)pInfo;
+ xDepth *depth;
+ xWindowRoot *root;
+
+ SwapConnSetup(pConnSetup, (xConnSetup *)pInfoT);
+ pInfo += sizeof(xConnSetup);
+ pInfoT += sizeof(xConnSetup);
+
+ /* Copy the vendor string */
+ i = pad_to_int32(pConnSetup->nbytesVendor);
+ memcpy(pInfoT, pInfo, i);
+ pInfo += i;
+ pInfoT += i;
+
+ /* The Pixmap formats don't need to be swapped, just copied. */
+ i = sizeof(xPixmapFormat) * pConnSetup->numFormats;
+ memcpy(pInfoT, pInfo, i);
+ pInfo += i;
+ pInfoT += i;
+
+ for(i = 0; i < pConnSetup->numRoots; i++)
+ {
+ root = (xWindowRoot*)pInfo;
+ SwapWinRoot(root, (xWindowRoot *)pInfoT);
+ pInfo += sizeof(xWindowRoot);
+ pInfoT += sizeof(xWindowRoot);
+
+ for(j = 0; j < root->nDepths; j++)
+ {
+ depth = (xDepth*)pInfo;
+ ((xDepth *)pInfoT)->depth = depth->depth;
+ cpswaps(depth->nVisuals, ((xDepth *)pInfoT)->nVisuals);
+ pInfo += sizeof(xDepth);
+ pInfoT += sizeof(xDepth);
+ for(k = 0; k < depth->nVisuals; k++)
+ {
+ SwapVisual((xVisualType *)pInfo, (xVisualType *)pInfoT);
+ pInfo += sizeof(xVisualType);
+ pInfoT += sizeof(xVisualType);
+ }
+ }
+ }
+}
+
+void
+WriteSConnectionInfo(ClientPtr pClient, unsigned long size, char *pInfo)
+{
+ char *pInfoTBase;
+
+ pInfoTBase = malloc(size);
+ if (!pInfoTBase)
+ {
+ pClient->noClientException = -1;
+ return;
+ }
+ SwapConnSetupInfo(pInfo, pInfoTBase);
+ (void)WriteToClient(pClient, (int)size, (char *) pInfoTBase);
+ free(pInfoTBase);
+}
+
+void
+SwapConnSetupPrefix(xConnSetupPrefix *pcspFrom, xConnSetupPrefix *pcspTo)
+{
+ pcspTo->success = pcspFrom->success;
+ pcspTo->lengthReason = pcspFrom->lengthReason;
+ cpswaps(pcspFrom->majorVersion, pcspTo->majorVersion);
+ cpswaps(pcspFrom->minorVersion, pcspTo->minorVersion);
+ cpswaps(pcspFrom->length, pcspTo->length);
+}
+
+void
+WriteSConnSetupPrefix(ClientPtr pClient, xConnSetupPrefix *pcsp)
+{
+ xConnSetupPrefix cspT;
+
+ SwapConnSetupPrefix(pcsp, &cspT);
+ (void)WriteToClient(pClient, sizeof(cspT), (char *) &cspT);
+}
+
+/*
+ * Dummy entry for ReplySwapVector[]
+ */
+
+void
+ReplyNotSwappd(
+ ClientPtr pClient ,
+ int size ,
+ void * pbuf
+ )
+{
+ FatalError("Not implemented");
+}
+
diff --git a/dix/swapreq.c b/dix/swapreq.c
new file mode 100644
index 0000000..2e34711
--- /dev/null
+++ b/dix/swapreq.c
@@ -0,0 +1,1099 @@
+/************************************************************
+
+Copyright 1987, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+********************************************************/
+
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include <X11/Xprotostr.h>
+#include "misc.h"
+#include "dixstruct.h"
+#include "extnsionst.h" /* for SendEvent */
+#include "swapreq.h"
+
+/* Thanks to Jack Palevich for testing and subsequently rewriting all this */
+
+/* Byte swap a list of longs */
+void
+SwapLongs (CARD32 *list, unsigned long count)
+{
+ char n;
+
+ while (count >= 8) {
+ swapl(list+0, n);
+ swapl(list+1, n);
+ swapl(list+2, n);
+ swapl(list+3, n);
+ swapl(list+4, n);
+ swapl(list+5, n);
+ swapl(list+6, n);
+ swapl(list+7, n);
+ list += 8;
+ count -= 8;
+ }
+ if (count != 0) {
+ do {
+ swapl(list, n);
+ list++;
+ } while (--count != 0);
+ }
+}
+
+/* Byte swap a list of shorts */
+void
+SwapShorts (short *list, unsigned long count)
+{
+ char n;
+
+ while (count >= 16) {
+ swaps(list+0, n);
+ swaps(list+1, n);
+ swaps(list+2, n);
+ swaps(list+3, n);
+ swaps(list+4, n);
+ swaps(list+5, n);
+ swaps(list+6, n);
+ swaps(list+7, n);
+ swaps(list+8, n);
+ swaps(list+9, n);
+ swaps(list+10, n);
+ swaps(list+11, n);
+ swaps(list+12, n);
+ swaps(list+13, n);
+ swaps(list+14, n);
+ swaps(list+15, n);
+ list += 16;
+ count -= 16;
+ }
+ if (count != 0) {
+ do {
+ swaps(list, n);
+ list++;
+ } while (--count != 0);
+ }
+}
+
+/* The following is used for all requests that have
+ no fields to be swapped (except "length") */
+int
+SProcSimpleReq(ClientPtr client)
+{
+ char n;
+
+ REQUEST(xReq);
+ swaps(&stuff->length, n);
+ return(*ProcVector[stuff->reqType])(client);
+}
+
+/* The following is used for all requests that have
+ only a single 32-bit field to be swapped, coming
+ right after the "length" field */
+int
+SProcResourceReq(ClientPtr client)
+{
+ char n;
+
+ REQUEST(xResourceReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xResourceReq); /* not EXACT */
+ swapl(&stuff->id, n);
+ return(*ProcVector[stuff->reqType])(client);
+}
+
+int
+SProcCreateWindow(ClientPtr client)
+{
+ char n;
+
+ REQUEST(xCreateWindowReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xCreateWindowReq);
+ swapl(&stuff->wid, n);
+ swapl(&stuff->parent, n);
+ swaps(&stuff->x, n);
+ swaps(&stuff->y, n);
+ swaps(&stuff->width, n);
+ swaps(&stuff->height, n);
+ swaps(&stuff->borderWidth, n);
+ swaps(&stuff->class, n);
+ swapl(&stuff->visual, n);
+ swapl(&stuff->mask, n);
+ SwapRestL(stuff);
+ return((* ProcVector[X_CreateWindow])(client));
+}
+
+int
+SProcChangeWindowAttributes(ClientPtr client)
+{
+ char n;
+
+ REQUEST(xChangeWindowAttributesReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xChangeWindowAttributesReq);
+ swapl(&stuff->window, n);
+ swapl(&stuff->valueMask, n);
+ SwapRestL(stuff);
+ return((* ProcVector[X_ChangeWindowAttributes])(client));
+}
+
+int
+SProcReparentWindow(ClientPtr client)
+{
+ char n;
+ REQUEST(xReparentWindowReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xReparentWindowReq);
+ swapl(&stuff->window, n);
+ swapl(&stuff->parent, n);
+ swaps(&stuff->x, n);
+ swaps(&stuff->y, n);
+ return((* ProcVector[X_ReparentWindow])(client));
+}
+
+int
+SProcConfigureWindow(ClientPtr client)
+{
+ char n;
+ REQUEST(xConfigureWindowReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xConfigureWindowReq);
+ swapl(&stuff->window, n);
+ swaps(&stuff->mask, n);
+ SwapRestL(stuff);
+ return((* ProcVector[X_ConfigureWindow])(client));
+
+}
+
+
+int
+SProcInternAtom(ClientPtr client)
+{
+ char n;
+ REQUEST(xInternAtomReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xInternAtomReq);
+ swaps(&stuff->nbytes, n);
+ return((* ProcVector[X_InternAtom])(client));
+}
+
+int
+SProcChangeProperty(ClientPtr client)
+{
+ char n;
+ REQUEST(xChangePropertyReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xChangePropertyReq);
+ swapl(&stuff->window, n);
+ swapl(&stuff->property, n);
+ swapl(&stuff->type, n);
+ swapl(&stuff->nUnits, n);
+ switch ( stuff->format ) {
+ case 8 :
+ break;
+ case 16:
+ SwapRestS(stuff);
+ break;
+ case 32:
+ SwapRestL(stuff);
+ break;
+ }
+ return((* ProcVector[X_ChangeProperty])(client));
+}
+
+int
+SProcDeleteProperty(ClientPtr client)
+{
+ char n;
+ REQUEST(xDeletePropertyReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xDeletePropertyReq);
+ swapl(&stuff->window, n);
+ swapl(&stuff->property, n);
+ return((* ProcVector[X_DeleteProperty])(client));
+
+}
+
+int
+SProcGetProperty(ClientPtr client)
+{
+ char n;
+ REQUEST(xGetPropertyReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xGetPropertyReq);
+ swapl(&stuff->window, n);
+ swapl(&stuff->property, n);
+ swapl(&stuff->type, n);
+ swapl(&stuff->longOffset, n);
+ swapl(&stuff->longLength, n);
+ return((* ProcVector[X_GetProperty])(client));
+}
+
+int
+SProcSetSelectionOwner(ClientPtr client)
+{
+ char n;
+ REQUEST(xSetSelectionOwnerReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xSetSelectionOwnerReq);
+ swapl(&stuff->window, n);
+ swapl(&stuff->selection, n);
+ swapl(&stuff->time, n);
+ return((* ProcVector[X_SetSelectionOwner])(client));
+}
+
+int
+SProcConvertSelection(ClientPtr client)
+{
+ char n;
+ REQUEST(xConvertSelectionReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xConvertSelectionReq);
+ swapl(&stuff->requestor, n);
+ swapl(&stuff->selection, n);
+ swapl(&stuff->target, n);
+ swapl(&stuff->property, n);
+ swapl(&stuff->time, n);
+ return((* ProcVector[X_ConvertSelection])(client));
+}
+
+int
+SProcSendEvent(ClientPtr client)
+{
+ char n;
+ xEvent eventT;
+ EventSwapPtr proc;
+ REQUEST(xSendEventReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xSendEventReq);
+ swapl(&stuff->destination, n);
+ swapl(&stuff->eventMask, n);
+
+ /* Swap event */
+ proc = EventSwapVector[stuff->event.u.u.type & 0177];
+ if (!proc || proc == NotImplemented) /* no swapping proc; invalid event type? */
+ return BadValue;
+ (*proc)(&stuff->event, &eventT);
+ stuff->event = eventT;
+
+ return((* ProcVector[X_SendEvent])(client));
+}
+
+int
+SProcGrabPointer(ClientPtr client)
+{
+ char n;
+ REQUEST(xGrabPointerReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xGrabPointerReq);
+ swapl(&stuff->grabWindow, n);
+ swaps(&stuff->eventMask, n);
+ swapl(&stuff->confineTo, n);
+ swapl(&stuff->cursor, n);
+ swapl(&stuff->time, n);
+ return((* ProcVector[X_GrabPointer])(client));
+}
+
+int
+SProcGrabButton(ClientPtr client)
+{
+ char n;
+ REQUEST(xGrabButtonReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xGrabButtonReq);
+ swapl(&stuff->grabWindow, n);
+ swaps(&stuff->eventMask, n);
+ swapl(&stuff->confineTo, n);
+ swapl(&stuff->cursor, n);
+ swaps(&stuff->modifiers, n);
+ return((* ProcVector[X_GrabButton])(client));
+}
+
+int
+SProcUngrabButton(ClientPtr client)
+{
+ char n;
+ REQUEST(xUngrabButtonReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xUngrabButtonReq);
+ swapl(&stuff->grabWindow, n);
+ swaps(&stuff->modifiers, n);
+ return((* ProcVector[X_UngrabButton])(client));
+}
+
+int
+SProcChangeActivePointerGrab(ClientPtr client)
+{
+ char n;
+ REQUEST(xChangeActivePointerGrabReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xChangeActivePointerGrabReq);
+ swapl(&stuff->cursor, n);
+ swapl(&stuff->time, n);
+ swaps(&stuff->eventMask, n);
+ return((* ProcVector[X_ChangeActivePointerGrab])(client));
+}
+
+int
+SProcGrabKeyboard(ClientPtr client)
+{
+ char n;
+ REQUEST(xGrabKeyboardReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xGrabKeyboardReq);
+ swapl(&stuff->grabWindow, n);
+ swapl(&stuff->time, n);
+ return((* ProcVector[X_GrabKeyboard])(client));
+}
+
+int
+SProcGrabKey(ClientPtr client)
+{
+ char n;
+ REQUEST(xGrabKeyReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xGrabKeyReq);
+ swapl(&stuff->grabWindow, n);
+ swaps(&stuff->modifiers, n);
+ return((* ProcVector[X_GrabKey])(client));
+}
+
+int
+SProcUngrabKey(ClientPtr client)
+{
+ char n;
+ REQUEST(xUngrabKeyReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xUngrabKeyReq);
+ swapl(&stuff->grabWindow, n);
+ swaps(&stuff->modifiers, n);
+ return((* ProcVector[X_UngrabKey])(client));
+}
+
+int
+SProcGetMotionEvents(ClientPtr client)
+{
+ char n;
+ REQUEST(xGetMotionEventsReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xGetMotionEventsReq);
+ swapl(&stuff->window, n);
+ swapl(&stuff->start, n);
+ swapl(&stuff->stop, n);
+ return((* ProcVector[X_GetMotionEvents])(client));
+}
+
+int
+SProcTranslateCoords(ClientPtr client)
+{
+ char n;
+ REQUEST(xTranslateCoordsReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xTranslateCoordsReq);
+ swapl(&stuff->srcWid, n);
+ swapl(&stuff->dstWid, n);
+ swaps(&stuff->srcX, n);
+ swaps(&stuff->srcY, n);
+ return((* ProcVector[X_TranslateCoords])(client));
+}
+
+int
+SProcWarpPointer(ClientPtr client)
+{
+ char n;
+ REQUEST(xWarpPointerReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xWarpPointerReq);
+ swapl(&stuff->srcWid, n);
+ swapl(&stuff->dstWid, n);
+ swaps(&stuff->srcX, n);
+ swaps(&stuff->srcY, n);
+ swaps(&stuff->srcWidth, n);
+ swaps(&stuff->srcHeight, n);
+ swaps(&stuff->dstX, n);
+ swaps(&stuff->dstY, n);
+ return((* ProcVector[X_WarpPointer])(client));
+}
+
+int
+SProcSetInputFocus(ClientPtr client)
+{
+ char n;
+ REQUEST(xSetInputFocusReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xSetInputFocusReq);
+ swapl(&stuff->focus, n);
+ swapl(&stuff->time, n);
+ return((* ProcVector[X_SetInputFocus])(client));
+}
+
+int
+SProcOpenFont(ClientPtr client)
+{
+ char n;
+ REQUEST(xOpenFontReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xOpenFontReq);
+ swapl(&stuff->fid, n);
+ swaps(&stuff->nbytes, n);
+ return((* ProcVector[X_OpenFont])(client));
+}
+
+int
+SProcListFonts(ClientPtr client)
+{
+ char n;
+ REQUEST(xListFontsReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xListFontsReq);
+ swaps(&stuff->maxNames, n);
+ swaps(&stuff->nbytes, n);
+ return((* ProcVector[X_ListFonts])(client));
+}
+
+int
+SProcListFontsWithInfo(ClientPtr client)
+{
+ char n;
+ REQUEST(xListFontsWithInfoReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xListFontsWithInfoReq);
+ swaps(&stuff->maxNames, n);
+ swaps(&stuff->nbytes, n);
+ return((* ProcVector[X_ListFontsWithInfo])(client));
+}
+
+int
+SProcSetFontPath(ClientPtr client)
+{
+ char n;
+ REQUEST(xSetFontPathReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xSetFontPathReq);
+ swaps(&stuff->nFonts, n);
+ return((* ProcVector[X_SetFontPath])(client));
+}
+
+int
+SProcCreatePixmap(ClientPtr client)
+{
+ char n;
+ REQUEST(xCreatePixmapReq);
+
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xCreatePixmapReq);
+ swapl(&stuff->pid, n);
+ swapl(&stuff->drawable, n);
+ swaps(&stuff->width, n);
+ swaps(&stuff->height, n);
+ return((* ProcVector[X_CreatePixmap])(client));
+}
+
+int
+SProcCreateGC(ClientPtr client)
+{
+ char n;
+ REQUEST(xCreateGCReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xCreateGCReq);
+ swapl(&stuff->gc, n);
+ swapl(&stuff->drawable, n);
+ swapl(&stuff->mask, n);
+ SwapRestL(stuff);
+ return((* ProcVector[X_CreateGC])(client));
+}
+
+int
+SProcChangeGC(ClientPtr client)
+{
+ char n;
+ REQUEST(xChangeGCReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xChangeGCReq);
+ swapl(&stuff->gc, n);
+ swapl(&stuff->mask, n);
+ SwapRestL(stuff);
+ return((* ProcVector[X_ChangeGC])(client));
+}
+
+int
+SProcCopyGC(ClientPtr client)
+{
+ char n;
+ REQUEST(xCopyGCReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xCopyGCReq);
+ swapl(&stuff->srcGC, n);
+ swapl(&stuff->dstGC, n);
+ swapl(&stuff->mask, n);
+ return((* ProcVector[X_CopyGC])(client));
+}
+
+int
+SProcSetDashes(ClientPtr client)
+{
+ char n;
+ REQUEST(xSetDashesReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xSetDashesReq);
+ swapl(&stuff->gc, n);
+ swaps(&stuff->dashOffset, n);
+ swaps(&stuff->nDashes, n);
+ return((* ProcVector[X_SetDashes])(client));
+
+}
+
+int
+SProcSetClipRectangles(ClientPtr client)
+{
+ char n;
+ REQUEST(xSetClipRectanglesReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xSetClipRectanglesReq);
+ swapl(&stuff->gc, n);
+ swaps(&stuff->xOrigin, n);
+ swaps(&stuff->yOrigin, n);
+ SwapRestS(stuff);
+ return((* ProcVector[X_SetClipRectangles])(client));
+}
+
+int
+SProcClearToBackground(ClientPtr client)
+{
+ char n;
+ REQUEST(xClearAreaReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xClearAreaReq);
+ swapl(&stuff->window, n);
+ swaps(&stuff->x, n);
+ swaps(&stuff->y, n);
+ swaps(&stuff->width, n);
+ swaps(&stuff->height, n);
+ return((* ProcVector[X_ClearArea])(client));
+}
+
+int
+SProcCopyArea(ClientPtr client)
+{
+ char n;
+ REQUEST(xCopyAreaReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xCopyAreaReq);
+ swapl(&stuff->srcDrawable, n);
+ swapl(&stuff->dstDrawable, n);
+ swapl(&stuff->gc, n);
+ swaps(&stuff->srcX, n);
+ swaps(&stuff->srcY, n);
+ swaps(&stuff->dstX, n);
+ swaps(&stuff->dstY, n);
+ swaps(&stuff->width, n);
+ swaps(&stuff->height, n);
+ return((* ProcVector[X_CopyArea])(client));
+}
+
+int
+SProcCopyPlane(ClientPtr client)
+{
+ char n;
+ REQUEST(xCopyPlaneReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xCopyPlaneReq);
+ swapl(&stuff->srcDrawable, n);
+ swapl(&stuff->dstDrawable, n);
+ swapl(&stuff->gc, n);
+ swaps(&stuff->srcX, n);
+ swaps(&stuff->srcY, n);
+ swaps(&stuff->dstX, n);
+ swaps(&stuff->dstY, n);
+ swaps(&stuff->width, n);
+ swaps(&stuff->height, n);
+ swapl(&stuff->bitPlane, n);
+ return((* ProcVector[X_CopyPlane])(client));
+}
+
+/* The following routine is used for all Poly drawing requests
+ (except FillPoly, which uses a different request format) */
+int
+SProcPoly(ClientPtr client)
+{
+ char n;
+
+ REQUEST(xPolyPointReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xPolyPointReq);
+ swapl(&stuff->drawable, n);
+ swapl(&stuff->gc, n);
+ SwapRestS(stuff);
+ return((* ProcVector[stuff->reqType])(client));
+}
+
+/* cannot use SProcPoly for this one, because xFillPolyReq
+ is longer than xPolyPointReq, and we don't want to swap
+ the difference as shorts! */
+int
+SProcFillPoly(ClientPtr client)
+{
+ char n;
+
+ REQUEST(xFillPolyReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xFillPolyReq);
+ swapl(&stuff->drawable, n);
+ swapl(&stuff->gc, n);
+ SwapRestS(stuff);
+ return((* ProcVector[X_FillPoly])(client));
+}
+
+int
+SProcPutImage(ClientPtr client)
+{
+ char n;
+ REQUEST(xPutImageReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xPutImageReq);
+ swapl(&stuff->drawable, n);
+ swapl(&stuff->gc, n);
+ swaps(&stuff->width, n);
+ swaps(&stuff->height, n);
+ swaps(&stuff->dstX, n);
+ swaps(&stuff->dstY, n);
+ /* Image should already be swapped */
+ return((* ProcVector[X_PutImage])(client));
+
+}
+
+int
+SProcGetImage(ClientPtr client)
+{
+ char n;
+ REQUEST(xGetImageReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xGetImageReq);
+ swapl(&stuff->drawable, n);
+ swaps(&stuff->x, n);
+ swaps(&stuff->y, n);
+ swaps(&stuff->width, n);
+ swaps(&stuff->height, n);
+ swapl(&stuff->planeMask, n);
+ return((* ProcVector[X_GetImage])(client));
+}
+
+/* ProcPolyText used for both PolyText8 and PolyText16 */
+
+int
+SProcPolyText(ClientPtr client)
+{
+ char n;
+ REQUEST(xPolyTextReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xPolyTextReq);
+ swapl(&stuff->drawable, n);
+ swapl(&stuff->gc, n);
+ swaps(&stuff->x, n);
+ swaps(&stuff->y, n);
+ return((* ProcVector[stuff->reqType])(client));
+}
+
+/* ProcImageText used for both ImageText8 and ImageText16 */
+
+int
+SProcImageText(ClientPtr client)
+{
+ char n;
+ REQUEST(xImageTextReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xImageTextReq);
+ swapl(&stuff->drawable, n);
+ swapl(&stuff->gc, n);
+ swaps(&stuff->x, n);
+ swaps(&stuff->y, n);
+ return((* ProcVector[stuff->reqType])(client));
+}
+
+int
+SProcCreateColormap(ClientPtr client)
+{
+ char n;
+ REQUEST(xCreateColormapReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xCreateColormapReq);
+ swapl(&stuff->mid, n);
+ swapl(&stuff->window, n);
+ swapl(&stuff->visual, n);
+ return((* ProcVector[X_CreateColormap])(client));
+}
+
+
+int
+SProcCopyColormapAndFree(ClientPtr client)
+{
+ char n;
+ REQUEST(xCopyColormapAndFreeReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xCopyColormapAndFreeReq);
+ swapl(&stuff->mid, n);
+ swapl(&stuff->srcCmap, n);
+ return((* ProcVector[X_CopyColormapAndFree])(client));
+
+}
+
+int
+SProcAllocColor(ClientPtr client)
+{
+ char n;
+ REQUEST(xAllocColorReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xAllocColorReq);
+ swapl(&stuff->cmap, n);
+ swaps(&stuff->red, n);
+ swaps(&stuff->green, n);
+ swaps(&stuff->blue, n);
+ return((* ProcVector[X_AllocColor])(client));
+}
+
+int
+SProcAllocNamedColor(ClientPtr client)
+{
+ char n;
+
+ REQUEST(xAllocNamedColorReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xAllocNamedColorReq);
+ swapl(&stuff->cmap, n);
+ swaps(&stuff->nbytes, n);
+ return((* ProcVector[X_AllocNamedColor])(client));
+}
+
+int
+SProcAllocColorCells(ClientPtr client)
+{
+ char n;
+ REQUEST(xAllocColorCellsReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xAllocColorCellsReq);
+ swapl(&stuff->cmap, n);
+ swaps(&stuff->colors, n);
+ swaps(&stuff->planes, n);
+ return((* ProcVector[X_AllocColorCells])(client));
+}
+
+int
+SProcAllocColorPlanes(ClientPtr client)
+{
+ char n;
+ REQUEST(xAllocColorPlanesReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xAllocColorPlanesReq);
+ swapl(&stuff->cmap, n);
+ swaps(&stuff->colors, n);
+ swaps(&stuff->red, n);
+ swaps(&stuff->green, n);
+ swaps(&stuff->blue, n);
+ return((* ProcVector[X_AllocColorPlanes])(client));
+}
+
+int
+SProcFreeColors(ClientPtr client)
+{
+ char n;
+ REQUEST(xFreeColorsReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xFreeColorsReq);
+ swapl(&stuff->cmap, n);
+ swapl(&stuff->planeMask, n);
+ SwapRestL(stuff);
+ return((* ProcVector[X_FreeColors])(client));
+
+}
+
+void
+SwapColorItem(xColorItem *pItem)
+{
+ char n;
+
+ swapl(&pItem->pixel, n);
+ swaps(&pItem->red, n);
+ swaps(&pItem->green, n);
+ swaps(&pItem->blue, n);
+}
+
+int
+SProcStoreColors(ClientPtr client)
+{
+ char n;
+ long count;
+ xColorItem *pItem;
+
+ REQUEST(xStoreColorsReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xStoreColorsReq);
+ swapl(&stuff->cmap, n);
+ pItem = (xColorItem *) &stuff[1];
+ for(count = LengthRestB(stuff)/sizeof(xColorItem); --count >= 0; )
+ SwapColorItem(pItem++);
+ return((* ProcVector[X_StoreColors])(client));
+}
+
+int
+SProcStoreNamedColor (ClientPtr client)
+{
+ char n;
+ REQUEST(xStoreNamedColorReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xStoreNamedColorReq);
+ swapl(&stuff->cmap, n);
+ swapl(&stuff->pixel, n);
+ swaps(&stuff->nbytes, n);
+ return((* ProcVector[X_StoreNamedColor])(client));
+}
+
+int
+SProcQueryColors (ClientPtr client)
+{
+ char n;
+ REQUEST(xQueryColorsReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xQueryColorsReq);
+ swapl(&stuff->cmap, n);
+ SwapRestL(stuff);
+ return((* ProcVector[X_QueryColors])(client));
+}
+
+int
+SProcLookupColor (ClientPtr client)
+{
+ char n;
+ REQUEST(xLookupColorReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xLookupColorReq);
+ swapl(&stuff->cmap, n);
+ swaps(&stuff->nbytes, n);
+ return((* ProcVector[X_LookupColor])(client));
+}
+
+int
+SProcCreateCursor (ClientPtr client)
+{
+ char n;
+ REQUEST(xCreateCursorReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xCreateCursorReq);
+ swapl(&stuff->cid, n);
+ swapl(&stuff->source, n);
+ swapl(&stuff->mask, n);
+ swaps(&stuff->foreRed, n);
+ swaps(&stuff->foreGreen, n);
+ swaps(&stuff->foreBlue, n);
+ swaps(&stuff->backRed, n);
+ swaps(&stuff->backGreen, n);
+ swaps(&stuff->backBlue, n);
+ swaps(&stuff->x, n);
+ swaps(&stuff->y, n);
+ return((* ProcVector[X_CreateCursor])(client));
+}
+
+int
+SProcCreateGlyphCursor (ClientPtr client)
+{
+ char n;
+ REQUEST(xCreateGlyphCursorReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xCreateGlyphCursorReq);
+ swapl(&stuff->cid, n);
+ swapl(&stuff->source, n);
+ swapl(&stuff->mask, n);
+ swaps(&stuff->sourceChar, n);
+ swaps(&stuff->maskChar, n);
+ swaps(&stuff->foreRed, n);
+ swaps(&stuff->foreGreen, n);
+ swaps(&stuff->foreBlue, n);
+ swaps(&stuff->backRed, n);
+ swaps(&stuff->backGreen, n);
+ swaps(&stuff->backBlue, n);
+ return((* ProcVector[X_CreateGlyphCursor])(client));
+}
+
+
+int
+SProcRecolorCursor (ClientPtr client)
+{
+ char n;
+ REQUEST(xRecolorCursorReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xRecolorCursorReq);
+ swapl(&stuff->cursor, n);
+ swaps(&stuff->foreRed, n);
+ swaps(&stuff->foreGreen, n);
+ swaps(&stuff->foreBlue, n);
+ swaps(&stuff->backRed, n);
+ swaps(&stuff->backGreen, n);
+ swaps(&stuff->backBlue, n);
+ return((* ProcVector[X_RecolorCursor])(client));
+}
+
+int
+SProcQueryBestSize (ClientPtr client)
+{
+ char n;
+ REQUEST(xQueryBestSizeReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xQueryBestSizeReq);
+ swapl(&stuff->drawable, n);
+ swaps(&stuff->width, n);
+ swaps(&stuff->height, n);
+ return((* ProcVector[X_QueryBestSize])(client));
+
+}
+
+int
+SProcQueryExtension (ClientPtr client)
+{
+ char n;
+ REQUEST(xQueryExtensionReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xQueryExtensionReq);
+ swaps(&stuff->nbytes, n);
+ return((* ProcVector[X_QueryExtension])(client));
+}
+
+int
+SProcChangeKeyboardMapping (ClientPtr client)
+{
+ char n;
+ REQUEST(xChangeKeyboardMappingReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xChangeKeyboardMappingReq);
+ SwapRestL(stuff);
+ return((* ProcVector[X_ChangeKeyboardMapping])(client));
+}
+
+
+int
+SProcChangeKeyboardControl (ClientPtr client)
+{
+ char n;
+ REQUEST(xChangeKeyboardControlReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xChangeKeyboardControlReq);
+ swapl(&stuff->mask, n);
+ SwapRestL(stuff);
+ return((* ProcVector[X_ChangeKeyboardControl])(client));
+}
+
+int
+SProcChangePointerControl (ClientPtr client)
+{
+ char n;
+ REQUEST(xChangePointerControlReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xChangePointerControlReq);
+ swaps(&stuff->accelNum, n);
+ swaps(&stuff->accelDenum, n);
+ swaps(&stuff->threshold, n);
+ return((* ProcVector[X_ChangePointerControl])(client));
+}
+
+
+int
+SProcSetScreenSaver (ClientPtr client)
+{
+ char n;
+ REQUEST(xSetScreenSaverReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xSetScreenSaverReq);
+ swaps(&stuff->timeout, n);
+ swaps(&stuff->interval, n);
+ return((* ProcVector[X_SetScreenSaver])(client));
+}
+
+int
+SProcChangeHosts (ClientPtr client)
+{
+ char n;
+
+ REQUEST(xChangeHostsReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xChangeHostsReq);
+ swaps(&stuff->hostLength, n);
+ return((* ProcVector[X_ChangeHosts])(client));
+
+}
+
+int SProcRotateProperties (ClientPtr client)
+{
+ char n;
+ REQUEST(xRotatePropertiesReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xRotatePropertiesReq);
+ swapl(&stuff->window, n);
+ swaps(&stuff->nAtoms, n);
+ swaps(&stuff->nPositions, n);
+ SwapRestL(stuff);
+ return ((* ProcVector[X_RotateProperties])(client));
+}
+
+int
+SProcNoOperation(ClientPtr client)
+{
+ char n;
+ REQUEST(xReq);
+ swaps(&stuff->length, n);
+ return ((* ProcVector[X_NoOperation])(client));
+}
+
+void
+SwapConnClientPrefix(xConnClientPrefix *pCCP)
+{
+ char n;
+
+ swaps(&pCCP->majorVersion, n);
+ swaps(&pCCP->minorVersion, n);
+ swaps(&pCCP->nbytesAuthProto, n);
+ swaps(&pCCP->nbytesAuthString, n);
+}
diff --git a/dix/tables.c b/dix/tables.c
new file mode 100644
index 0000000..5bd9ea0
--- /dev/null
+++ b/dix/tables.c
@@ -0,0 +1,986 @@
+/***********************************************************
+
+Copyright 1987, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+******************************************************************/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include "windowstr.h"
+#include "extnsionst.h"
+#include "dixstruct.h"
+#include "dixevents.h"
+#include "dispatch.h"
+#include "swaprep.h"
+#include "swapreq.h"
+
+int (* InitialVector[3]) (
+ ClientPtr /* client */
+ ) =
+{
+ 0,
+ ProcInitialConnection,
+ ProcEstablishConnection
+};
+
+int (* ProcVector[256]) (
+ ClientPtr /* client */
+ ) =
+{
+ ProcBadRequest,
+ ProcCreateWindow,
+ ProcChangeWindowAttributes,
+ ProcGetWindowAttributes,
+ ProcDestroyWindow,
+ ProcDestroySubwindows, /* 5 */
+ ProcChangeSaveSet,
+ ProcReparentWindow,
+ ProcMapWindow,
+ ProcMapSubwindows,
+ ProcUnmapWindow, /* 10 */
+ ProcUnmapSubwindows,
+ ProcConfigureWindow,
+ ProcCirculateWindow,
+ ProcGetGeometry,
+ ProcQueryTree, /* 15 */
+ ProcInternAtom,
+ ProcGetAtomName,
+ ProcChangeProperty,
+ ProcDeleteProperty,
+ ProcGetProperty, /* 20 */
+ ProcListProperties,
+ ProcSetSelectionOwner,
+ ProcGetSelectionOwner,
+ ProcConvertSelection,
+ ProcSendEvent, /* 25 */
+ ProcGrabPointer,
+ ProcUngrabPointer,
+ ProcGrabButton,
+ ProcUngrabButton,
+ ProcChangeActivePointerGrab, /* 30 */
+ ProcGrabKeyboard,
+ ProcUngrabKeyboard,
+ ProcGrabKey,
+ ProcUngrabKey,
+ ProcAllowEvents, /* 35 */
+ ProcGrabServer,
+ ProcUngrabServer,
+ ProcQueryPointer,
+ ProcGetMotionEvents,
+ ProcTranslateCoords, /* 40 */
+ ProcWarpPointer,
+ ProcSetInputFocus,
+ ProcGetInputFocus,
+ ProcQueryKeymap,
+ ProcOpenFont, /* 45 */
+ ProcCloseFont,
+ ProcQueryFont,
+ ProcQueryTextExtents,
+ ProcListFonts,
+ ProcListFontsWithInfo, /* 50 */
+ ProcSetFontPath,
+ ProcGetFontPath,
+ ProcCreatePixmap,
+ ProcFreePixmap,
+ ProcCreateGC, /* 55 */
+ ProcChangeGC,
+ ProcCopyGC,
+ ProcSetDashes,
+ ProcSetClipRectangles,
+ ProcFreeGC, /* 60 */
+ ProcClearToBackground,
+ ProcCopyArea,
+ ProcCopyPlane,
+ ProcPolyPoint,
+ ProcPolyLine, /* 65 */
+ ProcPolySegment,
+ ProcPolyRectangle,
+ ProcPolyArc,
+ ProcFillPoly,
+ ProcPolyFillRectangle, /* 70 */
+ ProcPolyFillArc,
+ ProcPutImage,
+ ProcGetImage,
+ ProcPolyText,
+ ProcPolyText, /* 75 */
+ ProcImageText8,
+ ProcImageText16,
+ ProcCreateColormap,
+ ProcFreeColormap,
+ ProcCopyColormapAndFree, /* 80 */
+ ProcInstallColormap,
+ ProcUninstallColormap,
+ ProcListInstalledColormaps,
+ ProcAllocColor,
+ ProcAllocNamedColor, /* 85 */
+ ProcAllocColorCells,
+ ProcAllocColorPlanes,
+ ProcFreeColors,
+ ProcStoreColors,
+ ProcStoreNamedColor, /* 90 */
+ ProcQueryColors,
+ ProcLookupColor,
+ ProcCreateCursor,
+ ProcCreateGlyphCursor,
+ ProcFreeCursor, /* 95 */
+ ProcRecolorCursor,
+ ProcQueryBestSize,
+ ProcQueryExtension,
+ ProcListExtensions,
+ ProcChangeKeyboardMapping, /* 100 */
+ ProcGetKeyboardMapping,
+ ProcChangeKeyboardControl,
+ ProcGetKeyboardControl,
+ ProcBell,
+ ProcChangePointerControl, /* 105 */
+ ProcGetPointerControl,
+ ProcSetScreenSaver,
+ ProcGetScreenSaver,
+ ProcChangeHosts,
+ ProcListHosts, /* 110 */
+ ProcChangeAccessControl,
+ ProcChangeCloseDownMode,
+ ProcKillClient,
+ ProcRotateProperties,
+ ProcForceScreenSaver, /* 115 */
+ ProcSetPointerMapping,
+ ProcGetPointerMapping,
+ ProcSetModifierMapping,
+ ProcGetModifierMapping,
+ ProcBadRequest, /* 120 */
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest, /* 125 */
+ ProcBadRequest,
+ ProcNoOperation,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest
+};
+
+int (* SwappedProcVector[256]) (
+ ClientPtr /* client */
+ ) =
+{
+ ProcBadRequest,
+ SProcCreateWindow,
+ SProcChangeWindowAttributes,
+ SProcResourceReq, /* GetWindowAttributes */
+ SProcResourceReq, /* DestroyWindow */
+ SProcResourceReq, /* 5 DestroySubwindows */
+ SProcResourceReq, /* SProcChangeSaveSet, */
+ SProcReparentWindow,
+ SProcResourceReq, /* MapWindow */
+ SProcResourceReq, /* MapSubwindows */
+ SProcResourceReq, /* 10 UnmapWindow */
+ SProcResourceReq, /* UnmapSubwindows */
+ SProcConfigureWindow,
+ SProcResourceReq, /* SProcCirculateWindow, */
+ SProcResourceReq, /* GetGeometry */
+ SProcResourceReq, /* 15 QueryTree */
+ SProcInternAtom,
+ SProcResourceReq, /* SProcGetAtomName, */
+ SProcChangeProperty,
+ SProcDeleteProperty,
+ SProcGetProperty, /* 20 */
+ SProcResourceReq, /* SProcListProperties, */
+ SProcSetSelectionOwner,
+ SProcResourceReq, /* SProcGetSelectionOwner, */
+ SProcConvertSelection,
+ SProcSendEvent, /* 25 */
+ SProcGrabPointer,
+ SProcResourceReq, /* SProcUngrabPointer, */
+ SProcGrabButton,
+ SProcUngrabButton,
+ SProcChangeActivePointerGrab, /* 30 */
+ SProcGrabKeyboard,
+ SProcResourceReq, /* SProcUngrabKeyboard, */
+ SProcGrabKey,
+ SProcUngrabKey,
+ SProcResourceReq, /* 35 SProcAllowEvents, */
+ SProcSimpleReq, /* SProcGrabServer, */
+ SProcSimpleReq, /* SProcUngrabServer, */
+ SProcResourceReq, /* SProcQueryPointer, */
+ SProcGetMotionEvents,
+ SProcTranslateCoords, /*40 */
+ SProcWarpPointer,
+ SProcSetInputFocus,
+ SProcSimpleReq, /* SProcGetInputFocus, */
+ SProcSimpleReq, /* QueryKeymap, */
+ SProcOpenFont, /* 45 */
+ SProcResourceReq, /* SProcCloseFont, */
+ SProcResourceReq, /* SProcQueryFont, */
+ SProcResourceReq, /* SProcQueryTextExtents, */
+ SProcListFonts,
+ SProcListFontsWithInfo, /* 50 */
+ SProcSetFontPath,
+ SProcSimpleReq, /* GetFontPath, */
+ SProcCreatePixmap,
+ SProcResourceReq, /* SProcFreePixmap, */
+ SProcCreateGC, /* 55 */
+ SProcChangeGC,
+ SProcCopyGC,
+ SProcSetDashes,
+ SProcSetClipRectangles,
+ SProcResourceReq, /* 60 SProcFreeGC, */
+ SProcClearToBackground,
+ SProcCopyArea,
+ SProcCopyPlane,
+ SProcPoly, /* PolyPoint, */
+ SProcPoly, /* 65 PolyLine */
+ SProcPoly, /* PolySegment, */
+ SProcPoly, /* PolyRectangle, */
+ SProcPoly, /* PolyArc, */
+ SProcFillPoly,
+ SProcPoly, /* 70 PolyFillRectangle */
+ SProcPoly, /* PolyFillArc, */
+ SProcPutImage,
+ SProcGetImage,
+ SProcPolyText,
+ SProcPolyText, /* 75 */
+ SProcImageText,
+ SProcImageText,
+ SProcCreateColormap,
+ SProcResourceReq, /* SProcFreeColormap, */
+ SProcCopyColormapAndFree, /* 80 */
+ SProcResourceReq, /* SProcInstallColormap, */
+ SProcResourceReq, /* SProcUninstallColormap, */
+ SProcResourceReq, /* SProcListInstalledColormaps, */
+ SProcAllocColor,
+ SProcAllocNamedColor, /* 85 */
+ SProcAllocColorCells,
+ SProcAllocColorPlanes,
+ SProcFreeColors,
+ SProcStoreColors,
+ SProcStoreNamedColor, /* 90 */
+ SProcQueryColors,
+ SProcLookupColor,
+ SProcCreateCursor,
+ SProcCreateGlyphCursor,
+ SProcResourceReq, /* 95 SProcFreeCursor, */
+ SProcRecolorCursor,
+ SProcQueryBestSize,
+ SProcQueryExtension,
+ SProcSimpleReq, /* ListExtensions, */
+ SProcChangeKeyboardMapping, /* 100 */
+ SProcSimpleReq, /* GetKeyboardMapping, */
+ SProcChangeKeyboardControl,
+ SProcSimpleReq, /* GetKeyboardControl, */
+ SProcSimpleReq, /* Bell, */
+ SProcChangePointerControl, /* 105 */
+ SProcSimpleReq, /* GetPointerControl, */
+ SProcSetScreenSaver,
+ SProcSimpleReq, /* GetScreenSaver, */
+ SProcChangeHosts,
+ SProcSimpleReq, /* 110 ListHosts, */
+ SProcSimpleReq, /* SProcChangeAccessControl, */
+ SProcSimpleReq, /* SProcChangeCloseDownMode, */
+ SProcResourceReq, /* SProcKillClient, */
+ SProcRotateProperties,
+ SProcSimpleReq, /* 115 ForceScreenSaver */
+ SProcSimpleReq, /* SetPointerMapping, */
+ SProcSimpleReq, /* GetPointerMapping, */
+ SProcSimpleReq, /* SetModifierMapping, */
+ SProcSimpleReq, /* GetModifierMapping, */
+ ProcBadRequest, /* 120 */
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest, /* 125 */
+ ProcBadRequest,
+ SProcNoOperation,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest,
+ ProcBadRequest
+};
+
+EventSwapPtr EventSwapVector[128] =
+{
+ (EventSwapPtr)SErrorEvent,
+ NotImplemented,
+ SKeyButtonPtrEvent,
+ SKeyButtonPtrEvent,
+ SKeyButtonPtrEvent,
+ SKeyButtonPtrEvent, /* 5 */
+ SKeyButtonPtrEvent,
+ SEnterLeaveEvent,
+ SEnterLeaveEvent,
+ SFocusEvent,
+ SFocusEvent, /* 10 */
+ SKeymapNotifyEvent,
+ SExposeEvent,
+ SGraphicsExposureEvent,
+ SNoExposureEvent,
+ SVisibilityEvent, /* 15 */
+ SCreateNotifyEvent,
+ SDestroyNotifyEvent,
+ SUnmapNotifyEvent,
+ SMapNotifyEvent,
+ SMapRequestEvent, /* 20 */
+ SReparentEvent,
+ SConfigureNotifyEvent,
+ SConfigureRequestEvent,
+ SGravityEvent,
+ SResizeRequestEvent, /* 25 */
+ SCirculateEvent,
+ SCirculateEvent,
+ SPropertyEvent,
+ SSelectionClearEvent,
+ SSelectionRequestEvent, /* 30 */
+ SSelectionNotifyEvent,
+ SColormapEvent,
+ SClientMessageEvent,
+ SMappingEvent,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented,
+ NotImplemented
+};
+
+
+ReplySwapPtr ReplySwapVector[256] =
+{
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ (ReplySwapPtr)SGetWindowAttributesReply,
+ ReplyNotSwappd,
+ ReplyNotSwappd, /* 5 */
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd, /* 10 */
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ (ReplySwapPtr)SGetGeometryReply,
+ (ReplySwapPtr)SQueryTreeReply, /* 15 */
+ (ReplySwapPtr)SInternAtomReply,
+ (ReplySwapPtr)SGetAtomNameReply,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ (ReplySwapPtr)SGetPropertyReply, /* 20 */
+ (ReplySwapPtr)SListPropertiesReply,
+ ReplyNotSwappd,
+ (ReplySwapPtr)SGetSelectionOwnerReply,
+ ReplyNotSwappd,
+ ReplyNotSwappd, /* 25 */
+ (ReplySwapPtr)SGenericReply, /* SGrabPointerReply, */
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd, /* 30 */
+ (ReplySwapPtr)SGenericReply, /* SGrabKeyboardReply, */
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd, /* 35 */
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ (ReplySwapPtr)SQueryPointerReply,
+ (ReplySwapPtr)SGetMotionEventsReply,
+ (ReplySwapPtr)STranslateCoordsReply, /* 40 */
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ (ReplySwapPtr)SGetInputFocusReply,
+ (ReplySwapPtr)SQueryKeymapReply,
+ ReplyNotSwappd, /* 45 */
+ ReplyNotSwappd,
+ (ReplySwapPtr)SQueryFontReply,
+ (ReplySwapPtr)SQueryTextExtentsReply,
+ (ReplySwapPtr)SListFontsReply,
+ (ReplySwapPtr)SListFontsWithInfoReply, /* 50 */
+ ReplyNotSwappd,
+ (ReplySwapPtr)SGetFontPathReply,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd, /* 55 */
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd, /* 60 */
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd, /* 65 */
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd, /* 70 */
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ (ReplySwapPtr)SGetImageReply,
+ ReplyNotSwappd,
+ ReplyNotSwappd, /* 75 */
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd, /* 80 */
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ (ReplySwapPtr)SListInstalledColormapsReply,
+ (ReplySwapPtr)SAllocColorReply,
+ (ReplySwapPtr)SAllocNamedColorReply, /* 85 */
+ (ReplySwapPtr)SAllocColorCellsReply,
+ (ReplySwapPtr)SAllocColorPlanesReply,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd, /* 90 */
+ (ReplySwapPtr)SQueryColorsReply,
+ (ReplySwapPtr)SLookupColorReply,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd, /* 95 */
+ ReplyNotSwappd,
+ (ReplySwapPtr)SQueryBestSizeReply,
+ (ReplySwapPtr)SGenericReply, /* SQueryExtensionReply, */
+ (ReplySwapPtr)SListExtensionsReply,
+ ReplyNotSwappd, /* 100 */
+ (ReplySwapPtr)SGetKeyboardMappingReply,
+ ReplyNotSwappd,
+ (ReplySwapPtr)SGetKeyboardControlReply,
+ ReplyNotSwappd,
+ ReplyNotSwappd, /* 105 */
+ (ReplySwapPtr)SGetPointerControlReply,
+ ReplyNotSwappd,
+ (ReplySwapPtr)SGetScreenSaverReply,
+ ReplyNotSwappd,
+ (ReplySwapPtr)SListHostsReply, /* 110 */
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd, /* 115 */
+ (ReplySwapPtr)SGenericReply, /* SetPointerMapping */
+ (ReplySwapPtr)SGetPointerMappingReply,
+ (ReplySwapPtr)SGenericReply, /* SetModifierMapping */
+ (ReplySwapPtr)SGetModifierMappingReply, /* 119 */
+ ReplyNotSwappd, /* 120 */
+ ReplyNotSwappd, /* 121 */
+ ReplyNotSwappd, /* 122 */
+ ReplyNotSwappd, /* 123 */
+ ReplyNotSwappd, /* 124 */
+ ReplyNotSwappd, /* 125 */
+ ReplyNotSwappd, /* 126 */
+ ReplyNotSwappd, /* NoOperation */
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd,
+ ReplyNotSwappd
+};
diff --git a/dix/window.c b/dix/window.c
new file mode 100644
index 0000000..9be7064
--- /dev/null
+++ b/dix/window.c
@@ -0,0 +1,3686 @@
+/*
+
+Copyright (c) 2006, Red Hat, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+Copyright 1987, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+*/
+
+/* The panoramix components contained the following notice */
+/*****************************************************************
+
+Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
+BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of Digital Equipment Corporation
+shall not be used in advertising or otherwise to promote the sale, use or other
+dealings in this Software without prior written authorization from Digital
+Equipment Corporation.
+
+******************************************************************/
+
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "misc.h"
+#include "scrnintstr.h"
+#include "os.h"
+#include "regionstr.h"
+#include "validate.h"
+#include "windowstr.h"
+#include "input.h"
+#include "inputstr.h"
+#include "resource.h"
+#include "colormapst.h"
+#include "cursorstr.h"
+#include "dixstruct.h"
+#include "gcstruct.h"
+#include "servermd.h"
+#ifdef PANORAMIX
+#include "panoramiX.h"
+#include "panoramiXsrv.h"
+#endif
+#include "dixevents.h"
+#include "globals.h"
+#include "mi.h" /* miPaintWindow */
+
+#include "privates.h"
+#include "xace.h"
+
+/******
+ * Window stuff for server
+ *
+ * CreateRootWindow, CreateWindow, ChangeWindowAttributes,
+ * GetWindowAttributes, DeleteWindow, DestroySubWindows,
+ * HandleSaveSet, ReparentWindow, MapWindow, MapSubWindows,
+ * UnmapWindow, UnmapSubWindows, ConfigureWindow, CirculateWindow,
+ * ChangeWindowDeviceCursor
+ ******/
+
+Bool bgNoneRoot = FALSE;
+
+static unsigned char _back_lsb[4] = {0x88, 0x22, 0x44, 0x11};
+static unsigned char _back_msb[4] = {0x11, 0x44, 0x22, 0x88};
+
+static Bool WindowParentHasDeviceCursor(WindowPtr pWin,
+ DeviceIntPtr pDev,
+ CursorPtr pCurs);
+static Bool
+WindowSeekDeviceCursor(WindowPtr pWin,
+ DeviceIntPtr pDev,
+ DevCursNodePtr* pNode,
+ DevCursNodePtr* pPrev);
+
+int screenIsSaved = SCREEN_SAVER_OFF;
+
+static Bool TileScreenSaver(ScreenPtr pScreen, int kind);
+
+#define INPUTONLY_LEGAL_MASK (CWWinGravity | CWEventMask | \
+ CWDontPropagate | CWOverrideRedirect | CWCursor )
+
+#define BOXES_OVERLAP(b1, b2) \
+ (!( ((b1)->x2 <= (b2)->x1) || \
+ ( ((b1)->x1 >= (b2)->x2)) || \
+ ( ((b1)->y2 <= (b2)->y1)) || \
+ ( ((b1)->y1 >= (b2)->y2)) ) )
+
+#define RedirectSend(pWin) \
+ ((pWin->eventMask|wOtherEventMasks(pWin)) & SubstructureRedirectMask)
+
+#define SubSend(pWin) \
+ ((pWin->eventMask|wOtherEventMasks(pWin)) & SubstructureNotifyMask)
+
+#define StrSend(pWin) \
+ ((pWin->eventMask|wOtherEventMasks(pWin)) & StructureNotifyMask)
+
+#define SubStrSend(pWin,pParent) (StrSend(pWin) || SubSend(pParent))
+
+#ifdef DEBUG
+/******
+ * PrintWindowTree
+ * For debugging only
+ ******/
+
+static void
+PrintChildren(WindowPtr p1, int indent)
+{
+ WindowPtr p2;
+ int i;
+
+ while (p1)
+ {
+ p2 = p1->firstChild;
+ ErrorF("[dix] ");
+ for (i=0; i<indent; i++) ErrorF(" ");
+ ErrorF("%lx\n", p1->drawable.id);
+ RegionPrint(&p1->clipList);
+ PrintChildren(p2, indent+4);
+ p1 = p1->nextSib;
+ }
+}
+
+static void
+PrintWindowTree(void)
+{
+ int i;
+ WindowPtr pWin, p1;
+
+ for (i=0; i<screenInfo.numScreens; i++)
+ {
+ ErrorF("[dix] WINDOW %d\n", i);
+ pWin = screenInfo.screens[i]->root;
+ RegionPrint(&pWin->clipList);
+ p1 = pWin->firstChild;
+ PrintChildren(p1, 4);
+ }
+}
+#endif
+
+int
+TraverseTree(WindowPtr pWin, VisitWindowProcPtr func, pointer data)
+{
+ int result;
+ WindowPtr pChild;
+
+ if (!(pChild = pWin))
+ return WT_NOMATCH;
+ while (1)
+ {
+ result = (* func)(pChild, data);
+ if (result == WT_STOPWALKING)
+ return WT_STOPWALKING;
+ if ((result == WT_WALKCHILDREN) && pChild->firstChild)
+ {
+ pChild = pChild->firstChild;
+ continue;
+ }
+ while (!pChild->nextSib && (pChild != pWin))
+ pChild = pChild->parent;
+ if (pChild == pWin)
+ break;
+ pChild = pChild->nextSib;
+ }
+ return WT_NOMATCH;
+}
+
+/*****
+ * WalkTree
+ * Walk the window tree, for SCREEN, preforming FUNC(pWin, data) on
+ * each window. If FUNC returns WT_WALKCHILDREN, traverse the children,
+ * if it returns WT_DONTWALKCHILDREN, dont. If it returns WT_STOPWALKING
+ * exit WalkTree. Does depth-first traverse.
+ *****/
+
+int
+WalkTree(ScreenPtr pScreen, VisitWindowProcPtr func, pointer data)
+{
+ return(TraverseTree(pScreen->root, func, data));
+}
+
+/* hack for forcing backing store on all windows */
+int defaultBackingStore = NotUseful;
+/* hack to force no backing store */
+Bool disableBackingStore = FALSE;
+Bool enableBackingStore = FALSE;
+
+static void
+SetWindowToDefaults(WindowPtr pWin)
+{
+ pWin->prevSib = NullWindow;
+ pWin->firstChild = NullWindow;
+ pWin->lastChild = NullWindow;
+
+ pWin->valdata = (ValidatePtr)NULL;
+ pWin->optional = (WindowOptPtr)NULL;
+ pWin->cursorIsNone = TRUE;
+
+ pWin->backingStore = NotUseful;
+ pWin->DIXsaveUnder = FALSE;
+ pWin->backStorage = (pointer) NULL;
+
+ pWin->mapped = FALSE; /* off */
+ pWin->realized = FALSE; /* off */
+ pWin->viewable = FALSE;
+ pWin->visibility = VisibilityNotViewable;
+ pWin->overrideRedirect = FALSE;
+ pWin->saveUnder = FALSE;
+
+ pWin->bitGravity = ForgetGravity;
+ pWin->winGravity = NorthWestGravity;
+
+ pWin->eventMask = 0;
+ pWin->deliverableEvents = 0;
+ pWin->dontPropagate = 0;
+ pWin->forcedBS = FALSE;
+ pWin->redirectDraw = RedirectDrawNone;
+ pWin->forcedBG = FALSE;
+
+#ifdef ROOTLESS
+ pWin->rootlessUnhittable = FALSE;
+#endif
+
+#ifdef COMPOSITE
+ pWin->damagedDescendants = FALSE;
+#endif
+}
+
+static void
+MakeRootTile(WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ GCPtr pGC;
+ unsigned char back[128];
+ int len = BitmapBytePad(sizeof(long));
+ unsigned char *from, *to;
+ int i, j;
+
+ pWin->background.pixmap = (*pScreen->CreatePixmap)(pScreen, 4, 4,
+ pScreen->rootDepth, 0);
+
+ pWin->backgroundState = BackgroundPixmap;
+ pGC = GetScratchGC(pScreen->rootDepth, pScreen);
+ if (!pWin->background.pixmap || !pGC)
+ FatalError("could not create root tile");
+
+ {
+ ChangeGCVal attributes[2];
+
+ attributes[0].val = pScreen->whitePixel;
+ attributes[1].val = pScreen->blackPixel;
+
+ (void)ChangeGC(NullClient, pGC, GCForeground | GCBackground, attributes);
+ }
+
+ ValidateGC((DrawablePtr)pWin->background.pixmap, pGC);
+
+ from = (screenInfo.bitmapBitOrder == LSBFirst) ? _back_lsb : _back_msb;
+ to = back;
+
+ for (i = 4; i > 0; i--, from++)
+ for (j = len; j > 0; j--)
+ *to++ = *from;
+
+ (*pGC->ops->PutImage)((DrawablePtr)pWin->background.pixmap, pGC, 1,
+ 0, 0, len, 4, 0, XYBitmap, (char *)back);
+
+ FreeScratchGC(pGC);
+
+}
+
+/*****
+ * CreateRootWindow
+ * Makes a window at initialization time for specified screen
+ *****/
+
+Bool
+CreateRootWindow(ScreenPtr pScreen)
+{
+ WindowPtr pWin;
+ BoxRec box;
+ PixmapFormatRec *format;
+
+ pWin = dixAllocateObjectWithPrivates(WindowRec, PRIVATE_WINDOW);
+ if (!pWin)
+ return FALSE;
+
+ pScreen->screensaver.pWindow = NULL;
+ pScreen->screensaver.wid = FakeClientID(0);
+ pScreen->screensaver.ExternalScreenSaver = NULL;
+ screenIsSaved = SCREEN_SAVER_OFF;
+
+ pScreen->root = pWin;
+
+ pWin->drawable.pScreen = pScreen;
+ pWin->drawable.type = DRAWABLE_WINDOW;
+
+ pWin->drawable.depth = pScreen->rootDepth;
+ for (format = screenInfo.formats;
+ format->depth != pScreen->rootDepth;
+ format++)
+ ;
+ pWin->drawable.bitsPerPixel = format->bitsPerPixel;
+
+ pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+
+ pWin->parent = NullWindow;
+ SetWindowToDefaults(pWin);
+
+ pWin->optional = malloc(sizeof (WindowOptRec));
+ if (!pWin->optional)
+ return FALSE;
+
+ pWin->optional->dontPropagateMask = 0;
+ pWin->optional->otherEventMasks = 0;
+ pWin->optional->otherClients = NULL;
+ pWin->optional->passiveGrabs = NULL;
+ pWin->optional->userProps = NULL;
+ pWin->optional->backingBitPlanes = ~0L;
+ pWin->optional->backingPixel = 0;
+ pWin->optional->boundingShape = NULL;
+ pWin->optional->clipShape = NULL;
+ pWin->optional->inputShape = NULL;
+ pWin->optional->inputMasks = NULL;
+ pWin->optional->deviceCursors = NULL;
+ pWin->optional->colormap = pScreen->defColormap;
+ pWin->optional->visual = pScreen->rootVisual;
+
+ pWin->nextSib = NullWindow;
+
+ pWin->drawable.id = FakeClientID(0);
+
+ pWin->origin.x = pWin->origin.y = 0;
+ pWin->drawable.height = pScreen->height;
+ pWin->drawable.width = pScreen->width;
+ pWin->drawable.x = pWin->drawable.y = 0;
+
+ box.x1 = 0;
+ box.y1 = 0;
+ box.x2 = pScreen->width;
+ box.y2 = pScreen->height;
+ RegionInit(&pWin->clipList, &box, 1);
+ RegionInit(&pWin->winSize, &box, 1);
+ RegionInit(&pWin->borderSize, &box, 1);
+ RegionInit(&pWin->borderClip, &box, 1);
+
+ pWin->drawable.class = InputOutput;
+ pWin->optional->visual = pScreen->rootVisual;
+
+ pWin->backgroundState = BackgroundPixel;
+ pWin->background.pixel = pScreen->whitePixel;
+
+ pWin->borderIsPixel = TRUE;
+ pWin->border.pixel = pScreen->blackPixel;
+ pWin->borderWidth = 0;
+
+ /* security creation/labeling check
+ */
+ if (XaceHook(XACE_RESOURCE_ACCESS, serverClient, pWin->drawable.id,
+ RT_WINDOW, pWin, RT_NONE, NULL, DixCreateAccess))
+ return FALSE;
+
+ if (!AddResource(pWin->drawable.id, RT_WINDOW, (pointer)pWin))
+ return FALSE;
+
+ if (disableBackingStore)
+ pScreen->backingStoreSupport = NotUseful;
+ if (enableBackingStore)
+ pScreen->backingStoreSupport = Always;
+
+ pScreen->saveUnderSupport = NotUseful;
+
+ return TRUE;
+}
+
+void
+InitRootWindow(WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ int backFlag = CWBorderPixel | CWCursor | CWBackingStore;
+
+ if (!(*pScreen->CreateWindow)(pWin))
+ return; /* XXX */
+ (*pScreen->PositionWindow)(pWin, 0, 0);
+
+ pWin->cursorIsNone = FALSE;
+ pWin->optional->cursor = rootCursor;
+ rootCursor->refcnt++;
+
+
+ if (party_like_its_1989) {
+ MakeRootTile(pWin);
+ backFlag |= CWBackPixmap;
+ } else if (pScreen->canDoBGNoneRoot && bgNoneRoot) {
+ pWin->backgroundState = XaceBackgroundNoneState(pWin);
+ pWin->background.pixel = pScreen->whitePixel;
+ backFlag |= CWBackPixmap;
+ } else {
+ if (whiteRoot)
+ pWin->background.pixel = pScreen->whitePixel;
+ else
+ pWin->background.pixel = pScreen->blackPixel;
+ backFlag |= CWBackPixel;
+ }
+
+ pWin->backingStore = defaultBackingStore;
+ pWin->forcedBS = (defaultBackingStore != NotUseful);
+ /* We SHOULD check for an error value here XXX */
+ (*pScreen->ChangeWindowAttributes)(pWin, backFlag);
+
+ MapWindow(pWin, serverClient);
+}
+
+/* Set the region to the intersection of the rectangle and the
+ * window's winSize. The window is typically the parent of the
+ * window from which the region came.
+ */
+
+static void
+ClippedRegionFromBox(WindowPtr pWin, RegionPtr Rgn,
+ int x, int y,
+ int w, int h)
+{
+ BoxRec box = *RegionExtents(&pWin->winSize);
+
+ /* we do these calculations to avoid overflows */
+ if (x > box.x1)
+ box.x1 = x;
+ if (y > box.y1)
+ box.y1 = y;
+ x += w;
+ if (x < box.x2)
+ box.x2 = x;
+ y += h;
+ if (y < box.y2)
+ box.y2 = y;
+ if (box.x1 > box.x2)
+ box.x2 = box.x1;
+ if (box.y1 > box.y2)
+ box.y2 = box.y1;
+ RegionReset(Rgn, &box);
+ RegionIntersect(Rgn, Rgn, &pWin->winSize);
+}
+
+static RealChildHeadProc realChildHeadProc = NULL;
+
+void
+RegisterRealChildHeadProc (RealChildHeadProc proc)
+{
+ realChildHeadProc = proc;
+}
+
+
+WindowPtr
+RealChildHead(WindowPtr pWin)
+{
+ if (realChildHeadProc) {
+ return realChildHeadProc (pWin);
+ }
+
+ if (!pWin->parent &&
+ (screenIsSaved == SCREEN_SAVER_ON) &&
+ (HasSaverWindow (pWin->drawable.pScreen)))
+ return pWin->firstChild;
+ else
+ return NullWindow;
+}
+
+/*****
+ * CreateWindow
+ * Makes a window in response to client request
+ *****/
+
+WindowPtr
+CreateWindow(Window wid, WindowPtr pParent, int x, int y, unsigned w,
+ unsigned h, unsigned bw, unsigned class, Mask vmask, XID *vlist,
+ int depth, ClientPtr client, VisualID visual, int *error)
+{
+ WindowPtr pWin;
+ WindowPtr pHead;
+ ScreenPtr pScreen;
+ xEvent event;
+ int idepth, ivisual;
+ Bool fOK;
+ DepthPtr pDepth;
+ PixmapFormatRec *format;
+ WindowOptPtr ancwopt;
+
+ if (class == CopyFromParent)
+ class = pParent->drawable.class;
+
+ if ((class != InputOutput) && (class != InputOnly))
+ {
+ *error = BadValue;
+ client->errorValue = class;
+ return NullWindow;
+ }
+
+ if ((class != InputOnly) && (pParent->drawable.class == InputOnly))
+ {
+ *error = BadMatch;
+ return NullWindow;
+ }
+
+ if ((class == InputOnly) && ((bw != 0) || (depth != 0)))
+ {
+ *error = BadMatch;
+ return NullWindow;
+ }
+
+ pScreen = pParent->drawable.pScreen;
+ if ((class == InputOutput) && (depth == 0))
+ depth = pParent->drawable.depth;
+ ancwopt = pParent->optional;
+ if (!ancwopt)
+ ancwopt = FindWindowWithOptional(pParent)->optional;
+ if (visual == CopyFromParent) {
+ visual = ancwopt->visual;
+ }
+
+ /* Find out if the depth and visual are acceptable for this Screen */
+ if ((visual != ancwopt->visual) || (depth != pParent->drawable.depth))
+ {
+ fOK = FALSE;
+ for(idepth = 0; idepth < pScreen->numDepths; idepth++)
+ {
+ pDepth = (DepthPtr) &pScreen->allowedDepths[idepth];
+ if ((depth == pDepth->depth) || (depth == 0))
+ {
+ for (ivisual = 0; ivisual < pDepth->numVids; ivisual++)
+ {
+ if (visual == pDepth->vids[ivisual])
+ {
+ fOK = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ if (fOK == FALSE)
+ {
+ *error = BadMatch;
+ return NullWindow;
+ }
+ }
+
+ if (((vmask & (CWBorderPixmap | CWBorderPixel)) == 0) &&
+ (class != InputOnly) &&
+ (depth != pParent->drawable.depth))
+ {
+ *error = BadMatch;
+ return NullWindow;
+ }
+
+ if (((vmask & CWColormap) == 0) &&
+ (class != InputOnly) &&
+ ((visual != ancwopt->visual) || (ancwopt->colormap == None)))
+ {
+ *error = BadMatch;
+ return NullWindow;
+ }
+
+ pWin = dixAllocateObjectWithPrivates(WindowRec, PRIVATE_WINDOW);
+ if (!pWin)
+ {
+ *error = BadAlloc;
+ return NullWindow;
+ }
+ pWin->drawable = pParent->drawable;
+ pWin->drawable.depth = depth;
+ if (depth == pParent->drawable.depth)
+ pWin->drawable.bitsPerPixel = pParent->drawable.bitsPerPixel;
+ else
+ {
+ for (format = screenInfo.formats; format->depth != depth; format++)
+ ;
+ pWin->drawable.bitsPerPixel = format->bitsPerPixel;
+ }
+ if (class == InputOnly)
+ pWin->drawable.type = (short) UNDRAWABLE_WINDOW;
+ pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+
+ pWin->drawable.id = wid;
+ pWin->drawable.class = class;
+
+ pWin->parent = pParent;
+ SetWindowToDefaults(pWin);
+
+ if (visual != ancwopt->visual)
+ {
+ if (!MakeWindowOptional (pWin))
+ {
+ dixFreeObjectWithPrivates(pWin, PRIVATE_WINDOW);
+ *error = BadAlloc;
+ return NullWindow;
+ }
+ pWin->optional->visual = visual;
+ pWin->optional->colormap = None;
+ }
+
+ pWin->borderWidth = bw;
+
+ /* security creation/labeling check
+ */
+ *error = XaceHook(XACE_RESOURCE_ACCESS, client, wid, RT_WINDOW, pWin,
+ RT_WINDOW, pWin->parent, DixCreateAccess|DixSetAttrAccess);
+ if (*error != Success) {
+ dixFreeObjectWithPrivates(pWin, PRIVATE_WINDOW);
+ return NullWindow;
+ }
+
+ pWin->backgroundState = XaceBackgroundNoneState(pWin);
+ pWin->background.pixel = pScreen->whitePixel;
+
+ pWin->borderIsPixel = pParent->borderIsPixel;
+ pWin->border = pParent->border;
+ if (pWin->borderIsPixel == FALSE)
+ pWin->border.pixmap->refcnt++;
+
+ pWin->origin.x = x + (int)bw;
+ pWin->origin.y = y + (int)bw;
+ pWin->drawable.width = w;
+ pWin->drawable.height = h;
+ pWin->drawable.x = pParent->drawable.x + x + (int)bw;
+ pWin->drawable.y = pParent->drawable.y + y + (int)bw;
+
+ /* set up clip list correctly for unobscured WindowPtr */
+ RegionNull(&pWin->clipList);
+ RegionNull(&pWin->borderClip);
+ RegionNull(&pWin->winSize);
+ RegionNull(&pWin->borderSize);
+
+ pHead = RealChildHead(pParent);
+ if (pHead)
+ {
+ pWin->nextSib = pHead->nextSib;
+ if (pHead->nextSib)
+ pHead->nextSib->prevSib = pWin;
+ else
+ pParent->lastChild = pWin;
+ pHead->nextSib = pWin;
+ pWin->prevSib = pHead;
+ }
+ else
+ {
+ pWin->nextSib = pParent->firstChild;
+ if (pParent->firstChild)
+ pParent->firstChild->prevSib = pWin;
+ else
+ pParent->lastChild = pWin;
+ pParent->firstChild = pWin;
+ }
+
+ SetWinSize (pWin);
+ SetBorderSize (pWin);
+
+ /* We SHOULD check for an error value here XXX */
+ if (!(*pScreen->CreateWindow)(pWin))
+ {
+ *error = BadAlloc;
+ DeleteWindow(pWin, None);
+ return NullWindow;
+ }
+ /* We SHOULD check for an error value here XXX */
+ (*pScreen->PositionWindow)(pWin, pWin->drawable.x, pWin->drawable.y);
+
+ if (!(vmask & CWEventMask))
+ RecalculateDeliverableEvents(pWin);
+
+ if (vmask)
+ *error = ChangeWindowAttributes(pWin, vmask, vlist, wClient (pWin));
+ else
+ *error = Success;
+
+ if (*error != Success)
+ {
+ DeleteWindow(pWin, None);
+ return NullWindow;
+ }
+ if (!(vmask & CWBackingStore) && (defaultBackingStore != NotUseful))
+ {
+ XID value = defaultBackingStore;
+ (void)ChangeWindowAttributes(pWin, CWBackingStore, &value, wClient (pWin));
+ pWin->forcedBS = TRUE;
+ }
+
+ if (SubSend(pParent))
+ {
+ memset(&event, 0, sizeof(xEvent));
+ event.u.u.type = CreateNotify;
+ event.u.createNotify.window = wid;
+ event.u.createNotify.parent = pParent->drawable.id;
+ event.u.createNotify.x = x;
+ event.u.createNotify.y = y;
+ event.u.createNotify.width = w;
+ event.u.createNotify.height = h;
+ event.u.createNotify.borderWidth = bw;
+ event.u.createNotify.override = pWin->overrideRedirect;
+ DeliverEvents(pParent, &event, 1, NullWindow);
+ }
+ return pWin;
+}
+
+static void
+DisposeWindowOptional (WindowPtr pWin)
+{
+ if (!pWin->optional)
+ return;
+ /*
+ * everything is peachy. Delete the optional record
+ * and clean up
+ */
+ if (pWin->optional->cursor)
+ {
+ FreeCursor (pWin->optional->cursor, (Cursor)0);
+ pWin->cursorIsNone = FALSE;
+ }
+ else
+ pWin->cursorIsNone = TRUE;
+
+ if (pWin->optional->deviceCursors)
+ {
+ DevCursorList pList;
+ DevCursorList pPrev;
+ pList = pWin->optional->deviceCursors;
+ while(pList)
+ {
+ if (pList->cursor)
+ FreeCursor(pList->cursor, (XID)0);
+ pPrev = pList;
+ pList = pList->next;
+ free(pPrev);
+ }
+ pWin->optional->deviceCursors = NULL;
+ }
+
+ free(pWin->optional);
+ pWin->optional = NULL;
+}
+
+static void
+FreeWindowResources(WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+
+ DeleteWindowFromAnySaveSet(pWin);
+ DeleteWindowFromAnySelections(pWin);
+ DeleteWindowFromAnyEvents(pWin, TRUE);
+ RegionUninit(&pWin->clipList);
+ RegionUninit(&pWin->winSize);
+ RegionUninit(&pWin->borderClip);
+ RegionUninit(&pWin->borderSize);
+ if (wBoundingShape (pWin))
+ RegionDestroy(wBoundingShape (pWin));
+ if (wClipShape (pWin))
+ RegionDestroy(wClipShape (pWin));
+ if (wInputShape (pWin))
+ RegionDestroy(wInputShape (pWin));
+ if (pWin->borderIsPixel == FALSE)
+ (*pScreen->DestroyPixmap)(pWin->border.pixmap);
+ if (pWin->backgroundState == BackgroundPixmap)
+ (*pScreen->DestroyPixmap)(pWin->background.pixmap);
+
+ DeleteAllWindowProperties(pWin);
+ /* We SHOULD check for an error value here XXX */
+ (*pScreen->DestroyWindow)(pWin);
+ DisposeWindowOptional (pWin);
+}
+
+static void
+CrushTree(WindowPtr pWin)
+{
+ WindowPtr pChild, pSib, pParent;
+ UnrealizeWindowProcPtr UnrealizeWindow;
+ xEvent event;
+
+ if (!(pChild = pWin->firstChild))
+ return;
+ UnrealizeWindow = pWin->drawable.pScreen->UnrealizeWindow;
+ while (1)
+ {
+ if (pChild->firstChild)
+ {
+ pChild = pChild->firstChild;
+ continue;
+ }
+ while (1)
+ {
+ pParent = pChild->parent;
+ if (SubStrSend(pChild, pParent))
+ {
+ memset(&event, 0, sizeof(xEvent));
+ event.u.u.type = DestroyNotify;
+ event.u.destroyNotify.window = pChild->drawable.id;
+ DeliverEvents(pChild, &event, 1, NullWindow);
+ }
+ FreeResource(pChild->drawable.id, RT_WINDOW);
+ pSib = pChild->nextSib;
+ pChild->viewable = FALSE;
+ if (pChild->realized)
+ {
+ pChild->realized = FALSE;
+ (*UnrealizeWindow)(pChild);
+ }
+ FreeWindowResources(pChild);
+ dixFreeObjectWithPrivates(pChild, PRIVATE_WINDOW);
+ if ( (pChild = pSib) )
+ break;
+ pChild = pParent;
+ pChild->firstChild = NullWindow;
+ pChild->lastChild = NullWindow;
+ if (pChild == pWin)
+ return;
+ }
+ }
+}
+
+/*****
+ * DeleteWindow
+ * Deletes child of window then window itself
+ * If wid is None, don't send any events
+ *****/
+
+int
+DeleteWindow(pointer value, XID wid)
+ {
+ WindowPtr pParent;
+ WindowPtr pWin = (WindowPtr)value;
+ xEvent event;
+
+ UnmapWindow(pWin, FALSE);
+
+ CrushTree(pWin);
+
+ pParent = pWin->parent;
+ if (wid && pParent && SubStrSend(pWin, pParent))
+ {
+ memset(&event, 0, sizeof(xEvent));
+ event.u.u.type = DestroyNotify;
+ event.u.destroyNotify.window = pWin->drawable.id;
+ DeliverEvents(pWin, &event, 1, NullWindow);
+ }
+
+ FreeWindowResources(pWin);
+ if (pParent)
+ {
+ if (pParent->firstChild == pWin)
+ pParent->firstChild = pWin->nextSib;
+ if (pParent->lastChild == pWin)
+ pParent->lastChild = pWin->prevSib;
+ if (pWin->nextSib)
+ pWin->nextSib->prevSib = pWin->prevSib;
+ if (pWin->prevSib)
+ pWin->prevSib->nextSib = pWin->nextSib;
+ }
+ else
+ pWin->drawable.pScreen->root = NULL;
+ dixFreeObjectWithPrivates(pWin, PRIVATE_WINDOW);
+ return Success;
+}
+
+int
+DestroySubwindows(WindowPtr pWin, ClientPtr client)
+{
+ /* XXX
+ * The protocol is quite clear that each window should be
+ * destroyed in turn, however, unmapping all of the first
+ * eliminates most of the calls to ValidateTree. So,
+ * this implementation is incorrect in that all of the
+ * UnmapNotifies occur before all of the DestroyNotifies.
+ * If you care, simply delete the call to UnmapSubwindows.
+ */
+ UnmapSubwindows(pWin);
+ while (pWin->lastChild) {
+ int rc = XaceHook(XACE_RESOURCE_ACCESS, client,
+ pWin->lastChild->drawable.id, RT_WINDOW,
+ pWin->lastChild, RT_NONE, NULL, DixDestroyAccess);
+ if (rc != Success)
+ return rc;
+ FreeResource(pWin->lastChild->drawable.id, RT_NONE);
+ }
+ return Success;
+}
+
+static void
+SetRootWindowBackground(WindowPtr pWin, ScreenPtr pScreen, Mask *index2)
+{
+ /* following the protocol: "Changing the background of a root window to
+ * None or ParentRelative restores the default background pixmap" */
+ if (bgNoneRoot) {
+ pWin->backgroundState = XaceBackgroundNoneState(pWin);
+ pWin->background.pixel = pScreen->whitePixel;
+ }
+ else if (party_like_its_1989)
+ MakeRootTile(pWin);
+ else {
+ if (whiteRoot)
+ pWin->background.pixel = pScreen->whitePixel;
+ else
+ pWin->background.pixel = pScreen->blackPixel;
+ *index2 = CWBackPixel;
+ }
+}
+
+/*****
+ * ChangeWindowAttributes
+ *
+ * The value-mask specifies which attributes are to be changed; the
+ * value-list contains one value for each one bit in the mask, from least
+ * to most significant bit in the mask.
+ *****/
+
+int
+ChangeWindowAttributes(WindowPtr pWin, Mask vmask, XID *vlist, ClientPtr client)
+{
+ XID *pVlist;
+ PixmapPtr pPixmap;
+ Pixmap pixID;
+ CursorPtr pCursor, pOldCursor;
+ Cursor cursorID;
+ WindowPtr pChild;
+ Colormap cmap;
+ ColormapPtr pCmap;
+ xEvent xE;
+ int error, rc;
+ ScreenPtr pScreen;
+ Mask index2, tmask, vmaskCopy = 0;
+ unsigned int val;
+ Bool checkOptional = FALSE, borderRelative = FALSE;
+
+ if ((pWin->drawable.class == InputOnly) && (vmask & (~INPUTONLY_LEGAL_MASK)))
+ return BadMatch;
+
+ error = Success;
+ pScreen = pWin->drawable.pScreen;
+ pVlist = vlist;
+ tmask = vmask;
+ while (tmask)
+ {
+ index2 = (Mask) lowbit (tmask);
+ tmask &= ~index2;
+ switch (index2)
+ {
+ case CWBackPixmap:
+ pixID = (Pixmap )*pVlist;
+ pVlist++;
+ if (pWin->backgroundState == ParentRelative)
+ borderRelative = TRUE;
+ if (pixID == None)
+ {
+ if (pWin->backgroundState == BackgroundPixmap)
+ (*pScreen->DestroyPixmap)(pWin->background.pixmap);
+ if (!pWin->parent)
+ SetRootWindowBackground(pWin, pScreen, &index2);
+ else {
+ pWin->backgroundState = XaceBackgroundNoneState(pWin);
+ pWin->background.pixel = pScreen->whitePixel;
+ }
+ }
+ else if (pixID == ParentRelative)
+ {
+ if (pWin->parent &&
+ pWin->drawable.depth != pWin->parent->drawable.depth)
+ {
+ error = BadMatch;
+ goto PatchUp;
+ }
+ if (pWin->backgroundState == BackgroundPixmap)
+ (*pScreen->DestroyPixmap)(pWin->background.pixmap);
+ if (!pWin->parent)
+ SetRootWindowBackground(pWin, pScreen, &index2);
+ else
+ pWin->backgroundState = ParentRelative;
+ borderRelative = TRUE;
+ /* Note that the parent's backgroundTile's refcnt is NOT
+ * incremented. */
+ }
+ else
+ {
+ rc = dixLookupResourceByType((pointer *)&pPixmap, pixID, RT_PIXMAP,
+ client, DixReadAccess);
+ if (rc == Success)
+ {
+ if ((pPixmap->drawable.depth != pWin->drawable.depth) ||
+ (pPixmap->drawable.pScreen != pScreen))
+ {
+ error = BadMatch;
+ goto PatchUp;
+ }
+ if (pWin->backgroundState == BackgroundPixmap)
+ (*pScreen->DestroyPixmap)(pWin->background.pixmap);
+ pWin->backgroundState = BackgroundPixmap;
+ pWin->background.pixmap = pPixmap;
+ pPixmap->refcnt++;
+ }
+ else
+ {
+ error = rc;
+ client->errorValue = pixID;
+ goto PatchUp;
+ }
+ }
+ break;
+ case CWBackPixel:
+ if (pWin->backgroundState == ParentRelative)
+ borderRelative = TRUE;
+ if (pWin->backgroundState == BackgroundPixmap)
+ (*pScreen->DestroyPixmap)(pWin->background.pixmap);
+ pWin->backgroundState = BackgroundPixel;
+ pWin->background.pixel = (CARD32 ) *pVlist;
+ /* background pixel overrides background pixmap,
+ so don't let the ddx layer see both bits */
+ vmaskCopy &= ~CWBackPixmap;
+ pVlist++;
+ break;
+ case CWBorderPixmap:
+ pixID = (Pixmap ) *pVlist;
+ pVlist++;
+ if (pixID == CopyFromParent)
+ {
+ if (!pWin->parent ||
+ (pWin->drawable.depth != pWin->parent->drawable.depth))
+ {
+ error = BadMatch;
+ goto PatchUp;
+ }
+ if (pWin->parent->borderIsPixel == TRUE) {
+ if (pWin->borderIsPixel == FALSE)
+ (*pScreen->DestroyPixmap)(pWin->border.pixmap);
+ pWin->border = pWin->parent->border;
+ pWin->borderIsPixel = TRUE;
+ index2 = CWBorderPixel;
+ break;
+ }
+ else
+ {
+ pixID = pWin->parent->border.pixmap->drawable.id;
+ }
+ }
+ rc = dixLookupResourceByType((pointer *)&pPixmap, pixID, RT_PIXMAP,
+ client, DixReadAccess);
+ if (rc == Success)
+ {
+ if ((pPixmap->drawable.depth != pWin->drawable.depth) ||
+ (pPixmap->drawable.pScreen != pScreen))
+ {
+ error = BadMatch;
+ goto PatchUp;
+ }
+ if (pWin->borderIsPixel == FALSE)
+ (*pScreen->DestroyPixmap)(pWin->border.pixmap);
+ pWin->borderIsPixel = FALSE;
+ pWin->border.pixmap = pPixmap;
+ pPixmap->refcnt++;
+ }
+ else
+ {
+ error = rc;
+ client->errorValue = pixID;
+ goto PatchUp;
+ }
+ break;
+ case CWBorderPixel:
+ if (pWin->borderIsPixel == FALSE)
+ (*pScreen->DestroyPixmap)(pWin->border.pixmap);
+ pWin->borderIsPixel = TRUE;
+ pWin->border.pixel = (CARD32) *pVlist;
+ /* border pixel overrides border pixmap,
+ so don't let the ddx layer see both bits */
+ vmaskCopy &= ~CWBorderPixmap;
+ pVlist++;
+ break;
+ case CWBitGravity:
+ val = (CARD8 )*pVlist;
+ pVlist++;
+ if (val > StaticGravity)
+ {
+ error = BadValue;
+ client->errorValue = val;
+ goto PatchUp;
+ }
+ pWin->bitGravity = val;
+ break;
+ case CWWinGravity:
+ val = (CARD8 )*pVlist;
+ pVlist++;
+ if (val > StaticGravity)
+ {
+ error = BadValue;
+ client->errorValue = val;
+ goto PatchUp;
+ }
+ pWin->winGravity = val;
+ break;
+ case CWBackingStore:
+ val = (CARD8 )*pVlist;
+ pVlist++;
+ if ((val != NotUseful) && (val != WhenMapped) && (val != Always))
+ {
+ error = BadValue;
+ client->errorValue = val;
+ goto PatchUp;
+ }
+ pWin->backingStore = val;
+ pWin->forcedBS = FALSE;
+ break;
+ case CWBackingPlanes:
+ if (pWin->optional || ((CARD32)*pVlist != (CARD32)~0L)) {
+ if (!pWin->optional && !MakeWindowOptional (pWin))
+ {
+ error = BadAlloc;
+ goto PatchUp;
+ }
+ pWin->optional->backingBitPlanes = (CARD32) *pVlist;
+ if ((CARD32)*pVlist == (CARD32)~0L)
+ checkOptional = TRUE;
+ }
+ pVlist++;
+ break;
+ case CWBackingPixel:
+ if (pWin->optional || (CARD32) *pVlist) {
+ if (!pWin->optional && !MakeWindowOptional (pWin))
+ {
+ error = BadAlloc;
+ goto PatchUp;
+ }
+ pWin->optional->backingPixel = (CARD32) *pVlist;
+ if (!*pVlist)
+ checkOptional = TRUE;
+ }
+ pVlist++;
+ break;
+ case CWSaveUnder:
+ val = (BOOL) *pVlist;
+ pVlist++;
+ if ((val != xTrue) && (val != xFalse))
+ {
+ error = BadValue;
+ client->errorValue = val;
+ goto PatchUp;
+ }
+ pWin->saveUnder = val;
+ break;
+ case CWEventMask:
+ rc = EventSelectForWindow(pWin, client, (Mask )*pVlist);
+ if (rc)
+ {
+ error = rc;
+ goto PatchUp;
+ }
+ pVlist++;
+ break;
+ case CWDontPropagate:
+ rc = EventSuppressForWindow(pWin, client, (Mask )*pVlist,
+ &checkOptional);
+ if (rc)
+ {
+ error = rc;
+ goto PatchUp;
+ }
+ pVlist++;
+ break;
+ case CWOverrideRedirect:
+ val = (BOOL ) *pVlist;
+ pVlist++;
+ if ((val != xTrue) && (val != xFalse))
+ {
+ error = BadValue;
+ client->errorValue = val;
+ goto PatchUp;
+ }
+ if (val == xTrue) {
+ rc = XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id,
+ RT_WINDOW, pWin, RT_NONE, NULL, DixGrabAccess);
+ if (rc != Success) {
+ error = rc;
+ client->errorValue = pWin->drawable.id;
+ goto PatchUp;
+ }
+ }
+ pWin->overrideRedirect = val;
+ break;
+ case CWColormap:
+ cmap = (Colormap) *pVlist;
+ pVlist++;
+ if (cmap == CopyFromParent)
+ {
+ if (pWin->parent &&
+ (!pWin->optional ||
+ pWin->optional->visual == wVisual (pWin->parent)))
+ {
+ cmap = wColormap (pWin->parent);
+ }
+ else
+ cmap = None;
+ }
+ if (cmap == None)
+ {
+ error = BadMatch;
+ goto PatchUp;
+ }
+ rc = dixLookupResourceByType((pointer *)&pCmap, cmap, RT_COLORMAP,
+ client, DixUseAccess);
+ if (rc != Success)
+ {
+ error = rc;
+ client->errorValue = cmap;
+ goto PatchUp;
+ }
+ if (pCmap->pVisual->vid != wVisual (pWin) ||
+ pCmap->pScreen != pScreen)
+ {
+ error = BadMatch;
+ goto PatchUp;
+ }
+ if (cmap != wColormap (pWin))
+ {
+ if (!pWin->optional)
+ {
+ if (!MakeWindowOptional (pWin))
+ {
+ error = BadAlloc;
+ goto PatchUp;
+ }
+ }
+ else if (pWin->parent && cmap == wColormap (pWin->parent))
+ checkOptional = TRUE;
+
+ /*
+ * propagate the original colormap to any children
+ * inheriting it
+ */
+
+ for (pChild = pWin->firstChild; pChild; pChild=pChild->nextSib)
+ {
+ if (!pChild->optional && !MakeWindowOptional (pChild))
+ {
+ error = BadAlloc;
+ goto PatchUp;
+ }
+ }
+
+ pWin->optional->colormap = cmap;
+
+ /*
+ * check on any children now matching the new colormap
+ */
+
+ for (pChild = pWin->firstChild; pChild; pChild=pChild->nextSib)
+ {
+ if (pChild->optional->colormap == cmap)
+ CheckWindowOptionalNeed (pChild);
+ }
+
+ xE.u.u.type = ColormapNotify;
+ xE.u.colormap.window = pWin->drawable.id;
+ xE.u.colormap.colormap = cmap;
+ xE.u.colormap.new = xTrue;
+ xE.u.colormap.state = IsMapInstalled(cmap, pWin);
+ DeliverEvents(pWin, &xE, 1, NullWindow);
+ }
+ break;
+ case CWCursor:
+ cursorID = (Cursor ) *pVlist;
+ pVlist++;
+ /*
+ * install the new
+ */
+ if ( cursorID == None)
+ {
+ if (pWin == pWin->drawable.pScreen->root)
+ pCursor = rootCursor;
+ else
+ pCursor = (CursorPtr) None;
+ }
+ else
+ {
+ rc = dixLookupResourceByType((pointer *)&pCursor, cursorID,
+ RT_CURSOR, client, DixUseAccess);
+ if (rc != Success)
+ {
+ error = rc;
+ client->errorValue = cursorID;
+ goto PatchUp;
+ }
+ }
+
+ if (pCursor != wCursor (pWin))
+ {
+ /*
+ * patch up child windows so they don't lose cursors.
+ */
+
+ for (pChild = pWin->firstChild; pChild; pChild=pChild->nextSib)
+ {
+ if (!pChild->optional && !pChild->cursorIsNone &&
+ !MakeWindowOptional (pChild))
+ {
+ error = BadAlloc;
+ goto PatchUp;
+ }
+ }
+
+ pOldCursor = 0;
+ if (pCursor == (CursorPtr) None)
+ {
+ pWin->cursorIsNone = TRUE;
+ if (pWin->optional)
+ {
+ pOldCursor = pWin->optional->cursor;
+ pWin->optional->cursor = (CursorPtr) None;
+ checkOptional = TRUE;
+ }
+ } else {
+ if (!pWin->optional)
+ {
+ if (!MakeWindowOptional (pWin))
+ {
+ error = BadAlloc;
+ goto PatchUp;
+ }
+ }
+ else if (pWin->parent && pCursor == wCursor (pWin->parent))
+ checkOptional = TRUE;
+ pOldCursor = pWin->optional->cursor;
+ pWin->optional->cursor = pCursor;
+ pCursor->refcnt++;
+ pWin->cursorIsNone = FALSE;
+ /*
+ * check on any children now matching the new cursor
+ */
+
+ for (pChild=pWin->firstChild; pChild; pChild=pChild->nextSib)
+ {
+ if (pChild->optional &&
+ (pChild->optional->cursor == pCursor))
+ CheckWindowOptionalNeed (pChild);
+ }
+ }
+
+ if (pWin->realized)
+ WindowHasNewCursor( pWin);
+
+ /* Can't free cursor until here - old cursor
+ * is needed in WindowHasNewCursor
+ */
+ if (pOldCursor)
+ FreeCursor (pOldCursor, (Cursor)0);
+ }
+ break;
+ default:
+ error = BadValue;
+ client->errorValue = vmask;
+ goto PatchUp;
+ }
+ vmaskCopy |= index2;
+ }
+PatchUp:
+ if (checkOptional)
+ CheckWindowOptionalNeed (pWin);
+
+ /* We SHOULD check for an error value here XXX */
+ (*pScreen->ChangeWindowAttributes)(pWin, vmaskCopy);
+
+ /*
+ If the border contents have changed, redraw the border.
+ Note that this has to be done AFTER pScreen->ChangeWindowAttributes
+ for the tile to be rotated, and the correct function selected.
+ */
+ if (((vmaskCopy & (CWBorderPixel | CWBorderPixmap)) || borderRelative)
+ && pWin->viewable && HasBorder (pWin))
+ {
+ RegionRec exposed;
+
+ RegionNull(&exposed);
+ RegionSubtract(&exposed, &pWin->borderClip, &pWin->winSize);
+ miPaintWindow(pWin, &exposed, PW_BORDER);
+ RegionUninit(&exposed);
+ }
+ return error;
+}
+
+
+/*****
+ * GetWindowAttributes
+ * Notice that this is different than ChangeWindowAttributes
+ *****/
+
+void
+GetWindowAttributes(WindowPtr pWin, ClientPtr client, xGetWindowAttributesReply *wa)
+{
+ wa->type = X_Reply;
+ wa->bitGravity = pWin->bitGravity;
+ wa->winGravity = pWin->winGravity;
+ if (pWin->forcedBS && pWin->backingStore != Always)
+ wa->backingStore = NotUseful;
+ else
+ wa->backingStore = pWin->backingStore;
+ wa->length = bytes_to_int32(sizeof(xGetWindowAttributesReply) -
+ sizeof(xGenericReply));
+ wa->sequenceNumber = client->sequence;
+ wa->backingBitPlanes = wBackingBitPlanes (pWin);
+ wa->backingPixel = wBackingPixel (pWin);
+ wa->saveUnder = (BOOL)pWin->saveUnder;
+ wa->override = pWin->overrideRedirect;
+ if (!pWin->mapped)
+ wa->mapState = IsUnmapped;
+ else if (pWin->realized)
+ wa->mapState = IsViewable;
+ else
+ wa->mapState = IsUnviewable;
+
+ wa->colormap = wColormap (pWin);
+ wa->mapInstalled = (wa->colormap == None) ? xFalse
+ : IsMapInstalled(wa->colormap, pWin);
+
+ wa->yourEventMask = EventMaskForClient(pWin, client);
+ wa->allEventMasks = pWin->eventMask | wOtherEventMasks (pWin);
+ wa->doNotPropagateMask = wDontPropagateMask (pWin);
+ wa->class = pWin->drawable.class;
+ wa->visualID = wVisual (pWin);
+}
+
+
+WindowPtr
+MoveWindowInStack(WindowPtr pWin, WindowPtr pNextSib)
+{
+ WindowPtr pParent = pWin->parent;
+ WindowPtr pFirstChange = pWin; /* highest window where list changes */
+
+ if (pWin->nextSib != pNextSib)
+ {
+ WindowPtr pOldNextSib = pWin->nextSib;
+
+ if (!pNextSib) /* move to bottom */
+ {
+ if (pParent->firstChild == pWin)
+ pParent->firstChild = pWin->nextSib;
+ /* if (pWin->nextSib) */ /* is always True: pNextSib == NULL
+ * and pWin->nextSib != pNextSib
+ * therefore pWin->nextSib != NULL */
+ pFirstChange = pWin->nextSib;
+ pWin->nextSib->prevSib = pWin->prevSib;
+ if (pWin->prevSib)
+ pWin->prevSib->nextSib = pWin->nextSib;
+ pParent->lastChild->nextSib = pWin;
+ pWin->prevSib = pParent->lastChild;
+ pWin->nextSib = NullWindow;
+ pParent->lastChild = pWin;
+ }
+ else if (pParent->firstChild == pNextSib) /* move to top */
+ {
+ pFirstChange = pWin;
+ if (pParent->lastChild == pWin)
+ pParent->lastChild = pWin->prevSib;
+ if (pWin->nextSib)
+ pWin->nextSib->prevSib = pWin->prevSib;
+ if (pWin->prevSib)
+ pWin->prevSib->nextSib = pWin->nextSib;
+ pWin->nextSib = pParent->firstChild;
+ pWin->prevSib = (WindowPtr ) NULL;
+ pNextSib->prevSib = pWin;
+ pParent->firstChild = pWin;
+ }
+ else /* move in middle of list */
+ {
+ WindowPtr pOldNext = pWin->nextSib;
+
+ pFirstChange = NullWindow;
+ if (pParent->firstChild == pWin)
+ pFirstChange = pParent->firstChild = pWin->nextSib;
+ if (pParent->lastChild == pWin) {
+ pFirstChange = pWin;
+ pParent->lastChild = pWin->prevSib;
+ }
+ if (pWin->nextSib)
+ pWin->nextSib->prevSib = pWin->prevSib;
+ if (pWin->prevSib)
+ pWin->prevSib->nextSib = pWin->nextSib;
+ pWin->nextSib = pNextSib;
+ pWin->prevSib = pNextSib->prevSib;
+ if (pNextSib->prevSib)
+ pNextSib->prevSib->nextSib = pWin;
+ pNextSib->prevSib = pWin;
+ if (!pFirstChange) { /* do we know it yet? */
+ pFirstChange = pParent->firstChild; /* no, search from top */
+ while ((pFirstChange != pWin) && (pFirstChange != pOldNext))
+ pFirstChange = pFirstChange->nextSib;
+ }
+ }
+ if(pWin->drawable.pScreen->RestackWindow)
+ (*pWin->drawable.pScreen->RestackWindow)(pWin, pOldNextSib);
+ }
+
+#ifdef ROOTLESS
+ /*
+ * In rootless mode we can't optimize away window restacks.
+ * There may be non-X windows around, so even if the window
+ * is in the correct position from X's point of view,
+ * the underlying window system may want to reorder it.
+ */
+ else if (pWin->drawable.pScreen->RestackWindow)
+ (*pWin->drawable.pScreen->RestackWindow)(pWin, pWin->nextSib);
+#endif
+
+ return pFirstChange;
+}
+
+void
+SetWinSize (WindowPtr pWin)
+{
+#ifdef COMPOSITE
+ if (pWin->redirectDraw != RedirectDrawNone)
+ {
+ BoxRec box;
+
+ /*
+ * Redirected clients get clip list equal to their
+ * own geometry, not clipped to their parent
+ */
+ box.x1 = pWin->drawable.x;
+ box.y1 = pWin->drawable.y;
+ box.x2 = pWin->drawable.x + pWin->drawable.width;
+ box.y2 = pWin->drawable.y + pWin->drawable.height;
+ RegionReset(&pWin->winSize, &box);
+ }
+ else
+#endif
+ ClippedRegionFromBox(pWin->parent, &pWin->winSize,
+ pWin->drawable.x, pWin->drawable.y,
+ (int)pWin->drawable.width,
+ (int)pWin->drawable.height);
+ if (wBoundingShape (pWin) || wClipShape (pWin)) {
+ RegionTranslate(&pWin->winSize, - pWin->drawable.x,
+ - pWin->drawable.y);
+ if (wBoundingShape (pWin))
+ RegionIntersect(&pWin->winSize, &pWin->winSize,
+ wBoundingShape (pWin));
+ if (wClipShape (pWin))
+ RegionIntersect(&pWin->winSize, &pWin->winSize,
+ wClipShape (pWin));
+ RegionTranslate(&pWin->winSize, pWin->drawable.x,
+ pWin->drawable.y);
+ }
+}
+
+void
+SetBorderSize (WindowPtr pWin)
+{
+ int bw;
+
+ if (HasBorder (pWin)) {
+ bw = wBorderWidth (pWin);
+#ifdef COMPOSITE
+ if (pWin->redirectDraw != RedirectDrawNone)
+ {
+ BoxRec box;
+
+ /*
+ * Redirected clients get clip list equal to their
+ * own geometry, not clipped to their parent
+ */
+ box.x1 = pWin->drawable.x - bw;
+ box.y1 = pWin->drawable.y - bw;
+ box.x2 = pWin->drawable.x + pWin->drawable.width + bw;
+ box.y2 = pWin->drawable.y + pWin->drawable.height + bw;
+ RegionReset(&pWin->borderSize, &box);
+ }
+ else
+#endif
+ ClippedRegionFromBox(pWin->parent, &pWin->borderSize,
+ pWin->drawable.x - bw, pWin->drawable.y - bw,
+ (int)(pWin->drawable.width + (bw<<1)),
+ (int)(pWin->drawable.height + (bw<<1)));
+ if (wBoundingShape (pWin)) {
+ RegionTranslate(&pWin->borderSize, - pWin->drawable.x,
+ - pWin->drawable.y);
+ RegionIntersect(&pWin->borderSize, &pWin->borderSize,
+ wBoundingShape (pWin));
+ RegionTranslate(&pWin->borderSize, pWin->drawable.x,
+ pWin->drawable.y);
+ RegionUnion(&pWin->borderSize, &pWin->borderSize,
+ &pWin->winSize);
+ }
+ } else {
+ RegionCopy(&pWin->borderSize, &pWin->winSize);
+ }
+}
+
+/**
+ *
+ * \param x,y new window position
+ * \param oldx,oldy old window position
+ * \param destx,desty position relative to gravity
+ */
+
+void
+GravityTranslate (int x, int y, int oldx, int oldy,
+ int dw, int dh, unsigned gravity,
+ int *destx, int *desty)
+{
+ switch (gravity) {
+ case NorthGravity:
+ *destx = x + dw / 2;
+ *desty = y;
+ break;
+ case NorthEastGravity:
+ *destx = x + dw;
+ *desty = y;
+ break;
+ case WestGravity:
+ *destx = x;
+ *desty = y + dh / 2;
+ break;
+ case CenterGravity:
+ *destx = x + dw / 2;
+ *desty = y + dh / 2;
+ break;
+ case EastGravity:
+ *destx = x + dw;
+ *desty = y + dh / 2;
+ break;
+ case SouthWestGravity:
+ *destx = x;
+ *desty = y + dh;
+ break;
+ case SouthGravity:
+ *destx = x + dw / 2;
+ *desty = y + dh;
+ break;
+ case SouthEastGravity:
+ *destx = x + dw;
+ *desty = y + dh;
+ break;
+ case StaticGravity:
+ *destx = oldx;
+ *desty = oldy;
+ break;
+ default:
+ *destx = x;
+ *desty = y;
+ break;
+ }
+}
+
+/* XXX need to retile border on each window with ParentRelative origin */
+void
+ResizeChildrenWinSize(WindowPtr pWin, int dx, int dy, int dw, int dh)
+{
+ ScreenPtr pScreen;
+ WindowPtr pSib, pChild;
+ Bool resized = (dw || dh);
+
+ pScreen = pWin->drawable.pScreen;
+
+ for (pSib = pWin->firstChild; pSib; pSib = pSib->nextSib)
+ {
+ if (resized && (pSib->winGravity > NorthWestGravity))
+ {
+ int cwsx, cwsy;
+
+ cwsx = pSib->origin.x;
+ cwsy = pSib->origin.y;
+ GravityTranslate (cwsx, cwsy, cwsx - dx, cwsy - dy, dw, dh,
+ pSib->winGravity, &cwsx, &cwsy);
+ if (cwsx != pSib->origin.x || cwsy != pSib->origin.y)
+ {
+ xEvent event;
+
+ event.u.u.type = GravityNotify;
+ event.u.gravity.window = pSib->drawable.id;
+ event.u.gravity.x = cwsx - wBorderWidth (pSib);
+ event.u.gravity.y = cwsy - wBorderWidth (pSib);
+ DeliverEvents (pSib, &event, 1, NullWindow);
+ pSib->origin.x = cwsx;
+ pSib->origin.y = cwsy;
+ }
+ }
+ pSib->drawable.x = pWin->drawable.x + pSib->origin.x;
+ pSib->drawable.y = pWin->drawable.y + pSib->origin.y;
+ SetWinSize (pSib);
+ SetBorderSize (pSib);
+ (*pScreen->PositionWindow)(pSib, pSib->drawable.x, pSib->drawable.y);
+
+ if ( (pChild = pSib->firstChild) )
+ {
+ while (1)
+ {
+ pChild->drawable.x = pChild->parent->drawable.x +
+ pChild->origin.x;
+ pChild->drawable.y = pChild->parent->drawable.y +
+ pChild->origin.y;
+ SetWinSize (pChild);
+ SetBorderSize (pChild);
+ (*pScreen->PositionWindow)(pChild,
+ pChild->drawable.x, pChild->drawable.y);
+ if (pChild->firstChild)
+ {
+ pChild = pChild->firstChild;
+ continue;
+ }
+ while (!pChild->nextSib && (pChild != pSib))
+ pChild = pChild->parent;
+ if (pChild == pSib)
+ break;
+ pChild = pChild->nextSib;
+ }
+ }
+ }
+}
+
+#define GET_INT16(m, f) \
+ if (m & mask) \
+ { \
+ f = (INT16) *pVlist;\
+ pVlist++; \
+ }
+#define GET_CARD16(m, f) \
+ if (m & mask) \
+ { \
+ f = (CARD16) *pVlist;\
+ pVlist++;\
+ }
+
+#define GET_CARD8(m, f) \
+ if (m & mask) \
+ { \
+ f = (CARD8) *pVlist;\
+ pVlist++;\
+ }
+
+#define ChangeMask ((Mask)(CWX | CWY | CWWidth | CWHeight))
+
+#define IllegalInputOnlyConfigureMask (CWBorderWidth)
+
+/*
+ * IsSiblingAboveMe
+ * returns Above if pSib above pMe in stack or Below otherwise
+ */
+
+static int
+IsSiblingAboveMe(
+ WindowPtr pMe,
+ WindowPtr pSib)
+{
+ WindowPtr pWin;
+
+ pWin = pMe->parent->firstChild;
+ while (pWin)
+ {
+ if (pWin == pSib)
+ return Above;
+ else if (pWin == pMe)
+ return Below;
+ pWin = pWin->nextSib;
+ }
+ return Below;
+}
+
+static BoxPtr
+WindowExtents(
+ WindowPtr pWin,
+ BoxPtr pBox)
+{
+ pBox->x1 = pWin->drawable.x - wBorderWidth (pWin);
+ pBox->y1 = pWin->drawable.y - wBorderWidth (pWin);
+ pBox->x2 = pWin->drawable.x + (int)pWin->drawable.width
+ + wBorderWidth (pWin);
+ pBox->y2 = pWin->drawable.y + (int)pWin->drawable.height
+ + wBorderWidth (pWin);
+ return pBox;
+}
+
+#define IS_SHAPED(pWin) (wBoundingShape (pWin) != (RegionPtr) NULL)
+
+static RegionPtr
+MakeBoundingRegion (
+ WindowPtr pWin,
+ BoxPtr pBox)
+{
+ RegionPtr pRgn = RegionCreate(pBox, 1);
+ if (wBoundingShape (pWin)) {
+ RegionTranslate(pRgn, -pWin->origin.x, -pWin->origin.y);
+ RegionIntersect(pRgn, pRgn, wBoundingShape (pWin));
+ RegionTranslate(pRgn, pWin->origin.x, pWin->origin.y);
+ }
+ return pRgn;
+}
+
+static Bool
+ShapeOverlap (
+ WindowPtr pWin,
+ BoxPtr pWinBox,
+ WindowPtr pSib,
+ BoxPtr pSibBox)
+{
+ RegionPtr pWinRgn, pSibRgn;
+ Bool ret;
+
+ if (!IS_SHAPED(pWin) && !IS_SHAPED(pSib))
+ return TRUE;
+ pWinRgn = MakeBoundingRegion (pWin, pWinBox);
+ pSibRgn = MakeBoundingRegion (pSib, pSibBox);
+ RegionIntersect(pWinRgn, pWinRgn, pSibRgn);
+ ret = RegionNotEmpty(pWinRgn);
+ RegionDestroy(pWinRgn);
+ RegionDestroy(pSibRgn);
+ return ret;
+}
+
+static Bool
+AnyWindowOverlapsMe(
+ WindowPtr pWin,
+ WindowPtr pHead,
+ BoxPtr box)
+{
+ WindowPtr pSib;
+ BoxRec sboxrec;
+ BoxPtr sbox;
+
+ for (pSib = pWin->prevSib; pSib != pHead; pSib = pSib->prevSib)
+ {
+ if (pSib->mapped)
+ {
+ sbox = WindowExtents(pSib, &sboxrec);
+ if (BOXES_OVERLAP(sbox, box)
+ && ShapeOverlap (pWin, box, pSib, sbox)
+ )
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static Bool
+IOverlapAnyWindow(
+ WindowPtr pWin,
+ BoxPtr box)
+{
+ WindowPtr pSib;
+ BoxRec sboxrec;
+ BoxPtr sbox;
+
+ for (pSib = pWin->nextSib; pSib; pSib = pSib->nextSib)
+ {
+ if (pSib->mapped)
+ {
+ sbox = WindowExtents(pSib, &sboxrec);
+ if (BOXES_OVERLAP(sbox, box)
+ && ShapeOverlap (pWin, box, pSib, sbox)
+ )
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * WhereDoIGoInTheStack()
+ * Given pWin and pSib and the relationshipe smode, return
+ * the window that pWin should go ABOVE.
+ * If a pSib is specified:
+ * Above: pWin is placed just above pSib
+ * Below: pWin is placed just below pSib
+ * TopIf: if pSib occludes pWin, then pWin is placed
+ * at the top of the stack
+ * BottomIf: if pWin occludes pSib, then pWin is
+ * placed at the bottom of the stack
+ * Opposite: if pSib occludes pWin, then pWin is placed at the
+ * top of the stack, else if pWin occludes pSib, then
+ * pWin is placed at the bottom of the stack
+ *
+ * If pSib is NULL:
+ * Above: pWin is placed at the top of the stack
+ * Below: pWin is placed at the bottom of the stack
+ * TopIf: if any sibling occludes pWin, then pWin is placed at
+ * the top of the stack
+ * BottomIf: if pWin occludes any sibline, then pWin is placed at
+ * the bottom of the stack
+ * Opposite: if any sibling occludes pWin, then pWin is placed at
+ * the top of the stack, else if pWin occludes any
+ * sibling, then pWin is placed at the bottom of the stack
+ *
+ */
+
+static WindowPtr
+WhereDoIGoInTheStack(
+ WindowPtr pWin,
+ WindowPtr pSib,
+ short x,
+ short y,
+ unsigned short w,
+ unsigned short h,
+ int smode)
+{
+ BoxRec box;
+ WindowPtr pHead, pFirst;
+
+ if ((pWin == pWin->parent->firstChild) &&
+ (pWin == pWin->parent->lastChild))
+ return((WindowPtr ) NULL);
+ pHead = RealChildHead(pWin->parent);
+ pFirst = pHead ? pHead->nextSib : pWin->parent->firstChild;
+ box.x1 = x;
+ box.y1 = y;
+ box.x2 = x + (int)w;
+ box.y2 = y + (int)h;
+ switch (smode)
+ {
+ case Above:
+ if (pSib)
+ return pSib;
+ else if (pWin == pFirst)
+ return pWin->nextSib;
+ else
+ return pFirst;
+ case Below:
+ if (pSib)
+ if (pSib->nextSib != pWin)
+ return pSib->nextSib;
+ else
+ return pWin->nextSib;
+ else
+ return NullWindow;
+ case TopIf:
+ if ((!pWin->mapped || (pSib && !pSib->mapped)))
+ return pWin->nextSib;
+ else if (pSib)
+ {
+ if ((IsSiblingAboveMe(pWin, pSib) == Above) &&
+ (RegionContainsRect(&pSib->borderSize, &box) != rgnOUT))
+ return pFirst;
+ else
+ return pWin->nextSib;
+ }
+ else if (AnyWindowOverlapsMe(pWin, pHead, &box))
+ return pFirst;
+ else
+ return pWin->nextSib;
+ case BottomIf:
+ if ((!pWin->mapped || (pSib && !pSib->mapped)))
+ return pWin->nextSib;
+ else if (pSib)
+ {
+ if ((IsSiblingAboveMe(pWin, pSib) == Below) &&
+ (RegionContainsRect(&pSib->borderSize, &box) != rgnOUT))
+ return NullWindow;
+ else
+ return pWin->nextSib;
+ }
+ else if (IOverlapAnyWindow(pWin, &box))
+ return NullWindow;
+ else
+ return pWin->nextSib;
+ case Opposite:
+ if ((!pWin->mapped || (pSib && !pSib->mapped)))
+ return pWin->nextSib;
+ else if (pSib)
+ {
+ if (RegionContainsRect(&pSib->borderSize, &box) != rgnOUT)
+ {
+ if (IsSiblingAboveMe(pWin, pSib) == Above)
+ return pFirst;
+ else
+ return NullWindow;
+ }
+ else
+ return pWin->nextSib;
+ }
+ else if (AnyWindowOverlapsMe(pWin, pHead, &box))
+ {
+ /* If I'm occluded, I can't possibly be the first child
+ * if (pWin == pWin->parent->firstChild)
+ * return pWin->nextSib;
+ */
+ return pFirst;
+ }
+ else if (IOverlapAnyWindow(pWin, &box))
+ return NullWindow;
+ else
+ return pWin->nextSib;
+ default:
+ {
+ /* should never happen; make something up. */
+ return pWin->nextSib;
+ }
+ }
+}
+
+static void
+ReflectStackChange(
+ WindowPtr pWin,
+ WindowPtr pSib,
+ VTKind kind)
+{
+/* Note that pSib might be NULL */
+
+ Bool WasViewable = (Bool)pWin->viewable;
+ Bool anyMarked;
+ WindowPtr pFirstChange;
+ WindowPtr pLayerWin;
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+
+ /* if this is a root window, can't be restacked */
+ if (!pWin->parent)
+ return;
+
+ pFirstChange = MoveWindowInStack(pWin, pSib);
+
+ if (WasViewable)
+ {
+ anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pFirstChange,
+ &pLayerWin);
+ if (pLayerWin != pWin) pFirstChange = pLayerWin;
+ if (anyMarked)
+ {
+ (*pScreen->ValidateTree)(pLayerWin->parent, pFirstChange, kind);
+ (*pScreen->HandleExposures)(pLayerWin->parent);
+ }
+ if (anyMarked && pWin->drawable.pScreen->PostValidateTree)
+ (*pScreen->PostValidateTree)(pLayerWin->parent, pFirstChange, kind);
+ }
+ if (pWin->realized)
+ WindowsRestructured ();
+}
+
+/*****
+ * ConfigureWindow
+ *****/
+
+int
+ConfigureWindow(WindowPtr pWin, Mask mask, XID *vlist, ClientPtr client)
+{
+#define RESTACK_WIN 0
+#define MOVE_WIN 1
+#define RESIZE_WIN 2
+#define REBORDER_WIN 3
+ WindowPtr pSib = NullWindow;
+ WindowPtr pParent = pWin->parent;
+ Window sibwid = 0;
+ Mask index2, tmask;
+ XID *pVlist;
+ short x, y, beforeX, beforeY;
+ unsigned short w = pWin->drawable.width,
+ h = pWin->drawable.height,
+ bw = pWin->borderWidth;
+ int rc, action, smode = Above;
+ xEvent event;
+
+ if ((pWin->drawable.class == InputOnly) && (mask & IllegalInputOnlyConfigureMask))
+ return BadMatch;
+
+ if ((mask & CWSibling) && !(mask & CWStackMode))
+ return BadMatch;
+
+ pVlist = vlist;
+
+ if (pParent)
+ {
+ x = pWin->drawable.x - pParent->drawable.x - (int)bw;
+ y = pWin->drawable.y - pParent->drawable.y - (int)bw;
+ }
+ else
+ {
+ x = pWin->drawable.x;
+ y = pWin->drawable.y;
+ }
+ beforeX = x;
+ beforeY = y;
+ action = RESTACK_WIN;
+ if ((mask & (CWX | CWY)) && (!(mask & (CWHeight | CWWidth))))
+ {
+ GET_INT16(CWX, x);
+ GET_INT16(CWY, y);
+ action = MOVE_WIN;
+ }
+ /* or should be resized */
+ else if (mask & (CWX | CWY | CWWidth | CWHeight))
+ {
+ GET_INT16(CWX, x);
+ GET_INT16(CWY, y);
+ GET_CARD16(CWWidth, w);
+ GET_CARD16 (CWHeight, h);
+ if (!w || !h)
+ {
+ client->errorValue = 0;
+ return BadValue;
+ }
+ action = RESIZE_WIN;
+ }
+ tmask = mask & ~ChangeMask;
+ while (tmask)
+ {
+ index2 = (Mask)lowbit (tmask);
+ tmask &= ~index2;
+ switch (index2)
+ {
+ case CWBorderWidth:
+ GET_CARD16(CWBorderWidth, bw);
+ break;
+ case CWSibling:
+ sibwid = (Window ) *pVlist;
+ pVlist++;
+ rc = dixLookupWindow(&pSib, sibwid, client, DixGetAttrAccess);
+ if (rc != Success)
+ {
+ client->errorValue = sibwid;
+ return rc;
+ }
+ if (pSib->parent != pParent)
+ return BadMatch;
+ if (pSib == pWin)
+ return BadMatch;
+ break;
+ case CWStackMode:
+ GET_CARD8(CWStackMode, smode);
+ if ((smode != TopIf) && (smode != BottomIf) &&
+ (smode != Opposite) && (smode != Above) && (smode != Below))
+ {
+ client->errorValue = smode;
+ return BadValue;
+ }
+ break;
+ default:
+ client->errorValue = mask;
+ return BadValue;
+ }
+ }
+ /* root really can't be reconfigured, so just return */
+ if (!pParent)
+ return Success;
+
+ /* Figure out if the window should be moved. Doesnt
+ make the changes to the window if event sent */
+
+ if (mask & CWStackMode)
+ pSib = WhereDoIGoInTheStack(pWin, pSib, pParent->drawable.x + x,
+ pParent->drawable.y + y,
+ w + (bw << 1), h + (bw << 1), smode);
+ else
+ pSib = pWin->nextSib;
+
+
+ if ((!pWin->overrideRedirect) &&
+ (RedirectSend(pParent)
+ ))
+ {
+ memset(&event, 0, sizeof(xEvent));
+ event.u.u.type = ConfigureRequest;
+ event.u.configureRequest.window = pWin->drawable.id;
+ if (mask & CWSibling)
+ event.u.configureRequest.sibling = sibwid;
+ else
+ event.u.configureRequest.sibling = None;
+ if (mask & CWStackMode)
+ event.u.u.detail = smode;
+ else
+ event.u.u.detail = Above;
+ event.u.configureRequest.x = x;
+ event.u.configureRequest.y = y;
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension && (!pParent || !pParent->parent)) {
+ event.u.configureRequest.x += screenInfo.screens[0]->x;
+ event.u.configureRequest.y += screenInfo.screens[0]->y;
+ }
+#endif
+ event.u.configureRequest.width = w;
+ event.u.configureRequest.height = h;
+ event.u.configureRequest.borderWidth = bw;
+ event.u.configureRequest.valueMask = mask;
+ event.u.configureRequest.parent = pParent->drawable.id;
+ if (MaybeDeliverEventsToClient(pParent, &event, 1,
+ SubstructureRedirectMask, client) == 1)
+ return Success;
+ }
+ if (action == RESIZE_WIN)
+ {
+ Bool size_change = (w != pWin->drawable.width)
+ || (h != pWin->drawable.height);
+ if (size_change && ((pWin->eventMask|wOtherEventMasks(pWin)) & ResizeRedirectMask))
+ {
+ xEvent eventT;
+ memset(&eventT, 0, sizeof(xEvent));
+ eventT.u.u.type = ResizeRequest;
+ eventT.u.resizeRequest.window = pWin->drawable.id;
+ eventT.u.resizeRequest.width = w;
+ eventT.u.resizeRequest.height = h;
+ if (MaybeDeliverEventsToClient(pWin, &eventT, 1,
+ ResizeRedirectMask, client) == 1)
+ {
+ /* if event is delivered, leave the actual size alone. */
+ w = pWin->drawable.width;
+ h = pWin->drawable.height;
+ size_change = FALSE;
+ }
+ }
+ if (!size_change)
+ {
+ if (mask & (CWX | CWY))
+ action = MOVE_WIN;
+ else if (mask & (CWStackMode | CWBorderWidth))
+ action = RESTACK_WIN;
+ else /* really nothing to do */
+ return(Success) ;
+ }
+ }
+
+ if (action == RESIZE_WIN)
+ /* we've already checked whether there's really a size change */
+ goto ActuallyDoSomething;
+ if ((mask & CWX) && (x != beforeX))
+ goto ActuallyDoSomething;
+ if ((mask & CWY) && (y != beforeY))
+ goto ActuallyDoSomething;
+ if ((mask & CWBorderWidth) && (bw != wBorderWidth (pWin)))
+ goto ActuallyDoSomething;
+ if (mask & CWStackMode)
+ {
+#ifndef ROOTLESS
+ /* See above for why we always reorder in rootless mode. */
+ if (pWin->nextSib != pSib)
+#endif
+ goto ActuallyDoSomething;
+ }
+ return Success;
+
+ActuallyDoSomething:
+ if (pWin->drawable.pScreen->ConfigNotify)
+ {
+ int ret;
+ ret = (*pWin->drawable.pScreen->ConfigNotify)(pWin, x, y, w, h, bw, pSib);
+ if (ret) {
+ client->errorValue = 0;
+ return ret;
+ }
+ }
+
+ if (SubStrSend(pWin, pParent))
+ {
+ memset(&event, 0, sizeof(xEvent));
+ event.u.u.type = ConfigureNotify;
+ event.u.configureNotify.window = pWin->drawable.id;
+ if (pSib)
+ event.u.configureNotify.aboveSibling = pSib->drawable.id;
+ else
+ event.u.configureNotify.aboveSibling = None;
+ event.u.configureNotify.x = x;
+ event.u.configureNotify.y = y;
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension && (!pParent || !pParent->parent)) {
+ event.u.configureNotify.x += screenInfo.screens[0]->x;
+ event.u.configureNotify.y += screenInfo.screens[0]->y;
+ }
+#endif
+ event.u.configureNotify.width = w;
+ event.u.configureNotify.height = h;
+ event.u.configureNotify.borderWidth = bw;
+ event.u.configureNotify.override = pWin->overrideRedirect;
+ DeliverEvents(pWin, &event, 1, NullWindow);
+ }
+ if (mask & CWBorderWidth)
+ {
+ if (action == RESTACK_WIN)
+ {
+ action = MOVE_WIN;
+ pWin->borderWidth = bw;
+ }
+ else if ((action == MOVE_WIN) &&
+ (beforeX + wBorderWidth (pWin) == x + (int)bw) &&
+ (beforeY + wBorderWidth (pWin) == y + (int)bw))
+ {
+ action = REBORDER_WIN;
+ (*pWin->drawable.pScreen->ChangeBorderWidth)(pWin, bw);
+ }
+ else
+ pWin->borderWidth = bw;
+ }
+ if (action == MOVE_WIN)
+ (*pWin->drawable.pScreen->MoveWindow)(pWin, x, y, pSib,
+ (mask & CWBorderWidth) ? VTOther : VTMove);
+ else if (action == RESIZE_WIN)
+ (*pWin->drawable.pScreen->ResizeWindow)(pWin, x, y, w, h, pSib);
+ else if (mask & CWStackMode)
+ ReflectStackChange(pWin, pSib, VTOther);
+
+ if (action != RESTACK_WIN)
+ CheckCursorConfinement(pWin);
+ return Success;
+#undef RESTACK_WIN
+#undef MOVE_WIN
+#undef RESIZE_WIN
+#undef REBORDER_WIN
+}
+
+
+/******
+ *
+ * CirculateWindow
+ * For RaiseLowest, raises the lowest mapped child (if any) that is
+ * obscured by another child to the top of the stack. For LowerHighest,
+ * lowers the highest mapped child (if any) that is obscuring another
+ * child to the bottom of the stack. Exposure processing is performed
+ *
+ ******/
+
+int
+CirculateWindow(WindowPtr pParent, int direction, ClientPtr client)
+{
+ WindowPtr pWin, pHead, pFirst;
+ xEvent event;
+ BoxRec box;
+
+ pHead = RealChildHead(pParent);
+ pFirst = pHead ? pHead->nextSib : pParent->firstChild;
+ if (direction == RaiseLowest)
+ {
+ for (pWin = pParent->lastChild;
+ (pWin != pHead) &&
+ !(pWin->mapped &&
+ AnyWindowOverlapsMe(pWin, pHead, WindowExtents(pWin, &box)));
+ pWin = pWin->prevSib) ;
+ if (pWin == pHead)
+ return Success;
+ }
+ else
+ {
+ for (pWin = pFirst;
+ pWin &&
+ !(pWin->mapped &&
+ IOverlapAnyWindow(pWin, WindowExtents(pWin, &box)));
+ pWin = pWin->nextSib) ;
+ if (!pWin)
+ return Success;
+ }
+
+ event.u.circulate.window = pWin->drawable.id;
+ event.u.circulate.parent = pParent->drawable.id;
+ event.u.circulate.event = pParent->drawable.id;
+ if (direction == RaiseLowest)
+ event.u.circulate.place = PlaceOnTop;
+ else
+ event.u.circulate.place = PlaceOnBottom;
+
+ if (RedirectSend(pParent))
+ {
+ event.u.u.type = CirculateRequest;
+ if (MaybeDeliverEventsToClient(pParent, &event, 1,
+ SubstructureRedirectMask, client) == 1)
+ return Success;
+ }
+
+ event.u.u.type = CirculateNotify;
+ DeliverEvents(pWin, &event, 1, NullWindow);
+ ReflectStackChange(pWin,
+ (direction == RaiseLowest) ? pFirst : NullWindow,
+ VTStack);
+
+ return Success;
+}
+
+static int
+CompareWIDs(
+ WindowPtr pWin,
+ pointer value) /* must conform to VisitWindowProcPtr */
+{
+ Window *wid = (Window *)value;
+
+ if (pWin->drawable.id == *wid)
+ return WT_STOPWALKING;
+ else
+ return WT_WALKCHILDREN;
+}
+
+/*****
+ * ReparentWindow
+ *****/
+
+int
+ReparentWindow(WindowPtr pWin, WindowPtr pParent,
+ int x, int y, ClientPtr client)
+{
+ WindowPtr pPrev, pPriorParent;
+ Bool WasMapped = (Bool)(pWin->mapped);
+ xEvent event;
+ int bw = wBorderWidth (pWin);
+ ScreenPtr pScreen;
+
+ pScreen = pWin->drawable.pScreen;
+ if (TraverseTree(pWin, CompareWIDs, (pointer)&pParent->drawable.id) == WT_STOPWALKING)
+ return BadMatch;
+ if (!MakeWindowOptional(pWin))
+ return BadAlloc;
+
+ if (WasMapped)
+ UnmapWindow(pWin, FALSE);
+
+ memset(&event, 0, sizeof(xEvent));
+ event.u.u.type = ReparentNotify;
+ event.u.reparent.window = pWin->drawable.id;
+ event.u.reparent.parent = pParent->drawable.id;
+ event.u.reparent.x = x;
+ event.u.reparent.y = y;
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension && !pParent->parent) {
+ event.u.reparent.x += screenInfo.screens[0]->x;
+ event.u.reparent.y += screenInfo.screens[0]->y;
+ }
+#endif
+ event.u.reparent.override = pWin->overrideRedirect;
+ DeliverEvents(pWin, &event, 1, pParent);
+
+ /* take out of sibling chain */
+
+ pPriorParent = pPrev = pWin->parent;
+ if (pPrev->firstChild == pWin)
+ pPrev->firstChild = pWin->nextSib;
+ if (pPrev->lastChild == pWin)
+ pPrev->lastChild = pWin->prevSib;
+
+ if (pWin->nextSib)
+ pWin->nextSib->prevSib = pWin->prevSib;
+ if (pWin->prevSib)
+ pWin->prevSib->nextSib = pWin->nextSib;
+
+ /* insert at begining of pParent */
+ pWin->parent = pParent;
+ pPrev = RealChildHead(pParent);
+ if (pPrev)
+ {
+ pWin->nextSib = pPrev->nextSib;
+ if (pPrev->nextSib)
+ pPrev->nextSib->prevSib = pWin;
+ else
+ pParent->lastChild = pWin;
+ pPrev->nextSib = pWin;
+ pWin->prevSib = pPrev;
+ }
+ else
+ {
+ pWin->nextSib = pParent->firstChild;
+ pWin->prevSib = NullWindow;
+ if (pParent->firstChild)
+ pParent->firstChild->prevSib = pWin;
+ else
+ pParent->lastChild = pWin;
+ pParent->firstChild = pWin;
+ }
+
+ pWin->origin.x = x + bw;
+ pWin->origin.y = y + bw;
+ pWin->drawable.x = x + bw + pParent->drawable.x;
+ pWin->drawable.y = y + bw + pParent->drawable.y;
+
+ /* clip to parent */
+ SetWinSize (pWin);
+ SetBorderSize (pWin);
+
+ if (pScreen->ReparentWindow)
+ (*pScreen->ReparentWindow)(pWin, pPriorParent);
+ (*pScreen->PositionWindow)(pWin, pWin->drawable.x, pWin->drawable.y);
+ ResizeChildrenWinSize(pWin, 0, 0, 0, 0);
+
+ CheckWindowOptionalNeed(pWin);
+
+ if (WasMapped)
+ MapWindow(pWin, client);
+ RecalculateDeliverableEvents(pWin);
+ return Success;
+}
+
+static void
+RealizeTree(WindowPtr pWin)
+{
+ WindowPtr pChild;
+ RealizeWindowProcPtr Realize;
+
+ Realize = pWin->drawable.pScreen->RealizeWindow;
+ pChild = pWin;
+ while (1)
+ {
+ if (pChild->mapped)
+ {
+ pChild->realized = TRUE;
+ pChild->viewable = (pChild->drawable.class == InputOutput);
+ (* Realize)(pChild);
+ if (pChild->firstChild)
+ {
+ pChild = pChild->firstChild;
+ continue;
+ }
+ }
+ while (!pChild->nextSib && (pChild != pWin))
+ pChild = pChild->parent;
+ if (pChild == pWin)
+ return;
+ pChild = pChild->nextSib;
+ }
+}
+
+static WindowPtr windowDisableMapUnmapEvents;
+
+void
+DisableMapUnmapEvents(WindowPtr pWin)
+{
+ assert (windowDisableMapUnmapEvents == NULL);
+
+ windowDisableMapUnmapEvents = pWin;
+}
+
+void
+EnableMapUnmapEvents(WindowPtr pWin)
+{
+ assert (windowDisableMapUnmapEvents != NULL);
+
+ windowDisableMapUnmapEvents = NULL;
+}
+
+static Bool
+MapUnmapEventsEnabled(WindowPtr pWin)
+{
+ return pWin != windowDisableMapUnmapEvents;
+}
+
+/*****
+ * MapWindow
+ * If some other client has selected SubStructureReDirect on the parent
+ * and override-redirect is xFalse, then a MapRequest event is generated,
+ * but the window remains unmapped. Otherwise, the window is mapped and a
+ * MapNotify event is generated.
+ *****/
+
+int
+MapWindow(WindowPtr pWin, ClientPtr client)
+{
+ ScreenPtr pScreen;
+
+ WindowPtr pParent;
+ WindowPtr pLayerWin;
+
+ if (pWin->mapped)
+ return Success;
+
+ /* general check for permission to map window */
+ if (XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id, RT_WINDOW,
+ pWin, RT_NONE, NULL, DixShowAccess) != Success)
+ return Success;
+
+ pScreen = pWin->drawable.pScreen;
+ if ( (pParent = pWin->parent) )
+ {
+ xEvent event;
+ Bool anyMarked;
+
+ if ((!pWin->overrideRedirect) &&
+ (RedirectSend(pParent)
+ ))
+ {
+ memset(&event, 0, sizeof(xEvent));
+ event.u.u.type = MapRequest;
+ event.u.mapRequest.window = pWin->drawable.id;
+ event.u.mapRequest.parent = pParent->drawable.id;
+
+ if (MaybeDeliverEventsToClient(pParent, &event, 1,
+ SubstructureRedirectMask, client) == 1)
+ return Success;
+ }
+
+ pWin->mapped = TRUE;
+ if (SubStrSend(pWin, pParent) && MapUnmapEventsEnabled(pWin))
+ {
+ memset(&event, 0, sizeof(xEvent));
+ event.u.u.type = MapNotify;
+ event.u.mapNotify.window = pWin->drawable.id;
+ event.u.mapNotify.override = pWin->overrideRedirect;
+ DeliverEvents(pWin, &event, 1, NullWindow);
+ }
+
+ if (!pParent->realized)
+ return Success;
+ RealizeTree(pWin);
+ if (pWin->viewable)
+ {
+ anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin,
+ &pLayerWin);
+ if (anyMarked)
+ {
+ (*pScreen->ValidateTree)(pLayerWin->parent, pLayerWin, VTMap);
+ (*pScreen->HandleExposures)(pLayerWin->parent);
+ }
+ if (anyMarked && pScreen->PostValidateTree)
+ (*pScreen->PostValidateTree)(pLayerWin->parent, pLayerWin, VTMap);
+ }
+ WindowsRestructured ();
+ }
+ else
+ {
+ RegionRec temp;
+
+ pWin->mapped = TRUE;
+ pWin->realized = TRUE; /* for roots */
+ pWin->viewable = pWin->drawable.class == InputOutput;
+ /* We SHOULD check for an error value here XXX */
+ (*pScreen->RealizeWindow)(pWin);
+ if (pScreen->ClipNotify)
+ (*pScreen->ClipNotify) (pWin, 0, 0);
+ if (pScreen->PostValidateTree)
+ (*pScreen->PostValidateTree)(NullWindow, pWin, VTMap);
+ RegionNull(&temp);
+ RegionCopy(&temp, &pWin->clipList);
+ (*pScreen->WindowExposures) (pWin, &temp, NullRegion);
+ RegionUninit(&temp);
+ }
+
+ return Success;
+}
+
+
+/*****
+ * MapSubwindows
+ * Performs a MapWindow all unmapped children of the window, in top
+ * to bottom stacking order.
+ *****/
+
+void
+MapSubwindows(WindowPtr pParent, ClientPtr client)
+{
+ WindowPtr pWin;
+ WindowPtr pFirstMapped = NullWindow;
+ ScreenPtr pScreen;
+ Mask parentRedirect;
+ Mask parentNotify;
+ xEvent event;
+ Bool anyMarked;
+ WindowPtr pLayerWin;
+
+ pScreen = pParent->drawable.pScreen;
+ parentRedirect = RedirectSend(pParent);
+ parentNotify = SubSend(pParent);
+ anyMarked = FALSE;
+ for (pWin = pParent->firstChild; pWin; pWin = pWin->nextSib)
+ {
+ if (!pWin->mapped)
+ {
+ if (parentRedirect && !pWin->overrideRedirect)
+ {
+ memset(&event, 0, sizeof(xEvent));
+ event.u.u.type = MapRequest;
+ event.u.mapRequest.window = pWin->drawable.id;
+ event.u.mapRequest.parent = pParent->drawable.id;
+
+ if (MaybeDeliverEventsToClient(pParent, &event, 1,
+ SubstructureRedirectMask, client) == 1)
+ continue;
+ }
+
+ pWin->mapped = TRUE;
+ if (parentNotify || StrSend(pWin))
+ {
+ memset(&event, 0, sizeof(xEvent));
+ event.u.u.type = MapNotify;
+ event.u.mapNotify.window = pWin->drawable.id;
+ event.u.mapNotify.override = pWin->overrideRedirect;
+ DeliverEvents(pWin, &event, 1, NullWindow);
+ }
+
+ if (!pFirstMapped)
+ pFirstMapped = pWin;
+ if (pParent->realized)
+ {
+ RealizeTree(pWin);
+ if (pWin->viewable)
+ {
+ anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pWin,
+ (WindowPtr *)NULL);
+ }
+ }
+ }
+ }
+
+ if (pFirstMapped)
+ {
+ pLayerWin = (*pScreen->GetLayerWindow)(pParent);
+ if (pLayerWin->parent != pParent) {
+ anyMarked |= (*pScreen->MarkOverlappedWindows)(pLayerWin,
+ pLayerWin,
+ (WindowPtr *)NULL);
+ pFirstMapped = pLayerWin;
+ }
+ if (anyMarked)
+ {
+ (*pScreen->ValidateTree)(pLayerWin->parent, pFirstMapped, VTMap);
+ (*pScreen->HandleExposures)(pLayerWin->parent);
+ }
+ if (anyMarked && pScreen->PostValidateTree)
+ (*pScreen->PostValidateTree)(pLayerWin->parent, pFirstMapped,
+ VTMap);
+ WindowsRestructured ();
+ }
+}
+
+static void
+UnrealizeTree(
+ WindowPtr pWin,
+ Bool fromConfigure)
+{
+ WindowPtr pChild;
+ UnrealizeWindowProcPtr Unrealize;
+ MarkUnrealizedWindowProcPtr MarkUnrealizedWindow;
+
+ Unrealize = pWin->drawable.pScreen->UnrealizeWindow;
+ MarkUnrealizedWindow = pWin->drawable.pScreen->MarkUnrealizedWindow;
+ pChild = pWin;
+ while (1)
+ {
+ if (pChild->realized)
+ {
+ pChild->realized = FALSE;
+ pChild->visibility = VisibilityNotViewable;
+#ifdef PANORAMIX
+ if(!noPanoramiXExtension && !pChild->drawable.pScreen->myNum) {
+ PanoramiXRes *win;
+ int rc = dixLookupResourceByType((pointer *)&win,
+ pChild->drawable.id, XRT_WINDOW,
+ serverClient, DixWriteAccess);
+ if (rc == Success)
+ win->u.win.visibility = VisibilityNotViewable;
+ }
+#endif
+ (* Unrealize)(pChild);
+ if (MapUnmapEventsEnabled(pWin))
+ DeleteWindowFromAnyEvents(pChild, FALSE);
+ if (pChild->viewable)
+ {
+ pChild->viewable = FALSE;
+ (* MarkUnrealizedWindow)(pChild, pWin, fromConfigure);
+ pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ }
+ if (pChild->firstChild)
+ {
+ pChild = pChild->firstChild;
+ continue;
+ }
+ }
+ while (!pChild->nextSib && (pChild != pWin))
+ pChild = pChild->parent;
+ if (pChild == pWin)
+ return;
+ pChild = pChild->nextSib;
+ }
+}
+
+/*****
+ * UnmapWindow
+ * If the window is already unmapped, this request has no effect.
+ * Otherwise, the window is unmapped and an UnMapNotify event is
+ * generated. Cannot unmap a root window.
+ *****/
+
+int
+UnmapWindow(WindowPtr pWin, Bool fromConfigure)
+{
+ WindowPtr pParent;
+ xEvent event;
+ Bool wasRealized = (Bool)pWin->realized;
+ Bool wasViewable = (Bool)pWin->viewable;
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ WindowPtr pLayerWin = pWin;
+
+ if ((!pWin->mapped) || (!(pParent = pWin->parent)))
+ return Success;
+ if (SubStrSend(pWin, pParent) && MapUnmapEventsEnabled(pWin))
+ {
+ memset(&event, 0, sizeof(xEvent));
+ event.u.u.type = UnmapNotify;
+ event.u.unmapNotify.window = pWin->drawable.id;
+ event.u.unmapNotify.fromConfigure = fromConfigure;
+ DeliverEvents(pWin, &event, 1, NullWindow);
+ }
+ if (wasViewable && !fromConfigure)
+ {
+ pWin->valdata = UnmapValData;
+ (*pScreen->MarkOverlappedWindows)(pWin, pWin->nextSib, &pLayerWin);
+ (*pScreen->MarkWindow)(pLayerWin->parent);
+ }
+ pWin->mapped = FALSE;
+ if (wasRealized)
+ UnrealizeTree(pWin, fromConfigure);
+ if (wasViewable)
+ {
+ if (!fromConfigure)
+ {
+ (*pScreen->ValidateTree)(pLayerWin->parent, pWin, VTUnmap);
+ (*pScreen->HandleExposures)(pLayerWin->parent);
+ }
+ if (!fromConfigure && pScreen->PostValidateTree)
+ (*pScreen->PostValidateTree)(pLayerWin->parent, pWin, VTUnmap);
+ }
+ if (wasRealized && !fromConfigure)
+ WindowsRestructured ();
+ return Success;
+}
+
+/*****
+ * UnmapSubwindows
+ * Performs an UnmapWindow request with the specified mode on all mapped
+ * children of the window, in bottom to top stacking order.
+ *****/
+
+void
+UnmapSubwindows(WindowPtr pWin)
+{
+ WindowPtr pChild, pHead;
+ xEvent event;
+ Bool wasRealized = (Bool)pWin->realized;
+ Bool wasViewable = (Bool)pWin->viewable;
+ Bool anyMarked = FALSE;
+ Mask parentNotify;
+ WindowPtr pLayerWin = NULL;
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+
+ if (!pWin->firstChild)
+ return;
+ parentNotify = SubSend(pWin);
+ pHead = RealChildHead(pWin);
+
+ if (wasViewable)
+ pLayerWin = (*pScreen->GetLayerWindow)(pWin);
+
+ for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib)
+ {
+ if (pChild->mapped)
+ {
+ if (parentNotify || StrSend(pChild))
+ {
+ event.u.u.type = UnmapNotify;
+ event.u.unmapNotify.window = pChild->drawable.id;
+ event.u.unmapNotify.fromConfigure = xFalse;
+ DeliverEvents(pChild, &event, 1, NullWindow);
+ }
+ if (pChild->viewable)
+ {
+ pChild->valdata = UnmapValData;
+ anyMarked = TRUE;
+ }
+ pChild->mapped = FALSE;
+ if (pChild->realized)
+ UnrealizeTree(pChild, FALSE);
+ if (wasViewable)
+ {
+ }
+ }
+ }
+ if (wasViewable)
+ {
+ if (anyMarked)
+ {
+ if (pLayerWin->parent == pWin)
+ (*pScreen->MarkWindow)(pWin);
+ else
+ {
+ WindowPtr ptmp;
+ (*pScreen->MarkOverlappedWindows)(pWin, pLayerWin,
+ (WindowPtr *)NULL);
+ (*pScreen->MarkWindow)(pLayerWin->parent);
+
+ /* Windows between pWin and pLayerWin may not have been marked */
+ ptmp = pWin;
+
+ while (ptmp != pLayerWin->parent)
+ {
+ (*pScreen->MarkWindow)(ptmp);
+ ptmp = ptmp->parent;
+ }
+ pHead = pWin->firstChild;
+ }
+ (*pScreen->ValidateTree)(pLayerWin->parent, pHead, VTUnmap);
+ (*pScreen->HandleExposures)(pLayerWin->parent);
+ }
+ if (anyMarked && pScreen->PostValidateTree)
+ (*pScreen->PostValidateTree)(pLayerWin->parent, pHead, VTUnmap);
+ }
+ if (wasRealized)
+ WindowsRestructured ();
+}
+
+
+void
+HandleSaveSet(ClientPtr client)
+{
+ WindowPtr pParent, pWin;
+ int j;
+
+ for (j=0; j<client->numSaved; j++)
+ {
+ pWin = SaveSetWindow(client->saveSet[j]);
+#ifdef XFIXES
+ if (SaveSetToRoot(client->saveSet[j]))
+ pParent = pWin->drawable.pScreen->root;
+ else
+#endif
+ {
+ pParent = pWin->parent;
+ while (pParent && (wClient (pParent) == client))
+ pParent = pParent->parent;
+ }
+ if (pParent)
+ {
+ if (pParent != pWin->parent)
+ {
+#ifdef XFIXES
+ /* unmap first so that ReparentWindow doesn't remap */
+ if (!SaveSetShouldMap (client->saveSet[j]))
+ UnmapWindow(pWin, FALSE);
+#endif
+ ReparentWindow(pWin, pParent,
+ pWin->drawable.x - wBorderWidth (pWin) - pParent->drawable.x,
+ pWin->drawable.y - wBorderWidth (pWin) - pParent->drawable.y,
+ client);
+ if(!pWin->realized && pWin->mapped)
+ pWin->mapped = FALSE;
+ }
+#ifdef XFIXES
+ if (SaveSetShouldMap (client->saveSet[j]))
+#endif
+ MapWindow(pWin, client);
+ }
+ }
+ free(client->saveSet);
+ client->numSaved = 0;
+ client->saveSet = (SaveSetElt *)NULL;
+}
+
+/**
+ *
+ * \param x,y in root
+ */
+Bool
+PointInWindowIsVisible(WindowPtr pWin, int x, int y)
+{
+ BoxRec box;
+
+ if (!pWin->realized)
+ return FALSE;
+ if (RegionContainsPoint(&pWin->borderClip,
+ x, y, &box)
+ && (!wInputShape(pWin) ||
+ RegionContainsPoint(wInputShape(pWin),
+ x - pWin->drawable.x,
+ y - pWin->drawable.y, &box)))
+ return TRUE;
+ return FALSE;
+}
+
+
+RegionPtr
+NotClippedByChildren(WindowPtr pWin)
+{
+ RegionPtr pReg = RegionCreate(NullBox, 1);
+ if (pWin->parent ||
+ screenIsSaved != SCREEN_SAVER_ON ||
+ !HasSaverWindow (pWin->drawable.pScreen))
+ {
+ RegionIntersect(pReg, &pWin->borderClip, &pWin->winSize);
+ }
+ return pReg;
+}
+
+void
+SendVisibilityNotify(WindowPtr pWin)
+{
+ xEvent event;
+ unsigned int visibility = pWin->visibility;
+
+ if (!MapUnmapEventsEnabled(pWin))
+ return;
+#ifdef PANORAMIX
+ /* This is not quite correct yet, but it's close */
+ if(!noPanoramiXExtension) {
+ PanoramiXRes *win;
+ WindowPtr pWin2;
+ int rc, i, Scrnum;
+
+ Scrnum = pWin->drawable.pScreen->myNum;
+
+ win = PanoramiXFindIDByScrnum(XRT_WINDOW, pWin->drawable.id, Scrnum);
+
+ if(!win || (win->u.win.visibility == visibility))
+ return;
+
+ switch(visibility) {
+ case VisibilityUnobscured:
+ for(i = 0; i < PanoramiXNumScreens; i++) {
+ if(i == Scrnum) continue;
+
+ rc = dixLookupWindow(&pWin2, win->info[i].id, serverClient,
+ DixWriteAccess);
+
+ if (rc == Success) {
+ if(pWin2->visibility == VisibilityPartiallyObscured)
+ return;
+
+ if(!i) pWin = pWin2;
+ }
+ }
+ break;
+ case VisibilityPartiallyObscured:
+ if(Scrnum) {
+ rc = dixLookupWindow(&pWin2, win->info[0].id, serverClient,
+ DixWriteAccess);
+ if (rc == Success) pWin = pWin2;
+ }
+ break;
+ case VisibilityFullyObscured:
+ for(i = 0; i < PanoramiXNumScreens; i++) {
+ if(i == Scrnum) continue;
+
+ rc = dixLookupWindow(&pWin2, win->info[i].id, serverClient,
+ DixWriteAccess);
+
+ if (rc == Success) {
+ if(pWin2->visibility != VisibilityFullyObscured)
+ return;
+
+ if(!i) pWin = pWin2;
+ }
+ }
+ break;
+ }
+
+ win->u.win.visibility = visibility;
+ }
+#endif
+
+ memset(&event, 0, sizeof(xEvent));
+ event.u.u.type = VisibilityNotify;
+ event.u.visibility.window = pWin->drawable.id;
+ event.u.visibility.state = visibility;
+ DeliverEvents(pWin, &event, 1, NullWindow);
+}
+
+#define RANDOM_WIDTH 32
+int
+dixSaveScreens(ClientPtr client, int on, int mode)
+{
+ int rc, i, what, type;
+
+ if (on == SCREEN_SAVER_FORCER)
+ {
+ if (mode == ScreenSaverReset)
+ what = SCREEN_SAVER_OFF;
+ else
+ what = SCREEN_SAVER_ON;
+ type = what;
+ }
+ else
+ {
+ what = on;
+ type = what;
+ if (what == screenIsSaved)
+ type = SCREEN_SAVER_CYCLE;
+ }
+
+ for (i = 0; i < screenInfo.numScreens; i++) {
+ rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, screenInfo.screens[i],
+ DixShowAccess | DixHideAccess);
+ if (rc != Success)
+ return rc;
+ }
+ for (i = 0; i < screenInfo.numScreens; i++)
+ {
+ ScreenPtr pScreen = screenInfo.screens[i];
+ if (on == SCREEN_SAVER_FORCER)
+ (* pScreen->SaveScreen) (pScreen, on);
+ if (pScreen->screensaver.ExternalScreenSaver)
+ {
+ if ((*pScreen->screensaver.ExternalScreenSaver)
+ (pScreen, type, on == SCREEN_SAVER_FORCER))
+ continue;
+ }
+ if (type == screenIsSaved)
+ continue;
+ switch (type) {
+ case SCREEN_SAVER_OFF:
+ if (pScreen->screensaver.blanked == SCREEN_IS_BLANKED)
+ {
+ (* pScreen->SaveScreen) (pScreen, what);
+ }
+ else if (HasSaverWindow (pScreen))
+ {
+ pScreen->screensaver.pWindow = NullWindow;
+ FreeResource(pScreen->screensaver.wid, RT_NONE);
+ }
+ break;
+ case SCREEN_SAVER_CYCLE:
+ if (pScreen->screensaver.blanked == SCREEN_IS_TILED)
+ {
+ WindowPtr pWin = pScreen->screensaver.pWindow;
+ /* make it look like screen saver is off, so that
+ * NotClippedByChildren will compute a clip list
+ * for the root window, so miPaintWindow works
+ */
+ screenIsSaved = SCREEN_SAVER_OFF;
+ (*pWin->drawable.pScreen->MoveWindow)(pWin,
+ (short)(-(rand() % RANDOM_WIDTH)),
+ (short)(-(rand() % RANDOM_WIDTH)),
+ pWin->nextSib, VTMove);
+ screenIsSaved = SCREEN_SAVER_ON;
+ }
+ /*
+ * Call the DDX saver in case it wants to do something
+ * at cycle time
+ */
+ else if (pScreen->screensaver.blanked == SCREEN_IS_BLANKED)
+ {
+ (* pScreen->SaveScreen) (pScreen, type);
+ }
+ break;
+ case SCREEN_SAVER_ON:
+ if (ScreenSaverBlanking != DontPreferBlanking)
+ {
+ if ((* pScreen->SaveScreen) (pScreen, what))
+ {
+ pScreen->screensaver.blanked = SCREEN_IS_BLANKED;
+ continue;
+ }
+ if ((ScreenSaverAllowExposures != DontAllowExposures) &&
+ TileScreenSaver(pScreen, SCREEN_IS_BLACK))
+ {
+ pScreen->screensaver.blanked = SCREEN_IS_BLACK;
+ continue;
+ }
+ }
+ if ((ScreenSaverAllowExposures != DontAllowExposures) &&
+ TileScreenSaver(pScreen, SCREEN_IS_TILED))
+ {
+ pScreen->screensaver.blanked = SCREEN_IS_TILED;
+ }
+ else
+ pScreen->screensaver.blanked = SCREEN_ISNT_SAVED;
+ break;
+ }
+ }
+ screenIsSaved = what;
+ if (mode == ScreenSaverReset) {
+ if (on == SCREEN_SAVER_FORCER) {
+ UpdateCurrentTimeIf();
+ lastDeviceEventTime = currentTime;
+ }
+ SetScreenSaverTimer();
+ }
+ return Success;
+}
+
+int
+SaveScreens(int on, int mode)
+{
+ return dixSaveScreens(serverClient, on, mode);
+}
+
+static Bool
+TileScreenSaver(ScreenPtr pScreen, int kind)
+{
+ int j;
+ int result;
+ XID attributes[3];
+ Mask mask;
+ WindowPtr pWin;
+ CursorMetricRec cm;
+ unsigned char *srcbits, *mskbits;
+ CursorPtr cursor;
+ XID cursorID = 0;
+ int attri;
+
+ mask = 0;
+ attri = 0;
+ switch (kind) {
+ case SCREEN_IS_TILED:
+ switch (pScreen->root->backgroundState) {
+ case BackgroundPixel:
+ attributes[attri++] = pScreen->root->background.pixel;
+ mask |= CWBackPixel;
+ break;
+ case BackgroundPixmap:
+ attributes[attri++] = None;
+ mask |= CWBackPixmap;
+ break;
+ default:
+ break;
+ }
+ break;
+ case SCREEN_IS_BLACK:
+ attributes[attri++] = pScreen->root->drawable.pScreen->blackPixel;
+ mask |= CWBackPixel;
+ break;
+ }
+ mask |= CWOverrideRedirect;
+ attributes[attri++] = xTrue;
+
+ /*
+ * create a blank cursor
+ */
+
+ cm.width=16;
+ cm.height=16;
+ cm.xhot=8;
+ cm.yhot=8;
+ srcbits = malloc( BitmapBytePad(32)*16);
+ mskbits = malloc( BitmapBytePad(32)*16);
+ if (!srcbits || !mskbits)
+ {
+ free(srcbits);
+ free(mskbits);
+ cursor = 0;
+ }
+ else
+ {
+ for (j=0; j<BitmapBytePad(32)*16; j++)
+ srcbits[j] = mskbits[j] = 0x0;
+ result = AllocARGBCursor(srcbits, mskbits, NULL, &cm, 0, 0, 0, 0, 0, 0,
+ &cursor, serverClient, (XID)0);
+ if (cursor)
+ {
+ cursorID = FakeClientID(0);
+ if (AddResource (cursorID, RT_CURSOR, (pointer) cursor))
+ {
+ attributes[attri] = cursorID;
+ mask |= CWCursor;
+ }
+ else
+ cursor = 0;
+ }
+ else
+ {
+ free(srcbits);
+ free(mskbits);
+ }
+ }
+
+ pWin = pScreen->screensaver.pWindow =
+ CreateWindow(pScreen->screensaver.wid,
+ pScreen->root,
+ -RANDOM_WIDTH, -RANDOM_WIDTH,
+ (unsigned short)pScreen->width + RANDOM_WIDTH,
+ (unsigned short)pScreen->height + RANDOM_WIDTH,
+ 0, InputOutput, mask, attributes, 0, serverClient,
+ wVisual (pScreen->root), &result);
+
+ if (cursor)
+ FreeResource (cursorID, RT_NONE);
+
+ if (!pWin)
+ return FALSE;
+
+ if (!AddResource(pWin->drawable.id, RT_WINDOW,
+ (pointer)pScreen->screensaver.pWindow))
+ return FALSE;
+
+ if (mask & CWBackPixmap)
+ {
+ MakeRootTile (pWin);
+ (*pWin->drawable.pScreen->ChangeWindowAttributes)(pWin, CWBackPixmap);
+ }
+ MapWindow(pWin, serverClient);
+ return TRUE;
+}
+
+/*
+ * FindWindowWithOptional
+ *
+ * search ancestors of the given window for an entry containing
+ * a WindowOpt structure. Assumptions: some parent will
+ * contain the structure.
+ */
+
+WindowPtr
+FindWindowWithOptional (WindowPtr w)
+{
+ do
+ w = w->parent;
+ while (!w->optional);
+ return w;
+}
+
+/*
+ * CheckWindowOptionalNeed
+ *
+ * check each optional entry in the given window to see if
+ * the value is satisfied by the default rules. If so,
+ * release the optional record
+ */
+
+void
+CheckWindowOptionalNeed (WindowPtr w)
+{
+ WindowOptPtr optional;
+ WindowOptPtr parentOptional;
+
+ if (!w->parent || !w->optional)
+ return;
+ optional = w->optional;
+ if (optional->dontPropagateMask != DontPropagateMasks[w->dontPropagate])
+ return;
+ if (optional->otherEventMasks != 0)
+ return;
+ if (optional->otherClients != NULL)
+ return;
+ if (optional->passiveGrabs != NULL)
+ return;
+ if (optional->userProps != NULL)
+ return;
+ if (optional->backingBitPlanes != ~0L)
+ return;
+ if (optional->backingPixel != 0)
+ return;
+ if (optional->boundingShape != NULL)
+ return;
+ if (optional->clipShape != NULL)
+ return;
+ if (optional->inputShape != NULL)
+ return;
+ if (optional->inputMasks != NULL)
+ return;
+ if (optional->deviceCursors != NULL)
+ {
+ DevCursNodePtr pNode = optional->deviceCursors;
+ while(pNode)
+ {
+ if (pNode->cursor != None)
+ return;
+ pNode = pNode->next;
+ }
+ }
+
+ parentOptional = FindWindowWithOptional(w)->optional;
+ if (optional->visual != parentOptional->visual)
+ return;
+ if (optional->cursor != None &&
+ (optional->cursor != parentOptional->cursor ||
+ w->parent->cursorIsNone))
+ return;
+ if (optional->colormap != parentOptional->colormap)
+ return;
+ DisposeWindowOptional (w);
+}
+
+/*
+ * MakeWindowOptional
+ *
+ * create an optional record and initialize it with the default
+ * values.
+ */
+
+Bool
+MakeWindowOptional (WindowPtr pWin)
+{
+ WindowOptPtr optional;
+ WindowOptPtr parentOptional;
+
+ if (pWin->optional)
+ return TRUE;
+ optional = malloc(sizeof (WindowOptRec));
+ if (!optional)
+ return FALSE;
+ optional->dontPropagateMask = DontPropagateMasks[pWin->dontPropagate];
+ optional->otherEventMasks = 0;
+ optional->otherClients = NULL;
+ optional->passiveGrabs = NULL;
+ optional->userProps = NULL;
+ optional->backingBitPlanes = ~0L;
+ optional->backingPixel = 0;
+ optional->boundingShape = NULL;
+ optional->clipShape = NULL;
+ optional->inputShape = NULL;
+ optional->inputMasks = NULL;
+ optional->deviceCursors = NULL;
+
+ parentOptional = FindWindowWithOptional(pWin)->optional;
+ optional->visual = parentOptional->visual;
+ if (!pWin->cursorIsNone)
+ {
+ optional->cursor = parentOptional->cursor;
+ optional->cursor->refcnt++;
+ }
+ else
+ {
+ optional->cursor = None;
+ }
+ optional->colormap = parentOptional->colormap;
+ pWin->optional = optional;
+ return TRUE;
+}
+
+/*
+ * Changes the cursor struct for the given device and the given window.
+ * A cursor that does not have a device cursor set will use whatever the
+ * standard cursor is for the window. If all devices have a cursor set,
+ * changing the window cursor (e.g. using XDefineCursor()) will not have any
+ * visible effect. Only when one of the device cursors is set to None again,
+ * this device's cursor will display the changed standard cursor.
+ *
+ * CursorIsNone of the window struct is NOT modified if you set a device
+ * cursor.
+ *
+ * Assumption: If there is a node for a device in the list, the device has a
+ * cursor. If the cursor is set to None, it is inherited by the parent.
+ */
+int
+ChangeWindowDeviceCursor(WindowPtr pWin,
+ DeviceIntPtr pDev,
+ CursorPtr pCursor)
+{
+ DevCursNodePtr pNode, pPrev;
+ CursorPtr pOldCursor = NULL;
+ ScreenPtr pScreen;
+ WindowPtr pChild;
+
+ if (!pWin->optional && !MakeWindowOptional(pWin))
+ return BadAlloc;
+
+ /* 1) Check if window has device cursor set
+ * Yes: 1.1) swap cursor with given cursor if parent does not have same
+ * cursor, free old cursor
+ * 1.2) free old cursor, use parent cursor
+ * No: 1.1) add node to beginning of list.
+ * 1.2) add cursor to node if parent does not have same cursor
+ * 1.3) use parent cursor if parent does not have same cursor
+ * 2) Patch up children if child has a devcursor
+ * 2.1) if child has cursor None, it inherited from parent, set to old
+ * cursor
+ * 2.2) if child has same cursor as new cursor, remove and set to None
+ */
+
+ pScreen = pWin->drawable.pScreen;
+
+ if (WindowSeekDeviceCursor(pWin, pDev, &pNode, &pPrev))
+ {
+ /* has device cursor */
+
+ if (pNode->cursor == pCursor)
+ return Success;
+
+ pOldCursor = pNode->cursor;
+
+ if (!pCursor) /* remove from list */
+ {
+ if(pPrev)
+ pPrev->next = pNode->next;
+ else
+ /* first item in list */
+ pWin->optional->deviceCursors = pNode->next;
+
+ free(pNode);
+ goto out;
+ }
+
+ } else
+ {
+ /* no device cursor yet */
+ DevCursNodePtr pNewNode;
+
+ if (!pCursor)
+ return Success;
+
+ pNewNode = malloc(sizeof(DevCursNodeRec));
+ pNewNode->dev = pDev;
+ pNewNode->next = pWin->optional->deviceCursors;
+ pWin->optional->deviceCursors = pNewNode;
+ pNode = pNewNode;
+
+ }
+
+ if (pCursor && WindowParentHasDeviceCursor(pWin, pDev, pCursor))
+ pNode->cursor = None;
+ else
+ {
+ pNode->cursor = pCursor;
+ pCursor->refcnt++;
+ }
+
+ pNode = pPrev = NULL;
+ /* fix up children */
+ for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib)
+ {
+ if (WindowSeekDeviceCursor(pChild, pDev, &pNode, &pPrev))
+ {
+ if (pNode->cursor == None) /* inherited from parent */
+ {
+ pNode->cursor = pOldCursor;
+ pOldCursor->refcnt++;
+ } else if (pNode->cursor == pCursor)
+ {
+ pNode->cursor = None;
+ FreeCursor(pCursor, (Cursor)0); /* fix up refcnt */
+ }
+ }
+ }
+
+out:
+ if (pWin->realized)
+ WindowHasNewCursor(pWin);
+
+ if (pOldCursor)
+ FreeCursor(pOldCursor, (Cursor)0);
+
+ /* FIXME: We SHOULD check for an error value here XXX
+ (comment taken from ChangeWindowAttributes) */
+ (*pScreen->ChangeWindowAttributes)(pWin, CWCursor);
+
+ return Success;
+}
+
+/* Get device cursor for given device or None if none is set */
+CursorPtr
+WindowGetDeviceCursor(WindowPtr pWin, DeviceIntPtr pDev)
+{
+ DevCursorList pList;
+
+ if (!pWin->optional || !pWin->optional->deviceCursors)
+ return NULL;
+
+ pList = pWin->optional->deviceCursors;
+
+ while(pList)
+ {
+ if (pList->dev == pDev)
+ {
+ if (pList->cursor == None) /* inherited from parent */
+ return WindowGetDeviceCursor(pWin->parent, pDev);
+ else
+ return pList->cursor;
+ }
+ pList = pList->next;
+ }
+ return NULL;
+}
+
+/* Searches for a DevCursorNode for the given window and device. If one is
+ * found, return True and set pNode and pPrev to the node and to the node
+ * before the node respectively. Otherwise return False.
+ * If the device is the first in list, pPrev is set to NULL.
+ */
+static Bool
+WindowSeekDeviceCursor(WindowPtr pWin,
+ DeviceIntPtr pDev,
+ DevCursNodePtr* pNode,
+ DevCursNodePtr* pPrev)
+{
+ DevCursorList pList;
+
+ if (!pWin->optional)
+ return FALSE;
+
+ pList = pWin->optional->deviceCursors;
+
+ if (pList && pList->dev == pDev)
+ {
+ *pNode = pList;
+ *pPrev = NULL;
+ return TRUE;
+ }
+
+ while(pList)
+ {
+ if (pList->next)
+ {
+ if (pList->next->dev == pDev)
+ {
+ *pNode = pList->next;
+ *pPrev = pList;
+ return TRUE;
+ }
+ }
+ pList = pList->next;
+ }
+ return FALSE;
+}
+
+/* Return True if a parent has the same device cursor set or False if
+ * otherwise
+ */
+static Bool
+WindowParentHasDeviceCursor(WindowPtr pWin,
+ DeviceIntPtr pDev,
+ CursorPtr pCursor)
+{
+ WindowPtr pParent;
+ DevCursNodePtr pParentNode, pParentPrev;
+
+ pParent = pWin->parent;
+ while(pParent)
+ {
+ if (WindowSeekDeviceCursor(pParent, pDev,
+ &pParentNode, &pParentPrev))
+ {
+ /* if there is a node in the list, the win has a dev cursor */
+ if (!pParentNode->cursor) /* inherited. */
+ pParent = pParent->parent;
+ else if (pParentNode->cursor == pCursor) /* inherit */
+ return TRUE;
+ else /* different cursor */
+ return FALSE;
+ }
+ else
+ /* parent does not have a device cursor for our device */
+ return FALSE;
+ }
+ return FALSE;
+}
contact: Jan Huwald // Impressum