diff options
Diffstat (limited to 'dix')
-rw-r--r-- | dix/BuiltInAtoms | 329 | ||||
-rw-r--r-- | dix/Makefile.am | 75 | ||||
-rw-r--r-- | dix/Makefile.in | 877 | ||||
-rw-r--r-- | dix/Xserver-dtrace.h.in | 94 | ||||
-rw-r--r-- | dix/Xserver.d | 58 | ||||
-rw-r--r-- | dix/atom.c | 218 | ||||
-rw-r--r-- | dix/buildatoms | 43 | ||||
-rw-r--r-- | dix/colormap.c | 2771 | ||||
-rw-r--r-- | dix/cursor.c | 515 | ||||
-rw-r--r-- | dix/deprecated.c | 165 | ||||
-rw-r--r-- | dix/devices.c | 2633 | ||||
-rw-r--r-- | dix/dispatch.c | 3901 | ||||
-rw-r--r-- | dix/dispatch.h | 145 | ||||
-rw-r--r-- | dix/dix.c | 0 | ||||
-rw-r--r-- | dix/dixfonts.c | 2072 | ||||
-rw-r--r-- | dix/dixutils.c | 893 | ||||
-rw-r--r-- | dix/enterleave.c | 1389 | ||||
-rw-r--r-- | dix/enterleave.h | 97 | ||||
-rw-r--r-- | dix/eventconvert.c | 739 | ||||
-rw-r--r-- | dix/events.c | 5812 | ||||
-rw-r--r-- | dix/extension.c | 360 | ||||
-rw-r--r-- | dix/ffs.c | 48 | ||||
-rw-r--r-- | dix/gc.c | 1149 | ||||
-rw-r--r-- | dix/getevents.c | 1327 | ||||
-rw-r--r-- | dix/globals.c | 131 | ||||
-rw-r--r-- | dix/glyphcurs.c | 191 | ||||
-rw-r--r-- | dix/grabs.c | 557 | ||||
-rw-r--r-- | dix/initatoms.c | 84 | ||||
-rw-r--r-- | dix/inpututils.c | 558 | ||||
-rw-r--r-- | dix/main.c | 358 | ||||
-rw-r--r-- | dix/pixmap.c | 137 | ||||
-rw-r--r-- | dix/privates.c | 502 | ||||
-rw-r--r-- | dix/property.c | 644 | ||||
-rw-r--r-- | dix/protocol.txt | 1103 | ||||
-rw-r--r-- | dix/ptrveloc.c | 1175 | ||||
-rw-r--r-- | dix/region.c | 1659 | ||||
-rw-r--r-- | dix/registry.c | 336 | ||||
-rw-r--r-- | dix/resource.c | 965 | ||||
-rw-r--r-- | dix/selection.c | 311 | ||||
-rw-r--r-- | dix/swaprep.c | 1308 | ||||
-rw-r--r-- | dix/swapreq.c | 1099 | ||||
-rw-r--r-- | dix/tables.c | 986 | ||||
-rw-r--r-- | dix/window.c | 3686 |
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(¶m, 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, ¶m); + 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, + ¶m, 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(¶m, 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, ¶m, 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(¤t, 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(¶m, 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, + ¶m, (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; +} |