summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfaith <faith>2002-06-04 06:27:24 +0000
committerfaith <faith>2002-06-04 06:27:24 +0000
commit8d5933791ef8c25b816e3a946ae44c7f2575af91 (patch)
tree5e5ef580ca3434ee620bf0a00bb0416a8c617065
parent37d6f977b9eadad5c0e6f853aca28f520bcb5413 (diff)
Update to DMX code from dmx-0-1-20020531-finaldmx-1-0-20020604-phase1
Includes update of Imakefile if style and signature changes in dmxdpms.c
-rw-r--r--xc/config/cf/README1
-rw-r--r--xc/config/cf/X11.tmpl13
-rw-r--r--xc/config/cf/xf86site.def8
-rw-r--r--xc/config/cf/xfree86.cf55
-rw-r--r--xc/programs/Xserver/Imakefile85
-rw-r--r--xc/programs/Xserver/hw/Imakefile6
-rw-r--r--xc/programs/Xserver/hw/dmx/Imakefile71
-rw-r--r--xc/programs/Xserver/hw/dmx/Xdmx.man388
-rw-r--r--xc/programs/Xserver/hw/dmx/config/Canvas.c136
-rw-r--r--xc/programs/Xserver/hw/dmx/config/Canvas.h56
-rw-r--r--xc/programs/Xserver/hw/dmx/config/CanvasP.h66
-rw-r--r--xc/programs/Xserver/hw/dmx/config/Imakefile78
-rw-r--r--xc/programs/Xserver/hw/dmx/config/TODO7
-rw-r--r--xc/programs/Xserver/hw/dmx/config/dmxcompat.c222
-rw-r--r--xc/programs/Xserver/hw/dmx/config/dmxcompat.h39
-rw-r--r--xc/programs/Xserver/hw/dmx/config/dmxconfig.c348
-rw-r--r--xc/programs/Xserver/hw/dmx/config/dmxconfig.h42
-rw-r--r--xc/programs/Xserver/hw/dmx/config/dmxparse.c464
-rw-r--r--xc/programs/Xserver/hw/dmx/config/dmxparse.h241
-rw-r--r--xc/programs/Xserver/hw/dmx/config/dmxprint.c345
-rw-r--r--xc/programs/Xserver/hw/dmx/config/dmxprint.h41
-rw-r--r--xc/programs/Xserver/hw/dmx/config/dmxtodmx.c47
-rw-r--r--xc/programs/Xserver/hw/dmx/config/dmxtodmx.man41
-rw-r--r--xc/programs/Xserver/hw/dmx/config/parser.y203
-rw-r--r--xc/programs/Xserver/hw/dmx/config/scanner.l166
-rw-r--r--xc/programs/Xserver/hw/dmx/config/test-a.in1
-rw-r--r--xc/programs/Xserver/hw/dmx/config/test-a.out2
-rw-r--r--xc/programs/Xserver/hw/dmx/config/test-b.in1
-rw-r--r--xc/programs/Xserver/hw/dmx/config/test-b.out1
-rw-r--r--xc/programs/Xserver/hw/dmx/config/test-c.in1
-rw-r--r--xc/programs/Xserver/hw/dmx/config/test-c.out2
-rw-r--r--xc/programs/Xserver/hw/dmx/config/test-d.in1
-rw-r--r--xc/programs/Xserver/hw/dmx/config/test-d.out2
-rw-r--r--xc/programs/Xserver/hw/dmx/config/test-e.in1
-rw-r--r--xc/programs/Xserver/hw/dmx/config/test-e.out2
-rw-r--r--xc/programs/Xserver/hw/dmx/config/test-f.in2
-rw-r--r--xc/programs/Xserver/hw/dmx/config/test-f.out2
-rw-r--r--xc/programs/Xserver/hw/dmx/config/test-g.in4
-rw-r--r--xc/programs/Xserver/hw/dmx/config/test-g.out4
-rw-r--r--xc/programs/Xserver/hw/dmx/config/test-h.in7
-rw-r--r--xc/programs/Xserver/hw/dmx/config/test-h.out7
-rw-r--r--xc/programs/Xserver/hw/dmx/config/vdltodmx.c58
-rw-r--r--xc/programs/Xserver/hw/dmx/config/vdltodmx.man97
-rw-r--r--xc/programs/Xserver/hw/dmx/config/xdmxconfig.c1164
-rw-r--r--xc/programs/Xserver/hw/dmx/config/xdmxconfig.man63
-rw-r--r--xc/programs/Xserver/hw/dmx/dmx.h182
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxcb.c139
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxcb.h42
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxcmap.c153
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxcmap.h61
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxcursor.c668
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxcursor.h56
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxdpms.c54
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxfont.c302
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxfont.h51
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxgc.c338
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxgc.h83
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxgcops.c447
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxgcops.h93
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxinit.c528
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxinput.c71
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxinput.h81
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxlog.c256
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxlog.h65
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxpixmap.c190
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxpixmap.h57
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxprop.c217
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxprop.h43
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxscrinit.c445
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxscrinit.h46
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxshadow.c60
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxshadow.h44
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxvisual.c85
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxvisual.h45
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxwindow.c578
-rw-r--r--xc/programs/Xserver/hw/dmx/dmxwindow.h93
-rw-r--r--xc/programs/Xserver/hw/dmx/doc/Imakefile9
-rw-r--r--xc/programs/Xserver/hw/dmx/doc/Makefile.linux31
-rw-r--r--xc/programs/Xserver/hw/dmx/doc/dmx.sgml1419
-rw-r--r--xc/programs/Xserver/hw/dmx/doc/dmx.txt1716
-rw-r--r--xc/programs/Xserver/hw/dmx/input/Imakefile34
-rw-r--r--xc/programs/Xserver/hw/dmx/input/TODO18
-rw-r--r--xc/programs/Xserver/hw/dmx/input/dmxarg.c157
-rw-r--r--xc/programs/Xserver/hw/dmx/input/dmxarg.h47
-rw-r--r--xc/programs/Xserver/hw/dmx/input/dmxbackend.c336
-rw-r--r--xc/programs/Xserver/hw/dmx/input/dmxbackend.h46
-rw-r--r--xc/programs/Xserver/hw/dmx/input/dmxcommon.c338
-rw-r--r--xc/programs/Xserver/hw/dmx/input/dmxcommon.h91
-rw-r--r--xc/programs/Xserver/hw/dmx/input/dmxconsole.c690
-rw-r--r--xc/programs/Xserver/hw/dmx/input/dmxconsole.h46
-rw-r--r--xc/programs/Xserver/hw/dmx/input/dmxdummy.c60
-rw-r--r--xc/programs/Xserver/hw/dmx/input/dmxdummy.h42
-rw-r--r--xc/programs/Xserver/hw/dmx/input/dmxevents.c349
-rw-r--r--xc/programs/Xserver/hw/dmx/input/dmxevents.h49
-rw-r--r--xc/programs/Xserver/hw/dmx/input/dmxinputinit.c558
-rw-r--r--xc/programs/Xserver/hw/dmx/input/dmxinputinit.h142
-rw-r--r--xc/programs/Xserver/hw/dmx/input/dmxsigio.c202
-rw-r--r--xc/programs/Xserver/hw/dmx/input/dmxsigio.h43
-rw-r--r--xc/programs/Xserver/hw/dmx/input/dmxxtest.c138
-rw-r--r--xc/programs/Xserver/hw/dmx/input/dmxxtest.h41
-rw-r--r--xc/programs/Xserver/hw/dmx/input/lnx-keyboard.c966
-rw-r--r--xc/programs/Xserver/hw/dmx/input/lnx-keyboard.h63
-rw-r--r--xc/programs/Xserver/hw/dmx/input/lnx-ms.c282
-rw-r--r--xc/programs/Xserver/hw/dmx/input/lnx-ms.h52
-rw-r--r--xc/programs/Xserver/hw/dmx/input/lnx-ps2.c253
-rw-r--r--xc/programs/Xserver/hw/dmx/input/lnx-ps2.h51
-rw-r--r--xc/programs/Xserver/hw/dmx/input/xbell.c68
107 files changed, 18453 insertions, 48 deletions
diff --git a/xc/config/cf/README b/xc/config/cf/README
index a50959124..ee5a30efb 100644
--- a/xc/config/cf/README
+++ b/xc/config/cf/README
@@ -480,6 +480,7 @@ The following variables are used by some part of the tree:
HtmlDir path used by Web server for HTML and RX docs
CgiBinDir path used by Web server for CGI programs
ProxyManager ICE network ID to contact a running proxymngr
+ XdmxServer build distributed multihead X server
Make Variables
diff --git a/xc/config/cf/X11.tmpl b/xc/config/cf/X11.tmpl
index 3b6357147..f7d14c294 100644
--- a/xc/config/cf/X11.tmpl
+++ b/xc/config/cf/X11.tmpl
@@ -308,7 +308,7 @@ VENDORMANVERSION = XVendorManVersionString
#define BuildFontLib (BuildLibraries || \
(BuildServer && !DoLoadableServer) || \
XnestServer || XVirtualFramebufferServer || \
- XprtServer || KDriveXServer)
+ XprtServer || KDriveXServer || XdmxServer)
#endif
#endif
#ifndef BuildFontCache
@@ -484,6 +484,9 @@ VENDORMANVERSION = XVendorManVersionString
#ifndef BuildGLXLibrary
#define BuildGLXLibrary (BuildGlxExt && !BuildServersOnly)
#endif
+#ifndef BuildOSMesaLib
+#define BuildOSMesaLib (BuildGlxExt && defined(XFree86Version))
+#endif
#ifndef BuildGLULibrary
#define BuildGLULibrary (BuildGLXLibrary && HasCplusplus)
#endif
@@ -2087,7 +2090,11 @@ ProjectUnsharedLibReferences(XFONTCACHE,Xfontcache,$(XFONTCACHELIBSRC),XBuildLib
#endif
SharedLibReferences(XAUTH,Xau,$(XAUTHSRC),SOXAUTHREV,SharedXauRev)
#else
+#if BuildXauLib || UseInstalled
ProjectUnsharedLibReferences(XAUTH,Xau,$(XAUTHSRC),XBuildLibDir)
+#else
+ProjectUnsharedLibReferences(XAUTH,Xau,$(XAUTHSRC),$(USRLIBDIR))
+#endif
#endif
#ifndef SharedLibXdmcp
@@ -2109,7 +2116,11 @@ ProjectUnsharedLibReferences(XAUTH,Xau,$(XAUTHSRC),XBuildLibDir)
#endif
SharedLibReferences(XDMCP,Xdmcp,$(XDMCPLIBSRC),SOXDMCPREV,SharedXdmcpRev)
#else
+#if BuildXdmcpLib || UseInstalled
ProjectUnsharedLibReferences(XDMCP,Xdmcp,$(XDMCPLIBSRC),XBuildLibDir)
+#else
+ProjectUnsharedLibReferences(XDMCP,Xdmcp,$(XDMCPLIBSRC),$(USRLIBDIR))
+#endif
#endif
#ifndef SharedLibXmu
diff --git a/xc/config/cf/xf86site.def b/xc/config/cf/xf86site.def
index 6e9d86817..bc8351054 100644
--- a/xc/config/cf/xf86site.def
+++ b/xc/config/cf/xf86site.def
@@ -230,6 +230,12 @@ XCOMM $XFree86: xc/config/cf/xf86site.def,v 3.179 2002/01/16 18:36:00 dawes Exp
*/
/*
+ * To disable building Xdmx, uncomment this.
+ *
+#define XdmxServer NO
+ */
+
+/*
* To disable building Xprt, uncomment this.
*
#define XprtServer NO
@@ -738,7 +744,7 @@ XCOMM $XFree86: xc/config/cf/xf86site.def,v 3.179 2002/01/16 18:36:00 dawes Exp
*/
/*
- * The 3Dfx 3D DRI driver requires glide 3.
+ * Have glide 3?
*
#define HasGlide3 YES
*/
diff --git a/xc/config/cf/xfree86.cf b/xc/config/cf/xfree86.cf
index a256b330e..d099f5e4a 100644
--- a/xc/config/cf/xfree86.cf
+++ b/xc/config/cf/xfree86.cf
@@ -313,13 +313,22 @@ XCOMM $Xorg: xfree86.cf,v 1.4 2000/08/17 19:41:49 cpqbld Exp $
siliconmotion \
vesa vga XF86OSCardDrivers XF86ExtraCardDrivers
# endif
-# if HasGlide3
-# define TdfxDriDriver tdfx
-# else
-# define TdfxDriDriver /**/
+
+/*
+ * DRI drivers under development, or drivers included on this platform
+ * only for build testing.
+ */
+# ifndef DevelDRIDrivers
+# if XFree86Devel
+# define DevelDRIDrivers ffb
+# else
+# define DevelDRIDrivers /**/
+# endif
# endif
+
# ifndef DriDrivers
-# define DriDrivers gamma TdfxDriDriver mga i810 i830 r128 radeon sis
+# define DriDrivers gamma i810 i830 mga r128 radeon \
+ /*sis*/ tdfx DevelDRIDrivers
# endif
#endif
@@ -561,13 +570,8 @@ XCOMM $Xorg: xfree86.cf,v 1.4 2000/08/17 19:41:49 cpqbld Exp $
savage nv DevelDrivers siliconmotion vga \
XF86OSCardDrivers XF86ExtraCardDrivers
# endif
-# if HasGlide3
-# define TdfxDriDriver tdfx
-# else
-# define TdfxDriDriver /**/
-# endif
# ifndef DriDrivers
-# define DriDrivers gamma TdfxDriDriver mga r128 radeon sis
+# define DriDrivers gamma tdfx mga r128 radeon sis
# endif
#endif
@@ -657,13 +661,8 @@ XCOMM $Xorg: xfree86.cf,v 1.4 2000/08/17 19:41:49 cpqbld Exp $
DevelDrivers vga \
XF86OSCardDrivers XF86ExtraCardDrivers
# endif
-# if HasGlide3
-# define TdfxDriDriver tdfx
-# else
-# define TdfxDriDriver /**/
-# endif
# ifndef DriDrivers
-# define DriDrivers gamma TdfxDriDriver mga r128 radeon
+# define DriDrivers gamma tdfx mga r128 radeon
# endif
#endif
@@ -841,12 +840,22 @@ IPLAN2P8_DEFS = -DUSE_IPLAN2P8
* If more than one are defined, the compilation will fail with multiply
* defined references of GLX and OpenGL functions.
*/
+
+/*
+ * The first is a built-in driver that does software rendering client-side
+ * and renders to the X server via Xlib.
+ */
+
+# ifndef GlxBuiltInXMesa
+# define GlxBuiltInXMesa NO
+# endif
+
+/*
+ * The rest are hardware-specific DRI drivers.
+ */
# ifndef GlxBuiltInGamma
# define GlxBuiltInGamma NO
# endif
-# ifndef GlxBuiltInMesa
-# define GlxBuiltInMesa NO
-# endif
# ifndef GlxBuiltInTdfx
# define GlxBuiltInTdfx NO
# endif
@@ -891,8 +900,7 @@ IPLAN2P8_DEFS = -DUSE_IPLAN2P8
GlxBuiltInR128 || \
GlxBuiltInRadeon || \
GlxBuiltInFfb || \
- GlxBuiltInSIS || \
- GlxBuiltInMesa
+ GlxBuiltInSIS
# define GlxUseBuiltInDRIDriver YES
# define DRIDynLoadDefines /**/
# else
@@ -1397,6 +1405,9 @@ IPLAN2P8_DEFS = -DUSE_IPLAN2P8
#ifndef XVirtualFramebufferServer
# define XVirtualFramebufferServer YES
#endif
+#ifndef XdmxServer
+# define XdmxServer YES
+#endif
#ifndef XprtServer
# define XprtServer YES
#endif
diff --git a/xc/programs/Xserver/Imakefile b/xc/programs/Xserver/Imakefile
index 3991ddab1..649414b82 100644
--- a/xc/programs/Xserver/Imakefile
+++ b/xc/programs/Xserver/Imakefile
@@ -2,7 +2,7 @@ XCOMM $Xorg: Imakefile,v 1.4 2001/03/14 18:42:02 pookie Exp $
/*
* Server Master Makefile
*/
-XCOMM $XFree86: xc/programs/Xserver/Imakefile,v 3.254 2002/01/07 20:38:21 dawes Exp $
+XCOMM $XFree86: xc/programs/Xserver/Imakefile,v 3.257 2002/02/25 00:45:40 dawes Exp $
#ifndef InstallXserverSetUID
#define InstallXserverSetUID NO
@@ -85,11 +85,10 @@ INSTPGMFLAGS =
#else
#if DoLoadableServer
GLXLIB = GL/glx/ModuleLibraryTargetName(glx) \
- GL/mesa/src/ModuleLibraryTargetName(GLcore)
+ GL/mesa/GLcore/ModuleLibraryTargetName(GLcore)
#else
GLXLIB = GL/glx/ModuleLibraryTargetName(glx) \
- GL/mesa/src/X/ModuleLibraryTargetName(GLcoreX) \
- GL/mesa/src/ModuleLibraryTargetName(GLcore) \
+ GL/mesa/GLcore/ModuleLibraryTargetName(GLcore) \
$(DRILIB)
#endif
#endif
@@ -525,12 +524,16 @@ XNEST = Xnest
#if XVirtualFramebufferServer
XVFB = Xvfb
#endif
+#if XdmxServer
+XDMX = Xdmx
+#endif
#if XWinServer && !MakeDllModules
XWIN = XWin
#endif
#if defined(XF86Server) || \
defined(XnestServer) || \
defined(XVirtualFramebufferServer) || \
+ defined(XdmxServer) || \
(!MakeDllModules && defined(XWinServer))
MakeMutex($(XF86SERVER) $(XNEST) $(XVFB) $(XWIN))
#endif
@@ -654,7 +657,7 @@ MakeMutex($(XF86SERVERSUBDIRS) $(XF86SERVERLIBS) $(XF86SERVERSYSLIBS))
#endif
#if ForceServerRemake
$(XF86SERVERLIBS) $(XF86SERVERSYSLIBS):: $(XF86SERVERSUBDIRS)
- @if [ -f $@ ]; then touch $@; fi
+ @if [ -f $@ ]; then touch $@ >/dev/null 2>&1 || exit 0; fi
#endif
SetUIDServerTarget(XFree86,$(XF86SERVERSUBDIRS),$(XF86SERVEROBJS), \
$(XF86SERVERLIBS),$(XF86SERVERSYSLIBS))
@@ -716,7 +719,7 @@ MakeMutex($(FBDEVDIRS) $(FBDEVOBJS) $(FBDEVLIBS) $(FBDEVSYSLIBS))
#endif
#if ForceServerRemake
$(FBDEVOBJS) $(XFBDEV) $(FBDEVLIBS) $(FBDEVSYSLIBS):: $(FBDEVDIRS)
- @if [ -f $@ ]; then touch $@; fi
+ @if [ -f $@ ]; then touch $@ >/dev/null 2>&1 || exit 0; fi
#endif
ServerTarget(Xfbdev,$(FBDEVDIRS),$(FBDEVOBJS), \
$(FBDEVLIBS),$(FBDEVSYSLIBS))
@@ -742,7 +745,7 @@ MakeMutex($(SAVAGEDIRS) $(SAVAGEOBJS) $(SAVAGELIBS) $(SAVAGESYSLIBS))
#endif
#if ForceServerRemake
$(SAVAGEOBJS) $(XSAVAGE) $(SAVAGELIBS) $(SAVAGESYSLIBS):: $(SAVAGEDIRS)
- @if [ -f $@ ]; then touch $@; fi
+ @if [ -f $@ ]; then touch $@ >/dev/null 2>&1 || exit 0; fi
#endif
ServerTarget(Xsavage,$(SAVAGEDIRS),$(SAVAGEOBJS), \
$(SAVAGELIBS),$(SAVAGESYSLIBS))
@@ -768,7 +771,7 @@ MakeMutex($(IGSDIRS) $(IGSOBJS) $(IGSLIBS) $(IGSSYSLIBS))
#endif
#if ForceServerRemake
$(IGSOBJS) $(XIGS) $(IGSLIBS) $(IGSSYSLIBS):: $(IGSDIRS)
- @if [ -f $@ ]; then touch $@; fi
+ @if [ -f $@ ]; then touch $@ >/dev/null 2>&1 || exit 0; fi
#endif
ServerTarget(Xigs,$(IGSDIRS),$(IGSOBJS), \
$(IGSLIBS),$(IGSSYSLIBS))
@@ -799,7 +802,7 @@ MakeMutex($(TRIDENTDIRS) $(TRIDENTLIBS) $(TRIDENTSYSLIBS))
#endif
#if ForceServerRemake
$(TRIDENTOBJS) $(TRIDENTLIBS) $(TRIDENTSYSLIBS):: $(TRIDENTDIRS)
- @if [ -f $@ ]; then touch $@; fi
+ @if [ -f $@ ]; then touch $@ >/dev/null 2>&1 || exit 0; fi
#endif
ServerTarget(Xtrident,$(TRIDENTDIRS),$(TRIDENTOBJS), \
$(TRIDENTLIBS),$(TRIDENTSYSLIBS))
@@ -828,7 +831,7 @@ MakeMutex($(CHIPSDIRS) $(CHIPSLIBS) $(CHIPSSYSLIBS))
#endif
#if ForceServerRemake
$(CHIPSOBJS) $(CHIPSLIBS) $(CHIPSSYSLIBS):: $(CHIPSDIRS)
- @if [ -f $@ ]; then touch $@; fi
+ @if [ -f $@ ]; then touch $@ >/dev/null 2>&1 || exit 0; fi
#endif
ServerTarget(Xchips,$(CHIPSDIRS),$(CHIPSOBJS), \
$(CHIPSLIBS),$(CHIPSSYSLIBS))
@@ -857,7 +860,7 @@ MakeMutex($(MACH64DIRS) $(MACH64LIBS) $(MACH64SYSLIBS))
#endif
#if ForceServerRemake
$(MACH64OBJS) $(MACH64LIBS) $(MACH64SYSLIBS):: $(MACH64DIRS)
- @if [ -f $@ ]; then touch $@; fi
+ @if [ -f $@ ]; then touch $@ >/dev/null 2>&1 || exit 0; fi
#endif
ServerTarget(Xmach64,$(MACH64DIRS),$(MACH64OBJS), \
$(MACH64LIBS),$(MACH64SYSLIBS))
@@ -887,7 +890,7 @@ MakeMutex($(I810DIRS) $(I810LIBS) $(I810SYSLIBS))
#endif
#if ForceServerRemake
$(I810OBJS) $(I810LIBS) $(I810SYSLIBS):: $(I810DIRS)
- @if [ -f $@ ]; then touch $@; fi
+ @if [ -f $@ ]; then touch $@ >/dev/null 2>&1 || exit 0; fi
#endif
ServerTarget(Xi810,$(I810DIRS),$(I810OBJS), \
$(I810LIBS),$(I810SYSLIBS))
@@ -914,7 +917,7 @@ MakeMutex($(SIS530DIRS) $(SIS530OBJS) $(SIS530LIBS) $(SIS530SYSLIBS))
#endif
#if ForceServerRemake
$(SIS530OBJS) $(SIS530LIBS) $(SIS530SYSLIBS):: $(SIS530DIRS)
- @if [ -f $@ ]; then touch $@; fi
+ @if [ -f $@ ]; then touch $@ >/dev/null 2>&1 || exit 0; fi
#endif
ServerTarget(Xsis530,$(SIS530DIRS),$(SIS530OBJS), \
$(SIS530LIBS),$(SIS530SYSLIBS))
@@ -940,7 +943,7 @@ MakeMutex($(TRIODIRS) $(TRIOOBJS) $(TRIOLIBS) $(TRIOSYSLIBS))
#endif
#if ForceServerRemake
$(TRIOOBJS) $(TRIOLIBS) $(TRIOSYSLIBS):: $(TRIODIRS)
- @if [ -f $@ ]; then touch $@; fi
+ @if [ -f $@ ]; then touch $@ >/dev/null 2>&1 || exit 0; fi
#endif
ServerTarget(Xtrio,$(TRIODIRS),$(TRIOOBJS), \
$(TRIOLIBS),$(TRIOSYSLIBS))
@@ -974,7 +977,7 @@ MakeMutex($(IPAQDIRS) $(IPAQOBJS) $(IPAQLIBS) $(IPAQSYSLIBS))
#endif
#if ForceServerRemake
$(IPAQOBJS) $(IPAQLIBS) $(IPAQSYSLIBS):: $(IPAQDIRS)
- @if [ -f $@ ]; then touch $@; fi
+ @if [ -f $@ ]; then touch $@ >/dev/null 2>&1 || exit 0; fi
#endif
ServerTarget(Xipaq,$(IPAQDIRS),$(IPAQOBJS), \
$(IPAQLIBS),$(IPAQSYSLIBS))
@@ -1006,7 +1009,7 @@ MakeMutex($(TS300DIRS) $(TS300OBJS) $(TS300LIBS) $(TS300SYSLIBS))
#endif
#if ForceServerRemake
$(TS300OBJS) $(TS300LIBS) $(TS300SYSLIBS):: $(TS300DIRS)
- @if [ -f $@ ]; then touch $@; fi
+ @if [ -f $@ ]; then touch $@ >/dev/null 2>&1 || exit 0; fi
#endif
ServerTarget(Xts300,$(TS300DIRS),$(TS300OBJS), \
$(TS300LIBS),$(TS300SYSLIBS))
@@ -1031,7 +1034,7 @@ MakeMutex($(ITSYDIRS) $(ITSYOBJS) $(ITSYLIBS) $(ITSYSYSLIBS))
#endif
#if ForceServerRemake
$(ITSYOBJS) $(ITSYLIBS) $(ITSYSYSLIBS):: $(ITSYDIRS)
- @if [ -f $@ ]; then touch $@; fi
+ @if [ -f $@ ]; then touch $@ >/dev/null 2>&1 || exit 0; fi
#endif
ServerTarget(Xitsy,$(ITSYDIRS),$(ITSYOBJS), \
$(ITSYLIBS),$(ITSYSYSLIBS))
@@ -1057,7 +1060,7 @@ MakeMutex($(VESADIRS) $(VESAOBJS) $(VESALIBS) $(VESASYSLIBS))
#endif
#if ForceServerRemake
$(VESAOBJS) $(XVESA) $(VESALIBS) $(VESASYSLIBS):: $(VESADIRS)
- @if [ -f $@ ]; then touch $@; fi
+ @if [ -f $@ ]; then touch $@ >/dev/null 2>&1 || exit 0; fi
#endif
ServerTarget(Xvesa,$(VESADIRS),$(VESAOBJS), \
$(VESALIBS),$(VESASYSLIBS))
@@ -1097,7 +1100,7 @@ MakeMutex($(XPSUBDIRS) $(XPOBJS) $(XPLIBS) $(XPSYSLIBS))
#endif
#if ForceServerRemake
$(XPOBJS) $(XPLIBS) $(XPSYSLIBS):: $(XPSUBDIRS)
- @if [ -f $@ ]; then touch $@; fi
+ @if [ -f $@ ]; then touch $@ >/dev/null 2>&1 || exit 0; fi
#endif
ServerTarget(Xprt,$(XPSUBDIRS),$(XPOBJS), \
$(XPLIBS) $(LOADABLEEXTS) $(LIBCWRAPPER),$(XPSYSLIBS))
@@ -1128,7 +1131,7 @@ MakeMutex($(XNESTDIRS) $(XNESTOBJS) $(XNESTLIBS) $(XNESTSYSLIBS))
#endif
#if ForceServerRemake
$(XNESTOBJS) $(XNESTLIBS) $(XNESTSYSLIBS):: $(XNESTDIRS)
- @if [ -f $@ ]; then touch $@; fi
+ @if [ -f $@ ]; then touch $@ >/dev/null 2>&1 || exit 0; fi
#endif
ServerTarget(Xnest,$(XNESTDIRS),$(XNESTOBJS), \
$(XNESTLIBS) $(LOADABLEEXTS) $(LIBCWRAPPER),$(XNESTSYSLIBS))
@@ -1178,13 +1181,49 @@ MakeMutex($(XVFBDIRS) $(XVFBOBJS) $(XVFB) $(XVFBLIBS) $(XVFBSYSLIBS))
#endif
#if ForceServerRemake
$(XVFBOBJS) $(XVFB) $(XVFBLIBS) $(XVFBSYSLIBS):: $(XVFBDIRS)
- @if [ -f $@ ]; then touch $@; fi
+ @if [ -f $@ ]; then touch $@ >/dev/null 2>&1 || exit 0; fi
#endif
ServerTarget(Xvfb,$(XVFBDIRS),$(XVFBOBJS), \
$(XVFBLIBS) $(LOADABLEEXTS) $(LIBCWRAPPER),$(XVFBSYSLIBS))
#endif /* XVirtualFramebufferServer */
+#if XdmxServer
+XCOMM
+XCOMM distribued multihead Server
+XCOMM
+#ifndef Win32Architecture
+XDMXDDXDIR = hw/dmx
+#else
+XDMXDDXDIR = hw
+#endif
+FBDIR = fb
+SHADOWDIR = miext/shadow
+XDMXDIRS = $(STDDIRS) $(XDMXDDXDIR) $(SHADOWDIR) $(DEPDIRS) $(FBDIR)
+#if !defined(LynxOSArchitecture) && \
+ !defined(Win32Architecture) && \
+ !defined(QNX4Architecture)
+XDMXOBJS = hw/dmx/miinitext.o
+#else
+XDMXOBJS = hw/dmx/miinitext.o dix/main.o
+#endif
+XDMX = hw/dmx/LibraryTargetName(dmx) \
+ hw/dmx/input/LibraryTargetName(dmxinput) \
+ hw/dmx/config/LibraryTargetName(dmxconfig)
+XDMXLIBS = PreFbLibs $(XDMX) MiExtLibs FbPostFbLibs $(XDMX)
+XDMXSYSLIBS = $(FONTLIBS) $(LDPRELIBS) $(XILIB) $(XLIB) $(SYSLIBS) $(XMULIB)
+#if HasParallelMake
+MakeMutex($(XDMXDIRS) $(XDMXOBJS) $(XDMXLIBS) $(XDMXSYSLIBS))
+#endif
+#if ForceServerRemake
+$(XDMXOBJS) $(XDMXLIBS) $(XDMXSYSLIBS):: $(XDMXDIRS)
+ @if [ -f $@ ]; then touch $@ >/dev/null 2>&1 || exit 0; fi
+#endif
+ServerTarget(Xdmx,$(XDMXDIRS),$(XDMXOBJS), \
+ $(XDMXLIBS) $(LOADABLEEXTS) $(LIBCWRAPPER),$(XDMXSYSLIBS))
+#endif /* XdmxServer */
+
+
#if XWinServer
XCOMM
XCOMM X Server for MS Windows
@@ -1216,7 +1255,7 @@ MakeMutex($(XWINDIRS) $(XWINOBJS) $(XWINLIB) $(XWINLIBS) $(XWINSYSLIBS))
#if ForceServerRemake
$(XWINOBJS) $(XWINLIB) $(XWINLIBS) $(XWINSYSLIBS):: $(XWINDIRS)
- @if [ -f $@ ]; then touch $@; fi
+ @if [ -f $@ ]; then touch $@ >/dev/null 2>&1 || exit 0; fi
#endif
ServerTarget(XWin,$(XWINDIRS),$(XWINOBJS), \
@@ -1298,7 +1337,7 @@ MIEXTDIRS = $(SHADOWDIR) $(LAYERDIR)
IPLANDIRS = $(IPLAN2P2DIR) $(IPLAN2P4DIR) $(IPLAN2P8DIR)
DDXDIRS = $(DECWSDDXDIR) $(SUNDDXDIR) $(LYNXDDXDIR) \
$(HPDDXDIR) $(XFREE86DDXDIR) $(XWINDDXDIR) $(DARWINDDXDIR) \
- $(XVFBDDXDIR) $(XNESTDDXDIR)
+ $(XVFBDDXDIR) $(XNESTDDXDIR) $(XDMXDDXDIR)
SUBDIRS = $(STDDIRS) $(MFBDIR) $(CFBDIRS) $(IPLANDIRS) $(ILBMDIR) $(AFBDIR) \
$(LMFCFBDIR) $(DDXDIRS) $(FBDIR) $(KDRIVEDIRS) $(MIEXTDIRS)
diff --git a/xc/programs/Xserver/hw/Imakefile b/xc/programs/Xserver/hw/Imakefile
index 9b91287f3..42c0d57b6 100644
--- a/xc/programs/Xserver/hw/Imakefile
+++ b/xc/programs/Xserver/hw/Imakefile
@@ -14,7 +14,11 @@ XNESTDIR = xnest
XVFBDIR = vfb
#endif
-SUBDIRS= $(XNESTDIR) $(XVFBDIR)
+#if XdmxServer
+XDMXDIR = xdmx
+#endif
+
+SUBDIRS= $(XNESTDIR) $(XVFBDIR) $(XDMXDIR)
MakeSubdirs($(SUBDIRS))
DependSubdirs($(SUBDIRS))
diff --git a/xc/programs/Xserver/hw/dmx/Imakefile b/xc/programs/Xserver/hw/dmx/Imakefile
new file mode 100644
index 000000000..7e3b8a0a2
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/Imakefile
@@ -0,0 +1,71 @@
+XCOMM $XFree86$
+
+#include <Server.tmpl>
+
+#define IHaveSubdirs
+SUBDIRS= input config doc
+
+SRCS = dmxinit.c \
+ dmxscrinit.c \
+ dmxshadow.c \
+ dmxcursor.c \
+ dmxinput.c \
+ dmxdpms.c \
+ dmxgc.c \
+ dmxgcops.c \
+ dmxwindow.c \
+ dmxpixmap.c \
+ dmxfont.c \
+ dmxcmap.c \
+ dmxvisual.c \
+ dmxlog.c \
+ dmxcb.c \
+ dmxprop.c \
+ stubs.c \
+ miinitext.c
+
+OBJS = dmxinit.o \
+ dmxscrinit.o \
+ dmxshadow.o \
+ dmxcursor.o \
+ dmxinput.o \
+ dmxdpms.o \
+ dmxgc.o \
+ dmxgcops.o \
+ dmxwindow.o \
+ dmxpixmap.o \
+ dmxfont.o \
+ dmxcmap.o \
+ dmxvisual.o \
+ dmxlog.o \
+ dmxcb.o \
+ dmxprop.o \
+ stubs.o \
+ miinitext.o
+
+
+INCLUDES = -I. -I$(XBUILDINCDIR) -I$(FONTINCSRC) \
+ -I../../mi -I../../include -I../../os \
+ -I../../fb -I../../miext/shadow -I../../render \
+ -I$(EXTINCSRC) -I$(XINCLUDESRC) -I$(SERVERSRC)/Xext
+
+DEFINES = $(OS_DEFINES) $(EXT_DEFINES) -UMITSHM \
+ -UXF86VIDMODE -UXFreeXDGA -UXF86MISC -UXF86DRI -UXFree86LOADER \
+ -URENDER
+
+all:: $(OBJS)
+
+MakeSubdirs($(SUBDIRS))
+DependSubdirs($(SUBDIRS))
+
+LinkSourceFile(stubs.c,$(SERVERSRC)/Xi)
+/* SpecialCObjectRule(Init,$(ICONFIGFILES),$(_NOOP_)) */
+LinkSourceFile(miinitext.c,$(SERVERSRC)/mi)
+SpecialCObjectRule(miinitext,$(ICONFIGFILES),-UDPMSExtension)
+
+NormalLibraryObjectRule()
+NormalLibraryTarget(dmx,$(OBJS))
+
+InstallManPage(Xdmx,$(MANDIR))
+
+DependTarget()
diff --git a/xc/programs/Xserver/hw/dmx/Xdmx.man b/xc/programs/Xserver/hw/dmx/Xdmx.man
new file mode 100644
index 000000000..31ddc06b9
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/Xdmx.man
@@ -0,0 +1,388 @@
+.\" $XFree86$
+.TH Xdmx 1 __vendorversion__
+.SH NAME
+Xdmx - Distributed Multi-head X server
+.SH SYNOPSIS
+.B Xdmx
+[:display] [option ...]
+.SH DESCRIPTION
+.I Xdmx
+is an X server that uses one or more other X servers as its display
+devices. It provides multi-head X functionality for displays that might
+located on different machines.
+.I Xdmx
+functions as a front-end X server that acts as a proxy to a set of
+back-end X servers. All of the visible rendering is passed to the
+back-end X servers. Clients connect to the
+.I Xdmx
+front-end, and everything appears as it would in a regular multi-head
+configuration. If Xinerama is enabled (e.g., with
+.B +xinerama
+on the command line), the clients see a single large screen.
+.PP
+.I Xdmx
+communicates to the back-end X servers using the standard X11 protocol,
+and standard and/or commonly available X server extensions.
+.SH OPTIONS
+In addition to the normal X server options described in the
+.I Xserver(1)
+manual page,
+.I Xdmx
+accepts the following command line switches:
+.TP 8
+.BI "\-display " display-name
+This specifies the name(s) of the back-end X server display(s) to connect
+to. This option may be specified multiple times to connect to more than
+one back-end display. The first is used as screen 0, the second as screen 1,
+etc. If this option is omitted, the
+.B $DISPLAY
+environment variable is used as the single back-end X server display.
+.sp
+.TP 8
+.BI "\-inputfrom " input-source
+This specifies the source to use for the core input devices. The choices are:
+.RS 8
+.TP 4
+.B dummy
+A set of dummy core input drivers are used. These never generate any
+input events.
+.TP 4
+.B local
+The raw keyboard and pointer from the local computer are used. A
+comma-separated list of driver names can be appended. For example, to
+select the example Linux keyboard and PS/2 mouse driver use:
+.BR "-inputfrom local,kbd,ps2" .
+The following drivers have been implemented for Linux: kbd, ms (a
+two-button Microsoft mouse driver), and ps2 (a PS/2 mouse driver).
+Additional drivers may be implemented in the future. Appropriate
+defaults will be used if no comma-separated list is provided.
+.TP 4
+.I display-name
+If the display-name is a back-end server, then core input events are
+taken from the server specified. Otherwise, a console window will be
+opened on the specified display.
+.PP
+If this option isn't specified, the default input source is the first
+back-end server (the one used for screen 0). The console window shows
+the layout of the back-end display(s) and pointer movements and key
+presses within the console window will be used as core input devices.
+.PP
+Several special function keys are active, depending on the input
+source:
+.RS
+.B Ctrl-Alt-q
+will terminate the
+.I Xdmx
+server in all modes.
+.sp
+.B Ctrl-Alt-g
+will toggle a
+server grab in console mode (a special cursor, currently a spider, is
+used to indicate an active server grab).
+.sp
+.B Ctrl-Alt-f
+will toggle fine-grain motion in console mode (a special cursor,
+currently a cross hair, is used to indicate this mode). If this mode is
+combined with a server grab, then the cursor will have 4 lines instead
+of only 2.
+.sp
+.BR Ctrl-Alt-F1 " through " Ctrl-Alt-F12
+will switch to another VC in local (raw) mode.
+.RE
+.RE
+.sp
+.TP 8
+.BI "-shadowfb"
+This option turns on (legacy) support for the shadow frame buffer.
+.sp
+.TP 8
+.BI "-noshadowfb"
+This option turns off (legacy) support for the shadow frame buffer.
+Note that this option has been deprecated and will be removed in the
+next release.
+.sp
+.TP 8
+.BI "-nomulticursor"
+This option turns off support for displaying multiple cursors on
+overlapped backend displays. This option is available for testing and
+benchmarking purposes.
+.sp
+.TP 8
+.BI "-fontpath"
+This option sets the
+.I Xdmx
+server's default font path. This option can be specified mutiple times
+to accommodate multiple font paths. See the
+.B "FONT PATHS"
+section below for very important information regarding setting the
+default font path.
+.sp
+.TP 8
+.BI "-configfile " filename
+Specify the configuration file that should be read. Note that if the
+.B \-display
+command-line option is used, then the configuration file will be
+ignored.
+.sp
+.TP 8
+.BI "-config " name
+Specify a configuration to use. The
+.I name
+will be the name following the
+.B virtual
+keyword in the configuration file.
+.SH "CONFIGURATION FILE GRAMMAR"
+The following words and tokens are reserved:
+.RS
+.B virtual
+.B display
+.B wall
+.B {
+.B }
+.B ;
+.B #
+.RE
+.PP
+Comments start with a
+.B #
+mark and extend to the end of the line. They may appear anywhere. If a
+configuration file is read into
+.BR xdmxconfig ,
+the comments in that file will be preserved, but will not be editable.
+.PP
+The grammar is as follows:
+.RS
+virtual-list ::= [ virtual-list ] | virtual
+
+virtual ::=
+.B virtual
+[ name ] [ dim ]
+.B {
+dw-list
+.B }
+
+dw-list ::= [ dw-list ] | dw
+
+dw ::= display | wall | option
+
+display ::=
+.B display
+name [ geometry ] [ origin ]
+.B ;
+
+wall ::=
+.B wall
+[ dim ] [ dim ] name-list
+.B ;
+
+option ::=
+.B option
+name-list
+.B ;
+
+name-list ::= [ name-list ] | name
+
+name ::= string | double-quoted-string
+
+dim ::= integer
+.B x
+integer
+
+geometry ::= [ integer
+.B x
+integer ] [ signed-integer signed-integer ]
+
+origin ::=
+.B @
+integer
+.B x
+integer
+.RE
+.PP
+The name following
+.B virtual
+is used as an identifier for the configuration, and may be passed to
+.B Xdmx
+using the
+.B \-config
+command line option. The name of a display should be standard X display
+name, although no checking is performed (e.g., "machine:0").
+.PP
+For names, double quotes are optional unless the name is reserved or
+contains spaces.
+.PP
+The first dimension following
+.B wall
+is the dimension for tiling (e.g., 2x4 or 4x4). The second dimension
+following
+.B wall
+is the dimension of each display in the wall (e.g., 1280x1024).
+.PP
+The
+.B option
+line can be used to specify any command-line options (e.g.,
+.BR \-inputfrom ).
+(It cannot be used to specify the name of the front-end display.) The
+option line is processed once at server startup, just line command line
+options. This behavior may be unexpected.
+.SH "CONFIGURATION FILE EXAMPLES"
+Two displays being used for a desktop may be specified in any of the
+following formats:
+.RS
+.nf
+virtual example0 {
+ display d0:0 1280x1024 @0x0;
+ display d1:0 1280x1024 @1280x0;
+}
+.sp
+virtual example1 {
+ display d0:0 1280x1024;
+ display d1:0 @1280x0;
+}
+.sp
+virtual example2 {
+ display "d0:0";
+ display "d1:0" @1280x0;
+}
+.sp
+virtual example3 { wall 2x1 d0:0 d1:0; }
+.fi
+.RE
+A 4x4 wall of 16 total displays could be specified as follows (if no
+tiling dimension is specified, an approximate square is used):
+.RS
+.nf
+virtual example4 {
+ wall d0:0 d1:0 d2:0 d3:0
+ d4:0 d5:0 d6:0 d7:0
+ d8:0 d9:0 da:0 db:0
+ dc:0 dd:0 de:0 df:0;
+}
+.fi
+.RE
+.SH "FONT PATHS"
+The font path used by the
+.I Xdmx
+front-end server will be propogated to each back-end server,which
+requires that each back-end server have access to the exact same font
+paths as the front-end server. This can be most easily handled by
+either using a font server (e.g., xfs) or by remotely mounting the font
+paths on each back-end server, and then setting the
+.I Xdmx
+server's default font path with the
+-I "-fontpath"
+command line option described above.
+.PP
+For example, if you specify a font path with the following command line:
+.RS 8
+Xdmx :1 -display d0:0 -fontpath /usr/fonts/75dpi/ -fontpath /usr/fonts/Type1/ +xinerama
+.RE
+Then, /usr/fonts/75dpi/ and /usr/fonts/Type1/ must be valid font paths
+on the
+.I Xdmx
+server and all back-end server, which is d0 in this example.
+.PP
+Font servers can also be specified with the
+.I "-fontpath"
+option. For example, let's assume that a properly configured font
+server is running on host d0. Then, the following command line
+.RS 8
+Xdmx :1 -display d0:0 -display d1:0 -fontpath tcp/d0:7100 +xinerama
+.RE
+will initialize the front-end
+.I Xdmx
+server and each of the back-end servers to use the font server on d0.
+.PP
+Some fonts might not be supported by either the front-end or the
+back-end servers. For exmaple, let's assume the front-end
+.I Xdmx
+server includes support Type1 fonts, but one of the back-end servers
+does not. Let's also assume that the default font path for
+.I Xdmx
+includes Type1 fonts in its font path. Then, when
+.I Xdmx
+intializes the default font path to load the default font, the font path
+that includes Type1 fonts (along with the other default font paths that are used by the
+.I Xdmx
+server) is sent to the back-end server that cannot handle Type1 fonts.
+That back-end server then rejects the font path and sends an error back
+to the
+.I Xdmx
+server.
+.I Xdmx
+then prints an error message and exits because it failed to set the
+default font path and was unable load the default font.
+.PP
+To fix this error, the offending font path must be removed from the
+default font path by using a different
+.I "-fontpath"
+command line option.
+.PP
+The
+.I "-fontpath"
+option can also be added to the configuration file as described above.
+.SH "COMMAND-LINE EXAMPLES"
+The backend machines are d0 and d1, core input is from the pointer and
+keyboard attached to d0, clients will refer to :1 when opening windows:
+.RS 8
+Xdmx :1 -display d0:0 -display d1:0 +xinerama
+.RE
+.PP
+As above, except with core input from d1:
+.RS 8
+Xdmx :1 -display d0:0 -display d1:0 -inputfrom d1:0 +xinerama
+.RE
+.PP
+As above, except with core input from a console window on the local
+display:
+.RS 8
+Xdmx :1 -display d0:0 -display d1:0 -inputfrom :0 +xinerama
+.RE
+.PP
+As above, except with core input from the local keyboard and mouse:
+.RS 8
+Xdmx :1 -display d0:0 -display d1:0 -inputfrom local,kbd,ps2 +xinerama
+.RE
+Note that local input can be used under Linux while another X session is
+running on :0 (assuming the user can access the Linux console tty and
+mouse devices): a new (blank) VC will be used for keyboard input on the
+local machine and the Ctrl-Alt-F* sequence will be available to change
+to another VC (possibly back to another X session running on the local
+machine). Using Ctrl-Alt-Backspace on the blank VC will terminate the
+Xdmx session and return to the original VC.
+.PP
+This example uses the configuration file shown in the previous section:
+.RS
+Xdmx :1 -inputfrom :0 +xinerama -configfile filename -config example2
+.RE
+With this configuration file line:
+.RS
+option -inputfrom :0 +xinerama;
+.RE
+the command line can be shortened to:
+.RS
+Xdmx :1 -configfile filename -config example2
+.RE
+.ig
+.SH ENVIRONMENT
+..
+.ig
+.SH FILES
+..
+.SH "SEE ALSO"
+X(__miscmansuffix__), Xserver(1), xdmxconfig(1), vdltodmx(1), xfs(1)
+.SH AUTHORS
+Kevin E. Martin
+.I <kem@redhat.com>,
+David H. Dawes
+.I <dawes@xfree86.org>,
+and
+Rickard E. (Rik) Faith
+.IR <faith@redhat.com> .
+.PP
+Portions of
+.I Xdmx
+are based on code from The XFree86 Project
+.RI ( http://www.xfree86.org )
+and X.Org
+.RI ( http://www.x.org ).
diff --git a/xc/programs/Xserver/hw/dmx/config/Canvas.c b/xc/programs/Xserver/hw/dmx/config/Canvas.c
new file mode 100644
index 000000000..f0c2fa44e
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/Canvas.c
@@ -0,0 +1,136 @@
+/* $XFree86$ */
+/*
+
+Copyright 1987, 1998 The Open Group
+Copyright 2002 Red Hat Inc., Durham, North Carolina.
+
+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.
+
+*/
+
+/*
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ * This file was originally taken from xc/lib/Xaw/Template.c
+ */
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include "CanvasP.h"
+
+static void CanvasInitialize(Widget request, Widget w,
+ ArgList args, Cardinal *num_args)
+{
+}
+
+static void CanvasExpose(Widget w, XEvent *event, Region region)
+{
+ CanvasExposeDataRec data;
+
+ data.w = w;
+ data.event = event;
+ data.region = region;
+
+ if (!XtIsRealized(w)) return;
+ XtCallCallbacks(w, XtNcanvasExposeCallback, (XtPointer)&data);
+}
+
+static void CanvasResize(Widget w)
+{
+ if (!XtIsRealized(w)) return;
+ XtCallCallbacks(w, XtNcanvasResizeCallback, (XtPointer)w);
+}
+
+static void CanvasAction(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ XtCallCallbacks(w, XtNcallback, (XtPointer)event);
+}
+
+#define offset(field) XtOffsetOf(CanvasRec, canvas.field)
+static XtResource resources[] = {
+ { XtNcallback, XtCCallback, XtRCallback,
+ sizeof(XtCallbackList), offset(input_callback), XtRCallback, NULL },
+ { XtNcanvasExposeCallback, XtCcanvasExposeCallback, XtRCallback,
+ sizeof(XtCallbackList), offset(expose_callback), XtRCallback, NULL },
+ { XtNcanvasResizeCallback, XtCcanvasResizeCallback, XtRCallback,
+ sizeof(XtCallbackList), offset(resize_callback), XtRCallback, NULL },
+};
+#undef offset
+
+static XtActionsRec actions[] =
+{
+ {"canvas", CanvasAction},
+};
+
+static char translations[] =
+"<Key>: canvas()\n\
+<Motion>: canvas()\n\
+<BtnDown>: canvas()\n\
+<BtnUp>: canvas()\n\
+"
+;
+
+#define Superclass (&widgetClassRec)
+CanvasClassRec canvasClassRec = {
+ /* core */
+ {
+ (WidgetClass)Superclass, /* superclass */
+ "Canvas", /* class_name */
+ sizeof(CanvasRec), /* widget_size */
+ NULL, /* class_initialize */
+ NULL, /* class_part_initialize */
+ False, /* class_inited */
+ CanvasInitialize, /* initialize */
+ NULL, /* initialize_hook */
+ XtInheritRealize, /* realize */
+ actions, /* actions */
+ XtNumber(actions), /* num_actions */
+ resources, /* resources */
+ XtNumber(resources), /* num_resources */
+ NULLQUARK, /* xrm_class */
+ True, /* compress_motion */
+ True, /* compress_exposure */
+ True, /* compress_enterleave */
+ False, /* visible_interest */
+ NULL, /* destroy */
+ CanvasResize, /* resize */
+ CanvasExpose, /* expose */
+ NULL, /* set_values */
+ NULL, /* set_values_hook */
+ XtInheritSetValuesAlmost, /* set_values_almost */
+ NULL, /* get_values_hook */
+ NULL, /* accept_focus */
+ XtVersion, /* version */
+ NULL, /* callback_private */
+ translations, /* tm_table */
+ XtInheritQueryGeometry, /* query_geometry */
+ XtInheritDisplayAccelerator, /* display_accelerator */
+ NULL, /* extension */
+ },
+ /* canvas */
+ {
+ NULL, /* extension */
+ }
+};
+
+WidgetClass canvasWidgetClass = (WidgetClass)&canvasClassRec;
diff --git a/xc/programs/Xserver/hw/dmx/config/Canvas.h b/xc/programs/Xserver/hw/dmx/config/Canvas.h
new file mode 100644
index 000000000..a36851a6d
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/Canvas.h
@@ -0,0 +1,56 @@
+/* $XFree86$ */
+/*
+
+Copyright 1987, 1998 The Open Group
+Copyright 2002 Red Hat Inc., Durham, North Carolina.
+
+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.
+
+*/
+
+/*
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ * This file was originally taken from xc/lib/Xaw/Template.h
+ */
+
+#ifndef _Canvas_h
+#define _Canvas_h
+
+#include <X11/Intrinsic.h>
+
+#define XtNcanvasExposeCallback "canvasExposeCallback"
+#define XtCcanvasExposeCallback "CanvasExposeCallback"
+#define XtNcanvasResizeCallback "canvasResizeCallback"
+#define XtCcanvasResizeCallback "CanvasResizeCallback"
+
+typedef struct _CanvasClassRec *CanvasWidgetClass;
+typedef struct _CanvasRec *CanvasWidget;
+extern WidgetClass canvasWidgetClass;
+
+typedef struct _CanvasExposeDataRec {
+ Widget w;
+ XEvent *event;
+ Region region;
+} CanvasExposeDataRec, *CanvasExposeDataPtr;
+
+#endif /* _Canvas_h */
diff --git a/xc/programs/Xserver/hw/dmx/config/CanvasP.h b/xc/programs/Xserver/hw/dmx/config/CanvasP.h
new file mode 100644
index 000000000..98f95b94e
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/CanvasP.h
@@ -0,0 +1,66 @@
+/* $XFree86$ */
+/*
+
+Copyright 1987, 1998 The Open Group
+Copyright 2002 Red Hat Inc., Durham, North Carolina.
+
+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.
+
+*/
+
+/*
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ * This file was originally taken from xc/lib/Xaw/TemplateP.h
+ */
+
+#ifndef _CanvasP_h
+#define _CanvasP_h
+
+#include "Canvas.h"
+
+/* include superclass private header file */
+#include <X11/CoreP.h>
+
+typedef struct {
+ XtPointer extension;
+} CanvasClassPart;
+
+typedef struct _CanvasClassRec {
+ CoreClassPart core_class;
+ CanvasClassPart canvas_class;
+} CanvasClassRec;
+
+extern CanvasClassRec canvasClassRec;
+
+typedef struct {
+ XtCallbackList input_callback;
+ XtCallbackList expose_callback;
+ XtCallbackList resize_callback;
+} CanvasPart;
+
+typedef struct _CanvasRec {
+ CorePart core;
+ CanvasPart canvas;
+} CanvasRec;
+
+#endif /* _CanvasP_h */
diff --git a/xc/programs/Xserver/hw/dmx/config/Imakefile b/xc/programs/Xserver/hw/dmx/config/Imakefile
new file mode 100644
index 000000000..5e6a64562
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/Imakefile
@@ -0,0 +1,78 @@
+XCOMM $XFree86$
+
+#include <Server.tmpl>
+#include <lnxdoc.rules>
+
+YFLAGS = -d
+
+LIBSRCS = parser.c scanner.c dmxparse.c dmxprint.c dmxcompat.c dmxconfig.c
+LIBOBJS = parser.o scanner.o dmxparse.o dmxprint.o dmxcompat.o dmxconfig.o
+
+CONFIGSRCS = xdmxconfig.c dmxlog.c Canvas.c
+CONFIGOBJS = xdmxconfig.o dmxlog.o Canvas.o
+
+COMPATSRCS = vdltodmx.c
+COMPATOBJS = vdltodmx.o
+
+TESTSRCS = dmxtodmx.c
+TESTOBJS = dmxtodmx.o
+
+SRCS = $(LIBSRCS) $(CONFIGSRCS) $(COMPATSRCS) $(TESTSRCS)
+OBJS = $(LIBOBJS) $(CONFIGOBJS) $(COMPATOBJS) $(TESTOBJS)
+
+EXES = xdmxconfig vdltodmx dmxtodmx
+
+LOCAL_LIBRARIES = -L. -ldmxconfig
+
+INCLUDES = -I. -I.. -I$(XBUILDINCDIR) -I$(FONTINCSRC) -I../../../mi \
+ -I../../../include -I$(EXTINCSRC)
+
+DEFINES = $(OS_DEFINES) $(EXT_DEFINES) -DDMX_LOG_STANDALONE
+
+all::
+
+LexFile(scanner)
+YaccFile(parser,$(YFLAGS))
+
+NormalLibraryObjectRule()
+NormalLibraryTarget(dmxconfig,$(LIBOBJS))
+
+NormalProgramTarget(xdmxconfig,$(CONFIGOBJS),\
+ libdmxconfig.a XawClientDepLibs $(DEPXTOOLLIB),\
+ $(LOCAL_LIBRARIES) XawClientLibs $(XTOOLLIB),NullParameter)
+AllTarget(ProgramTargetName(xdmxconfig))
+
+NormalProgramTarget(vdltodmx,$(COMPATOBJS),libdmxconfig.a,\
+ $(LOCAL_LIBRARIES),NullParameter)
+AllTarget(ProgramTargetName(vdltodmx))
+
+NormalProgramTarget(dmxtodmx,$(TESTOBJS),libdmxconfig.a,\
+ $(LOCAL_LIBRARIES),NullParameter)
+AllTarget(ProgramTargetName(dmxtodmx))
+
+LinkSourceFile(dmxlog.c,..)
+
+InstallManPage(dmxtodmx,$(MANDIR))
+InstallManPage(vdltodmx,$(MANDIR))
+InstallManPage(xdmxconfig,$(MANDIR))
+
+DependTarget()
+
+tests: $(EXES)
+ @for i in test-*.in; do \
+ b=`echo $$i | sed 's,.in$$,,'` \
+ export b; \
+ (./dmxtodmx < $$i > $$b.tmp 2>&1; exit 0); \
+ if cmp -s ./$$b.out ./$$b.tmp; \
+ then echo PASSED $$b; rm -f $$b.tmp; \
+ else echo "FAILED $$b **********"; \
+ fi \
+ done
+
+tests-update:
+ @for i in test-*.in; do \
+ b=`echo $$i | sed 's,.in$$,,'` \
+ export b; \
+ echo Writing $$b.out; \
+ (./dmxtodmx < $$i > $$b.out 2>&1; exit 0) \
+ done
diff --git a/xc/programs/Xserver/hw/dmx/config/TODO b/xc/programs/Xserver/hw/dmx/config/TODO
new file mode 100644
index 000000000..2998ff4a0
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/TODO
@@ -0,0 +1,7 @@
+Fri May 31 13:20:17 2002
+
+1) Sanitize values from input boxes.
+
+2) Add canvas colors to cavas widget resources or to command-line options.
+
+3) Add ability to edit option line(s) and wall.
diff --git a/xc/programs/Xserver/hw/dmx/config/dmxcompat.c b/xc/programs/Xserver/hw/dmx/config/dmxcompat.c
new file mode 100644
index 000000000..ac31ab6c4
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/dmxcompat.c
@@ -0,0 +1,222 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ * This file provides some compatibility support for reading VDL files
+ * that are used by xmovie
+ * (http://www.llnl.gov/icc/lc/img/xmovie/xmovie.html).
+ */
+
+#include "dmxconfig.h"
+#include "dmxparse.h"
+#include "dmxcompat.h"
+#include "parser.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+static int dmxVDLReadLine(FILE *str, char *buf, int len)
+{
+ if (fgets(buf, len, str)) return strlen(buf);
+ return 0;
+}
+
+static int dmxVDLCount(const char *buf)
+{
+ return strtol(buf, NULL, 10);
+}
+
+static void dmxVDLVirtualEntry(const char *buf,
+ char *name, int *len,
+ int *x, int *y)
+{
+ char *end;
+ const char *s;
+ char *d;
+ int start;
+
+ *x = strtol(buf, &end, 10);
+ *y = strtol(end, &end, 10);
+
+ for (s = end, d = name, start = 1; *s && *s != '['; ++s) {
+ if (start && isspace(*s)) continue;
+ *d++ = *s;
+ start = 0;
+ }
+ *d = '\0';
+ while (d > name && isspace(d[-1])) *--d = '\0'; /* remove trailing space */
+ *len = strlen(name);
+}
+
+static void dmxVDLDisplayEntry(const char *buf,
+ char *name, int *len,
+ int *x, int *y,
+ int *xoff, int *yoff,
+ int *xorig, int *yorig)
+{
+ const char *pt;
+ char *end;
+
+ pt = strchr(buf, ' ');
+ strncpy(name, buf, pt-buf);
+ name[pt-buf] = '\0';
+ *len = strlen(name);
+
+ *x = strtol(pt, &end, 10);
+ *y = strtol(end, &end, 10);
+ *xorig = strtol(end, &end, 10);
+ *yorig = strtol(end, &end, 10);
+ *xoff = strtol(end, &end, 10);
+ *yoff = strtol(end, NULL, 10);
+}
+
+DMXConfigEntryPtr dmxVDLRead(const char *filename)
+{
+ FILE *str;
+ char buf[2048];
+ char *pt;
+ int lineno = 0;
+ DMXConfigEntryPtr entry = NULL;
+ DMXConfigVirtualPtr virtual = NULL;
+ DMXConfigSubPtr sub = NULL;
+ DMXConfigDisplayPtr display = NULL;
+ int vcount = 0;
+ int dcount = 0;
+ int icount = 0;
+ int x, y, xoff, yoff, xorig, yorig;
+ char name[2048];
+ const char *tmp;
+ int len;
+ enum {
+ simulateFlag,
+ virtualCount,
+ virtualEntry,
+ displayCount,
+ displayEntry,
+ ignoreCount,
+ ignoreEntry
+ } state = simulateFlag;
+
+ if (!filename) str = stdin;
+ else str = fopen(filename, "r");
+ if (!str) return NULL;
+
+ while (dmxVDLReadLine(str, buf, sizeof(buf))) {
+ DMXConfigCommentPtr comment = NULL;
+
+ ++lineno;
+ for (pt = buf; *pt; pt++)
+ if (*pt == '\r' || *pt == '\n') {
+ *pt = '\0';
+ break;
+ }
+ if (buf[0] == '#') {
+ tmp = dmxConfigCopyString(buf + 1, strlen(buf + 1));
+ comment = dmxConfigCreateComment(T_COMMENT, lineno, tmp);
+ entry = dmxConfigAddEntry(entry, dmxConfigComment, comment, NULL);
+ continue;
+ }
+ switch (state) {
+ case simulateFlag:
+ state = virtualCount;
+ break;
+ case virtualCount:
+ vcount = dmxVDLCount(buf);
+ state = virtualEntry;
+ break;
+ case virtualEntry:
+ len = sizeof(name);
+ dmxVDLVirtualEntry(buf, name, &len, &x, &y);
+ tmp = dmxConfigCopyString(name, len);
+ virtual = dmxConfigCreateVirtual(NULL,
+ dmxConfigCreateString(T_STRING,
+ lineno,
+ NULL,
+ tmp),
+ dmxConfigCreatePair(T_DIMENSION,
+ lineno,
+ NULL,
+ x, y, 0, 0),
+ NULL, NULL, NULL);
+ state = displayCount;
+ break;
+ case displayCount:
+ dcount = dmxVDLCount(buf);
+ state = displayEntry;
+ break;
+ case displayEntry:
+ dmxVDLDisplayEntry(buf, name, &len, &x, &y, &xoff, &yoff,
+ &xorig, &yorig);
+ tmp = dmxConfigCopyString(name, len);
+ display = dmxConfigCreateDisplay(NULL,
+ dmxConfigCreateString(T_STRING,
+ lineno,
+ NULL,
+ tmp),
+ dmxConfigCreatePair(T_DIMENSION,
+ lineno,
+ NULL,
+ x, y, 0, 0),
+ dmxConfigCreatePair(T_OFFSET,
+ lineno,
+ NULL,
+ xoff, yoff,
+ xoff, yoff),
+ dmxConfigCreatePair(T_ORIGIN,
+ lineno,
+ NULL,
+ xorig, yorig,
+ 0, 0),
+ NULL);
+ sub = dmxConfigAddSub(sub, dmxConfigSubDisplay(display));
+ if (!--dcount) {
+ state = ignoreCount;
+ virtual->subentry = sub;
+ entry = dmxConfigAddEntry(entry,
+ dmxConfigVirtual,
+ NULL,
+ virtual);
+ virtual = NULL;
+ sub = NULL;
+ }
+ break;
+ case ignoreCount:
+ icount = dmxVDLCount(buf);
+ state = ignoreEntry;
+ break;
+ case ignoreEntry:
+ if (!--icount) state = virtualEntry;
+ break;
+ }
+ }
+ return entry;
+}
diff --git a/xc/programs/Xserver/hw/dmx/config/dmxcompat.h b/xc/programs/Xserver/hw/dmx/config/dmxcompat.h
new file mode 100644
index 000000000..1a2ae790a
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/dmxcompat.h
@@ -0,0 +1,39 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef _DMXCOMPAT_H_
+#define _DMXCOMPAT_H_
+
+extern DMXConfigEntryPtr dmxVDLRead(const char *filename);
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/config/dmxconfig.c b/xc/programs/Xserver/hw/dmx/config/dmxconfig.c
new file mode 100644
index 000000000..a9cbe99e4
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/dmxconfig.c
@@ -0,0 +1,348 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#include "dmx.h"
+#include "dmxinput.h"
+#include "dmxconfig.h"
+#include "dmxparse.h"
+#include "dmxlog.h"
+#include "dmxcb.h"
+#include "parser.h"
+
+typedef struct DMXConfigListStruct {
+ const char *name;
+ struct DMXConfigListStruct *next;
+} DMXConfigList, *DMXConfigListPtr;
+
+typedef struct DMXConfigCmdStruct {
+ const char *filename;
+ const char *config;
+ DMXConfigList *displays;
+ DMXConfigList *inputs;
+} DMXConfigCmd, *DMXConfigCmdPtr;
+
+DMXConfigEntryPtr dmxConfigEntry;
+static DMXConfigCmd dmxConfigCmd;
+
+void dmxConfigStoreDisplay(const char *display)
+{
+ DMXConfigListPtr entry = malloc(sizeof(*entry));
+ entry->name = strdup(display);
+ entry->next = NULL;
+ if (!dmxConfigCmd.displays) dmxConfigCmd.displays = entry;
+ else {
+ DMXConfigList *pt;
+ for (pt = dmxConfigCmd.displays; pt->next; pt = pt->next);
+ if (!pt)
+ dmxLog(dmxFatal, "dmxConfigStoreDisplay: end of list non-NULL\n");
+ pt->next = entry;
+ }
+}
+
+void dmxConfigStoreInput(const char *input)
+{
+ DMXConfigListPtr entry = malloc(sizeof(*entry));
+ entry->name = strdup(input);
+ entry->next = NULL;
+ if (!dmxConfigCmd.inputs) dmxConfigCmd.inputs = entry;
+ else {
+ DMXConfigList *pt;
+ for (pt = dmxConfigCmd.inputs; pt->next; pt = pt->next);
+ if (!pt)
+ dmxLog(dmxFatal, "dmxConfigStoreInput: end of list non-NULL\n");
+ pt->next = entry;
+ }
+}
+
+void dmxConfigStoreFile(const char *file)
+{
+ if (dmxConfigCmd.filename)
+ dmxLog(dmxFatal, "Only one -configfile allowed\n");
+ dmxConfigCmd.filename = strdup(file);
+}
+
+void dmxConfigStoreConfig(const char *config)
+{
+ if (dmxConfigCmd.config) dmxLog(dmxFatal, "Only one -config allowed\n");
+ dmxConfigCmd.config = strdup(config);
+}
+
+static int dmxConfigReadFile(const char *filename, int debug)
+{
+ FILE *str;
+
+ if (!(str = fopen(filename, "r"))) return -1;
+ dmxLog(dmxInfo, "Reading configuration file \"%s\"\n", filename);
+ yyin = str;
+ yydebug = debug;
+ yyparse();
+ fclose(str);
+ return 0;
+}
+
+static const char *dmxConfigMatch(const char *target, DMXConfigEntryPtr entry)
+{
+ DMXConfigVirtualPtr v = entry->virtual;
+ const char *name = NULL;
+
+ if (v && v->name) name = v->name;
+
+ if (v && !dmxConfigCmd.config) return v->name ? v->name : "<noname>";
+ if (!name) return NULL;
+ if (!strcmp(name, target)) return name;
+ return NULL;
+}
+
+static DMXScreenInfo *dmxConfigAddDisplay(const char *name,
+ int width, int height,
+ int xoff, int yoff,
+ int xsign, int ysign)
+{
+ DMXScreenInfo *dmxScreen;
+
+ if (!(dmxScreens = realloc(dmxScreens,
+ (dmxNumScreens+1) * sizeof(*dmxScreens))))
+ dmxLog(dmxFatal,
+ "dmxConfigAddDisplay: realloc failed for screen %d (%s)\n",
+ dmxNumScreens, name);
+
+ dmxScreen = &dmxScreens[dmxNumScreens];
+ memset(dmxScreen, 0, sizeof(*dmxScreen));
+ dmxScreen->name = name;
+ dmxScreen->index = dmxNumScreens;
+ dmxScreen->width = width;
+ dmxScreen->height = height;
+ dmxScreen->xoff = xoff;
+ dmxScreen->yoff = yoff;
+ dmxScreen->xsign = xsign;
+ dmxScreen->ysign = ysign;
+ ++dmxNumScreens;
+ return dmxScreen;
+}
+
+static DMXInputInfo *dmxConfigAddInput(const char *name)
+{
+ DMXInputInfo *dmxInput;
+
+ if (!(dmxInputs = realloc(dmxInputs,
+ (dmxNumInputs+1) * sizeof(*dmxInputs))))
+ dmxLog(dmxFatal,
+ "dmxConfigAddInput: realloc failed for input %d (%s)\n",
+ dmxNumInputs, name);
+
+ dmxInput = &dmxInputs[dmxNumInputs];
+ memset(dmxInput, 0, sizeof(*dmxInput));
+ dmxInput->name = name;
+ dmxInput->index = dmxNumInputs;
+ ++dmxNumInputs;
+ return dmxInput;
+}
+
+static void dmxConfigCopyFromDisplay(DMXConfigDisplayPtr d)
+{
+ DMXScreenInfo *dmxScreen;
+
+ dmxScreen = dmxConfigAddDisplay(d->name, d->width, d->height,
+ d->xoff, d->yoff,
+ d->xsign, d->ysign);
+ dmxScreen->where = PosAbsolute;
+ dmxScreen->whereX = d->xorig;
+ dmxScreen->whereY = d->yorig;
+}
+
+static void dmxConfigCopyFromWall(DMXConfigWallPtr w)
+{
+ DMXConfigStringPtr pt;
+ DMXScreenInfo *dmxScreen;
+ int edge = dmxNumScreens;
+ int last = dmxNumScreens;
+
+ if (!w->xwall && !w->ywall) { /* Try to make it square */
+ int count;
+ for (pt = w->nameList, count = 0; pt; pt = pt->next) ++count;
+ w->xwall = sqrt(count) + .5;
+ }
+
+ for (pt = w->nameList; pt; pt = pt->next) {
+ dmxScreen = dmxConfigAddDisplay(pt->string, w->width, w->height,
+ 0, 0, 0, 0);
+ if (pt == w->nameList) { /* Upper left */
+ dmxScreen->where = PosAbsolute;
+ dmxScreen->whereX = 0;
+ dmxScreen->whereY = 0;
+ } else if (w->xwall) { /* Tile left to right, then top to bottom */
+ if (!((dmxNumScreens-1) % w->xwall)) {
+ dmxScreen->where = PosBelow;
+ dmxScreen->whereRefScreen = edge;
+ edge = dmxNumScreens-1;
+ } else {
+ dmxScreen->where = PosRightOf;
+ dmxScreen->whereRefScreen = last;
+ }
+ } else { /* Tile top to bottom, then left to right */
+ if (!((dmxNumScreens-1) % w->ywall)) {
+ dmxScreen->where = PosRightOf;
+ dmxScreen->whereRefScreen = edge;
+ edge = dmxNumScreens-1;
+ } else {
+ dmxScreen->where = PosBelow;
+ dmxScreen->whereRefScreen = last;
+ }
+
+ }
+ last = dmxNumScreens-1;
+ if (dmxScreen->where == PosAbsolute)
+ dmxLog(dmxInfo, "Added %s at %d %d\n",
+ pt->string, dmxScreen->whereX, dmxScreen->whereY);
+ else
+ dmxLog(dmxInfo, "Added %s %s %s\n",
+ pt->string,
+ dmxScreen->where == PosBelow ? "below" : "right of",
+ dmxScreens[dmxScreen->whereRefScreen].name);
+ }
+}
+
+static void dmxConfigCopyFromOption(DMXConfigOptionPtr o)
+{
+ DMXConfigStringPtr pt;
+ int argc = 0;
+ char **argv = NULL;
+
+ if (serverGeneration != 1) return; /* FIXME: only do once, for now */
+ if (!o || !o->string) return;
+ for (pt = o->option; pt; pt = pt->next) {
+ if (pt->string) {
+ ++argc;
+ argv = realloc(argv, (argc+1) * sizeof(*argv));
+ argv[argc] = (char *)pt->string;
+ }
+ }
+ argv[0] = NULL;
+ ProcessCommandLine(argc+1, argv);
+ free(argv);
+}
+
+static void dmxConfigCopyData(DMXConfigVirtualPtr v)
+{
+ DMXConfigSubPtr sub;
+
+ if (v->dim) dmxSetWidthHeight(v->dim->x, v->dim->y);
+ else dmxSetWidthHeight(0, 0);
+ for (sub = v->subentry; sub; sub = sub->next) {
+ switch (sub->type) {
+ case dmxConfigDisplay: dmxConfigCopyFromDisplay(sub->display); break;
+ case dmxConfigWall: dmxConfigCopyFromWall(sub->wall); break;
+ case dmxConfigOption: dmxConfigCopyFromOption(sub->option); break;
+ default:
+ dmxLog(dmxFatal,
+ "dmxConfigCopyData: not a display, wall, or value\n");
+ }
+ }
+}
+
+static void dmxConfigFromCommandLine(void)
+{
+ DMXConfigListPtr pt;
+
+ dmxLog(dmxInfo, "Using configuration from command line\n");
+ for (pt = dmxConfigCmd.displays; pt; pt = pt->next) {
+ DMXScreenInfo *dmxScreen = dmxConfigAddDisplay(pt->name, 0, 0,
+ 0, 0, 0, 0);
+ if (dmxNumScreens == 1) {
+ dmxScreen->where = PosAbsolute;
+ dmxScreen->whereX = 0;
+ dmxScreen->whereY = 0;
+ } else {
+ dmxScreen->where = PosRightOf;
+ dmxScreen->whereRefScreen = 0;
+ }
+ }
+}
+
+static void dmxConfigFromConfigFile(void)
+{
+ DMXConfigEntryPtr pt;
+ const char *name;
+
+ for (pt = dmxConfigEntry; pt; pt = pt->next) {
+ /* FIXME -- if an input is specified, use it */
+ if (pt->type != dmxConfigVirtual) continue;
+ if ((name = dmxConfigMatch(dmxConfigCmd.config, pt))) {
+ dmxLog(dmxInfo, "Using configuration \"%s\"\n", name);
+ dmxConfigCopyData(pt->virtual);
+ return;
+ }
+ }
+ dmxLog(dmxFatal, "Could not find configuration \"%s\" in \"%s\"\n",
+ dmxConfigCmd.config, dmxConfigCmd.filename);
+}
+
+static void dmxConfigConfigInputs(void)
+{
+ DMXConfigListPtr pt;
+
+ if (dmxNumInputs) return;
+
+ if (dmxConfigCmd.inputs) { /* Use command line */
+ for (pt = dmxConfigCmd.inputs; pt; pt = pt->next)
+ dmxConfigAddInput(pt->name);
+ } else if (dmxNumScreens) { /* Use first display */
+ dmxConfigAddInput(dmxScreens[0].name);
+ } else { /* Use dummy */
+ dmxConfigAddInput("dummy");
+ }
+}
+
+void dmxConfigConfigure(void)
+{
+ if (dmxConfigEntry) {
+ dmxConfigFreeEntry(dmxConfigEntry);
+ dmxConfigEntry = NULL;
+ }
+ if (dmxConfigCmd.filename) {
+ if (dmxConfigCmd.displays)
+ dmxLog(dmxWarning,
+ "Using configuraiton file \"%s\" instead of command line\n",
+ dmxConfigCmd.filename);
+ dmxConfigReadFile(dmxConfigCmd.filename, 0);
+ dmxConfigFromConfigFile();
+ } else {
+ if (dmxConfigCmd.config)
+ dmxLog(dmxWarning,
+ "Configuration name (%s) without configuration file\n",
+ dmxConfigCmd.config);
+ dmxConfigFromCommandLine();
+ }
+ dmxConfigConfigInputs();
+}
diff --git a/xc/programs/Xserver/hw/dmx/config/dmxconfig.h b/xc/programs/Xserver/hw/dmx/config/dmxconfig.h
new file mode 100644
index 000000000..98e633b7a
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/dmxconfig.h
@@ -0,0 +1,42 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef _DMXCONFIG_H_
+#define _DMXCONFIG_H_
+extern void dmxConfigStoreDisplay(const char *display);
+extern void dmxConfigStoreInput(const char *input);
+extern void dmxConfigStoreFile(const char *file);
+extern void dmxConfigStoreConfig(const char *config);
+extern void dmxConfigConfigure(void);
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/config/dmxparse.c b/xc/programs/Xserver/hw/dmx/config/dmxparse.c
new file mode 100644
index 000000000..78cfab67d
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/dmxparse.c
@@ -0,0 +1,464 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include "dmxparse.h"
+#include "dmxlog.h"
+
+void dmxConfigLog(const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+}
+
+void *dmxConfigAlloc(unsigned long bytes)
+{
+ void *area = malloc(bytes);
+ if (!area) {
+ dmxConfigLog("dmxConfigAlloc: out of memory\n");
+ return NULL;
+ }
+ memset(area, 0, bytes);
+ return area;
+}
+
+void *dmxConfigRealloc(void *orig, unsigned long orig_bytes,
+ unsigned long bytes)
+{
+ unsigned char *area = realloc(orig, bytes);
+ if (!area) {
+ dmxConfigLog("dmxConfigRealloc: out of memory\n");
+ return NULL;
+ }
+ memset(area + orig_bytes, 0, bytes - orig_bytes);
+ return area;
+}
+
+const char *dmxConfigCopyString(const char *string, int length)
+{
+ char *copy;
+
+ if (!length) length = strlen(string);
+ copy = dmxConfigAlloc(length + 1);
+ if (length) strncpy(copy, string, length);
+ copy[length] = '\0';
+ return copy;
+}
+
+void dmxConfigFree(void *area)
+{
+ if (area) free(area);
+}
+
+DMXConfigTokenPtr dmxConfigCreateToken(int token, int line,
+ const char *comment)
+{
+ DMXConfigTokenPtr pToken = dmxConfigAlloc(sizeof(*pToken));
+ pToken->token = token;
+ pToken->line = line;
+ pToken->comment = comment;
+ return pToken;
+}
+
+void dmxConfigFreeToken(DMXConfigTokenPtr p)
+{
+ if (!p) return;
+ dmxConfigFree((void *)p->comment);
+ dmxConfigFree(p);
+}
+
+DMXConfigStringPtr dmxConfigCreateString(int token, int line,
+ const char *comment,
+ const char *string)
+{
+ DMXConfigStringPtr pString = dmxConfigAlloc(sizeof(*pString));
+
+ pString->token = token;
+ pString->line = line;
+ pString->comment = comment;
+ pString->string = string;
+ return pString;
+}
+
+void dmxConfigFreeString(DMXConfigStringPtr p)
+{
+ DMXConfigStringPtr next;
+
+ if (!p) return;
+ do {
+ next = p->next;
+ dmxConfigFree((void *)p->comment);
+ dmxConfigFree((void *)p->string);
+ dmxConfigFree(p);
+ } while ((p = next));
+}
+
+DMXConfigNumberPtr dmxConfigCreateNumber(int token, int line,
+ const char *comment,
+ int number)
+{
+ DMXConfigNumberPtr pNumber = dmxConfigAlloc(sizeof(*pNumber));
+
+ pNumber->token = token;
+ pNumber->line = line;
+ pNumber->comment = comment;
+ pNumber->number = number;
+ return pNumber;
+}
+
+void dmxConfigFreeNumber(DMXConfigNumberPtr p)
+{
+ if (!p) return;
+ dmxConfigFree((void *)p->comment);
+ dmxConfigFree(p);
+}
+
+DMXConfigPairPtr dmxConfigCreatePair(int token, int line,
+ const char *comment,
+ int x, int y,
+ int xsign, int ysign)
+{
+ DMXConfigPairPtr pPair = dmxConfigAlloc(sizeof(*pPair));
+
+ pPair->token = token;
+ pPair->line = line;
+ pPair->comment = comment;
+ pPair->x = x;
+ pPair->y = y;
+ pPair->xsign = (xsign < 0) ? -1 : 1;
+ pPair->ysign = (ysign < 0) ? -1 : 1;
+ return pPair;
+}
+
+void dmxConfigFreePair(DMXConfigPairPtr p)
+{
+ if (!p) return;
+ dmxConfigFree((void *)p->comment);
+ dmxConfigFree(p);
+}
+
+DMXConfigCommentPtr dmxConfigCreateComment(int token, int line,
+ const char *comment)
+{
+ DMXConfigCommentPtr pComment = dmxConfigAlloc(sizeof(*pComment));
+
+ pComment->token = token;
+ pComment->line = line;
+ pComment->comment = comment;
+ return pComment;
+}
+
+void dmxConfigFreeComment(DMXConfigCommentPtr p)
+{
+ if (!p) return;
+ dmxConfigFree((void *)p->comment);
+ dmxConfigFree(p);
+}
+
+DMXConfigDisplayPtr dmxConfigCreateDisplay(DMXConfigTokenPtr pStart,
+ DMXConfigStringPtr pName,
+ DMXConfigPairPtr pDim,
+ DMXConfigPairPtr pOffset,
+ DMXConfigPairPtr pOrigin,
+ DMXConfigTokenPtr pEnd)
+{
+ DMXConfigDisplayPtr pDisplay = dmxConfigAlloc(sizeof(*pDisplay));
+
+ pDisplay->start = pStart;
+ pDisplay->dname = pName;
+ pDisplay->dim = pDim;
+ pDisplay->offset = pOffset;
+ pDisplay->origin = pOrigin;
+ pDisplay->end = pEnd;
+
+ pDisplay->name = pName ? pName->string : NULL;
+ pDisplay->width = pDim ? pDim->x : 0;
+ pDisplay->height = pDim ? pDim->y : 0;
+ pDisplay->xoff = pOffset ? pOffset->x : 0;
+ pDisplay->yoff = pOffset ? pOffset->y : 0;
+ pDisplay->xsign = pOffset ? pOffset->xsign : 0;
+ pDisplay->ysign = pOffset ? pOffset->ysign : 0;
+ pDisplay->xorig = pOrigin ? pOrigin->x : 0;
+ pDisplay->yorig = pOrigin ? pOrigin->y : 0;
+
+ return pDisplay;
+}
+
+void dmxConfigFreeDisplay(DMXConfigDisplayPtr p)
+{
+ if (!p) return;
+ dmxConfigFreeToken(p->start);
+ dmxConfigFreeString(p->dname);
+ dmxConfigFreePair(p->dim);
+ dmxConfigFreePair(p->offset);
+ dmxConfigFreeToken(p->end);
+ dmxConfigFree(p);
+}
+
+DMXConfigWallPtr dmxConfigCreateWall(DMXConfigTokenPtr pStart,
+ DMXConfigPairPtr pWallDim,
+ DMXConfigPairPtr pDisplayDim,
+ DMXConfigStringPtr pNameList,
+ DMXConfigTokenPtr pEnd)
+{
+ DMXConfigWallPtr pWall = dmxConfigAlloc(sizeof(*pWall));
+
+ pWall->start = pStart;
+ pWall->wallDim = pWallDim;
+ pWall->displayDim = pDisplayDim;
+ pWall->nameList = pNameList;
+ pWall->end = pEnd;
+
+ pWall->width = pDisplayDim ? pDisplayDim->x : 0;
+ pWall->height = pDisplayDim ? pDisplayDim->y : 0;
+ pWall->xwall = pWallDim ? pWallDim->x : 0;
+ pWall->ywall = pWallDim ? pWallDim->y : 0;
+
+ return pWall;
+}
+
+void dmxConfigFreeWall(DMXConfigWallPtr p)
+{
+ if (!p) return;
+ dmxConfigFreeToken(p->start);
+ dmxConfigFreePair(p->wallDim);
+ dmxConfigFreePair(p->displayDim);
+ dmxConfigFreeString(p->nameList);
+ dmxConfigFreeToken(p->end);
+ dmxConfigFree(p);
+}
+
+DMXConfigOptionPtr dmxConfigCreateOption(DMXConfigTokenPtr pStart,
+ DMXConfigStringPtr pOption,
+ DMXConfigTokenPtr pEnd)
+{
+ int length = 0;
+ int offset = 0;
+ DMXConfigStringPtr p;
+ DMXConfigOptionPtr option = dmxConfigAlloc(sizeof(*option));
+
+ for (p = option->option; p; p = p->next) {
+ if (p->string) length += strlen(p->string + 1);
+ }
+
+ option->string = dmxConfigAlloc(length + 1);
+
+ for (p = option->option; p; p = p->next) {
+ if (p->string) {
+ strcpy(option->string + offset, p->string);
+ offset = strlen(option->string);
+ option->string[offset++] = ' ';
+ }
+ }
+ option->string[offset] = '\0';
+
+ option->start = pStart;
+ option->option = pOption;
+ option->end = pEnd;
+
+ return option;
+}
+
+void dmxConfigFreeOption(DMXConfigOptionPtr p)
+{
+ if (!p) return;
+ if (p->string) free(p->string);
+ dmxConfigFreeToken(p->start);
+ dmxConfigFreeString(p->option);
+ dmxConfigFreeToken(p->end);
+ dmxConfigFree(p);
+}
+
+DMXConfigSubPtr dmxConfigCreateSub(DMXConfigType type,
+ DMXConfigCommentPtr comment,
+ DMXConfigDisplayPtr display,
+ DMXConfigWallPtr wall,
+ DMXConfigOptionPtr option)
+{
+ DMXConfigSubPtr pSub = dmxConfigAlloc(sizeof(*pSub));
+ pSub->type = type;
+ switch (type) {
+ case dmxConfigComment: pSub->comment = comment; break;
+ case dmxConfigDisplay: pSub->display = display; break;
+ case dmxConfigWall: pSub->wall = wall; break;
+ case dmxConfigOption: pSub->option = option; break;
+ default: dmxConfigLog("Type %d not supported in subentry\n", type); break;
+ }
+ return pSub;
+}
+
+void dmxConfigFreeSub(DMXConfigSubPtr sub)
+{
+ DMXConfigSubPtr pt;
+
+ for (pt = sub; pt; pt = pt->next) {
+ switch (pt->type) {
+ case dmxConfigComment: dmxConfigFreeComment(pt->comment); break;
+ case dmxConfigDisplay: dmxConfigFreeDisplay(pt->display); break;
+ case dmxConfigWall: dmxConfigFreeWall(pt->wall); break;
+ case dmxConfigOption: dmxConfigFreeOption(pt->option); break;
+ default:
+ dmxConfigLog("Type %d not supported in subentry\n", pt->type);
+ break;
+ }
+ }
+ dmxConfigFree(sub);
+}
+
+DMXConfigSubPtr dmxConfigSubComment(DMXConfigCommentPtr comment)
+{
+ return dmxConfigCreateSub(dmxConfigComment, comment, NULL, NULL, NULL);
+}
+
+DMXConfigSubPtr dmxConfigSubDisplay(DMXConfigDisplayPtr display)
+{
+ return dmxConfigCreateSub(dmxConfigDisplay, NULL, display, NULL, NULL);
+}
+
+DMXConfigSubPtr dmxConfigSubWall(DMXConfigWallPtr wall)
+{
+ return dmxConfigCreateSub(dmxConfigWall, NULL, NULL, wall, NULL);
+}
+
+DMXConfigSubPtr dmxConfigSubOption(DMXConfigOptionPtr option)
+{
+ return dmxConfigCreateSub(dmxConfigOption, NULL, NULL, NULL, option);
+}
+
+extern DMXConfigSubPtr dmxConfigAddSub(DMXConfigSubPtr head,
+ DMXConfigSubPtr sub)
+{
+ DMXConfigSubPtr pt;
+
+ if (!head) return sub;
+ for (pt = head; pt->next; pt = pt->next);
+ pt->next = sub;
+ return head;
+}
+
+DMXConfigVirtualPtr dmxConfigCreateVirtual(DMXConfigTokenPtr pStart,
+ DMXConfigStringPtr pName,
+ DMXConfigPairPtr pDim,
+ DMXConfigTokenPtr pOpen,
+ DMXConfigSubPtr pSubentry,
+ DMXConfigTokenPtr pClose)
+{
+ DMXConfigVirtualPtr pVirtual = dmxConfigAlloc(sizeof(*pVirtual));
+
+ pVirtual->start = pStart;
+ pVirtual->vname = pName;
+ pVirtual->dim = pDim;
+ pVirtual->open = pOpen;
+ pVirtual->subentry = pSubentry;
+ pVirtual->close = pClose;
+
+ pVirtual->name = pName ? pName->string : NULL;
+ pVirtual->width = pDim ? pDim->x : 0;
+ pVirtual->height = pDim ? pDim->y : 0;
+
+ return pVirtual;
+}
+
+void dmxConfigFreeVirtual(DMXConfigVirtualPtr virtual)
+{
+ dmxConfigFreeToken(virtual->start);
+ dmxConfigFreeString(virtual->vname);
+ dmxConfigFreePair(virtual->dim);
+ dmxConfigFreeToken(virtual->open);
+ dmxConfigFreeSub(virtual->subentry);
+ dmxConfigFreeToken(virtual->close);
+ dmxConfigFree(virtual);
+}
+
+DMXConfigEntryPtr dmxConfigCreateEntry(DMXConfigType type,
+ DMXConfigCommentPtr comment,
+ DMXConfigVirtualPtr virtual)
+{
+ DMXConfigEntryPtr pEntry = dmxConfigAlloc(sizeof(*pEntry));
+ pEntry->type = type;
+ switch (type) {
+ case dmxConfigComment: pEntry->comment = comment; break;
+ case dmxConfigVirtual: pEntry->virtual = virtual; break;
+ default: dmxConfigLog("Type %d not supported in entry\n", type); break;
+ }
+ return pEntry;
+}
+
+void dmxConfigFreeEntry(DMXConfigEntryPtr entry)
+{
+ DMXConfigEntryPtr pt;
+
+ for (pt = entry; pt; pt = pt->next) {
+ switch (pt->type) {
+ case dmxConfigComment: dmxConfigFreeComment(pt->comment); break;
+ case dmxConfigVirtual: dmxConfigFreeVirtual(pt->virtual); break;
+ default:
+ dmxConfigLog("Type %d not supported in entry\n", pt->type);
+ break;
+ }
+ }
+ dmxConfigFree(entry);
+}
+
+DMXConfigEntryPtr dmxConfigAddEntry(DMXConfigEntryPtr head,
+ DMXConfigType type,
+ DMXConfigCommentPtr comment,
+ DMXConfigVirtualPtr virtual)
+{
+ DMXConfigEntryPtr child = dmxConfigCreateEntry(type, comment, virtual);
+ DMXConfigEntryPtr pt;
+
+ if (!head) return child;
+
+ for (pt = head; pt->next; pt = pt->next);
+ pt->next = child;
+
+ return head;
+}
+
+DMXConfigEntryPtr dmxConfigEntryComment(DMXConfigCommentPtr comment)
+{
+ return dmxConfigCreateEntry(dmxConfigComment, comment, NULL);
+}
+
+DMXConfigEntryPtr dmxConfigEntryVirtual(DMXConfigVirtualPtr virtual)
+{
+ return dmxConfigCreateEntry(dmxConfigVirtual, NULL, virtual);
+}
diff --git a/xc/programs/Xserver/hw/dmx/config/dmxparse.h b/xc/programs/Xserver/hw/dmx/config/dmxparse.h
new file mode 100644
index 000000000..5b359c542
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/dmxparse.h
@@ -0,0 +1,241 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef _DMXPARSE_H_
+#define _DMXPARSE_H_
+
+#include <stdio.h> /* For FILE */
+
+typedef struct _DMXConfigToken {
+ int token;
+ int line;
+ const char *comment;
+} DMXConfigToken, *DMXConfigTokenPtr;
+
+typedef struct _DMXConfigString {
+ int token;
+ int line;
+ const char *comment;
+ const char *string;
+ struct _DMXConfigString *next;
+} DMXConfigString, *DMXConfigStringPtr;
+
+typedef struct _DMXConfigNumber {
+ int token;
+ int line;
+ const char *comment;
+ int number;
+} DMXConfigNumber, *DMXConfigNumberPtr;
+
+typedef struct _DMXConfigPair {
+ int token;
+ int line;
+ const char *comment;
+ int x;
+ int y;
+ int xsign;
+ int ysign;
+} DMXConfigPair, *DMXConfigPairPtr;
+
+typedef struct _DMXConfigComment {
+ int token;
+ int line;
+ const char *comment;
+} DMXConfigComment, *DMXConfigCommentPtr;
+
+typedef enum {
+ dmxConfigComment,
+ dmxConfigVirtual,
+ dmxConfigDisplay,
+ dmxConfigWall,
+ dmxConfigOption
+} DMXConfigType;
+
+typedef struct _DMXConfigDisplay {
+ /* Summary information */
+ const char *name;
+ /* Geometry */
+ int width, height;
+ int xoff, yoff;
+ int xsign, ysign;
+ /* Origin in global space */
+ int xorig, yorig;
+
+ /* Raw configuration information */
+ DMXConfigTokenPtr start;
+ DMXConfigStringPtr dname;
+ DMXConfigPairPtr dim;
+ DMXConfigPairPtr offset;
+ DMXConfigPairPtr origin;
+ DMXConfigTokenPtr end;
+} DMXConfigDisplay, *DMXConfigDisplayPtr;
+
+typedef struct _DMXConfigWall {
+ /* Summary information */
+ int width, height; /* dimensions of displays */
+ int xwall, ywall; /* dimensions of wall, in tiles */
+
+
+ /* Raw configuration informaiton */
+ DMXConfigTokenPtr start;
+ DMXConfigPairPtr wallDim;
+ DMXConfigPairPtr displayDim;
+ DMXConfigStringPtr nameList;
+ DMXConfigTokenPtr end;
+} DMXConfigWall, *DMXConfigWallPtr;
+
+typedef struct _DMXConfigOption {
+ /* Summary information */
+ char *string;
+
+ /* Raw configuration informaiton */
+ DMXConfigTokenPtr start;
+ DMXConfigStringPtr option;
+ DMXConfigTokenPtr end;
+} DMXConfigOption, *DMXConfigOptionPtr;
+
+typedef struct _DMXConfigSub {
+ DMXConfigType type;
+ DMXConfigCommentPtr comment;
+ DMXConfigDisplayPtr display;
+ DMXConfigWallPtr wall;
+ DMXConfigOptionPtr option;
+ struct _DMXConfigSub *next;
+} DMXConfigSub, *DMXConfigSubPtr;
+
+typedef struct _DMXConfigVirtual {
+ /* Summary information */
+ const char *name;
+ int width, height;
+
+ /* Raw configuration information */
+ DMXConfigTokenPtr start;
+ DMXConfigStringPtr vname;
+ DMXConfigPairPtr dim;
+ DMXConfigTokenPtr open;
+ DMXConfigSubPtr subentry;
+ DMXConfigTokenPtr close;
+} DMXConfigVirtual, *DMXConfigVirtualPtr;
+
+typedef struct _DMXConfigEntry {
+ DMXConfigType type;
+ DMXConfigCommentPtr comment;
+ DMXConfigVirtualPtr virtual;
+ struct _DMXConfigEntry *next;
+} DMXConfigEntry, *DMXConfigEntryPtr;
+
+extern DMXConfigEntryPtr dmxConfigEntry;
+
+extern int yylex(void);
+extern int yydebug;
+extern void yyerror(const char *message);
+extern int yylex(void);
+extern int yyparse(void);
+extern FILE *yyin;
+
+extern void dmxConfigLog(const char *format, ...);
+extern void *dmxConfigAlloc(unsigned long bytes);
+extern void *dmxConfigRealloc(void *orig,
+ unsigned long orig_bytes,
+ unsigned long bytes);
+extern const char *dmxConfigCopyString(const char *string,
+ int length);
+extern void dmxConfigFree(void *area);
+extern DMXConfigTokenPtr dmxConfigCreateToken(int token, int line,
+ const char *comment);
+extern void dmxConfigFreeToken(DMXConfigTokenPtr p);
+extern DMXConfigStringPtr dmxConfigCreateString(int token, int line,
+ const char *comment,
+ const char *string);
+extern void dmxConfigFreeString(DMXConfigStringPtr p);
+extern DMXConfigNumberPtr dmxConfigCreateNumber(int token, int line,
+ const char *comment,
+ int number);
+extern void dmxConfigFreeNumber(DMXConfigNumberPtr p);
+extern DMXConfigPairPtr dmxConfigCreatePair(int token, int line,
+ const char *comment,
+ int x, int y,
+ int xsign, int ysign);
+extern void dmxConfigFreePair(DMXConfigPairPtr p);
+extern DMXConfigCommentPtr dmxConfigCreateComment(int token, int line,
+ const char *comment);
+extern void dmxConfigFreeComment(DMXConfigCommentPtr p);
+extern DMXConfigDisplayPtr dmxConfigCreateDisplay(DMXConfigTokenPtr pStart,
+ DMXConfigStringPtr pName,
+ DMXConfigPairPtr pDim,
+ DMXConfigPairPtr pOffset,
+ DMXConfigPairPtr pOrigin,
+ DMXConfigTokenPtr pEnd);
+extern void dmxConfigFreeDisplay(DMXConfigDisplayPtr p);
+extern DMXConfigWallPtr dmxConfigCreateWall(DMXConfigTokenPtr pStart,
+ DMXConfigPairPtr pWallDim,
+ DMXConfigPairPtr pDisplayDim,
+ DMXConfigStringPtr pNameList,
+ DMXConfigTokenPtr pEnd);
+extern void dmxConfigFreeWall(DMXConfigWallPtr p);
+extern DMXConfigOptionPtr dmxConfigCreateOption(DMXConfigTokenPtr pStart,
+ DMXConfigStringPtr pOption,
+ DMXConfigTokenPtr pEnd);
+extern void dmxConfigFreeOption(DMXConfigOptionPtr p);
+extern DMXConfigSubPtr dmxConfigCreateSub(DMXConfigType type,
+ DMXConfigCommentPtr comment,
+ DMXConfigDisplayPtr display,
+ DMXConfigWallPtr wall,
+ DMXConfigOptionPtr option);
+extern void dmxConfigFreeSub(DMXConfigSubPtr sub);
+extern DMXConfigSubPtr dmxConfigSubComment(DMXConfigCommentPtr comment);
+extern DMXConfigSubPtr dmxConfigSubDisplay(DMXConfigDisplayPtr display);
+extern DMXConfigSubPtr dmxConfigSubWall(DMXConfigWallPtr wall);
+extern DMXConfigSubPtr dmxConfigSubOption(DMXConfigOptionPtr option);
+extern DMXConfigSubPtr dmxConfigAddSub(DMXConfigSubPtr head,
+ DMXConfigSubPtr sub);
+extern DMXConfigVirtualPtr dmxConfigCreateVirtual(DMXConfigTokenPtr pStart,
+ DMXConfigStringPtr pName,
+ DMXConfigPairPtr pDim,
+ DMXConfigTokenPtr pOpen,
+ DMXConfigSubPtr pSubentry,
+ DMXConfigTokenPtr pClose);
+extern void dmxConfigFreeVirtual(DMXConfigVirtualPtr virtual);
+extern DMXConfigEntryPtr dmxConfigCreateEntry(DMXConfigType type,
+ DMXConfigCommentPtr comment,
+ DMXConfigVirtualPtr virtual);
+extern void dmxConfigFreeEntry(DMXConfigEntryPtr entry);
+extern DMXConfigEntryPtr dmxConfigAddEntry(DMXConfigEntryPtr head,
+ DMXConfigType type,
+ DMXConfigCommentPtr comment,
+ DMXConfigVirtualPtr virtual);
+extern DMXConfigEntryPtr dmxConfigEntryComment(DMXConfigCommentPtr comment);
+extern DMXConfigEntryPtr dmxConfigEntryVirtual(DMXConfigVirtualPtr virtual);
+
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/config/dmxprint.c b/xc/programs/Xserver/hw/dmx/config/dmxprint.c
new file mode 100644
index 000000000..f50162eb6
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/dmxprint.c
@@ -0,0 +1,345 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#include "dmxconfig.h"
+#include "dmxparse.h"
+#include "dmxprint.h"
+#include "parser.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+static FILE *str = NULL;
+static int indent = 0;
+static int pos = 0;
+
+static struct stack {
+ int base;
+ int comment;
+ int step;
+ struct stack *next;
+} *stack, initialStack = { 0, 0, 4, NULL };
+
+static void dmxConfigIndent(void)
+{
+ int i;
+ if (indent < 0) indent = 0;
+ if (indent > 40) indent = 40;
+ for (i = 0; i < indent; i++) fprintf(str, " ");
+}
+
+static void dmxConfigNewline(void)
+{
+ if (pos) fprintf(str, "\n");
+ pos = 0;
+}
+
+static void dmxConfigPushState(int base, int comment, int step)
+{
+ struct stack *new = dmxConfigAlloc(sizeof(*new));
+ new->base = base;
+ new->comment = comment;
+ new->step = step;
+ new->next = stack;
+ stack = new;
+ indent = base;
+ dmxConfigNewline();
+}
+
+static void dmxConfigPushComment(void)
+{
+ if (stack) indent = stack->comment;
+}
+
+static void dmxConfigPushStep(void)
+{
+ if (stack) indent = stack->step;
+}
+
+static void dmxConfigPopState(void)
+{
+ struct stack *old = stack;
+
+ if (!stack) return;
+ indent = old->base;
+ stack = old->next;
+ if (!stack) {
+ dmxConfigLog("Stack underflow\n");
+ return;
+ }
+ dmxConfigFree(old);
+ dmxConfigNewline();
+}
+
+static void dmxConfigOutput(int addSpace, int doNewline, const char *comment,
+ const char *format, ...)
+{
+ va_list args;
+
+ if (!pos) dmxConfigIndent();
+ else if (addSpace) fprintf(str, " ");
+
+ if (format) {
+ va_start(args, format);
+ pos += vfprintf(str, format, args); /* assumes no newlines! */
+ va_end(args);
+ }
+
+ if (comment) {
+ if (pos) fprintf(str, " ");
+ pos += fprintf(str, "#%s", comment);
+ dmxConfigNewline();
+ dmxConfigPushComment();
+ } else if (doNewline) dmxConfigNewline();
+}
+
+static void dmxConfigPrintComment(DMXConfigCommentPtr p)
+{
+ dmxConfigOutput(1, 1, p->comment, NULL);
+}
+
+static void dmxConfigPrintToken(DMXConfigTokenPtr p)
+{
+ if (!p) return;
+ switch (p->token) {
+ case T_VIRTUAL:
+ dmxConfigPushState(0, 4, 4);
+ dmxConfigOutput(0, 0, p->comment, "virtual");
+ break;
+ case T_DISPLAY:
+ dmxConfigPushState(4, 12, 16);
+ dmxConfigOutput(0, 0, p->comment, "display");
+ break;
+ case T_WALL:
+ dmxConfigPushState(4, 12, 16);
+ dmxConfigOutput(0, 0, p->comment, "wall");
+ break;
+ case T_OPTION:
+ dmxConfigPushState(4, 12, 16);
+ dmxConfigOutput(0, 0, p->comment, "option");
+ break;
+ case ';':
+ dmxConfigOutput(0, 1, p->comment, ";");
+ dmxConfigPopState();
+ break;
+ case '{':
+ dmxConfigOutput(1, 1, p->comment, "{");
+ dmxConfigPushStep();
+ break;
+ case '}':
+ dmxConfigPopState();
+ dmxConfigOutput(0, 1, p->comment, "}");
+ break;
+ default:
+ dmxConfigLog("unknown token %d on line %d\n", p->token, p->line);
+ }
+}
+
+static int dmxConfigPrintQuotedString(const char *s)
+{
+ const char *pt;
+
+ if (!s || !s[0]) return 1; /* Quote empty string */
+ for (pt = s; *pt; ++pt) if (isspace(*pt)) return 1;
+ return 0;
+}
+
+static void dmxConfigPrintString(DMXConfigStringPtr p)
+{
+ DMXConfigStringPtr pt;
+
+ if (!p) return;
+ for (pt = p; pt; pt = pt->next) {
+ if (dmxConfigPrintQuotedString(pt->string))
+ dmxConfigOutput(1, 0, p->comment, "\"%s\"",
+ pt->string ? pt->string : "");
+ else
+ dmxConfigOutput(1, 0, p->comment, "%s",
+ pt->string ? pt->string : "");
+ }
+}
+
+static int dmxConfigPrintPair(DMXConfigPairPtr p, int addSpace)
+{
+ const char *format = NULL;
+
+ if (!p) return 0;
+ switch (p->token) {
+ case T_ORIGIN: format = "@%dx%d"; break;
+ case T_DIMENSION: format = "%dx%d"; break;
+ case T_OFFSET: format = "%c%d%c%d"; break;
+ }
+ if (p->token == T_OFFSET) {
+ if (!p->comment && !p->x && !p->y && p->xsign >= 0 && p->ysign >= 0)
+ return 0;
+ dmxConfigOutput(addSpace, 0, p->comment, format,
+ p->xsign < 0 ? '-' : '+', p->x,
+ p->ysign < 0 ? '-' : '+', p->y);
+ } else {
+ if (!p->comment && !p->x && !p->y) return 0;
+ dmxConfigOutput(addSpace, 0, p->comment, format, p->x, p->y);
+ }
+ return 1;
+}
+
+static void dmxConfigPrintDisplay(DMXConfigDisplayPtr p)
+{
+ DMXConfigToken dummyStart = { T_DISPLAY, 0, NULL };
+ DMXConfigToken dummyEnd = { ';', 0, NULL };
+ DMXConfigString dummyName = { T_STRING, 0, NULL, NULL, NULL };
+ DMXConfigPair dummyDim = { T_DIMENSION, 0, NULL, 0, 0, 0, 0 };
+ DMXConfigPair dummyOffset = { T_OFFSET, 0, NULL, 0, 0, 0, 0 };
+ DMXConfigPair dummyOrigin = { T_ORIGIN, 0, NULL, 0, 0, 0, 0 };
+ int output;
+
+ if (p->dname) p->dname->string = p->name;
+ else dummyName.string = p->name;
+
+ if (p->dim) p->dim->x = p->width, p->dim->y = p->height;
+ else dummyDim.x = p->width, dummyDim.y = p->height;
+
+ if (p->offset) p->offset->x = p->xoff, p->offset->y = p->yoff;
+ else dummyOffset.x = p->xoff, dummyOffset.y = p->yoff;
+
+ if (p->origin) {
+ p->origin->x = p->xorig, p->origin->y = p->yorig;
+ p->origin->xsign = p->xsign, p->origin->ysign = p->ysign;
+ } else {
+ dummyOrigin.x = p->xorig, dummyOrigin.y = p->yorig;
+ dummyOrigin.xsign = p->xsign, dummyOrigin.ysign = p->ysign;
+ }
+
+ dmxConfigPrintToken(p->start ? p->start : &dummyStart);
+ dmxConfigPrintString(p->dname ? p->dname : &dummyName);
+ output = dmxConfigPrintPair(p->dim ? p->dim : &dummyDim, 1);
+ dmxConfigPrintPair(p->offset ? p->offset : &dummyOffset, !output);
+ dmxConfigPrintPair(p->origin ? p->origin : &dummyOrigin, 1);
+ dmxConfigPrintToken(p->end ? p->end : &dummyEnd);
+}
+
+static void dmxConfigPrintWall(DMXConfigWallPtr p)
+{
+ dmxConfigPrintToken(p->start);
+ dmxConfigPrintPair(p->wallDim, 1);
+ dmxConfigPrintPair(p->displayDim, 1);
+ dmxConfigPrintString(p->nameList);
+ dmxConfigPrintToken(p->end);
+}
+
+static void dmxConfigPrintOption(DMXConfigOptionPtr p)
+{
+ DMXConfigToken dummyStart = { T_OPTION, 0, NULL };
+ DMXConfigString dummyOption = { T_STRING, 0, NULL, NULL, NULL };
+ DMXConfigToken dummyEnd = { ';', 0, NULL };
+
+ if (p->option) p->option->string = p->string;
+ else dummyOption.string = p->string;
+
+ dmxConfigPrintToken(p->start ? p->start : &dummyStart);
+ dmxConfigPrintString(p->option ? p->option : &dummyOption);
+ dmxConfigPrintToken(p->end ? p->end : &dummyEnd);
+}
+
+static void dmxConfigPrintSub(DMXConfigSubPtr p)
+{
+ DMXConfigSubPtr pt;
+
+ if (!p) return;
+ for (pt = p; pt; pt = pt->next) {
+ switch (pt->type) {
+ case dmxConfigComment: dmxConfigPrintComment(pt->comment); break;
+ case dmxConfigDisplay: dmxConfigPrintDisplay(pt->display); break;
+ case dmxConfigWall: dmxConfigPrintWall(pt->wall); break;
+ case dmxConfigOption: dmxConfigPrintOption(pt->option); break;
+ default:
+ dmxConfigLog("dmxConfigPrintSub:"
+ " cannot handle type %d in subentry\n", pt->type);
+ }
+ }
+}
+
+static void dmxConfigPrintVirtual(DMXConfigVirtualPtr p)
+{
+ DMXConfigToken dummyStart = { T_VIRTUAL, 0, NULL };
+ DMXConfigToken dummyOpen = { '{', 0, NULL };
+ DMXConfigToken dummyClose = { '}', 0, NULL };
+ DMXConfigString dummyName = { T_STRING, 0, NULL, NULL, NULL };
+ DMXConfigPair dummyDim = { T_DIMENSION, 0, NULL, 0, 0 };
+
+ if (p->vname) p->vname->string = p->name;
+ else dummyName.string = p->name;
+
+ if (p->dim) p->dim->x = p->width, p->dim->y = p->height;
+ else dummyDim.x = p->width, dummyDim.y = p->height;
+
+
+ dmxConfigPrintToken(p->start ? p->start : &dummyStart);
+ dmxConfigPrintString(p->vname ? p->vname : &dummyName);
+ dmxConfigPrintPair(p->dim ? p->dim : &dummyDim, 1);
+ dmxConfigPrintToken(p->open ? p->open : &dummyOpen);
+ dmxConfigPrintSub(p->subentry);
+ dmxConfigPrintToken(p->close ? p->close : &dummyClose);
+}
+
+void dmxConfigPrint(FILE *stream, DMXConfigEntryPtr entry)
+{
+ DMXConfigEntryPtr pt;
+
+ if (!stream) str = stdout;
+ else str = stream;
+
+ stack = &initialStack;
+
+ for (pt = entry; pt; pt = pt->next) {
+ switch (pt->type) {
+ case dmxConfigComment: dmxConfigPrintComment(pt->comment); break;
+ case dmxConfigVirtual: dmxConfigPrintVirtual(pt->virtual); break;
+ default:
+ dmxConfigLog("dmxConfigPrint: cannot handle type %d in entry\n",
+ pt->type);
+ }
+ }
+ if (pos) dmxConfigNewline();
+}
+
+void dmxConfigVirtualPrint(FILE *stream, DMXConfigVirtualPtr p)
+{
+ if (!stream) str = stdout;
+ else str = stream;
+
+ stack = &initialStack;
+
+ dmxConfigPrintVirtual(p);
+ if (pos) dmxConfigNewline();
+}
diff --git a/xc/programs/Xserver/hw/dmx/config/dmxprint.h b/xc/programs/Xserver/hw/dmx/config/dmxprint.h
new file mode 100644
index 000000000..560b56ce5
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/dmxprint.h
@@ -0,0 +1,41 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef _DMXPRINT_H_
+#define _DMXPRINT_H_
+
+void dmxConfigPrint(FILE *str, DMXConfigEntryPtr entry);
+void dmxConfigVirtualPrint(FILE *str, DMXConfigVirtualPtr p);
+
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/config/dmxtodmx.c b/xc/programs/Xserver/hw/dmx/config/dmxtodmx.c
new file mode 100644
index 000000000..02a552dff
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/dmxtodmx.c
@@ -0,0 +1,47 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ * This is a simple filter for testing.
+ */
+
+#include "dmxconfig.h"
+#include "dmxparse.h"
+#include "dmxprint.h"
+#include "dmxcompat.h"
+
+int main(int argc, char **argv)
+{
+ yydebug = 0;
+ yyparse();
+ dmxConfigPrint(stdout, dmxConfigEntry);
+ return 0;
+}
diff --git a/xc/programs/Xserver/hw/dmx/config/dmxtodmx.man b/xc/programs/Xserver/hw/dmx/config/dmxtodmx.man
new file mode 100644
index 000000000..68c7f5b40
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/dmxtodmx.man
@@ -0,0 +1,41 @@
+.\" $XFree86$
+.\" Copyright 2002 Red Hat Inc., Durham, North Carolina.
+.\" 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 on 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
+.\" NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+.\" 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:
+.\" Rickard E. (Rik) Faith <faith@redhat.com>
+.\"
+.TH dmxtodmx 1 __vendorversion__
+.SH NAME
+dmxtodmx - dmx configuration file parser and printer
+.SH SYNOPSIS
+.B dmxtodmx
+.SH DESCRIPTION
+.I dmxtodmx
+reads the standard input, parsing a configuration file for the
+.I Xdmx
+distributed multi-head X server. After a successful parse, the file is
+pretty-printed to standard output.
+.SH "SEE ALSO"
+Xdmx(1), vdltodmx(1), xdmxconfig(1)
diff --git a/xc/programs/Xserver/hw/dmx/config/parser.y b/xc/programs/Xserver/hw/dmx/config/parser.y
new file mode 100644
index 000000000..e44dbb784
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/parser.y
@@ -0,0 +1,203 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+%{
+#include "dmxparse.h"
+#include <string.h>
+#include <stdlib.h>
+#define YYDEBUG 1
+#define YYERROR_VERBOSE
+DMXConfigEntryPtr dmxConfigEntry = NULL;
+#define APPEND(type, h, t) \
+{ \
+ type pt; \
+ for (pt = h; pt->next; pt = pt->next); \
+ pt->next = t; \
+}
+%}
+
+%union {
+ DMXConfigTokenPtr token;
+ DMXConfigStringPtr string;
+ DMXConfigNumberPtr number;
+ DMXConfigPairPtr pair;
+ DMXConfigDisplayPtr display;
+ DMXConfigWallPtr wall;
+ DMXConfigOptionPtr option;
+ DMXConfigCommentPtr comment;
+ DMXConfigSubPtr subentry;
+ DMXConfigVirtualPtr virtual;
+ DMXConfigEntryPtr entry;
+}
+
+ /* Terminals */
+%token <token> '{' '}' ';' T_VIRTUAL T_DISPLAY T_WALL T_OPTION
+%token <string> T_STRING
+%token <pair> T_DIMENSION T_OFFSET T_ORIGIN
+%token <comment> T_COMMENT T_LINE_COMMENT
+
+ /* Non-termials */
+%type <token> Display Wall Terminal Open Close
+%type <string> NameList Name
+%type <pair> Dimension Offset Origin
+%type <display> DisplayEntry
+%type <option> OptionEntry
+%type <subentry> SubList Sub
+%type <wall> WallEntry
+%type <virtual> Virtual
+%type <entry> Program EntryList Entry
+
+%%
+
+Program : EntryList { dmxConfigEntry = $1; }
+ ;
+
+EntryList : Entry
+ | EntryList Entry { APPEND(DMXConfigEntryPtr,$1,$2); $$ = $1; }
+ ;
+
+Entry : Virtual { $$ = dmxConfigEntryVirtual($1); }
+ | T_LINE_COMMENT { $$ = dmxConfigEntryComment($1); }
+ ;
+
+Virtual : T_VIRTUAL Open SubList Close
+ { $$ = dmxConfigCreateVirtual($1, NULL, NULL, $2, $3, $4); }
+ | T_VIRTUAL Dimension Open SubList Close
+ { $$ = dmxConfigCreateVirtual($1, NULL, $2, $3, $4, $5); }
+ | T_VIRTUAL Name Open SubList Close
+ { $$ = dmxConfigCreateVirtual($1, $2, NULL, $3, $4, $5); }
+ | T_VIRTUAL Name Dimension Open SubList Close
+ { $$ = dmxConfigCreateVirtual($1, $2, $3, $4, $5, $6 ); }
+ ;
+
+SubList : Sub
+ | SubList Sub { APPEND(DMXConfigSubPtr,$1,$2); $$ = $1; }
+ ;
+
+Sub : T_LINE_COMMENT { $$ = dmxConfigSubComment($1); }
+ | DisplayEntry { $$ = dmxConfigSubDisplay($1); }
+ | WallEntry { $$ = dmxConfigSubWall($1); }
+ | OptionEntry { $$ = dmxConfigSubOption($1); }
+ ;
+
+OptionEntry : T_OPTION NameList Terminal
+ { $$ = dmxConfigCreateOption($1, $2, $3); }
+ ;
+
+DisplayEntry : Display Name Dimension Offset Origin Terminal
+ { $$ = dmxConfigCreateDisplay($1, $2, $3, $4, $5, $6); }
+
+ | Display Dimension Offset Origin Terminal
+ { $$ = dmxConfigCreateDisplay($1, NULL, $2, $3, $4, $5); }
+ | Display Name Offset Origin Terminal
+ { $$ = dmxConfigCreateDisplay($1, $2, NULL, $3, $4, $5); }
+ | Display Name Dimension Origin Terminal
+ { $$ = dmxConfigCreateDisplay($1, $2, $3, NULL, $4, $5); }
+ | Display Name Dimension Offset Terminal
+ { $$ = dmxConfigCreateDisplay($1, $2, $3, $4, NULL, $5); }
+
+ | Display Offset Origin Terminal
+ { $$ = dmxConfigCreateDisplay($1, NULL, NULL, $2, $3, $4); }
+ | Display Dimension Origin Terminal
+ { $$ = dmxConfigCreateDisplay($1, NULL, $2, NULL, $3, $4); }
+ | Display Dimension Offset Terminal
+ { $$ = dmxConfigCreateDisplay($1, NULL, $2, $3, NULL, $4); }
+
+ | Display Name Origin Terminal
+ { $$ = dmxConfigCreateDisplay($1, $2, NULL, NULL, $3, $4); }
+ | Display Name Offset Terminal
+ { $$ = dmxConfigCreateDisplay($1, $2, NULL, $3, NULL, $4); }
+
+ | Display Name Dimension Terminal
+ { $$ = dmxConfigCreateDisplay($1, $2, $3, NULL, NULL, $4); }
+
+ | Display Origin Terminal
+ { $$ = dmxConfigCreateDisplay($1, NULL, NULL, NULL, $2, $3); }
+ | Display Offset Terminal
+ { $$ = dmxConfigCreateDisplay($1, NULL, NULL, $2, NULL, $3); }
+ | Display Dimension Terminal
+ { $$ = dmxConfigCreateDisplay($1, NULL, $2, NULL, NULL, $3); }
+ | Display Name Terminal
+ { $$ = dmxConfigCreateDisplay($1, $2, NULL, NULL, NULL, $3); }
+
+ | Display Terminal
+ { $$ = dmxConfigCreateDisplay($1, NULL, NULL, NULL, NULL, $2); }
+ ;
+
+WallEntry : Wall Dimension Dimension NameList Terminal
+ { $$ = dmxConfigCreateWall($1, $2, $3, $4, $5); }
+ | Wall Dimension NameList Terminal
+ { $$ = dmxConfigCreateWall($1, $2, NULL, $3, $4); }
+ | Wall NameList Terminal
+ { $$ = dmxConfigCreateWall($1, NULL, NULL, $2, $3); }
+ ;
+
+Display : T_DISPLAY
+ | T_DISPLAY T_COMMENT { $$ = $1; $$->comment = $2->comment; }
+ ;
+
+Name : T_STRING
+ | T_STRING T_COMMENT { $$ = $1; $$->comment = $2->comment; }
+ ;
+
+Dimension : T_DIMENSION
+ | T_DIMENSION T_COMMENT { $$ = $1; $$->comment = $2->comment; }
+ ;
+
+Offset : T_OFFSET
+ | T_OFFSET T_COMMENT { $$ = $1; $$->comment = $2->comment; }
+ ;
+
+Origin : T_ORIGIN
+ | T_ORIGIN T_COMMENT { $$ = $1; $$->comment = $2->comment; }
+ ;
+
+Terminal : ';'
+ | ';' T_COMMENT { $$ = $1; $$->comment = $2->comment; }
+ ;
+
+Open : '{'
+ | '{' T_COMMENT { $$ = $1; $$->comment = $2->comment; }
+ ;
+
+Close : '}'
+ | '}' T_COMMENT { $$ = $1; $$->comment = $2->comment; }
+ ;
+
+Wall : T_WALL
+ | T_WALL T_COMMENT { $$ = $1; $$->comment = $2->comment; }
+
+NameList : Name
+ | NameList Name { APPEND(DMXConfigStringPtr, $1, $2); $$ = $1; }
+ ;
diff --git a/xc/programs/Xserver/hw/dmx/config/scanner.l b/xc/programs/Xserver/hw/dmx/config/scanner.l
new file mode 100644
index 000000000..8aef52d3b
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/scanner.l
@@ -0,0 +1,166 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+%{
+#include "dmxparse.h"
+#include "parser.h"
+#include <string.h>
+#include <ctype.h>
+static int getdimension(int token, const char *text, int leng);
+static int getstring(int token, const char *text, int leng);
+static int gettoken(int token, const char *text, int leng);
+static int getcomment(int token, const char *text, int leng);
+static int lineno = 1;
+%}
+%s OTHER
+comment #.*
+word ([[:alpha:]_/:\-\+\.\*][[:alnum:]_/:\-\+\.\*]+)
+string \"(([^\"\n])|\"\")*\"
+badstring \"(([^\"\n])|\"\")*
+number [[:digit:]x]+
+dimension [[:digit:]]+[[:blank:]]*x[[:blank:]]*[[:digit:]]+
+offset [+-][[:digit:]]+[[:blank:]]*[+-][[:blank:]]*[[:digit:]]+
+origin @[[:blank:]]*[[:digit:]]+[[:blank:]]*[[:blank:]]*x[[:digit:]]+
+NL \n
+WS [[:blank:]]+
+%%
+virtual return gettoken(T_VIRTUAL, yytext, yyleng);
+display return gettoken(T_DISPLAY, yytext, yyleng);
+wall return gettoken(T_WALL, yytext, yyleng);
+option return gettoken(T_OPTION, yytext, yyleng);
+{dimension} return getdimension(T_DIMENSION, yytext, yyleng);
+{offset} return getdimension(T_OFFSET, yytext+1, yyleng-1);
+{origin} return getdimension(T_ORIGIN, yytext+1, yyleng-1);
+{word} return getstring(T_STRING, yytext, yyleng);
+{string} return getstring(T_STRING, yytext+1, yyleng-2);
+{NL} ++lineno;
+{WS}
+\{ return gettoken(yytext[0], yytext, yyleng);
+\} return gettoken(yytext[0], yytext, yyleng);
+\; return gettoken(yytext[0], yytext, yyleng);
+^{comment} return getcomment(T_LINE_COMMENT, yytext, yyleng);
+{comment} return getcomment(T_COMMENT, yytext, yyleng);
+. return getstring(T_STRING, yytext, yyleng);
+<<EOF>> return 0;
+%%
+int yywrap(void)
+{
+ return 1;
+}
+
+void yyerror(const char *message)
+{
+ const char *pt;
+ struct _entry {
+ const char *from;
+ const char *to;
+ } *entry, list[] = {
+ { "`T_VIRTUAL'", "\"virtual\"" },
+ { "`T_DISPLAY'", "\"display\"" },
+ { "`T_WALL'", "\"wall\"" },
+ { "`T_OPTION'", "\"option\"" },
+ { "`T_DIMENSION'", "dimension (e.g., 2x2 or 1024x768)" },
+ { "`T_OFFSET'", "display offset (e.g., +10-10)" },
+ { "`T_ORIGIN'", "tile origin (e.g., @1280x1024)" },
+ { "`T_STRING'", "string" },
+ { "`T_COMMENT'", "comment (e.g., #...)" },
+ { "`T_LINE_COMMENT'", "comment (e.g., #...)" },
+ { NULL, NULL }
+ };
+
+ fprintf(stderr, "parse error on line %d at token \"%*.*s\"\n",
+ lineno, yyleng, yyleng, yytext);
+ for (pt = message; *pt; pt++) {
+ if (*pt == '`') {
+ const char *next = strchr(pt, '\'');
+ if (!next || !*next) goto bail;
+ if (next-pt == 1 && next[1]
+ && next[2] == '\'' && next[3] == '\'') {
+ fprintf(stderr, "\"%c\"", next[1]);
+ pt += 4;
+ goto cnt;
+ }
+ for (entry = list; entry->from; ++entry) {
+ if (!strncmp(entry->from, pt, strlen(entry->from))) {
+ fprintf(stderr, "%s", entry->to);
+ pt = next;
+ goto cnt;
+ }
+ }
+ }
+ bail:
+ putc(*pt, stderr);
+ cnt:
+ ;
+ }
+ fprintf(stderr, "\n");
+ exit( 1 );
+}
+
+static int getdimension(int token, const char *text, int leng)
+{
+ char *endptr;
+ char *tmp = dmxConfigAlloc(leng+1);
+ int x, y;
+
+ strncpy(tmp, text, leng);
+ x = strtol(tmp, &endptr, 10);
+ while (*endptr && !isdigit(*endptr)) ++endptr;
+ y = strtol(endptr, NULL, 10);
+ dmxConfigFree(tmp);
+ yylval.pair = dmxConfigCreatePair(token, lineno, NULL, x, y, 1, 1);
+ return token;
+}
+
+static int getstring(int token, const char *text, int leng)
+{
+ yylval.string = dmxConfigCreateString(token, lineno, NULL,
+ dmxConfigCopyString(leng ? text : "",
+ leng));
+ return token;
+}
+
+static int gettoken(int token, const char *text, int leng)
+{
+ yylval.token = dmxConfigCreateToken(token, lineno, NULL);
+ return token;
+}
+
+static int getcomment(int token, const char *text, int leng)
+{
+ yylval.comment = dmxConfigCreateComment(token, lineno,
+ dmxConfigCopyString(text + 1,
+ leng - 1));
+ return token;
+}
diff --git a/xc/programs/Xserver/hw/dmx/config/test-a.in b/xc/programs/Xserver/hw/dmx/config/test-a.in
new file mode 100644
index 000000000..827675374
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/test-a.in
@@ -0,0 +1 @@
+error
diff --git a/xc/programs/Xserver/hw/dmx/config/test-a.out b/xc/programs/Xserver/hw/dmx/config/test-a.out
new file mode 100644
index 000000000..539a09c3c
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/test-a.out
@@ -0,0 +1,2 @@
+parse error on line 1 at token "error"
+parse error, expecting "virtual" or comment (e.g., #...)
diff --git a/xc/programs/Xserver/hw/dmx/config/test-b.in b/xc/programs/Xserver/hw/dmx/config/test-b.in
new file mode 100644
index 000000000..308ec1db4
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/test-b.in
@@ -0,0 +1 @@
+# comment
diff --git a/xc/programs/Xserver/hw/dmx/config/test-b.out b/xc/programs/Xserver/hw/dmx/config/test-b.out
new file mode 100644
index 000000000..308ec1db4
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/test-b.out
@@ -0,0 +1 @@
+# comment
diff --git a/xc/programs/Xserver/hw/dmx/config/test-c.in b/xc/programs/Xserver/hw/dmx/config/test-c.in
new file mode 100644
index 000000000..e07ae5ba6
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/test-c.in
@@ -0,0 +1 @@
+virtual
diff --git a/xc/programs/Xserver/hw/dmx/config/test-c.out b/xc/programs/Xserver/hw/dmx/config/test-c.out
new file mode 100644
index 000000000..9499d1eb0
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/test-c.out
@@ -0,0 +1,2 @@
+parse error on line 2 at token " "
+parse error, expecting "{" or string or dimension (e.g., 2x2 or 1024x768)
diff --git a/xc/programs/Xserver/hw/dmx/config/test-d.in b/xc/programs/Xserver/hw/dmx/config/test-d.in
new file mode 100644
index 000000000..6827503b1
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/test-d.in
@@ -0,0 +1 @@
+display
diff --git a/xc/programs/Xserver/hw/dmx/config/test-d.out b/xc/programs/Xserver/hw/dmx/config/test-d.out
new file mode 100644
index 000000000..3e3cd5bfb
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/test-d.out
@@ -0,0 +1,2 @@
+parse error on line 1 at token "display"
+parse error, expecting "virtual" or comment (e.g., #...)
diff --git a/xc/programs/Xserver/hw/dmx/config/test-e.in b/xc/programs/Xserver/hw/dmx/config/test-e.in
new file mode 100644
index 000000000..21dbde95c
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/test-e.in
@@ -0,0 +1 @@
+display;
diff --git a/xc/programs/Xserver/hw/dmx/config/test-e.out b/xc/programs/Xserver/hw/dmx/config/test-e.out
new file mode 100644
index 000000000..3e3cd5bfb
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/test-e.out
@@ -0,0 +1,2 @@
+parse error on line 1 at token "display"
+parse error, expecting "virtual" or comment (e.g., #...)
diff --git a/xc/programs/Xserver/hw/dmx/config/test-f.in b/xc/programs/Xserver/hw/dmx/config/test-f.in
new file mode 100644
index 000000000..17f6c6327
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/test-f.in
@@ -0,0 +1,2 @@
+virtual {
+}
diff --git a/xc/programs/Xserver/hw/dmx/config/test-f.out b/xc/programs/Xserver/hw/dmx/config/test-f.out
new file mode 100644
index 000000000..12c50d648
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/test-f.out
@@ -0,0 +1,2 @@
+parse error on line 2 at token "}"
+parse error, expecting "display" or "wall" or comment (e.g., #...)
diff --git a/xc/programs/Xserver/hw/dmx/config/test-g.in b/xc/programs/Xserver/hw/dmx/config/test-g.in
new file mode 100644
index 000000000..453d8121c
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/test-g.in
@@ -0,0 +1,4 @@
+virtual a {
+ display d0:0 1280x1024;
+ display d1:0 1280x1024;
+}
diff --git a/xc/programs/Xserver/hw/dmx/config/test-g.out b/xc/programs/Xserver/hw/dmx/config/test-g.out
new file mode 100644
index 000000000..453d8121c
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/test-g.out
@@ -0,0 +1,4 @@
+virtual a {
+ display d0:0 1280x1024;
+ display d1:0 1280x1024;
+}
diff --git a/xc/programs/Xserver/hw/dmx/config/test-h.in b/xc/programs/Xserver/hw/dmx/config/test-h.in
new file mode 100644
index 000000000..1193d309e
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/test-h.in
@@ -0,0 +1,7 @@
+# comment a
+# comment b
+## comment c
+# <-- tab
+# Next comment is empty
+#
+# Non empty
diff --git a/xc/programs/Xserver/hw/dmx/config/test-h.out b/xc/programs/Xserver/hw/dmx/config/test-h.out
new file mode 100644
index 000000000..1193d309e
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/test-h.out
@@ -0,0 +1,7 @@
+# comment a
+# comment b
+## comment c
+# <-- tab
+# Next comment is empty
+#
+# Non empty
diff --git a/xc/programs/Xserver/hw/dmx/config/vdltodmx.c b/xc/programs/Xserver/hw/dmx/config/vdltodmx.c
new file mode 100644
index 000000000..33cd8fe8a
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/vdltodmx.c
@@ -0,0 +1,58 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#include "dmxconfig.h"
+#include "dmxparse.h"
+#include "dmxprint.h"
+#include "dmxcompat.h"
+
+int main(int argc, char **argv)
+{
+ DMXConfigEntryPtr entry;
+ FILE *str;
+
+ if (argc != 2 && argc !=3) {
+ fprintf(stderr, "Usage: vdltodmx inFile [outFile]\n");
+ return 1;
+ }
+ if (argc == 2) {
+ str = stdout;
+ } else if (!(str = fopen(argv[2], "w"))) {
+ fprintf(stderr, "Cannot open %s for write\n", argv[2]);
+ return 2;
+ }
+ entry = dmxVDLRead(argv[1]);
+ dmxConfigPrint(str, entry);
+ return 0;
+}
diff --git a/xc/programs/Xserver/hw/dmx/config/vdltodmx.man b/xc/programs/Xserver/hw/dmx/config/vdltodmx.man
new file mode 100644
index 000000000..056fff34c
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/vdltodmx.man
@@ -0,0 +1,97 @@
+.\" $XFree86$
+.\" Copyright 2002 Red Hat Inc., Durham, North Carolina.
+.\" 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 on 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
+.\" NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+.\" 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:
+.\" Rickard E. (Rik) Faith <faith@redhat.com>
+.\"
+.TH vdltodmx 1 __vendorversion__
+.SH NAME
+vdltodmx - dmx configuration file parser and printer
+.SH SYNOPSIS
+.B vdltodmx
+.I infile
+.I outfile
+.SH DESCRIPTION
+.I vdltodmx
+reads the input file, which should be in VDL configuration file format.
+After a successful parse, a file in Xdmx configuration file format is
+written to the output file.
+.P
+The VDL file format is used with
+.IR xmovie ,
+which is available from
+http://www.llnl.gov/icc/lc/img/xmovie/xmovie.html
+.SH EXAMPLE
+Given the following VDL-format file:
+.RS
+.nf
+0
+2
+#
+# two-thirds
+#
+2560 2048 Left two-thirds [restrict=*:2]
+2
+:2.1 1280 2048 0 0 0 0
+:2.2 1280 2048 1280 0 0 0
+4
+1280 1024 0 0
+1280 1024 0 1024
+1280 1024 1280 0
+1280 1024 1280 1024
+#
+2560 2048 Right two-thirds [restrict=*:2]
+2
+:2.2 1280 2048 0 0 0 0
+:2.3 1280 2048 1280 0 0 0
+4
+1280 1024 1280 0
+1280 1024 1280 1024
+1280 1024 2560 0
+1280 1024 2560 1024
+.fi
+.RE
+the following DMX-format file will be produced:
+.RS
+.nf
+#
+# two-thirds
+#
+virtual "Left two-thirds" 2560x2048 {
+ display :2.1 1280x2048;
+ display :2.2 1280x2048 @1280x0;
+}
+#
+virtual "Right two-thirds" 2560x2048 {
+ display :2.2 1280x2048;
+ display :2.3 1280x2048 @1280x0;
+}
+.fi
+.RE
+.SH BUGS
+If the VDL file is not in the expected format, the program will probably
+dump core.
+.SH "SEE ALSO"
+Xdmx(1), xdmxconfig(1), vdl(3), xmovie(1)
diff --git a/xc/programs/Xserver/hw/dmx/config/xdmxconfig.c b/xc/programs/Xserver/hw/dmx/config/xdmxconfig.c
new file mode 100644
index 000000000..38aa17351
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/xdmxconfig.c
@@ -0,0 +1,1164 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xaw/Form.h>
+#include <X11/Xaw/Box.h>
+/* #include <X11/Xaw/Paned.h> */
+#include <X11/Xaw/Command.h>
+#include <X11/Xaw/SimpleMenu.h>
+#include <X11/Xaw/SmeBSB.h>
+#include <X11/Xaw/MenuButton.h>
+#include <X11/Xaw/Viewport.h>
+#include <X11/Xaw/Dialog.h>
+#include <X11/keysym.h>
+#include <X11/Xmu/SysUtil.h>
+#include "Canvas.h"
+
+#include "dmxparse.h"
+#include "dmxprint.h"
+#include "dmxlog.h"
+
+#define DMX_INFO "xdmxconfig v0.9\nCopyright 2002 Red Hat Inc.\n$Id: xdmxconfig.c,v 1.1.4.1 2002/06/04 06:27:25 faith Exp $"
+
+#define DMX_MAIN_WIDTH 800
+#define DMX_MAIN_HEIGHT 600
+#define DMX_DATA_WIDTH 200
+#define DMX_DATA_HEIGHT 200
+#define DMX_CANVAS_WIDTH 400
+#define DMX_CANVAS_HEIGHT 500
+
+DMXConfigEntryPtr dmxConfigEntry;
+static DMXConfigVirtualPtr dmxConfigCurrent, dmxConfigNewVirtual;
+static DMXConfigDisplayPtr dmxConfigCurrentDisplay, dmxConfigNewDisplay;
+static int dmxConfigGrabbed, dmxConfigGrabbedFine;
+static int dmxConfigGrabbedX, dmxConfigGrabbedY;
+static char *dmxConfigFilename;
+static GC dmxConfigGC, dmxConfigGCRev, dmxConfigGCHL;
+static int dmxConfigGCInit = 0;
+static Dimension dmxConfigWidgetWidth, dmxConfigWidgetHeight;
+static Dimension dmxConfigWallWidth, dmxConfigWallHeight;
+static double dmxConfigScaleX, dmxConfigScaleY;
+static int dmxConfigNotSaved;
+static enum {
+ dmxConfigStateOpen,
+ dmxConfigStateSave
+} dmxConfigState;
+
+/* Global widgets */
+static Widget canvas;
+static Widget cnamebox, cdimbox;
+static Widget openpopup, opendialog;
+static Widget namebox, dimbox, origbox, okbutton, buttonpopup;
+static Widget ecbutton, dcbutton;
+static Widget ndbutton0, ndbutton1, edbutton, ddbutton;
+static Widget ecpopup, ecdialog0, ecdialog1;
+static Widget edpopup, eddialog0, eddialog1, eddialog2;
+static Widget aboutpopup, quitpopup;
+
+static void dmxConfigCanvasGCs(void)
+{
+ Display *dpy = XtDisplay(canvas);
+ Window win = XtWindow(canvas);
+ XGCValues gcvals;
+ unsigned long mask;
+ Colormap colormap;
+ XColor fg, bg, hl, tmp;
+
+ if (dmxConfigGCInit++) return;
+
+ XtVaGetValues(canvas, XtNcolormap, &colormap, NULL);
+ XAllocNamedColor(XtDisplay(canvas), colormap, "black", &bg, &tmp);
+ XAllocNamedColor(XtDisplay(canvas), colormap, "white", &fg, &tmp);
+ XAllocNamedColor(XtDisplay(canvas), colormap, "red", &hl, &tmp);
+
+ mask = (GCFunction | GCPlaneMask | GCClipMask | GCForeground |
+ GCBackground | GCLineWidth | GCLineStyle | GCCapStyle |
+ GCFillStyle);
+
+ /* FIXME: copy this from widget */
+ gcvals.function = GXcopy;
+ gcvals.plane_mask = AllPlanes;
+ gcvals.clip_mask = None;
+ gcvals.foreground = fg.pixel;
+ gcvals.background = bg.pixel;
+ gcvals.line_width = 0;
+ gcvals.line_style = LineSolid;
+ gcvals.cap_style = CapNotLast;
+ gcvals.fill_style = FillSolid;
+
+ dmxConfigGC = XCreateGC(dpy, win, mask, &gcvals);
+ gcvals.foreground = hl.pixel;
+ dmxConfigGCHL = XCreateGC(dpy, win, mask, &gcvals);
+ gcvals.foreground = bg.pixel;
+ gcvals.background = fg.pixel;
+ dmxConfigGCRev = XCreateGC(dpy, win, mask, &gcvals);
+}
+
+static void dmxConfigGetDims(int *maxWidth, int *maxHeight)
+{
+ DMXConfigSubPtr pt;
+ DMXConfigEntryPtr e;
+
+ *maxWidth = dmxConfigWallWidth = 0;
+ *maxWidth = dmxConfigWallHeight = 0;
+ if (!dmxConfigCurrent) return;
+
+ dmxConfigWallWidth = dmxConfigCurrent->width;
+ dmxConfigWallHeight = dmxConfigCurrent->height;
+ if (!dmxConfigWallWidth || !dmxConfigWallHeight) {
+ for (pt = dmxConfigCurrent->subentry; pt; pt = pt->next) {
+ if (pt->type == dmxConfigDisplay) {
+ int x = pt->display->width + pt->display->xorig;
+ int y = pt->display->height + pt->display->yorig;
+ if (x > dmxConfigWallWidth) dmxConfigWallWidth = x;
+ if (y > dmxConfigWallHeight) dmxConfigWallHeight = y;
+ }
+ }
+ }
+ /* Compute maximums */
+ *maxWidth = *maxHeight = 0;
+ for (e = dmxConfigEntry; e; e = e->next) {
+ if (e->type != dmxConfigVirtual) continue;
+ for (pt = e->virtual->subentry; pt; pt = pt->next) {
+ if (pt->type == dmxConfigDisplay) {
+ int x = pt->display->width + pt->display->xorig;
+ int y = pt->display->height + pt->display->yorig;
+ if (x > *maxWidth) *maxWidth = x;
+ if (y > *maxHeight) *maxHeight = y;
+ }
+ }
+ }
+ if (dmxConfigWallWidth > *maxWidth) *maxWidth = dmxConfigWallWidth;
+ if (dmxConfigWallHeight > *maxHeight) *maxHeight = dmxConfigWallHeight;
+}
+
+static int scalex(int x) { return (int)((x * dmxConfigScaleX) + .5); }
+static int scaley(int y) { return (int)((y * dmxConfigScaleY) + .5); }
+static int unscalex(int x) { return (int)((x / dmxConfigScaleX) + .5); }
+static int unscaley(int y) { return (int)((y / dmxConfigScaleY) + .5); }
+
+static void dmxConfigDataUpdate(void)
+{
+ char cnambuf[512];
+ char cdimbuf[128];
+ char nambuf[512];
+ char dimbuf[128];
+ char offbuf[128];
+ const char *name;
+
+ if (!dmxConfigCurrent) {
+ XtVaSetValues(cnamebox, XtNlabel, "", XtNsensitive, False, NULL);
+ XtVaSetValues(cdimbox, XtNlabel, "", XtNsensitive, False, NULL);
+ XtVaSetValues(ecbutton, XtNsensitive, False, NULL);
+ XtVaSetValues(dcbutton, XtNsensitive, False, NULL);
+ XtVaSetValues(ndbutton0, XtNsensitive, False, NULL);
+ XtVaSetValues(ndbutton1, XtNsensitive, False, NULL);
+ } else {
+ name = dmxConfigCurrent->name;
+ XmuSnprintf(cnambuf, sizeof(cnambuf), "%s", name ? name : "");
+ XmuSnprintf(cdimbuf, sizeof(cdimbuf), "%dx%d",
+ dmxConfigWallWidth, dmxConfigWallHeight);
+ XtVaSetValues(cnamebox, XtNlabel, cnambuf, XtNsensitive, True, NULL);
+ XtVaSetValues(cdimbox, XtNlabel, cdimbuf, XtNsensitive, True, NULL);
+ XtVaSetValues(ecbutton, XtNsensitive, True, NULL);
+ XtVaSetValues(dcbutton, XtNsensitive, True, NULL);
+ XtVaSetValues(ndbutton0, XtNsensitive, True, NULL);
+ XtVaSetValues(ndbutton1, XtNsensitive, True, NULL);
+ }
+
+ if (!dmxConfigCurrentDisplay) {
+ XtVaSetValues(namebox, XtNlabel, "", XtNsensitive, False, NULL);
+ XtVaSetValues(dimbox, XtNlabel, "", XtNsensitive, False, NULL);
+ XtVaSetValues(origbox, XtNlabel, "", XtNsensitive, False, NULL);
+ XtVaSetValues(edbutton, XtNsensitive, False, NULL);
+ XtVaSetValues(ddbutton, XtNsensitive, False, NULL);
+ } else {
+ name = dmxConfigCurrentDisplay->name;
+ XmuSnprintf(nambuf, sizeof(nambuf), "%s", name ? name : "");
+ XmuSnprintf(dimbuf, sizeof(dimbuf), "%dx%d%c%d%c%d",
+ dmxConfigCurrentDisplay->width,
+ dmxConfigCurrentDisplay->height,
+ dmxConfigCurrentDisplay->xsign < 0 ? '-' : '+',
+ dmxConfigCurrentDisplay->xoff,
+ dmxConfigCurrentDisplay->ysign < 0 ? '-' : '+',
+ dmxConfigCurrentDisplay->yoff);
+ XmuSnprintf(offbuf, sizeof(offbuf), "@%dx%d",
+ dmxConfigCurrentDisplay->xorig,
+ dmxConfigCurrentDisplay->yorig);
+ XtVaSetValues(namebox, XtNlabel, nambuf, XtNsensitive, True, NULL);
+ XtVaSetValues(dimbox, XtNlabel, dimbuf, XtNsensitive, True, NULL);
+ XtVaSetValues(origbox, XtNlabel, offbuf, XtNsensitive, True, NULL);
+ XtVaSetValues(edbutton, XtNsensitive, True, NULL);
+ XtVaSetValues(ddbutton, XtNsensitive, True, NULL);
+ }
+}
+
+static void dmxConfigCanvasUpdate(void)
+{
+ DMXConfigSubPtr pt;
+ Display *dpy = XtDisplay(canvas);
+ Window win = XtWindow(canvas);
+ GContext gcontext = XGContextFromGC(dmxConfigGC);
+ XFontStruct *fs;
+ int w, h;
+
+ XFillRectangle(dpy, win, dmxConfigGCRev,
+ 0, 0, dmxConfigWidgetWidth, dmxConfigWidgetHeight);
+ dmxConfigDataUpdate();
+ if (!dmxConfigCurrent) return;
+
+ w = scalex(dmxConfigWallWidth);
+ h = scaley(dmxConfigWallHeight);
+ if (w > dmxConfigWidgetWidth - 1) w = dmxConfigWidgetWidth - 1;
+ if (h > dmxConfigWidgetHeight - 1) h = dmxConfigWidgetHeight - 1;
+ XDrawRectangle(dpy, win, dmxConfigGC, 0, 0, w, h);
+ fs = XQueryFont(dpy, gcontext);
+ for (pt = dmxConfigCurrent->subentry; pt; pt = pt->next) {
+ int x, y, len;
+ int xo = 3, yo = fs->ascent + fs->descent + 2;
+ GC gc;
+
+ if (pt->type != dmxConfigDisplay) continue;
+ gc = (pt->display == dmxConfigCurrentDisplay
+ ? dmxConfigGCHL
+ : dmxConfigGC);
+ x = scalex(pt->display->xorig);
+ y = scaley(pt->display->yorig);
+ w = scalex(pt->display->width);
+ h = scaley(pt->display->height);
+ len = pt->display->name ? strlen(pt->display->name) : 0;
+ if (x > dmxConfigWidgetWidth - 1) x = dmxConfigWidgetWidth - 1;
+ if (y > dmxConfigWidgetHeight - 1) y = dmxConfigWidgetHeight - 1;
+ XDrawRectangle(dpy, win, gc, x, y, w, h);
+ if (fs && len) {
+ while (len && XTextWidth(fs, pt->display->name, len) >= w - 2 * xo)
+ --len;
+ if (len)
+ XDrawString(dpy, win, gc, x+xo, y+yo, pt->display->name, len);
+ }
+ }
+ if (fs) XFreeFontInfo(NULL, fs, 0);
+}
+
+static void dmxConfigCanvasDraw(Region region)
+{
+ Display *dpy = XtDisplay(canvas);
+ int maxWidth, maxHeight;
+
+ dmxConfigCanvasGCs();
+ if (region) {
+ XSetRegion(dpy, dmxConfigGC, region);
+ XSetRegion(dpy, dmxConfigGCRev, region);
+ XSetRegion(dpy, dmxConfigGCHL, region);
+ }
+ XtVaGetValues(canvas,
+ XtNwidth, &dmxConfigWidgetWidth,
+ XtNheight, &dmxConfigWidgetHeight,
+ NULL);
+ dmxConfigGetDims(&maxWidth, &maxHeight);
+ dmxConfigScaleX = (double)dmxConfigWidgetWidth / maxWidth;
+ dmxConfigScaleY = (double)dmxConfigWidgetHeight / maxHeight;
+ if (dmxConfigScaleX > dmxConfigScaleY) dmxConfigScaleX = dmxConfigScaleY;
+ if (dmxConfigScaleY > dmxConfigScaleX) dmxConfigScaleY = dmxConfigScaleX;
+ dmxConfigCanvasUpdate();
+ if (region) {
+ XSetClipMask(dpy, dmxConfigGC, None);
+ XSetClipMask(dpy, dmxConfigGCRev, None);
+ XSetClipMask(dpy, dmxConfigGCHL, None);
+ }
+}
+
+static void dmxConfigSelectCallback(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ dmxConfigCurrent = closure;
+ dmxConfigVirtualPrint(stdout, dmxConfigCurrent);
+ dmxConfigCanvasDraw(NULL);
+}
+
+static void dmxConfigCopystrings(void)
+{
+ DMXConfigEntryPtr pt;
+ DMXConfigSubPtr sub;
+
+ if (!dmxConfigCurrent) return;
+
+ /* FIXME: this is all a per-config file
+ * memory leak */
+ for (pt = dmxConfigEntry; pt; pt = pt->next) {
+ if (pt->type == dmxConfigVirtual) {
+ pt->virtual->name = XtNewString(pt->virtual->name
+ ? pt->virtual->name
+ : "");
+
+ for (sub = pt->virtual->subentry; sub; sub = sub->next) {
+ if (sub->type != dmxConfigDisplay) continue;
+ sub->display->name = XtNewString(sub->display->name
+ ? sub->display->name
+ : "");
+ }
+ }
+ }
+}
+
+static void dmxConfigGetValueString(char **d, Widget w)
+{
+ const char *tmp = XawDialogGetValueString(w);
+ if (*d) XtFree(*d);
+ *d = XtNewString(tmp);
+}
+
+static void dmxConfigSetupCnamemenu(void)
+{
+ static Widget cnamemenu = NULL;
+ Widget w;
+ DMXConfigEntryPtr pt;
+
+ if (cnamemenu) XtDestroyWidget(cnamemenu);
+ cnamemenu = NULL;
+
+ if (!dmxConfigCurrent) return;
+ cnamemenu = XtVaCreatePopupShell("cnamemenu", simpleMenuWidgetClass,
+ cnamebox,
+ NULL);
+
+ for (pt = dmxConfigEntry; pt; pt = pt->next) {
+ if (pt->type == dmxConfigVirtual) {
+ w = XtVaCreateManagedWidget(pt->virtual->name
+ ? pt->virtual->name
+ : "",
+ smeBSBObjectClass, cnamemenu,
+ NULL);
+ XtAddCallback(w, XtNcallback,
+ dmxConfigSelectCallback, pt->virtual);
+ }
+ }
+}
+
+static void dmxConfigReadFile(void)
+{
+ FILE *str;
+ DMXConfigEntryPtr pt;
+
+ if (!(str = fopen(dmxConfigFilename, "r"))) {
+ dmxLog(dmxWarning, "Unable to read configuration file %s\n",
+ dmxConfigFilename);
+ return;
+ }
+ yyin = str;
+ yydebug = 0;
+ yyparse();
+ fclose(str);
+ dmxLog(dmxInfo, "Read configuration file %s\n", dmxConfigFilename);
+
+ for (pt = dmxConfigEntry; pt; pt = pt->next) {
+ if (pt->type == dmxConfigVirtual) {
+ dmxConfigCurrent = pt->virtual;
+ break;
+ }
+ }
+
+
+
+ if (XtIsRealized(canvas)) {
+ dmxConfigCopystrings();
+ dmxConfigSetupCnamemenu();
+ dmxConfigCanvasDraw(NULL);
+ }
+ dmxConfigVirtualPrint(stdout, dmxConfigCurrent);
+}
+
+static void dmxConfigWriteFile(void)
+{
+ FILE *str;
+
+ if (!(str = fopen(dmxConfigFilename, "w"))) {
+ dmxLog(dmxWarning, "Unable to write configuration file %s\n",
+ dmxConfigFilename);
+ return;
+ }
+ dmxConfigPrint(str, dmxConfigEntry);
+ fclose(str);
+}
+
+static DMXConfigDisplayPtr dmxConfigFindDisplay(int x, int y)
+{
+ DMXConfigSubPtr pt;
+
+ if (!dmxConfigCurrent) return NULL;
+ for (pt = dmxConfigCurrent->subentry; pt; pt = pt->next) {
+ DMXConfigDisplayPtr d = pt->display;
+ if (pt->type != dmxConfigDisplay) continue;
+ if (x >= scalex(d->xorig)
+ && x <= scalex(d->xorig + d->width)
+ && y >= scaley(d->yorig)
+ && y <= scaley(d->yorig + d->height)) return d;
+ }
+ return NULL;
+}
+
+static void dmxConfigSetPopupPosition(Widget popup)
+{
+ Position x, y;
+ Window t1, t2;
+ int root_x, root_y;
+ int temp_x, temp_y;
+ unsigned int temp;
+
+
+ XtRealizeWidget(popup);
+ if (!XQueryPointer(XtDisplay(popup), XtWindow(popup), &t1, &t2,
+ &root_x, &root_y, &temp_x, &temp_y, &temp))
+ root_x = root_y = 0;
+
+ x = root_x - 5;
+ y = root_y - 5;
+ XtVaSetValues(popup, XtNx, x, XtNy, y, NULL);
+}
+
+static void dmxConfigPlaceMenu(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ dmxConfigSetPopupPosition(buttonpopup);
+}
+
+static void dmxConfigMove(int deltaX, int deltaY)
+{
+ dmxConfigCurrentDisplay->xorig += deltaX;
+ dmxConfigCurrentDisplay->yorig += deltaY;
+ if (dmxConfigCurrentDisplay->xorig < 0) dmxConfigCurrentDisplay->xorig = 0;
+ if (dmxConfigCurrentDisplay->yorig < 0) dmxConfigCurrentDisplay->yorig = 0;
+ if (dmxConfigWallWidth && dmxConfigWallHeight) {
+ if (dmxConfigCurrentDisplay->xorig >= dmxConfigWallWidth)
+ dmxConfigCurrentDisplay->xorig = dmxConfigWallWidth - 1;
+ if (dmxConfigCurrentDisplay->yorig >= dmxConfigWallHeight)
+ dmxConfigCurrentDisplay->yorig = dmxConfigWallHeight - 1;
+ }
+ dmxConfigCanvasUpdate();
+ dmxConfigNotSaved = 1;
+}
+
+static void dmxConfigCanvasInput(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ XEvent *e = (XEvent *)callData;
+ DMXConfigDisplayPtr display = NULL;
+
+ switch (e->type) {
+ case ButtonPress:
+ if (e->xbutton.button == Button1) {
+ dmxConfigGrabbed = 1;
+ dmxConfigGrabbedFine = 0;
+ dmxConfigGrabbedX = e->xbutton.x;
+ dmxConfigGrabbedY = e->xbutton.y;
+ }
+ if (e->xbutton.button == Button2) {
+ dmxConfigGrabbed = 1;
+ dmxConfigGrabbedFine = 1;
+ dmxConfigGrabbedX = e->xbutton.x;
+ dmxConfigGrabbedY = e->xbutton.y;
+ }
+ break;
+ case ButtonRelease:
+ if (e->xbutton.button == Button1) dmxConfigGrabbed = 0;
+ if (e->xbutton.button == Button2) dmxConfigGrabbed = 0;
+ break;
+ case MotionNotify:
+ if (dmxConfigGrabbed && dmxConfigCurrentDisplay) {
+ int deltaX = e->xmotion.x - dmxConfigGrabbedX;
+ int deltaY = e->xmotion.y - dmxConfigGrabbedY;
+ dmxConfigMove(dmxConfigGrabbedFine ? deltaX : unscalex(deltaX),
+ dmxConfigGrabbedFine ? deltaY : unscaley(deltaY));
+ dmxConfigGrabbedX = e->xmotion.x;
+ dmxConfigGrabbedY = e->xmotion.y;
+ } else {
+ display = dmxConfigFindDisplay(e->xmotion.x, e->xmotion.y);
+ if (display != dmxConfigCurrentDisplay) {
+ dmxConfigCurrentDisplay = display;
+ dmxConfigCanvasUpdate();
+ }
+ }
+ break;
+ case KeyPress:
+ switch (XLookupKeysym(&e->xkey, 0)) {
+ case XK_Right: dmxConfigMove(1,0); break;
+ case XK_Left: dmxConfigMove(-1,0); break;
+ case XK_Down: dmxConfigMove(0,1); break;
+ case XK_Up: dmxConfigMove(0,-1); break;
+ }
+ break;
+ }
+}
+
+static void dmxConfigCanvasResize(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ dmxConfigCanvasDraw(NULL);
+}
+
+static void dmxConfigCanvasExpose(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ CanvasExposeDataPtr data = (CanvasExposeDataPtr)callData;
+
+ dmxConfigCanvasDraw(data->region);
+}
+
+static void dmxConfigOpenCallback(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ dmxConfigState = dmxConfigStateOpen;
+ XtVaSetValues(okbutton, XtNlabel, "Open", NULL);
+ dmxConfigSetPopupPosition(openpopup);
+ XtPopup(openpopup, XtGrabExclusive);
+}
+
+static void dmxConfigSaveCallback(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ dmxConfigState = dmxConfigStateSave;
+ XtVaSetValues(okbutton, XtNlabel, "Save", NULL);
+ dmxConfigSetPopupPosition(openpopup);
+ XtPopup(openpopup, XtGrabExclusive);
+}
+
+static void dmxConfigOkCallback(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ dmxConfigGetValueString(&dmxConfigFilename, opendialog);
+ XtPopdown(openpopup);
+ if (dmxConfigState == dmxConfigStateOpen) dmxConfigReadFile();
+ else dmxConfigWriteFile();
+ dmxConfigNotSaved = 0;
+}
+
+static void dmxConfigCanCallback(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ XtPopdown(openpopup);
+}
+
+static void dmxConfigECCallback(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ char buf[256];
+
+ if (!dmxConfigCurrent) return;
+ dmxConfigSetPopupPosition(ecpopup);
+ XtVaSetValues(ecdialog0, XtNvalue,
+ dmxConfigCurrent->name ? dmxConfigCurrent->name : "",
+ NULL);
+ XmuSnprintf(buf, sizeof(buf), "%dx%d",
+ dmxConfigCurrent->width, dmxConfigCurrent->height);
+ XtVaSetValues(ecdialog1, XtNvalue, buf, NULL);
+ XtPopup(ecpopup, XtGrabExclusive);
+}
+
+static void dmxConfigNCCallback(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ int width = 1280*2, height = 1024*2;
+
+ if (dmxConfigCurrent) {
+ width = dmxConfigCurrent->width;
+ height = dmxConfigCurrent->height;
+ }
+
+ dmxConfigCurrent = dmxConfigCreateVirtual(NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ dmxConfigNewVirtual = dmxConfigCurrent;
+ dmxConfigCurrent->width = width;
+ dmxConfigCurrent->height = height;
+ dmxConfigEntry = dmxConfigAddEntry(dmxConfigEntry, dmxConfigVirtual, NULL,
+ dmxConfigCurrent);
+ dmxConfigECCallback(w, closure, callData);
+}
+
+static void dmxConfigDCCallback(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ DMXConfigEntryPtr pt;
+
+ if (!dmxConfigEntry) return;
+ if (dmxConfigEntry
+ && dmxConfigEntry->type == dmxConfigVirtual
+ && dmxConfigEntry->virtual == dmxConfigCurrent) {
+ dmxConfigEntry = dmxConfigEntry->next;
+ } else {
+ for (pt = dmxConfigEntry; pt && pt->next; pt = pt->next)
+ if (pt->next->type == dmxConfigVirtual
+ && pt->next->virtual == dmxConfigCurrent) {
+ pt->next = pt->next->next;
+ break;
+ }
+ }
+ dmxConfigFreeVirtual(dmxConfigCurrent);
+ dmxConfigCurrent = NULL;
+ dmxConfigCurrentDisplay = NULL;
+
+ /* Make the first entry current */
+ for (pt = dmxConfigEntry; pt; pt = pt->next) {
+ if (pt->type == dmxConfigVirtual) {
+ dmxConfigCurrent = pt->virtual;
+ break;
+ }
+ }
+
+ dmxConfigSetupCnamemenu();
+ dmxConfigCanvasDraw(NULL);
+}
+
+static void dmxConfigECOkCallback(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ const char *value;
+ char *endpt;
+
+ dmxConfigGetValueString((char **)&dmxConfigCurrent->name, ecdialog0);
+ value = XawDialogGetValueString(ecdialog1);
+ dmxConfigCurrent->width = strtol(value, &endpt, 10);
+ dmxConfigCurrent->height = strtol(endpt+1, NULL, 10);
+ XtPopdown(ecpopup);
+ dmxConfigCurrentDisplay = NULL;
+ dmxConfigNewVirtual = NULL;
+ dmxConfigSetupCnamemenu();
+ dmxConfigCanvasDraw(NULL);
+ dmxConfigNotSaved = 1;
+}
+
+static void dmxConfigECCanCallback(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ if (dmxConfigNewVirtual) dmxConfigDCCallback(w, closure, callData);
+ dmxConfigNewVirtual = NULL;
+ XtPopdown(ecpopup);
+}
+
+static void dmxConfigEDCallback(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ char buf[256];
+
+ if (!dmxConfigCurrent || !dmxConfigCurrentDisplay) return;
+ dmxConfigSetPopupPosition(edpopup);
+ XtVaSetValues(eddialog0, XtNvalue,
+ dmxConfigCurrentDisplay->name
+ ? dmxConfigCurrentDisplay->name
+ : "",
+ NULL);
+ XmuSnprintf(buf, sizeof(buf), "%dx%d%c%d%c%d",
+ dmxConfigCurrentDisplay->width,
+ dmxConfigCurrentDisplay->height,
+ dmxConfigCurrentDisplay->xsign < 0 ? '-' : '+',
+ dmxConfigCurrentDisplay->xoff,
+ dmxConfigCurrentDisplay->ysign < 0 ? '-' : '+',
+ dmxConfigCurrentDisplay->yoff);
+ XtVaSetValues(eddialog1, XtNvalue, buf, NULL);
+ XmuSnprintf(buf, sizeof(buf), "@%dx%d",
+ dmxConfigCurrentDisplay->xorig,
+ dmxConfigCurrentDisplay->yorig);
+ XtVaSetValues(eddialog2, XtNvalue, buf, NULL);
+ XtPopup(edpopup, XtGrabExclusive);
+}
+
+static void dmxConfigNDCallback(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ int width = 1280, height = 1024;
+
+ if (!dmxConfigCurrent) return;
+ if (dmxConfigCurrentDisplay) {
+ width = dmxConfigCurrentDisplay->width;
+ height = dmxConfigCurrentDisplay->height;
+ }
+ dmxConfigCurrentDisplay = dmxConfigCreateDisplay(NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ dmxConfigNewDisplay = dmxConfigCurrentDisplay;
+ dmxConfigCurrentDisplay->width = width;
+ dmxConfigCurrentDisplay->height = height;
+
+ dmxConfigCurrent->subentry
+ = dmxConfigAddSub(dmxConfigCurrent->subentry,
+ dmxConfigSubDisplay(dmxConfigCurrentDisplay));
+ dmxConfigEDCallback(w, closure, callData);
+}
+
+static void dmxConfigDDCallback(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ DMXConfigSubPtr pt;
+
+ if (!dmxConfigCurrent || !dmxConfigCurrentDisplay) return;
+ /* First */
+ if (dmxConfigCurrent->subentry
+ && dmxConfigCurrent->subentry->type == dmxConfigDisplay
+ && dmxConfigCurrent->subentry->display == dmxConfigCurrentDisplay) {
+ dmxConfigCurrent->subentry = dmxConfigCurrent->subentry->next;
+ } else {
+ for (pt = dmxConfigCurrent->subentry; pt && pt->next; pt = pt->next)
+ if (pt->next->type == dmxConfigDisplay
+ && pt->next->display == dmxConfigCurrentDisplay) {
+ pt->next = pt->next->next;
+ break;
+ }
+ }
+ dmxConfigFreeDisplay(dmxConfigCurrentDisplay);
+ dmxConfigCurrentDisplay = NULL;
+ dmxConfigSetupCnamemenu();
+ dmxConfigCanvasDraw(NULL);
+}
+
+static void dmxConfigAboutCallback(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ dmxConfigSetPopupPosition(aboutpopup);
+ XtPopup(aboutpopup, XtGrabExclusive);
+}
+
+static void dmxConfigAboutOkCallback(Widget w, XtPointer closure,
+ XtPointer CallData)
+{
+ XtPopdown(aboutpopup);
+}
+
+static void dmxConfigQuitCallback(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ if (dmxConfigNotSaved) {
+ dmxConfigSetPopupPosition(quitpopup);
+ XtPopup(quitpopup, XtGrabExclusive);
+ return;
+ }
+ exit(0);
+}
+
+static void dmxConfigQuitOkCallback(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ XtPopdown(quitpopup);
+ exit(0);
+}
+
+static void dmxConfigQuitCanCallback(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ XtPopdown(quitpopup);
+}
+
+static void dmxConfigEDOkCallback(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ char *value;
+ char *endpt;
+
+ dmxConfigNewDisplay = NULL;
+ dmxConfigGetValueString((char **)&dmxConfigCurrentDisplay->name,
+ eddialog0);
+ value = XawDialogGetValueString(eddialog1);
+ if (*value == '-' || *value == '+') {
+ dmxConfigCurrentDisplay->width = 0;
+ dmxConfigCurrentDisplay->height = 0;
+ endpt = value;
+ } else {
+ dmxConfigCurrentDisplay->width = strtol(value, &endpt, 10);
+ dmxConfigCurrentDisplay->height = strtol(endpt+1, &endpt, 10);
+ }
+ if (*endpt) {
+ dmxConfigCurrentDisplay->xsign = (*endpt == '-') ? -1 : 1;
+ dmxConfigCurrentDisplay->xoff = strtol(endpt+1, &endpt, 10);
+ dmxConfigCurrentDisplay->ysign = (*endpt == '-') ? -1 : 1;
+ dmxConfigCurrentDisplay->yoff = strtol(endpt+1, NULL, 10);
+ }
+ if (dmxConfigCurrentDisplay->xoff < 0)
+ dmxConfigCurrentDisplay->xoff = -dmxConfigCurrentDisplay->xoff;
+ if (dmxConfigCurrentDisplay->yoff < 0)
+ dmxConfigCurrentDisplay->yoff = -dmxConfigCurrentDisplay->yoff;
+ value = XawDialogGetValueString(eddialog2);
+ dmxConfigCurrentDisplay->xorig = strtol(value+1, &endpt, 10);
+ dmxConfigCurrentDisplay->yorig = strtol(endpt+1, NULL, 10);
+ XtPopdown(edpopup);
+ dmxConfigSetupCnamemenu();
+ dmxConfigCanvasDraw(NULL);
+ dmxConfigNotSaved = 1;
+}
+
+static void dmxConfigEDCanCallback(Widget w, XtPointer closure,
+ XtPointer callData)
+{
+ if (dmxConfigNewDisplay) dmxConfigDDCallback(w, closure, callData);
+ dmxConfigNewDisplay = NULL;
+ XtPopdown(edpopup);
+}
+
+static void dmxConfigOkAction(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ Widget p = XtParent(w);
+ Widget t;
+
+ if (p == opendialog) dmxConfigOkCallback(w, NULL, NULL);
+
+ if (p == ecdialog0) {
+ t = XtNameToWidget(ecdialog1, "value");
+ XWarpPointer(XtDisplay(t), None, XtWindow(t), 0, 0, 0, 0, 0, 10);
+ }
+ if (p == ecdialog1) dmxConfigECOkCallback(w, NULL, NULL);
+
+ if (p == eddialog0) {
+ t = XtNameToWidget(eddialog1, "value");
+ XWarpPointer(XtDisplay(t), None, XtWindow(t), 0, 0, 0, 0, 0, 10);
+ }
+ if (p == eddialog1) {
+ t = XtNameToWidget(eddialog2, "value");
+ XWarpPointer(XtDisplay(t), None, XtWindow(t), 0, 0, 0, 0, 0, 10);
+ }
+ if (p == eddialog2) dmxConfigEDOkCallback(w, NULL, NULL);
+}
+
+int main(int argc, char **argv)
+{
+ XtAppContext appContext;
+ Widget toplevel;
+ Widget parent, menubox, bottombox, databox, canvasbox;
+ Widget filebutton, helpbutton;
+ Widget filemenu, openbutton, savebutton, quitbutton;
+ Widget helpmenu, aboutbutton, aboutbox, abouttext, aboutok;
+ Widget quitbox, quittext, quitok, quitcan;
+ Widget ncbutton;
+ Widget canbutton;
+ Widget ecbox, ecokbutton, eccanbutton;
+ Widget edbox, edokbutton;
+ Widget edcanbutton;
+ /* FIXME: add meta-i, ctrl,meta-z,v? */
+ const char *opentrans = "<Key>Return: openOk()\n\
+ <Key>Linefeed: openOk()\n\
+ Ctrl<Key>M: openOk()\n\
+ Ctrl<Key>J: openOk()\n\
+ Ctrl<Key>O: noop()\n\
+ Ctrl<Key>N: noop()\n\
+ Ctrl<Key>P: noop()";
+ const char *canvastrans =
+ "<Btn3Down>: placeMenu() XtMenuPopup(buttonpopup)";
+ XtActionsRec actiontable[] = {
+ { "openOk", dmxConfigOkAction },
+ { "placeMenu", dmxConfigPlaceMenu },
+ { "noop", NULL }
+ };
+
+ dmxConfigFilename = XtNewString((argc >= 2) ? argv[1] : "");
+
+ toplevel = XtVaAppInitialize(&appContext, "XDmxconfig",
+ NULL, 0,
+ &argc, argv,
+ NULL,
+ NULL);
+
+ /* Main boxes */
+ parent = XtVaCreateManagedWidget("parent", formWidgetClass, toplevel,
+ XtNorientation, XtorientVertical,
+ XtNwidth, DMX_MAIN_WIDTH,
+ XtNheight, DMX_MAIN_HEIGHT,
+ NULL);
+ menubox = XtVaCreateManagedWidget("menubox", boxWidgetClass, parent,
+ XtNborderWidth, 0,
+ XtNorientation, XtorientHorizontal,
+ XtNtop, XtChainTop,
+ NULL);
+ bottombox = XtVaCreateManagedWidget("bottombox", formWidgetClass, parent,
+ XtNborderWidth, 0,
+ XtNfromVert, menubox,
+ XtNorientation, XtorientHorizontal,
+ NULL);
+ databox = XtVaCreateManagedWidget("databox", formWidgetClass,
+ bottombox,
+ XtNborderWidth, 0,
+ XtNhorizDistance, 0,
+ XtNwidth, DMX_DATA_WIDTH,
+ XtNheight, DMX_DATA_HEIGHT,
+ XtNleft, XtChainLeft,
+ XtNorientation, XtorientVertical,
+ NULL);
+
+ /* Data */
+ cnamebox = XtVaCreateManagedWidget("cnamebox", menuButtonWidgetClass,
+ databox,
+ XtNtop, XtChainTop,
+ XtNjustify, XtJustifyLeft,
+ XtNwidth, DMX_DATA_WIDTH,
+ XtNlabel, "",
+ XtNmenuName, "cnamemenu",
+ NULL);
+ cdimbox = XtVaCreateManagedWidget("cdimbox", labelWidgetClass,
+ databox,
+ XtNfromVert, cnamebox,
+ XtNjustify, XtJustifyLeft,
+ XtNwidth, DMX_DATA_WIDTH,
+ XtNlabel, "",
+ NULL);
+ namebox = XtVaCreateManagedWidget("namebox", labelWidgetClass, databox,
+ XtNfromVert, cdimbox,
+ XtNjustify, XtJustifyLeft,
+ XtNwidth, DMX_DATA_WIDTH,
+ XtNlabel, "",
+ NULL);
+ dimbox = XtVaCreateManagedWidget("dimbox", labelWidgetClass,
+ databox,
+ XtNfromVert, namebox,
+ XtNjustify, XtJustifyLeft,
+ XtNwidth, DMX_DATA_WIDTH,
+ XtNlabel, "",
+ NULL);
+ origbox = XtVaCreateManagedWidget("origbox", labelWidgetClass,
+ databox,
+ XtNfromVert, dimbox,
+ XtNjustify, XtJustifyLeft,
+ XtNwidth, DMX_DATA_WIDTH,
+ XtNlabel, "",
+ NULL);
+
+ /* Canvas */
+ canvasbox = XtVaCreateManagedWidget("canvasbox", boxWidgetClass,
+ bottombox,
+ XtNborderWidth, 0,
+ XtNwidth, DMX_CANVAS_WIDTH,
+ XtNheight, DMX_CANVAS_HEIGHT,
+ XtNfromHoriz, databox,
+ NULL);
+
+ canvas = XtVaCreateManagedWidget("canvas", canvasWidgetClass,
+ canvasbox,
+ XtNwidth, DMX_CANVAS_WIDTH,
+ XtNheight, DMX_CANVAS_HEIGHT,
+ NULL);
+
+
+ /* Main menu buttons */
+ filebutton = XtVaCreateManagedWidget("File", menuButtonWidgetClass,
+ menubox,
+ XtNmenuName, "filemenu",
+ NULL);
+ helpbutton = XtVaCreateManagedWidget("Help", menuButtonWidgetClass,
+ menubox,
+ XtNmenuName, "helpmenu",
+ NULL);
+
+
+ /* File submenu buttons */
+ filemenu = XtVaCreatePopupShell("filemenu", simpleMenuWidgetClass,
+ filebutton, NULL);
+ openbutton = XtVaCreateManagedWidget("Open File", smeBSBObjectClass,
+ filemenu, NULL);
+ savebutton = XtVaCreateManagedWidget("Save File", smeBSBObjectClass,
+ filemenu,
+ NULL);
+ ncbutton = XtVaCreateManagedWidget("New Global", smeBSBObjectClass,
+ filemenu, NULL);
+ ecbutton = XtVaCreateManagedWidget("Edit Global", smeBSBObjectClass,
+ filemenu,
+ NULL);
+ dcbutton = XtVaCreateManagedWidget("Delete Global", smeBSBObjectClass,
+ filemenu,
+ NULL);
+ ndbutton0 = XtVaCreateManagedWidget("New Display", smeBSBObjectClass,
+ filemenu,
+ NULL);
+ quitbutton = XtVaCreateManagedWidget("Quit", smeBSBObjectClass,
+ filemenu, NULL);
+
+ /* Help submenu button */
+ helpmenu = XtVaCreatePopupShell("helpmenu", simpleMenuWidgetClass,
+ helpbutton, NULL);
+ aboutbutton = XtVaCreateManagedWidget("About", smeBSBObjectClass,
+ helpmenu, NULL);
+
+ /* Open popup */
+ openpopup = XtVaCreatePopupShell("openpopup", transientShellWidgetClass,
+ toplevel, NULL);
+ opendialog = XtVaCreateManagedWidget("opendialog", dialogWidgetClass,
+ openpopup,
+ XtNlabel, "Filename: ",
+ XtNvalue, dmxConfigFilename,
+ NULL);
+ okbutton = XtVaCreateManagedWidget("Open", commandWidgetClass,
+ opendialog, NULL);
+ canbutton = XtVaCreateManagedWidget("Cancel", commandWidgetClass,
+ opendialog, NULL);
+
+ /* EC popup */
+ ecpopup = XtVaCreatePopupShell("ecpopup", transientShellWidgetClass,
+ toplevel, NULL);
+ ecbox = XtVaCreateManagedWidget("ecbox", boxWidgetClass,
+ ecpopup, NULL);
+ ecdialog0 = XtVaCreateManagedWidget("ecdialog0", dialogWidgetClass,
+ ecbox,
+ XtNlabel, "Name: ",
+ XtNvalue, "",
+ NULL);
+ ecdialog1 = XtVaCreateManagedWidget("ecdialog1", dialogWidgetClass,
+ ecbox,
+ XtNlabel, "Dimension: ",
+ XtNvalue, "",
+ NULL);
+ ecokbutton = XtVaCreateManagedWidget("OK", commandWidgetClass,
+ ecbox, NULL);
+ eccanbutton = XtVaCreateManagedWidget("Cancel", commandWidgetClass,
+ ecbox, NULL);
+
+ /* ED popup */
+ edpopup = XtVaCreatePopupShell("edpopup", transientShellWidgetClass,
+ toplevel, NULL);
+ edbox = XtVaCreateManagedWidget("edbox", boxWidgetClass,
+ edpopup, NULL);
+ eddialog0 = XtVaCreateManagedWidget("eddialog0", dialogWidgetClass,
+ edbox,
+ XtNlabel, "Display Name: ",
+ XtNvalue, "",
+ NULL);
+ eddialog1 = XtVaCreateManagedWidget("eddialog1", dialogWidgetClass,
+ edbox,
+ XtNlabel, "Geometry: ",
+ XtNvalue, "",
+ NULL);
+ eddialog2 = XtVaCreateManagedWidget("eddialog2", dialogWidgetClass,
+ edbox,
+ XtNlabel, "Offset: ",
+ XtNvalue, "",
+ NULL);
+ edokbutton = XtVaCreateManagedWidget("OK", commandWidgetClass,
+ edbox, NULL);
+ edcanbutton = XtVaCreateManagedWidget("Cancel", commandWidgetClass,
+ edbox, NULL);
+
+ /* About popup */
+ aboutpopup = XtVaCreatePopupShell("aboutpopup",transientShellWidgetClass,
+ toplevel, NULL);
+ aboutbox = XtVaCreateManagedWidget("aboutbox", boxWidgetClass,
+ aboutpopup, NULL);
+ abouttext = XtVaCreateManagedWidget("abouttext", labelWidgetClass,
+ aboutbox,
+ XtNlabel, DMX_INFO,
+ NULL);
+ aboutok = XtVaCreateManagedWidget("OK", commandWidgetClass,
+ aboutbox, NULL);
+
+ /* Quit popup */
+ quitpopup = XtVaCreatePopupShell("quitpopup",transientShellWidgetClass,
+ toplevel, NULL);
+ quitbox = XtVaCreateManagedWidget("quitbox", boxWidgetClass,
+ quitpopup, NULL);
+ quittext = XtVaCreateManagedWidget("quittext", labelWidgetClass,
+ quitbox,
+ XtNlabel,
+ "Changes to the configuration\n"
+ "been made that have not yet\n"
+ "been saved. Do you want to\n"
+ "quit without saving?",
+ NULL);
+ quitok = XtVaCreateManagedWidget("Quit WITHOUT Saving",
+ commandWidgetClass,
+ quitbox, NULL);
+ quitcan = XtVaCreateManagedWidget("Continue Editing",
+ commandWidgetClass,
+ quitbox, NULL);
+
+ /* Button popup */
+ buttonpopup = XtVaCreatePopupShell("buttonpopup", simpleMenuWidgetClass,
+ toplevel, NULL);
+ ndbutton1 = XtVaCreateManagedWidget("New Display", smeBSBObjectClass,
+ buttonpopup,
+ NULL);
+ edbutton = XtVaCreateManagedWidget("Edit Display", smeBSBObjectClass,
+ buttonpopup,
+ NULL);
+ ddbutton = XtVaCreateManagedWidget("Delete Display", smeBSBObjectClass,
+ buttonpopup,
+ NULL);
+
+ /* Callbacks */
+ XtAddCallback(openbutton, XtNcallback, dmxConfigOpenCallback, NULL);
+ XtAddCallback(savebutton, XtNcallback, dmxConfigSaveCallback, NULL);
+ XtAddCallback(okbutton, XtNcallback, dmxConfigOkCallback, NULL);
+ XtAddCallback(canbutton, XtNcallback, dmxConfigCanCallback, NULL);
+
+ XtAppAddActions(appContext, actiontable, XtNumber(actiontable));
+ XtOverrideTranslations(canvas, XtParseTranslationTable(canvastrans));
+ XtOverrideTranslations(XtNameToWidget(opendialog, "value"),
+ XtParseTranslationTable(opentrans));
+ XtOverrideTranslations(XtNameToWidget(ecdialog0, "value"),
+ XtParseTranslationTable(opentrans));
+ XtOverrideTranslations(XtNameToWidget(ecdialog1, "value"),
+ XtParseTranslationTable(opentrans));
+ XtOverrideTranslations(XtNameToWidget(eddialog0, "value"),
+ XtParseTranslationTable(opentrans));
+ XtOverrideTranslations(XtNameToWidget(eddialog1, "value"),
+ XtParseTranslationTable(opentrans));
+ XtOverrideTranslations(XtNameToWidget(eddialog2, "value"),
+ XtParseTranslationTable(opentrans));
+
+ XtAddCallback(ncbutton, XtNcallback, dmxConfigNCCallback, NULL);
+ XtAddCallback(ecbutton, XtNcallback, dmxConfigECCallback, NULL);
+ XtAddCallback(ecokbutton, XtNcallback, dmxConfigECOkCallback, NULL);
+ XtAddCallback(eccanbutton, XtNcallback, dmxConfigECCanCallback, NULL);
+ XtAddCallback(dcbutton, XtNcallback, dmxConfigDCCallback, NULL);
+
+ XtAddCallback(ndbutton0, XtNcallback, dmxConfigNDCallback, NULL);
+ XtAddCallback(ndbutton1, XtNcallback, dmxConfigNDCallback, NULL);
+ XtAddCallback(edbutton, XtNcallback, dmxConfigEDCallback, NULL);
+ XtAddCallback(ddbutton, XtNcallback, dmxConfigDDCallback, NULL);
+ XtAddCallback(edokbutton, XtNcallback, dmxConfigEDOkCallback, NULL);
+ XtAddCallback(edcanbutton, XtNcallback, dmxConfigEDCanCallback, NULL);
+
+ XtAddCallback(aboutbutton, XtNcallback, dmxConfigAboutCallback, NULL);
+ XtAddCallback(aboutok, XtNcallback, dmxConfigAboutOkCallback, NULL);
+ XtAddCallback(quitok, XtNcallback, dmxConfigQuitOkCallback, NULL);
+ XtAddCallback(quitcan, XtNcallback, dmxConfigQuitCanCallback, NULL);
+
+ XtAddCallback(quitbutton, XtNcallback, dmxConfigQuitCallback, NULL);
+
+ XtAddCallback(canvas, XtNcallback, dmxConfigCanvasInput, NULL);
+ XtAddCallback(canvas, XtNcanvasExposeCallback, dmxConfigCanvasExpose,NULL);
+ XtAddCallback(canvas, XtNcanvasResizeCallback, dmxConfigCanvasResize,NULL);
+
+ if (dmxConfigFilename) dmxConfigReadFile();
+
+ XtRealizeWidget(toplevel);
+ dmxConfigCopystrings();
+ dmxConfigSetupCnamemenu();
+ XtAppMainLoop(appContext);
+ return 0;
+}
diff --git a/xc/programs/Xserver/hw/dmx/config/xdmxconfig.man b/xc/programs/Xserver/hw/dmx/config/xdmxconfig.man
new file mode 100644
index 000000000..dcceea0e3
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/config/xdmxconfig.man
@@ -0,0 +1,63 @@
+.\" $XFree86$
+.\" Copyright 2002 Red Hat Inc., Durham, North Carolina.
+.\" 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 on 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
+.\" NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+.\" 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:
+.\" Rickard E. (Rik) Faith <faith@redhat.com>
+.\"
+.TH xdmxconfig 1 __vendorversion__
+.SH NAME
+xdmxconfig - a graphical configuration tool for Xdmx configuration files
+.SH SYNOPSIS
+.B xdmxconfig
+[filename]
+.SH DESCRIPTION
+.I xdmxconfig
+reads, edits, and writes configuration files for the Xdmx server. The
+grammar for the configuration file is specified in the Xdmx(1) manual
+page.
+.PP
+To start from scratch, create a "New Global" and specify the name and
+overall dimensions for the configuration. Then use "New Display" to
+enter more displays.
+.PP
+If there is more than one configuration, the configuration name button
+will bring up a selection menu.
+.PP
+In the right-hand pannel, the left mouse button will move the
+highlighted display at "tool resolution"; the middle mouse button will
+move the highlighted display by a single pixel (at "wall resolution");
+and the right mouse button will bring up a menu allowing the highlighted
+display to be edited or deleted. The arrow keys will also move the
+highlighted display by a single pixel.
+.SH BUGS
+Currently, entries with the
+.B wall
+keyword are not editable, but will be preserved in the new output file.
+The tool will quit when requested by the user, even if a configuration
+file has not been written out (i.e., without warning). The menu
+interaction should be improved (menu entries that don't currently work
+should be greyed-out, for example). The Help button does not work.
+.SH "SEE ALSO"
+Xdmx(1), vdltodmx(1)
diff --git a/xc/programs/Xserver/hw/dmx/dmx.h b/xc/programs/Xserver/hw/dmx/dmx.h
new file mode 100644
index 000000000..0cf8a88da
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmx.h
@@ -0,0 +1,182 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ * David H. Dawes <dawes@xfree86.org>
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef DMX_H
+#define DMX_H
+
+#include "scrnintstr.h"
+
+#define GC XlibGC
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#undef GC
+
+#define DMX_MAX_SIGIO_FDS 4
+
+typedef enum {
+ PosNone = -1,
+ PosAbsolute = 0,
+ PosRightOf,
+ PosLeftOf,
+ PosAbove,
+ PosBelow,
+ PosRelative
+} PositionType;
+
+typedef struct _DMXScreenInfo {
+ const char *name; /* Name from command line or config file */
+ int index; /* Index into dmxScreens global */
+
+ Display *display;
+
+ Window window;
+ int shared; /* Non-zero if another Xdmx is running */
+ struct _DMXScreenInfo *next; /* List of windows on same display */
+ struct _DMXScreenInfo *over; /* List of windows that overlap */
+
+ /* Geometry and information about window */
+ int width, height, xoff, yoff, xsign, ysign;
+ int depth;
+ int bpp;
+ /* Dimensions of physical display */
+ int displayWidth, displayHeight;
+
+ void *shadow;
+
+ Bool WMRunningOnBE;
+
+ XlibGC gc;
+ XImage *image;
+
+ int numDepths;
+ int *depths;
+
+ int numPixmapFormats;
+ XPixmapFormatValues *pixmapFormats;
+
+ Drawable defDrawables[MAXFORMATS];
+
+ int numVisuals;
+ XVisualInfo *visuals;
+ int defVisualIndex;
+
+ int numDefColormaps;
+ Colormap *defColormaps;
+
+ Pixel blackPixel;
+ Pixel whitePixel;
+
+ Cursor noCursor;
+ Cursor curCursor;
+ /* Support for cursors on overlapped
+ * backend displays. */
+ CursorPtr cursor;
+ int cursorVisible;
+ int cursorNotShared; /* for overlapping screens on a backend */
+
+ /* Relative layout information */
+ PositionType where;
+ int whereX;
+ int whereY;
+ int whereRefScreen;
+
+ /* Absolute layout information -- from dixScreenOrigins */
+ int originX;
+ int originY;
+
+ /* Original screen saver timeout */
+ int savedTimeout;
+
+ CloseScreenProcPtr CloseScreen;
+ SaveScreenProcPtr SaveScreen;
+
+ CreateGCProcPtr CreateGC;
+
+ CreateWindowProcPtr CreateWindow;
+ DestroyWindowProcPtr DestroyWindow;
+ PositionWindowProcPtr PositionWindow;
+ ChangeWindowAttributesProcPtr ChangeWindowAttributes;
+ RealizeWindowProcPtr RealizeWindow;
+ UnrealizeWindowProcPtr UnrealizeWindow;
+ RestackWindowProcPtr RestackWindow;
+ WindowExposuresProcPtr WindowExposures;
+ PaintWindowBackgroundProcPtr PaintWindowBackground;
+ PaintWindowBorderProcPtr PaintWindowBorder;
+ CopyWindowProcPtr CopyWindow;
+
+ ResizeWindowProcPtr ResizeWindow;
+ ReparentWindowProcPtr ReparentWindow;
+
+ ChangeBorderWidthProcPtr ChangeBorderWidth;
+
+ GetImageProcPtr GetImage;
+ GetSpansProcPtr GetSpans;
+
+ CreatePixmapProcPtr CreatePixmap;
+ DestroyPixmapProcPtr DestroyPixmap;
+ BitmapToRegionProcPtr BitmapToRegion;
+
+ RealizeFontProcPtr RealizeFont;
+ UnrealizeFontProcPtr UnrealizeFont;
+
+ CreateColormapProcPtr CreateColormap;
+ DestroyColormapProcPtr DestroyColormap;
+ InstallColormapProcPtr InstallColormap;
+ StoreColorsProcPtr StoreColors;
+} DMXScreenInfo;
+
+/* Typedef DMXInputInfo here because log routines use it. */
+typedef struct _DMXInputInfo DMXInputInfo;
+
+/* Global variables available to all Xserver/hw/dmx routines. */
+extern int dmxNumScreens;
+extern DMXScreenInfo *dmxScreens;
+extern int dmxShadowFB;
+extern XErrorEvent dmxLastErrorEvent;
+extern Bool dmxErrorOccurred;
+
+#define DMX_WRAP(_entry, _newfunc, _saved, _actual) \
+do { \
+ (_saved)->_entry = (_actual)->_entry; \
+ (_actual)->_entry = (_newfunc); \
+} while (0)
+
+#define DMX_UNWRAP(_entry, _saved, _actual) \
+do { \
+ (_actual)->_entry = (_saved)->_entry; \
+} while (0)
+
+#endif /* DMX_H */
diff --git a/xc/programs/Xserver/hw/dmx/dmxcb.c b/xc/programs/Xserver/hw/dmx/dmxcb.c
new file mode 100644
index 000000000..b0def2286
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxcb.c
@@ -0,0 +1,139 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ * This code queries and modifies the connection block.
+ */
+
+#include "dmxcb.h"
+#include "dmx.h"
+#include "dmxlog.h"
+#include "globals.h"
+
+extern char *ConnectionInfo;
+extern int connBlockScreenStart;
+extern int PanoramiXPixWidth;
+extern int PanoramiXPixHeight;
+extern int PanoramiXNumScreens;
+
+ int dmxGlobalWidth, dmxGlobalHeight;
+
+/* We may want the wall dimensions to be different from the bounding box
+ * dimensions that Xinerama computes, so save those and update them
+ * here.
+ */
+void dmxSetWidthHeight(int width, int height)
+{
+ dmxGlobalWidth = width;
+ dmxGlobalHeight = height;
+}
+
+void dmxComputeWidthHeight(void)
+{
+ int i;
+ DMXScreenInfo *dmxScreen;
+ int w = 0;
+ int h = 0;
+
+ for (i = 0; i < dmxNumScreens; i++) {
+ dmxScreen = &dmxScreens[i];
+ if (w < dmxScreen->width + dmxScreen->originX)
+ w = dmxScreen->width + dmxScreen->originX;
+ if (h < dmxScreen->height + dmxScreen->originY)
+ h = dmxScreen->height + dmxScreen->originY;
+ }
+ if (!dmxGlobalWidth && !dmxGlobalHeight) {
+ dmxLog(dmxInfo, "Using %dx%d as global bounding box\n", w, h);
+ } else {
+ dmxLog(dmxInfo,
+ "Using %dx%d as global bounding box, instead of %dx%d\n",
+ w, h, dmxGlobalWidth, dmxGlobalHeight);
+ }
+
+ if (!dmxGlobalWidth) dmxGlobalWidth = w;
+ if (!dmxGlobalHeight) dmxGlobalHeight = h;
+}
+
+void dmxConnectionBlockCallback(void)
+{
+ xWindowRoot *root = (xWindowRoot *)(ConnectionInfo+connBlockScreenStart);
+ int offset = connBlockScreenStart + sizeof(xWindowRoot);
+ int i;
+
+ if(!noPanoramiXExtension) {
+ if (dmxGlobalWidth && dmxGlobalHeight
+ && dmxGlobalWidth != PanoramiXPixWidth
+ && dmxGlobalHeight != PanoramiXPixHeight) {
+ dmxLog(dmxInfo,
+ "Changing Xinerama screen dimensions from %d %d to %d %d\n",
+ PanoramiXPixWidth, PanoramiXPixHeight,
+ dmxGlobalWidth, dmxGlobalHeight);
+ PanoramiXPixWidth = root->pixWidth = dmxGlobalWidth;
+ PanoramiXPixHeight = root->pixHeight = dmxGlobalHeight;
+ } else {
+ dmxGlobalWidth = PanoramiXPixWidth;
+ dmxGlobalHeight = PanoramiXPixHeight;
+ }
+ dmxLog(dmxInfo, "%d screens configured with Xinerama (%d %d)\n",
+ PanoramiXNumScreens, PanoramiXPixWidth, PanoramiXPixHeight);
+ } else {
+ /* This never happens because we're
+ * called from a Xinerama callback. */
+ dmxLog(dmxInfo, "%d screens configured (%d %d)\n",
+ screenInfo.numScreens, root->pixWidth, root->pixHeight);
+ }
+
+ for (i = 0; i < root->nDepths; i++) {
+ xDepth *depth = (xDepth *)(ConnectionInfo + offset);
+ int voffset = offset + sizeof(xDepth);
+ xVisualType *visual = (xVisualType *)(ConnectionInfo + voffset);
+ int j;
+
+ dmxLog(dmxInfo, "%d visuals at depth %d\n",
+ depth->nVisuals, depth->depth);
+ for (j = 0; j < depth->nVisuals; j++, visual++) {
+ XVisualInfo vi;
+
+ vi.visual = NULL;
+ vi.visualid = visual->visualID;
+ vi.screen = 0;
+ vi.depth = depth->depth;
+ vi.class = visual->class;
+ vi.red_mask = visual->redMask;
+ vi.green_mask = visual->greenMask;
+ vi.blue_mask = visual->blueMask;
+ vi.colormap_size = visual->colormapEntries;
+ vi.bits_per_rgb = visual->bitsPerRGB;
+ dmxLogVisual(NULL, &vi, 0);
+ }
+ offset = voffset + depth->nVisuals * sizeof(xVisualType);
+ }
+}
diff --git a/xc/programs/Xserver/hw/dmx/dmxcb.h b/xc/programs/Xserver/hw/dmx/dmxcb.h
new file mode 100644
index 000000000..1acb394eb
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxcb.h
@@ -0,0 +1,42 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef _DMXCB_H_
+#define _DMXCB_H_
+extern int dmxGlobalWidth, dmxGlobalHeight;
+
+extern void dmxSetWidthHeight(int width, int height);
+extern void dmxComputeWidthHeight(void);
+extern void dmxConnectionBlockCallback(void);
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/dmxcmap.c b/xc/programs/Xserver/hw/dmx/dmxcmap.c
new file mode 100644
index 000000000..52ad6eb1d
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxcmap.c
@@ -0,0 +1,153 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ *
+ */
+
+#include "dmx.h"
+#include "dmxcmap.h"
+#include "dmxvisual.h"
+
+#include "micmap.h"
+
+static int dmxInitColormapPrivateFunc(ColormapPtr pColormap)
+{
+ return TRUE;
+}
+
+static Bool dmxAllocateColormapPrivates(ColormapPtr pColormap)
+{
+ static int dmxColormapGeneration;
+ dmxColormapPrivPtr pCmapPriv;
+
+ if (dmxColormapGeneration != serverGeneration) {
+ if ((dmxColormapPrivateIndex
+ = AllocateColormapPrivateIndex(dmxInitColormapPrivateFunc)) < 0)
+ return FALSE;
+
+ dmxColormapGeneration = serverGeneration;
+ }
+
+ pCmapPriv = (dmxColormapPrivPtr)xalloc(sizeof(*pCmapPriv));
+ if (!pCmapPriv)
+ return FALSE;
+
+ DMX_SET_COLORMAP_PRIV(pColormap, pCmapPriv);
+
+ return TRUE;
+}
+
+
+Bool dmxCreateColormap(ColormapPtr pColormap)
+{
+ ScreenPtr pScreen = pColormap->pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxColormapPrivPtr pCmapPriv;
+ VisualPtr pVisual = pColormap->pVisual;
+ Visual *visual;
+ Bool ret = TRUE;
+
+ if (!dmxAllocateColormapPrivates(pColormap))
+ return FALSE;
+
+ pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap);
+
+ visual = dmxLookupVisual(pScreen, pVisual);
+
+ pCmapPriv->cmap = XCreateColormap(dmxScreen->display,
+ dmxScreen->window,
+ visual,
+ (pVisual->class & DynamicClass ?
+ AllocAll : AllocNone));
+ if (!pCmapPriv->cmap)
+ return FALSE;
+
+ DMX_UNWRAP(CreateColormap, dmxScreen, pScreen);
+ if (pScreen->CreateColormap)
+ ret = pScreen->CreateColormap(pColormap);
+ DMX_WRAP(CreateColormap, dmxCreateColormap, dmxScreen, pScreen);
+
+ return ret;
+}
+
+void dmxDestroyColormap(ColormapPtr pColormap)
+{
+ ScreenPtr pScreen = pColormap->pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap);
+
+ XFreeColormap(dmxScreen->display, pCmapPriv->cmap);
+ xfree(pCmapPriv);
+ DMX_SET_COLORMAP_PRIV(pColormap, NULL);
+
+ DMX_UNWRAP(DestroyColormap, dmxScreen, pScreen);
+ if (pScreen->DestroyColormap)
+ pScreen->DestroyColormap(pColormap);
+ DMX_WRAP(DestroyColormap, dmxDestroyColormap, dmxScreen, pScreen);
+}
+
+void dmxInstallColormap(ColormapPtr pColormap)
+{
+ ScreenPtr pScreen = pColormap->pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap);
+
+ DMX_UNWRAP(InstallColormap, dmxScreen, pScreen);
+ if (pScreen->InstallColormap)
+ pScreen->InstallColormap(pColormap);
+ DMX_WRAP(InstallColormap, dmxInstallColormap, dmxScreen, pScreen);
+
+ XInstallColormap(dmxScreen->display, pCmapPriv->cmap);
+ XSync(dmxScreen->display, False);
+}
+
+void dmxStoreColors(ColormapPtr pColormap, int ndef, xColorItem *pdef)
+{
+ ScreenPtr pScreen = pColormap->pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap);
+
+ if (pColormap->pVisual->class & DynamicClass) {
+ XStoreColors(dmxScreen->display, pCmapPriv->cmap,
+ (XColor *)pdef, ndef);
+ XSync(dmxScreen->display, False);
+ }
+
+ DMX_UNWRAP(StoreColors, dmxScreen, pScreen);
+ if (pScreen->StoreColors)
+ pScreen->StoreColors(pColormap, ndef, pdef);
+ DMX_WRAP(StoreColors, dmxStoreColors, dmxScreen, pScreen);
+}
+
+Bool dmxCreateDefColormap(ScreenPtr pScreen)
+{
+ return miCreateDefColormap(pScreen);
+}
diff --git a/xc/programs/Xserver/hw/dmx/dmxcmap.h b/xc/programs/Xserver/hw/dmx/dmxcmap.h
new file mode 100644
index 000000000..e8cc7def4
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxcmap.h
@@ -0,0 +1,61 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ *
+ */
+
+#ifndef DMXCMAP_H
+#define DMXCMAP_H
+
+#include "colormapst.h"
+
+typedef struct _dmxColormapPriv {
+ Colormap cmap;
+} dmxColormapPrivRec, *dmxColormapPrivPtr;
+
+
+extern Bool dmxCreateColormap(ColormapPtr pColormap);
+extern void dmxDestroyColormap(ColormapPtr pColormap);
+extern void dmxInstallColormap(ColormapPtr pColormap);
+extern void dmxStoreColors(ColormapPtr pColormap, int ndef, xColorItem *pdef);
+
+extern Bool dmxCreateDefColormap(ScreenPtr pScreen);
+
+extern int dmxColormapPrivateIndex;
+
+#define DMX_SET_COLORMAP_PRIV(_pCMap, _pCMapPriv) \
+ (_pCMap)->devPrivates[dmxColormapPrivateIndex].ptr \
+ = (pointer)(_pCMapPriv);
+
+#define DMX_GET_COLORMAP_PRIV(_pCMap) \
+ (dmxColormapPrivPtr)(_pCMap)->devPrivates[dmxColormapPrivateIndex].ptr
+
+#endif /* DMXCMAP_H */
diff --git a/xc/programs/Xserver/hw/dmx/dmxcursor.c b/xc/programs/Xserver/hw/dmx/dmxcursor.c
new file mode 100644
index 000000000..65944e8a5
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxcursor.c
@@ -0,0 +1,668 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * David H. Dawes <dawes@xfree86.org>
+ * Kevin E. Martin <kem@redhat.com>
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#include "dmx.h"
+#include "dmxcursor.h"
+#include "dmxlog.h"
+#include "dmxprop.h"
+
+#include "mipointer.h"
+#include "globals.h"
+#include "cursorstr.h"
+
+#define DMX_CURSOR_DEBUG 0
+
+/*
+ * This code is based very closely on the XFree86 equivalent
+ * (xfree86/common/xf86Cursor.c). --DD
+ * This code was then extensively re-written, as explained here. --RF
+ *
+ * The code in xf86Cursor.c used edge lists to implement the
+ * CursorOffScreen function. The edge list computation was complex
+ * (especially in the face of arbitrarily overlapping screens) compared
+ * with the speed savings in the CursorOffScreen function. The new
+ * implementation has erred on the side of correctness, readability, and
+ * maintainability over efficiency. For the common (non-edge) case, the
+ * dmxCursorOffScreen function does avoid a loop over all the screens.
+ * When the cursor has left the screen, all the screens are searched,
+ * and the first screen (in dmxScreens order) containing the cursor will
+ * be returned. If run-time profiling shows that this routing is a
+ * performance bottle-neck, then an edge list may have to be
+ * reimplemented. An edge list algorithm is O(edges) whereas the new
+ * algorithm is O(dmxNumScreens). Since edges is usually 1-3 and
+ * dmxNumScreens may be 30-60 for large backend walls, this trade off
+ * may be compelling.
+ *
+ * The xf86InitOrigins routine uses bit masks during the computation and
+ * is therefore limited to the length of a word (e.g., 32 or 64 bits)
+ * screens. Because Xdmx is expected to be used with a large number of
+ * backend displays, this limitation was removed. The new
+ * implementation has erred on the side of readability over efficiency,
+ * using the dmxSL* routines to manage a screen list instead of a
+ * bitmap, and a function call to decrease the length of the main
+ * routine. Both algorithms are of the same order, and both are called
+ * only at server generation time, so trading clarity and long-term
+ * maintainability for efficiency does not seem justified in this case.
+ */
+
+static int dmxCursorDoMultiCursors = 1;
+
+void dmxCursorNoMulti(void)
+{
+ dmxCursorDoMultiCursors = 0;
+}
+
+static Bool dmxCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y)
+{
+ DMXScreenInfo *dmxScreen;
+ int i;
+ int localX = *x;
+ int localY = *y;
+ int globalX;
+ int globalY;
+
+ if (screenInfo.numScreens == 1) return FALSE;
+
+ /* On current screen? */
+ dmxScreen = &dmxScreens[(*ppScreen)->myNum];
+ if (localX >= 0
+ && localX < dmxScreen->width
+ && localY >= 0
+ && localY < dmxScreen->height) return FALSE;
+
+ /* Convert to global coordinate space */
+ globalX = dmxScreen->originX + localX;
+ globalY = dmxScreen->originY + localY;
+
+ /* Is cursor on the current screen?
+ * This efficiently exists this routine
+ * for the most common case. */
+ if (ppScreen && *ppScreen) {
+ dmxScreen = &dmxScreens[(*ppScreen)->myNum];
+ if (globalX >= dmxScreen->originX
+ && globalX < dmxScreen->originX + dmxScreen->width
+ && globalY >= dmxScreen->originY
+ && globalY < dmxScreen->originY + dmxScreen->height) return FALSE;
+ }
+
+ /* Find first screen cursor is on */
+ for (i = 0; i < dmxNumScreens; i++) {
+ dmxScreen = &dmxScreens[i];
+ if (globalX >= dmxScreen->originX
+ && globalX < dmxScreen->originX + dmxScreen->width
+ && globalY >= dmxScreen->originY
+ && globalY < dmxScreen->originY + dmxScreen->height) {
+ if (dmxScreen->index == (*ppScreen)->myNum) return FALSE;
+ *ppScreen = screenInfo.screens[dmxScreen->index];
+ *x = globalX - dmxScreen->originX;
+ *y = globalY - dmxScreen->originY;
+ return TRUE;
+ }
+ }
+ return FALSE; /* FIXME? What if it's not on any screen? */
+}
+
+static void dmxCrossScreen(ScreenPtr pScreen, Bool entering)
+{
+}
+
+static void dmxWarpCursor(ScreenPtr pScreen, int x, int y)
+{
+#if DMX_CURSOR_DEBUG
+ dmxLog(dmxDebug, "dmxWarpCursor(%d,%d,%d)\n", pScreen->myNum, x, y);
+#endif
+ miPointerWarpCursor(pScreen, x, y);
+}
+
+miPointerScreenFuncRec dmxPointerCursorFuncs =
+{
+ dmxCursorOffScreen,
+ dmxCrossScreen,
+ dmxWarpCursor,
+};
+
+
+/* Create a list of screens that we'll manipulate. */
+static int *dmxSLCreate(void)
+{
+ int *list = malloc(dmxNumScreens * sizeof(*list));
+ int i;
+
+ for (i = 0; i < dmxNumScreens; i++) list[i] = 1;
+ return list;
+}
+
+static void dmxSLFree(int *list)
+{
+ free(list);
+}
+
+static int dmxSLFindNext(int *list)
+{
+ int i;
+ for (i = 0; i < dmxNumScreens; i++) if (list[i]) return i;
+ return -1;
+}
+
+/* Make one pass over all the screens and return the number updated. */
+static int dmxTryComputeScreenOrigins(int *screensLeft)
+{
+ ScreenPtr pScreen;
+ DMXScreenInfo *screen;
+ int i, ref;
+ int changed = 0;
+
+ for (i = 0; i < dmxNumScreens; i++) {
+ if (!screensLeft[i]) continue;
+ screen = &dmxScreens[i];
+ switch (screen->where) {
+ case PosAbsolute:
+ dixScreenOrigins[i].x = screen->whereX;
+ dixScreenOrigins[i].y = screen->whereY;
+ ++changed, screensLeft[i] = 0;
+ break;
+ case PosRelative:
+ ref = screen->whereRefScreen;
+ if (screensLeft[ref]) break;
+ dixScreenOrigins[i].x = dixScreenOrigins[ref].x + screen->whereX;
+ dixScreenOrigins[i].y = dixScreenOrigins[ref].y + screen->whereY;
+ ++changed, screensLeft[i] = 0;
+ break;
+ case PosRightOf:
+ ref = screen->whereRefScreen;
+ if (screensLeft[ref]) break;
+ pScreen = screenInfo.screens[ref];
+ dixScreenOrigins[i].x = dixScreenOrigins[ref].x + pScreen->width;
+ dixScreenOrigins[i].y = dixScreenOrigins[ref].y;
+ ++changed, screensLeft[i] = 0;
+ break;
+ case PosLeftOf:
+ ref = screen->whereRefScreen;
+ if (screensLeft[ref]) break;
+ pScreen = screenInfo.screens[i];
+ dixScreenOrigins[i].x = dixScreenOrigins[ref].x - pScreen->width;
+ dixScreenOrigins[i].y = dixScreenOrigins[ref].y;
+ ++changed, screensLeft[i] = 0;
+ break;
+ case PosBelow:
+ ref = screen->whereRefScreen;
+ if (screensLeft[ref]) break;
+ pScreen = screenInfo.screens[ref];
+ dixScreenOrigins[i].x = dixScreenOrigins[ref].x;
+ dixScreenOrigins[i].y = dixScreenOrigins[ref].y + pScreen->height;
+ ++changed, screensLeft[i] = 0;
+ break;
+ case PosAbove:
+ ref = screen->whereRefScreen;
+ if (screensLeft[ref]) break;
+ pScreen = screenInfo.screens[i];
+ dixScreenOrigins[i].x = dixScreenOrigins[ref].x;
+ dixScreenOrigins[i].y = dixScreenOrigins[ref].y - pScreen->height;
+ ++changed, screensLeft[i] = 0;
+ break;
+ case PosNone:
+ dmxLog(dmxFatal, "No position information for screen %d\n", i);
+ }
+ }
+ return changed;
+}
+
+static void dmxComputeScreenOrigins(void)
+{
+ int *screensLeft;
+ int i, ref;
+ int minX, minY;
+
+ /* Compute origins based on
+ * configuration information. */
+ screensLeft = dmxSLCreate();
+ while ((i = dmxSLFindNext(screensLeft)) >= 0) {
+ while (dmxTryComputeScreenOrigins(screensLeft));
+ if ((i = dmxSLFindNext(screensLeft)) >= 0) {
+ /* All of the remaining screens are referencing each other.
+ * Assign a value to one of them and go through again. This
+ * guarantees that we will eventually terminate.
+ */
+ ref = dmxScreens[i].whereRefScreen;
+ dixScreenOrigins[ref].x = dixScreenOrigins[ref].y = 0;
+ screensLeft[i] = 0;
+ }
+ }
+ dmxSLFree(screensLeft);
+
+
+ /* Justify the topmost and leftmost to
+ * (0,0). */
+ minX = dixScreenOrigins[0].x;
+ minY = dixScreenOrigins[0].y;
+ for (i = 1; i < dmxNumScreens; i++) { /* Compute minX, minY */
+ if (dixScreenOrigins[i].x < minX) minX = dixScreenOrigins[i].x;
+ if (dixScreenOrigins[i].y < minY) minY = dixScreenOrigins[i].y;
+ }
+ if (minX || minY) {
+ for (i = 0; i < dmxNumScreens; i++) {
+ dixScreenOrigins[i].x -= minX;
+ dixScreenOrigins[i].y -= minY;
+ }
+ }
+}
+
+void dmxInitOrigins(void)
+{
+ int i;
+
+ if (dmxNumScreens > MAXSCREENS)
+ dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n",
+ dmxNumScreens, MAXSCREENS);
+
+ dmxComputeScreenOrigins();
+
+ /* Copy information to local structure */
+ for (i = 0; i < dmxNumScreens; i++) {
+ DMXScreenInfo *dmxScreen = &dmxScreens[i];
+ dmxScreen->originX = dixScreenOrigins[i].x;
+ dmxScreen->originY = dixScreenOrigins[i].y;
+ }
+
+ for (i = 0; i < dmxNumScreens; i++) {
+ DMXScreenInfo *dmxScreen = &dmxScreens[i];
+ dmxLogOutput(dmxScreen,
+ "%dx%d+%d+%d @%dx%d (physical=%dx%d, depth=%d, bpp=%d)\n",
+ dmxScreen->width, dmxScreen->height,
+ dmxScreen->xoff, dmxScreen->yoff,
+ dmxScreen->originX, dmxScreen->originY,
+ dmxScreen->displayWidth, dmxScreen->displayHeight,
+ dmxScreen->depth, dmxScreen->bpp);
+ }
+}
+
+static int dmxOnScreen(int x, int y, DMXScreenInfo *dmxScreen)
+{
+ if (x >= dmxScreen->originX
+ && x < dmxScreen->originX + dmxScreen->width
+ && y >= dmxScreen->originY
+ && y < dmxScreen->originY + dmxScreen->height) return 1;
+ return 0;
+}
+
+static int dmxDoesOverlap(DMXScreenInfo *a, DMXScreenInfo *b)
+{
+ if (dmxOnScreen(a->originX, a->originY, b)) return 1;
+ if (dmxOnScreen(a->originX, a->originY+a->width, b)) return 1;
+ if (dmxOnScreen(a->originX+a->height, a->originY, b)) return 1;
+ if (dmxOnScreen(a->originX+a->height, a->originY+a->width, b)) return 1;
+ if (dmxOnScreen(b->originX, b->originY, a)) return 1;
+ if (dmxOnScreen(b->originX, b->originY+b->width, a)) return 1;
+ if (dmxOnScreen(b->originX+b->height, b->originY, a)) return 1;
+ if (dmxOnScreen(b->originX+b->height, b->originY+b->width, a)) return 1;
+ return 0;
+}
+
+static void *dmxPrintOverlap(DMXScreenInfo *dmxScreen, void *closure)
+{
+ DMXScreenInfo *a = closure;
+ if (dmxScreen != a) {
+ if (dmxScreen->cursorNotShared)
+ dmxLogAdditional(a, " [%d/%s]", dmxScreen->index, dmxScreen->name);
+ else
+ dmxLogAdditional(a, " %d/%s", dmxScreen->index, dmxScreen->name);
+ }
+ return NULL;
+}
+
+static void *dmxIterateOverlap(DMXScreenInfo *start,
+ void *(*f)(DMXScreenInfo *dmxScreen, void *),
+ void *closure)
+{
+ DMXScreenInfo *pt;
+
+ if (!start->over) return f(start, closure);
+
+ for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
+ void *retval;
+ if ((retval = f(pt, closure))) return retval;
+ if (pt == start) break;
+ }
+ return NULL;
+}
+
+static void *dmxTestSameDisplay(DMXScreenInfo *a, void *closure)
+{
+ DMXScreenInfo *b = closure;
+
+ if (a == b) return a;
+ return NULL;
+}
+
+/* Detects overlapping dmxScreens and creates circular lists. This uses
+ * an O(dmxNumScreens^2) algorithm, but dmxNumScreens is < 100 and the
+ * computation only needs to be performed every server generation. */
+void dmxInitOverlap(void)
+{
+ int i, j;
+ DMXScreenInfo *a, *b, *pt;
+
+ for (i = 0; i < dmxNumScreens; i++) {
+ a = &dmxScreens[i];
+
+ for (j = i+1; j < dmxNumScreens; j++) {
+ b = &dmxScreens[j];
+ if (b->over) continue;
+
+ if (dmxDoesOverlap(a, b)) {
+ dmxLog(dmxDebug, "%d overlaps %d: a=%p %p b=%p %p\n",
+ a->index, b->index, a, a->over, b, b->over);
+ b->over = (a->over ? a->over : a);
+ a->over = b;
+ }
+ }
+ }
+
+ for (i = 0; i < dmxNumScreens; i++) {
+ a = &dmxScreens[i];
+
+ if (!a->over) continue;
+
+ /* Flag all pairs that are on same display */
+ for (pt = a->over; pt != a; pt = pt->over) {
+ if (dmxPropertyIterate(a, dmxTestSameDisplay, pt)) {
+ /* The ->over sets contain the transitive set of screens
+ * that overlap. For screens that are on the same
+ * backend display, we only want to exclude pairs of
+ * screens that mutually overlap on the backend display,
+ * so we call dmxDoesOverlap, which is stricter than the
+ * ->over set. */
+ if (!dmxDoesOverlap(a, pt)) continue;
+ a->cursorNotShared = 1;
+ pt->cursorNotShared = 1;
+ dmxLog(dmxDebug,
+ "Overlapping screens on same backend display: %d %d\n",
+ a->index, pt->index);
+ }
+ }
+ }
+
+ for (i = 0; i < dmxNumScreens; i++) {
+ a = &dmxScreens[i];
+
+ if (a->over) {
+ dmxLogOutput(a, "Overlaps");
+ dmxIterateOverlap(a, dmxPrintOverlap, a);
+ dmxLogAdditional(a, "\n");
+ }
+ }
+}
+
+static Bool _dmxRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ CursorBitsPtr pBits = pCursor->bits;
+ dmxCursorPrivPtr pCursorPriv;
+ Pixmap src, msk;
+ XColor fg, bg;
+ XImage *img;
+ XlibGC gc = NULL;
+ XGCValues v;
+ unsigned long m;
+ int i;
+
+#if DMX_CURSOR_DEBUG
+ dmxLog(dmxDebug, "_dmxRealizeCursor(%d,%p)\n", pScreen->myNum, pCursor);
+#endif
+
+ pCursor->devPriv[pScreen->myNum] = xalloc(sizeof(*pCursorPriv));
+ if (!pCursor->devPriv[pScreen->myNum])
+ return FALSE;
+
+ m = GCFunction | GCPlaneMask | GCForeground | GCBackground | GCClipMask;
+ v.function = GXcopy;
+ v.plane_mask = AllPlanes;
+ v.foreground = 1L;
+ v.background = 0L;
+ v.clip_mask = None;
+
+ for (i = 0; i < dmxScreen->numPixmapFormats; i++) {
+ if (dmxScreen->pixmapFormats[i].depth == 1) {
+ /* Create GC in the back-end servers */
+ gc = XCreateGC(dmxScreen->display, dmxScreen->defDrawables[i],
+ m, &v);
+ break;
+ }
+ }
+ if (!gc)
+ dmxLog(dmxFatal, "dmxRealizeCursor: gc not initialized\n");
+
+ src = XCreatePixmap(dmxScreen->display, dmxScreen->window,
+ pBits->width, pBits->height, 1);
+ msk = XCreatePixmap(dmxScreen->display, dmxScreen->window,
+ pBits->width, pBits->height, 1);
+
+ img = XCreateImage(dmxScreen->display,
+ dmxScreen->visuals[dmxScreen->defVisualIndex].visual,
+ 1, XYBitmap, 0, (char *)pBits->source,
+ pBits->width, pBits->height,
+ BitmapPad(dmxScreen->display), 0);
+
+ XPutImage(dmxScreen->display, src, gc, img, 0, 0, 0, 0,
+ pBits->width, pBits->height);
+
+ XFree(img);
+
+ img = XCreateImage(dmxScreen->display,
+ dmxScreen->visuals[dmxScreen->defVisualIndex].visual,
+ 1, XYBitmap, 0, (char *)pBits->mask,
+ pBits->width, pBits->height,
+ BitmapPad(dmxScreen->display), 0);
+
+ XPutImage(dmxScreen->display, msk, gc, img, 0, 0, 0, 0,
+ pBits->width, pBits->height);
+
+ XFree(img);
+
+ fg.red = pCursor->foreRed;
+ fg.green = pCursor->foreGreen;
+ fg.blue = pCursor->foreBlue;
+
+ bg.red = pCursor->backRed;
+ bg.green = pCursor->backGreen;
+ bg.blue = pCursor->backBlue;
+
+ pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
+ pCursorPriv->cursor = XCreatePixmapCursor(dmxScreen->display,
+ src, msk,
+ &fg, &bg,
+ pBits->xhot, pBits->yhot);
+
+ XFreePixmap(dmxScreen->display, src);
+ XFreePixmap(dmxScreen->display, msk);
+ XFreeGC(dmxScreen->display, gc);
+
+ XSync(dmxScreen->display, False);
+ return TRUE;
+}
+
+static Bool _dmxUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
+
+#if DMX_CURSOR_DEBUG
+ dmxLog(dmxDebug, "_dmxUnrealizeCursor(%d,%p) %p\n",
+ pScreen->myNum, pCursor, pCursorPriv);
+#endif
+
+ if (pCursorPriv) {
+ XFreeCursor(dmxScreen->display, pCursorPriv->cursor);
+ xfree(pCursor->devPriv[pScreen->myNum]);
+ }
+ pCursor->devPriv[pScreen->myNum] = NULL;
+
+ return TRUE;
+}
+
+static void _dmxMoveCursor(ScreenPtr pScreen, int x, int y)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+
+#if 0 && DMX_CURSOR_DEBUG
+ dmxLog(dmxDebug, "_dmxMoveCursor(%d,%d,%d)\n", pScreen->myNum, x, y);
+#endif
+ XWarpPointer(dmxScreen->display, None, dmxScreen->window,
+ 0, 0, 0, 0, x, y);
+ XSync(dmxScreen->display, False);
+}
+
+static void _dmxSetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+
+#if DMX_CURSOR_DEBUG
+ dmxLog(dmxDebug, "_dmxSetCursor(%d,%p,%d,%d)\n",
+ pScreen->myNum, pCursor, x, y);
+#endif
+ if (pCursor) {
+ dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
+ if (dmxScreen->curCursor != pCursorPriv->cursor) {
+ XDefineCursor(dmxScreen->display, dmxScreen->window,
+ pCursorPriv->cursor);
+ dmxScreen->curCursor = pCursorPriv->cursor;
+ }
+ _dmxMoveCursor(pScreen, x, y);
+ } else {
+ XDefineCursor(dmxScreen->display, dmxScreen->window,
+ dmxScreen->noCursor);
+ dmxScreen->curCursor = (Cursor)0;
+ }
+ XSync(dmxScreen->display, False);
+}
+
+static Bool dmxRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
+{
+ DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
+ DMXScreenInfo *pt;
+
+ if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared)
+ return _dmxRealizeCursor(pScreen, pCursor);
+
+ for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
+ if (pt->cursorNotShared) continue;
+ _dmxRealizeCursor(screenInfo.screens[pt->index], pCursor);
+ if (pt == start) break;
+ }
+ return TRUE;
+}
+
+static Bool dmxUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
+{
+ DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
+ DMXScreenInfo *pt;
+
+ if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared)
+ return _dmxUnrealizeCursor(pScreen, pCursor);
+
+ for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
+ if (pt->cursorNotShared) continue;
+ _dmxUnrealizeCursor(screenInfo.screens[pt->index], pCursor);
+ if (pt == start) break;
+ }
+ return TRUE;
+}
+
+static void dmxMoveCursor(ScreenPtr pScreen, int x, int y)
+{
+ DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
+ DMXScreenInfo *pt;
+
+ if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) {
+ _dmxMoveCursor(pScreen, x, y);
+ return;
+ }
+
+ for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
+ if (pt->cursorNotShared) continue;
+ if (dmxOnScreen(x + start->originX, y + start->originY, pt)) {
+ if (pt != start && !pt->cursorVisible) {
+ _dmxSetCursor(screenInfo.screens[pt->index],
+ pt->cursor,
+ x + start->originX - pt->originX,
+ y + start->originY - pt->originY);
+ pt->cursorVisible = 1;
+ }
+ _dmxMoveCursor(screenInfo.screens[pt->index],
+ x + start->originX - pt->originX,
+ y + start->originY - pt->originY);
+ } else if (pt != start && pt->cursorVisible) {
+ _dmxSetCursor(screenInfo.screens[pt->index],
+ NULL,
+ x + start->originX - pt->originX,
+ y + start->originY - pt->originY);
+ pt->cursorVisible = 0;
+ }
+ if (pt == start) break;
+ }
+}
+
+static void dmxSetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
+{
+ DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
+ DMXScreenInfo *pt;
+
+ if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) {
+ _dmxSetCursor(pScreen, pCursor, x, y);
+ return;
+ }
+
+ for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
+ if (pt->cursorNotShared) continue;
+ if (dmxOnScreen(x + start->originX, y + start->originY, pt)) {
+ _dmxSetCursor(screenInfo.screens[pt->index], pCursor,
+ x + start->originX - pt->originX,
+ y + start->originY - pt->originY);
+ pt->cursorVisible = 1;
+ } else
+ pt->cursorVisible = 0;
+ pt->cursor = pCursor;
+ if (pt == start) break;
+ }
+}
+
+miPointerSpriteFuncRec dmxPointerSpriteFuncs =
+{
+ dmxRealizeCursor,
+ dmxUnrealizeCursor,
+ dmxSetCursor,
+ dmxMoveCursor,
+};
diff --git a/xc/programs/Xserver/hw/dmx/dmxcursor.h b/xc/programs/Xserver/hw/dmx/dmxcursor.h
new file mode 100644
index 000000000..b069310ee
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxcursor.h
@@ -0,0 +1,56 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * David H. Dawes <dawes@xfree86.org>
+ * Kevin E. Martin <kem@redhat.com>
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef DMXCURSOR_H
+#define DMXCURSOR_H
+
+#include "mipointer.h"
+
+typedef struct _dmxCursorPriv {
+ Cursor cursor;
+} dmxCursorPrivRec, *dmxCursorPrivPtr;
+
+extern miPointerScreenFuncRec dmxPointerCursorFuncs;
+extern miPointerSpriteFuncRec dmxPointerSpriteFuncs;
+
+extern void dmxInitOrigins(void);
+extern void dmxInitOverlap(void);
+extern void dmxCursorNoMulti(void);
+
+#define DMX_GET_CURSOR_PRIV(_pCursor, _pScreen) \
+ (dmxCursorPrivPtr)(_pCursor)->devPriv[(_pScreen)->myNum]
+
+#endif /* DMXCURSOR_H */
diff --git a/xc/programs/Xserver/hw/dmx/dmxdpms.c b/xc/programs/Xserver/hw/dmx/dmxdpms.c
new file mode 100644
index 000000000..acd9fcf76
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxdpms.c
@@ -0,0 +1,54 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ * David H. Dawes <dawes@xfree86.org>
+ *
+ */
+
+#include "misc.h"
+
+#ifdef DPMSExtension
+#include "dpmsproc.h"
+
+void DPMSSet(int level)
+{
+}
+
+int DPMSGet(int *level)
+{
+ return -1;
+}
+
+Bool DPMSSupported(void)
+{
+ return FALSE;
+}
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/dmxfont.c b/xc/programs/Xserver/hw/dmx/dmxfont.c
new file mode 100644
index 000000000..55f604ca8
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxfont.c
@@ -0,0 +1,302 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ *
+ */
+
+#include "dmx.h"
+#include "dmxfont.h"
+#include "dmxlog.h"
+
+#include "fontstruct.h"
+#include "dixfont.h"
+#include "dixstruct.h"
+
+#define DMX_FONTPATH_DEBUG 0
+
+static int dmxFontLastError;
+
+static int dmxFontErrorHandler(Display *dpy, XErrorEvent *ev)
+{
+ dmxFontLastError = ev->error_code;
+
+ return 0;
+}
+
+static char **dmxGetFontPath(int *npaths)
+{
+ char **fp;
+ unsigned char *c, *paths;
+ char *newfp;
+ int len, l, i;
+
+ paths = GetFontPath(npaths, &len);
+
+ c = newfp = xalloc(*npaths + len);
+ fp = xalloc(*npaths * sizeof(*fp));
+
+ memmove(newfp, paths+1, *npaths + len - 1);
+ l = *paths;
+ for (i = 0; i < *npaths; i++) {
+ fp[i] = c;
+ c += l;
+ l = *c;
+ *c++ = '\0';
+ }
+
+#if DMX_FONTPATH_DEBUG
+ for (i = 0; i < *npaths; i++)
+ dmxLog(dmxDebug, "FontPath[%d] = %s\n", i, fp[i]);
+#endif
+
+ return fp;
+}
+
+static void dmxFreeFontPath(char **fp)
+{
+ xfree(fp[0]);
+ xfree(fp);
+}
+
+static int dmxSetFontPath(DMXScreenInfo *dmxScreen)
+{
+ int (*oldErrorHandler)(Display *, XErrorEvent *);
+ char **fp;
+ int result = Success;
+ int npaths;
+
+ fp = dmxGetFontPath(&npaths);
+ if (!fp) return BadAlloc;
+
+ dmxFontLastError = 0;
+ oldErrorHandler = XSetErrorHandler(dmxFontErrorHandler);
+ XSetFontPath(dmxScreen->display, fp, npaths);
+ XSync(dmxScreen->display, False);
+ XSetErrorHandler(oldErrorHandler);
+
+ if (dmxFontLastError) {
+ result = dmxFontLastError;
+ /* We could set *error here to the offending path, but it is
+ * ignored, so we don't bother figuring out which path is bad.
+ * If we do add this support in the future, we'll need to add
+ * error to the function's argument list.
+ */
+ }
+
+ dmxFreeFontPath(fp);
+
+ return result;
+}
+
+static int dmxCheckFontPath(DMXScreenInfo *dmxScreen, int *error)
+{
+ char **oldFontPath;
+ int nOldPaths;
+ int result = Success;
+
+ /* Save old font path */
+ oldFontPath = XGetFontPath(dmxScreen->display, &nOldPaths);
+
+ result = dmxSetFontPath(dmxScreen);
+
+ /* Restore old font path */
+ XSetFontPath(dmxScreen->display, oldFontPath, nOldPaths);
+ XFreeFontPath(oldFontPath);
+ XSync(dmxScreen->display, False);
+
+ return result;
+}
+
+static int dmxProcSetFontPath(ClientPtr client)
+{
+ unsigned char *ptr;
+ unsigned long nbytes, total;
+ long nfonts;
+ int i, n, result;
+ int error;
+ unsigned char *oldFontPath, *tmpFontPath;
+ int nOldPaths;
+ int lenOldPaths;
+ 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;
+
+ tmpFontPath = GetFontPath(&nOldPaths, &lenOldPaths);
+ oldFontPath = xalloc(nOldPaths + lenOldPaths);
+ memmove(oldFontPath, tmpFontPath, nOldPaths + lenOldPaths);
+
+ result = SetFontPath(client, stuff->nFonts, (unsigned char *)&stuff[1],
+ &error);
+ if (!result) {
+ for (i = 0; i < dmxNumScreens; i++)
+ if ((result = dmxCheckFontPath(&dmxScreens[i], &error)))
+ break;
+
+ if (result) {
+ int ignoreresult, ignoreerror;
+
+ /* Restore old fontpath in the DMX server */
+ ignoreresult = SetFontPath(client, nOldPaths, oldFontPath,
+ &ignoreerror);
+ } else {
+ result = client->noClientException;
+ client->errorValue = error;
+ }
+ }
+
+ xfree(oldFontPath);
+ return result;
+}
+
+void dmxInitFonts(void)
+{
+ /* FIXME: Currently we simply substitute our routine in the proc
+ * vector; however, in the extension we will need to save it at
+ * extension init and restore it at extension reset.
+ */
+ ProcVector[X_SetFontPath] = dmxProcSetFontPath;
+}
+
+Bool dmxRealizeFont(ScreenPtr pScreen, FontPtr pFont)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxFontPrivPtr pFontPriv;
+ char *name;
+ char **oldFontPath;
+ int nOldPaths;
+ Atom name_atom, value_atom;
+ int i;
+
+ if (!(pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex))) {
+ FontSetPrivate(pFont, dmxFontPrivateIndex, NULL);
+ pFontPriv = xalloc(sizeof(dmxFontPrivRec));
+ if (!pFontPriv) return FALSE;
+ pFontPriv->refcnt = 0;
+ }
+
+ FontSetPrivate(pFont, dmxFontPrivateIndex, (pointer)pFontPriv);
+
+ /* Save old font path */
+ oldFontPath = XGetFontPath(dmxScreen->display, &nOldPaths);
+
+ /* Set the font path for the font about to be loaded on the back-end */
+ if (dmxSetFontPath(dmxScreen)) {
+ char **fp;
+ int npaths;
+
+ /* This could fail only when first starting the X server and
+ * loading the default font. If it fails here, then the default
+ * font path is invalid.
+ */
+ fp = dmxGetFontPath(&npaths);
+
+ dmxLog(dmxError,
+ "The DMX server failed to set the font path on the "
+ "back-end servers\n");
+ dmxLog(dmxError,
+ "The font path that the DMX server tried to set was:\n");
+ for (i = 0; i < npaths; i++)
+ dmxLog(dmxError, " %s\n", fp[i]);
+ dmxLog(dmxError,
+ "Please see the Xdmx man page for information on how to "
+ "initialize\n");
+ dmxLog(dmxError,
+ "the DMX server's font path with \"-fontpath\"\n");
+
+ dmxFreeFontPath(fp);
+ XFreeFontPath(oldFontPath);
+ return FALSE;
+ }
+
+ /* Find requested font on back-end server */
+ name_atom = MakeAtom("FONT", 4, True);
+ value_atom = 0L;
+
+ for (i = 0; i < pFont->info.nprops; i++) {
+ if (pFont->info.props[i].name == name_atom) {
+ value_atom = pFont->info.props[i].value;
+ break;
+ }
+ }
+ if (!value_atom) return FALSE;
+
+ name = (char *)NameForAtom(value_atom);
+ if (!name) return FALSE;
+
+ pFontPriv->font[pScreen->myNum] = XLoadQueryFont(dmxScreen->display, name);
+
+ /* Restore old font path */
+ XSetFontPath(dmxScreen->display, oldFontPath, nOldPaths);
+ XFreeFontPath(oldFontPath);
+ XSync(dmxScreen->display, False);
+
+ if (!pFontPriv->font[pScreen->myNum]) return FALSE;
+
+ pFontPriv->refcnt++;
+
+ return TRUE;
+}
+
+Bool dmxUnrealizeFont(ScreenPtr pScreen, FontPtr pFont)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxFontPrivPtr pFontPriv;
+
+ if ((pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex))) {
+ /* In case the font failed to load properly */
+ if (!pFontPriv->refcnt) {
+ xfree(pFontPriv);
+ FontSetPrivate(pFont, dmxFontPrivateIndex, NULL);
+ } else if (pFontPriv->font[pScreen->myNum]) {
+ XFreeFont(dmxScreen->display, pFontPriv->font[pScreen->myNum]);
+ if (--pFontPriv->refcnt == 0) {
+ xfree(pFontPriv);
+ FontSetPrivate(pFont, dmxFontPrivateIndex, NULL);
+ }
+ }
+ }
+
+ return TRUE;
+}
diff --git a/xc/programs/Xserver/hw/dmx/dmxfont.h b/xc/programs/Xserver/hw/dmx/dmxfont.h
new file mode 100644
index 000000000..75720c25c
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxfont.h
@@ -0,0 +1,51 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ *
+ */
+
+#ifndef DMXFONT_H
+#define DMXFONT_H
+
+#include "fontstruct.h"
+
+typedef struct _dmxFontPriv {
+ int refcnt;
+ XFontStruct *font[MAXSCREENS];
+} dmxFontPrivRec, *dmxFontPrivPtr;
+
+extern void dmxInitFonts(void);
+extern Bool dmxRealizeFont(ScreenPtr pScreen, FontPtr pFont);
+extern Bool dmxUnrealizeFont(ScreenPtr pScreen, FontPtr pFont);
+
+extern int dmxFontPrivateIndex;
+
+#endif /* DMXFONT_H */
diff --git a/xc/programs/Xserver/hw/dmx/dmxgc.c b/xc/programs/Xserver/hw/dmx/dmxgc.c
new file mode 100644
index 000000000..6df2bb97b
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxgc.c
@@ -0,0 +1,338 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ *
+ */
+
+#include "dmx.h"
+#include "dmxgc.h"
+#include "dmxgcops.h"
+#include "dmxpixmap.h"
+#include "dmxfont.h"
+
+#include "gcstruct.h"
+#include "pixmapstr.h"
+
+static GCFuncs dmxGCFuncs = {
+ dmxValidateGC,
+ dmxChangeGC,
+ dmxCopyGC,
+ dmxDestroyGC,
+ dmxChangeClip,
+ dmxDestroyClip,
+ dmxCopyClip,
+};
+
+static GCOps dmxGCOps = {
+ dmxFillSpans,
+ dmxSetSpans,
+ dmxPutImage,
+ dmxCopyArea,
+ dmxCopyPlane,
+ dmxPolyPoint,
+ dmxPolylines,
+ dmxPolySegment,
+ dmxPolyRectangle,
+ dmxPolyArc,
+ dmxFillPolygon,
+ dmxPolyFillRect,
+ dmxPolyFillArc,
+ dmxPolyText8,
+ dmxPolyText16,
+ dmxImageText8,
+ dmxImageText16,
+ dmxImageGlyphBlt,
+ dmxPolyGlyphBlt,
+ dmxPushPixels
+};
+
+Bool dmxInitGC(ScreenPtr pScreen)
+{
+ if (!AllocateGCPrivate(pScreen, dmxGCPrivateIndex, sizeof(dmxGCPrivRec)))
+ return FALSE;
+
+ return TRUE;
+}
+
+Bool dmxCreateGC(GCPtr pGC)
+{
+ ScreenPtr pScreen = pGC->pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+ Bool ret;
+ int i;
+
+ DMX_UNWRAP(CreateGC, dmxScreen, pScreen);
+ if ((ret = pScreen->CreateGC(pGC))) {
+ /* Save the old funcs */
+ pGCPriv->funcs = pGC->funcs;
+ pGCPriv->ops = NULL;
+
+ pGC->funcs = &dmxGCFuncs;
+
+ for (i = 0; i < dmxScreen->numPixmapFormats; i++) {
+ if (pGC->depth == dmxScreen->pixmapFormats[i].depth) {
+ /* Create GC in the back-end servers */
+ pGCPriv->gc = XCreateGC(dmxScreen->display,
+ dmxScreen->defDrawables[i],
+ 0L, NULL);
+
+ /* Check for "magic special case"
+ * 1. see CreateGC in dix/gc.c for more info
+ * 2. see dmxChangeGC for more info
+ */
+ pGCPriv->msc = (!pGC->tileIsPixel && !pGC->tile.pixmap);
+ break;
+ }
+ }
+ }
+ DMX_WRAP(CreateGC, dmxCreateGC, dmxScreen, pScreen);
+
+ return ret;
+}
+
+void dmxValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
+{
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+
+ DMX_GC_FUNC_PROLOGUE(pGC);
+#if 0
+ pGC->funcs->ValidateGC(pGC, changes, pDrawable);
+#endif
+
+ if (pDrawable->type == DRAWABLE_WINDOW ||
+ pDrawable->type == DRAWABLE_PIXMAP) {
+ /* Save the old ops, since we're about to change the ops in the
+ * epilogue.
+ */
+ pGCPriv->ops = pGC->ops;
+ } else {
+ pGCPriv->ops = NULL;
+ }
+
+ DMX_GC_FUNC_EPILOGUE(pGC);
+}
+
+void dmxChangeGC(GCPtr pGC, unsigned long mask)
+{
+ ScreenPtr pScreen = pGC->pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+ XGCValues v;
+
+ DMX_GC_FUNC_PROLOGUE(pGC);
+#if 0
+ pGC->funcs->ChangeGC(pGC, mask);
+#endif
+
+ /* Handle "magic special case" from CreateGC */
+ if (pGCPriv->msc) {
+ /* The "magic special case" is used to handle the case where a
+ * foreground pixel is set when the GC is created so that a
+ * "pseudo default-tile" can be created and used in case the
+ * fillstyle was set to FillTiled. This specific case is tested
+ * in xtest (XCreateGC test #3). What has happened in dix by
+ * the time it reaches here is (1) the pGC->tile.pixel has been
+ * set to pGC->fgPixel and pGC->tileIsPixel is set, (2) if a
+ * tile has also been set, then pGC->tileIsPixel is unset and
+ * pGC->tile.pixmap is initialized; else, the default tile is
+ * created and pGC->tileIsPixel is unset and pGC->tile.pixmap is
+ * initialized to the "pseudo default-tile". In either case,
+ * pGC->tile.pixmap is set; however, in the "magic special case"
+ * the mask is not updated to allow us to detect that we should
+ * initialize the GCTile in the back-end server. Thus, we catch
+ * this case in dmxCreateGC and add GCTile to the mask here.
+ * Are there any cases that I've missed?
+ */
+
+ /* Make sure that the tile.pixmap is set, just in case the user
+ * set GCTile in the mask but forgot to set vals.pixmap
+ */
+ if (pGC->tile.pixmap) mask |= GCTile;
+
+ /* This only happens once when the GC is created */
+ pGCPriv->msc = False;
+ }
+
+ /* Update back-end server's gc */
+ if (mask & GCFunction) v.function = pGC->alu;
+ if (mask & GCPlaneMask) v.plane_mask = pGC->planemask;
+ if (mask & GCForeground) v.foreground = pGC->fgPixel;
+ if (mask & GCBackground) v.background = pGC->bgPixel;
+ if (mask & GCLineWidth) v.line_width = pGC->lineWidth;
+ if (mask & GCLineStyle) v.line_style = pGC->lineStyle;
+ if (mask & GCCapStyle) v.cap_style = pGC->capStyle;
+ if (mask & GCJoinStyle) v.join_style = pGC->joinStyle;
+ if (mask & GCFillStyle) v.fill_style = pGC->fillStyle;
+ if (mask & GCFillRule) v.fill_rule = pGC->fillRule;
+ if (mask & GCTile) {
+ if (pGC->tileIsPixel) {
+ mask &= ~GCTile;
+ } else {
+ dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pGC->tile.pixmap);
+ v.tile = (Drawable)pPixPriv->pixmap;
+ }
+ }
+ if (mask & GCStipple) {
+ dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pGC->stipple);
+ v.stipple = (Drawable)pPixPriv->pixmap;
+ }
+ if (mask & GCTileStipXOrigin) v.ts_x_origin = pGC->patOrg.x;
+ if (mask & GCTileStipYOrigin) v.ts_y_origin = pGC->patOrg.y;
+ if (mask & GCFont) {
+ dmxFontPrivPtr pFontPriv;
+ pFontPriv = FontGetPrivate(pGC->font, dmxFontPrivateIndex);
+ v.font = pFontPriv->font[pScreen->myNum]->fid;
+ }
+ if (mask & GCSubwindowMode) v.subwindow_mode = pGC->subWindowMode;
+ if (mask & GCGraphicsExposures) v.graphics_exposures =
+ pGC->graphicsExposures;
+ if (mask & GCClipXOrigin) v.clip_x_origin = pGC->clipOrg.x;
+ if (mask & GCClipYOrigin) v.clip_y_origin = pGC->clipOrg.y;
+ if (mask & GCClipMask) mask &= ~GCClipMask; /* See ChangeClip */
+ if (mask & GCDashOffset) v.dash_offset = pGC->dashOffset;
+ if (mask & GCDashList) {
+ mask &= ~GCDashList;
+ XSetDashes(dmxScreen->display, pGCPriv->gc,
+ pGC->dashOffset, (char *)pGC->dash,
+ pGC->numInDashList);
+ }
+ if (mask & GCArcMode) v.arc_mode = pGC->arcMode;
+
+ if (mask) {
+ XChangeGC(dmxScreen->display, pGCPriv->gc, mask, &v);
+ XSync(dmxScreen->display, False);
+ }
+
+ DMX_GC_FUNC_EPILOGUE(pGC);
+}
+
+void dmxCopyGC(GCPtr pGCSrc, unsigned long changes, GCPtr pGCDst)
+{
+ ScreenPtr pScreen = pGCSrc->pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxGCPrivPtr pGCSrcPriv = DMX_GET_GC_PRIV(pGCSrc);
+ dmxGCPrivPtr pGCDstPriv = DMX_GET_GC_PRIV(pGCDst);
+
+ DMX_GC_FUNC_PROLOGUE(pGCDst);
+ pGCDst->funcs->CopyGC(pGCSrc, changes, pGCDst);
+
+ /* Copy the GC on the back-end server */
+ XCopyGC(dmxScreen->display, pGCSrcPriv->gc, changes, pGCDstPriv->gc);
+
+ DMX_GC_FUNC_EPILOGUE(pGCDst);
+}
+
+void dmxDestroyGC(GCPtr pGC)
+{
+ ScreenPtr pScreen = pGC->pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+
+ DMX_GC_FUNC_PROLOGUE(pGC);
+ pGC->funcs->DestroyGC(pGC);
+
+ /* Free the GC on the back-end server */
+ XFreeGC(dmxScreen->display, pGCPriv->gc);
+
+ DMX_GC_FUNC_EPILOGUE(pGC);
+}
+
+void dmxChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects)
+{
+ ScreenPtr pScreen = pGC->pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+ XRectangle *pRects;
+ BoxPtr pBox;
+ int i, nRects;
+
+ DMX_GC_FUNC_PROLOGUE(pGC);
+ pGC->funcs->ChangeClip(pGC, type, pvalue, nrects);
+
+ /* Set the client clip on the back-end server */
+ switch (pGC->clientClipType) {
+ case CT_NONE:
+ XSetClipMask(dmxScreen->display, pGCPriv->gc, None);
+ break;
+
+ case CT_REGION:
+ nRects = REGION_NUM_RECTS((RegionPtr)pGC->clientClip);
+ pRects = xalloc(nRects * sizeof(*pRects));
+ pBox = REGION_RECTS((RegionPtr)pGC->clientClip);
+
+ for (i = 0; i < nRects; i++) {
+ pRects[i].x = pBox[i].x1;
+ pRects[i].y = pBox[i].y1;
+ pRects[i].width = pBox[i].x2 - pBox[i].x1;
+ pRects[i].height = pBox[i].y2 - pBox[i].y1;
+ }
+
+ XSetClipRectangles(dmxScreen->display, pGCPriv->gc,
+ pGC->clipOrg.x, pGC->clipOrg.y,
+ pRects, nRects, Unsorted);
+
+ xfree(pRects);
+ break;
+
+ case CT_PIXMAP:
+ case CT_UNSORTED:
+ case CT_YSORTED:
+ case CT_YXSORTED:
+ case CT_YXBANDED:
+ /* These clip types are condensed down to either NONE or REGION
+ in the mi code */
+ break;
+ }
+
+ DMX_GC_FUNC_EPILOGUE(pGC);
+}
+
+void dmxDestroyClip(GCPtr pGC)
+{
+ ScreenPtr pScreen = pGC->pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+ DMX_GC_FUNC_PROLOGUE(pGC);
+ pGC->funcs->DestroyClip(pGC);
+
+ /* Set the client clip on the back-end server to None */
+ XSetClipMask(dmxScreen->display, pGCPriv->gc, None);
+
+ DMX_GC_FUNC_EPILOGUE(pGC);
+}
+
+void dmxCopyClip(GCPtr pGCDst, GCPtr pGCSrc)
+{
+ DMX_GC_FUNC_PROLOGUE(pGCDst);
+ pGCDst->funcs->CopyClip(pGCDst, pGCSrc);
+ DMX_GC_FUNC_EPILOGUE(pGCDst);
+}
diff --git a/xc/programs/Xserver/hw/dmx/dmxgc.h b/xc/programs/Xserver/hw/dmx/dmxgc.h
new file mode 100644
index 000000000..7564565c3
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxgc.h
@@ -0,0 +1,83 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ *
+ */
+
+#ifndef DMXGC_H
+#define DMXGC_H
+
+#include "gcstruct.h"
+
+typedef struct _dmxGCPriv {
+ GCOps *ops;
+ GCFuncs *funcs;
+ XlibGC gc;
+ Bool msc;
+} dmxGCPrivRec, *dmxGCPrivPtr;
+
+
+extern Bool dmxInitGC(ScreenPtr pScreen);
+
+extern Bool dmxCreateGC(GCPtr pGC);
+extern void dmxValidateGC(GCPtr pGC, unsigned long changes,
+ DrawablePtr pDrawable);
+extern void dmxChangeGC(GCPtr pGC, unsigned long mask);
+extern void dmxCopyGC(GCPtr pGCSrc, unsigned long changes, GCPtr pGCDst);
+extern void dmxDestroyGC(GCPtr pGC);
+extern void dmxChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects);
+extern void dmxDestroyClip(GCPtr pGC);
+extern void dmxCopyClip(GCPtr pGCDst, GCPtr pGCSrc);
+
+
+extern int dmxGCPrivateIndex;
+
+
+#define DMX_GET_GC_PRIV(_pGC) \
+ (dmxGCPrivPtr)(_pGC)->devPrivates[dmxGCPrivateIndex].ptr
+
+#define DMX_GC_FUNC_PROLOGUE(_pGC) \
+do { \
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(_pGC); \
+ DMX_UNWRAP(funcs, pGCPriv, (_pGC)); \
+ if (pGCPriv->ops) \
+ DMX_UNWRAP(ops, pGCPriv, (_pGC)); \
+} while (0)
+
+#define DMX_GC_FUNC_EPILOGUE(_pGC) \
+do { \
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(_pGC); \
+ DMX_WRAP(funcs, &dmxGCFuncs, pGCPriv, (_pGC)); \
+ if (pGCPriv->ops) \
+ DMX_WRAP(ops, &dmxGCOps, pGCPriv, (_pGC)); \
+} while (0)
+
+#endif /* DMXGC_H */
diff --git a/xc/programs/Xserver/hw/dmx/dmxgcops.c b/xc/programs/Xserver/hw/dmx/dmxgcops.c
new file mode 100644
index 000000000..692b7746b
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxgcops.c
@@ -0,0 +1,447 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ *
+ */
+
+#include "dmx.h"
+#include "dmxgc.h"
+#include "dmxgcops.h"
+#include "dmxwindow.h"
+#include "dmxpixmap.h"
+
+#include "gcstruct.h"
+#include "pixmapstr.h"
+#include "dixfontstr.h"
+
+#define DMX_GCOPS_SET_DRAWABLE(_pDraw, _draw) \
+do { \
+ if ((_pDraw)->type == DRAWABLE_WINDOW) { \
+ dmxWinPrivPtr pWinPriv = \
+ DMX_GET_WINDOW_PRIV((WindowPtr)(_pDraw)); \
+ (_draw) = (Drawable)pWinPriv->window; \
+ } else { \
+ dmxPixPrivPtr pPixPriv = \
+ DMX_GET_PIXMAP_PRIV((PixmapPtr)(_pDraw)); \
+ (_draw) = (Drawable)pPixPriv->pixmap; \
+ } \
+} while (0)
+
+void dmxFillSpans(DrawablePtr pDrawable, GCPtr pGC,
+ int nInit, DDXPointPtr pptInit, int *pwidthInit,
+ int fSorted)
+{
+ /* Error -- this should never happen! */
+}
+
+void dmxSetSpans(DrawablePtr pDrawable, GCPtr pGC,
+ char *psrc, DDXPointPtr ppt, int *pwidth, int nspans,
+ int fSorted)
+{
+ /* Error -- this should never happen! */
+}
+
+void dmxPutImage(DrawablePtr pDrawable, GCPtr pGC,
+ int depth, int x, int y, int w, int h,
+ int leftPad, int format, char *pBits)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+ XImage *img;
+
+ img = XCreateImage(dmxScreen->display,
+ dmxScreen->visuals[dmxScreen->defVisualIndex].visual,
+ depth, format, leftPad, pBits, w, h,
+ BitmapPad(dmxScreen->display),
+ (format == ZPixmap) ?
+ PixmapBytePad(w, depth) : BitmapBytePad(w+leftPad));
+
+ if (img) {
+ Drawable draw;
+
+ DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
+
+ XPutImage(dmxScreen->display, draw, pGCPriv->gc,
+ img, 0, 0, x, y, w, h);
+ XFree(img);
+ XSync(dmxScreen->display, False);
+ } else {
+ /* Error -- this should not happen! */
+ }
+}
+
+static Bool dmxHandleBltExpPredicate(Display *display, XEvent *event,
+ char *args)
+{
+ return (event->type == GraphicsExpose || event->type == NoExpose);
+}
+
+static RegionPtr dmxHandleBltExposures(GCPtr pGC)
+{
+ ScreenPtr pScreen = pGC->pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ XEvent event;
+ RegionPtr pReg, pTmpReg;
+ BoxRec box;
+ Bool pending, overlap;
+
+ if (!pGC->graphicsExposures)
+ return NullRegion;
+
+ pReg = REGION_CREATE(pScreen, NULL, 1);
+ pTmpReg = REGION_CREATE(pScreen, NULL, 1);
+ if (!pReg || !pTmpReg) return NullRegion;
+
+ pending = TRUE;
+ while (pending) {
+ XIfEvent(dmxScreen->display, &event, dmxHandleBltExpPredicate, NULL);
+
+ switch (event.type) {
+ case NoExpose:
+ pending = FALSE;
+ break;
+
+ case GraphicsExpose:
+ box.x1 = event.xgraphicsexpose.x;
+ box.y1 = event.xgraphicsexpose.y;
+ box.x2 = event.xgraphicsexpose.x + event.xgraphicsexpose.width;
+ box.y2 = event.xgraphicsexpose.y + event.xgraphicsexpose.height;
+ REGION_RESET(pScreen, pTmpReg, &box);
+ REGION_APPEND(pScreen, pReg, pTmpReg);
+ pending = event.xgraphicsexpose.count;
+ break;
+ }
+ }
+
+ REGION_DESTROY(pScreen, pTmpReg);
+ REGION_VALIDATE(pScreen, pReg, &overlap);
+
+ return pReg;
+}
+
+RegionPtr dmxCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int w, int h, int dstx, int dsty)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pSrc->pScreen->myNum];
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+ Drawable srcDraw, dstDraw;
+
+ DMX_GCOPS_SET_DRAWABLE(pSrc, srcDraw);
+ DMX_GCOPS_SET_DRAWABLE(pDst, dstDraw);
+
+ XCopyArea(dmxScreen->display, srcDraw, dstDraw, pGCPriv->gc,
+ srcx, srcy, w, h, dstx, dsty);
+ XSync(dmxScreen->display, False);
+
+ return dmxHandleBltExposures(pGC);
+}
+
+RegionPtr dmxCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int width, int height,
+ int dstx, int dsty, unsigned long bitPlane)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pSrc->pScreen->myNum];
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+ Drawable srcDraw, dstDraw;
+
+ DMX_GCOPS_SET_DRAWABLE(pSrc, srcDraw);
+ DMX_GCOPS_SET_DRAWABLE(pDst, dstDraw);
+
+ XCopyPlane(dmxScreen->display, srcDraw, dstDraw, pGCPriv->gc,
+ srcx, srcy, width, height, dstx, dsty, bitPlane);
+ XSync(dmxScreen->display, False);
+
+ return dmxHandleBltExposures(pGC);
+}
+
+void dmxPolyPoint(DrawablePtr pDrawable, GCPtr pGC,
+ int mode, int npt, DDXPointPtr pptInit)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+ Drawable draw;
+
+ DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
+
+ XDrawPoints(dmxScreen->display, draw, pGCPriv->gc,
+ (XPoint *)pptInit, npt, mode);
+ XSync(dmxScreen->display, False);
+}
+
+void dmxPolylines(DrawablePtr pDrawable, GCPtr pGC,
+ int mode, int npt, DDXPointPtr pptInit)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+ Drawable draw;
+
+ DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
+
+ XDrawLines(dmxScreen->display, draw, pGCPriv->gc,
+ (XPoint *)pptInit, npt, mode);
+ XSync(dmxScreen->display, False);
+}
+
+void dmxPolySegment(DrawablePtr pDrawable, GCPtr pGC,
+ int nseg, xSegment *pSegs)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+ Drawable draw;
+
+ DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
+
+ XDrawSegments(dmxScreen->display, draw, pGCPriv->gc,
+ (XSegment *)pSegs, nseg);
+ XSync(dmxScreen->display, False);
+}
+
+void dmxPolyRectangle(DrawablePtr pDrawable, GCPtr pGC,
+ int nrects, xRectangle *pRects)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+ Drawable draw;
+
+ DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
+
+ XDrawRectangles(dmxScreen->display, draw, pGCPriv->gc,
+ (XRectangle *)pRects, nrects);
+
+ XSync(dmxScreen->display, False);
+}
+
+void dmxPolyArc(DrawablePtr pDrawable, GCPtr pGC,
+ int narcs, xArc *parcs)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+ Drawable draw;
+
+ DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
+
+ XDrawArcs(dmxScreen->display, draw, pGCPriv->gc,
+ (XArc *)parcs, narcs);
+ XSync(dmxScreen->display, False);
+}
+
+void dmxFillPolygon(DrawablePtr pDrawable, GCPtr pGC,
+ int shape, int mode, int count, DDXPointPtr pPts)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+ Drawable draw;
+
+ DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
+
+ XFillPolygon(dmxScreen->display, draw, pGCPriv->gc,
+ (XPoint *)pPts, count, shape, mode);
+ XSync(dmxScreen->display, False);
+}
+
+void dmxPolyFillRect(DrawablePtr pDrawable, GCPtr pGC,
+ int nrectFill, xRectangle *prectInit)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+ Drawable draw;
+
+ DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
+
+ XFillRectangles(dmxScreen->display, draw, pGCPriv->gc,
+ (XRectangle *)prectInit, nrectFill);
+ XSync(dmxScreen->display, False);
+}
+
+void dmxPolyFillArc(DrawablePtr pDrawable, GCPtr pGC,
+ int narcs, xArc *parcs)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+ Drawable draw;
+
+ DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
+
+ XFillArcs(dmxScreen->display, draw, pGCPriv->gc,
+ (XArc *)parcs, narcs);
+ XSync(dmxScreen->display, False);
+}
+
+int dmxPolyText8(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, int count, char *chars)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+ unsigned long n, i;
+ int w;
+ CharInfoPtr charinfo[255];
+ Drawable draw;
+
+ DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
+
+ GetGlyphs(pGC->font, (unsigned long)count, (unsigned char *)chars,
+ Linear8Bit, &n, charinfo);
+
+ /* Calculate text width */
+ w = 0;
+ for (i = 0; i < n; i++) w += charinfo[i]->metrics.characterWidth;
+
+ if (n != 0) {
+ XDrawString(dmxScreen->display, draw, pGCPriv->gc,
+ x, y, chars, count);
+ XSync(dmxScreen->display, False);
+ }
+
+ return x+w;
+}
+
+int dmxPolyText16(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, int count, unsigned short *chars)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+ unsigned long n, i;
+ int w;
+ CharInfoPtr charinfo[255];
+ Drawable draw;
+
+ DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
+
+ GetGlyphs(pGC->font, (unsigned long)count, (unsigned char *)chars,
+ (FONTLASTROW(pGC->font) == 0) ? Linear16Bit : TwoD16Bit,
+ &n, charinfo);
+
+ /* Calculate text width */
+ w = 0;
+ for (i = 0; i < n; i++) w += charinfo[i]->metrics.characterWidth;
+
+ if (n != 0) {
+ XDrawString16(dmxScreen->display, draw, pGCPriv->gc,
+ x, y, (XChar2b *)chars, count);
+ XSync(dmxScreen->display, False);
+ }
+
+ return x+w;
+}
+
+void dmxImageText8(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, int count, char *chars)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+ Drawable draw;
+
+ DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
+
+ XDrawImageString(dmxScreen->display, draw, pGCPriv->gc,
+ x, y, chars, count);
+ XSync(dmxScreen->display, False);
+}
+
+void dmxImageText16(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, int count, unsigned short *chars)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
+ Drawable draw;
+
+ DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
+
+ XDrawImageString16(dmxScreen->display, draw, pGCPriv->gc,
+ x, y, (XChar2b *)chars, count);
+ XSync(dmxScreen->display, False);
+}
+
+void dmxImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr *ppci, pointer pglyphBase)
+{
+ /* Error -- this should never happen! */
+}
+
+void dmxPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr *ppci, pointer pglyphBase)
+{
+ /* Error -- this should never happen! */
+}
+
+void dmxPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDst,
+ int w, int h, int x, int y)
+{
+ /* Error -- this should never happen! */
+}
+
+/**********************************************************************
+ * Miscellaneous drawing commands
+ */
+
+void dmxGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h,
+ unsigned int format, unsigned long planeMask, char *pdstLine)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
+ XImage *img;
+ Drawable draw;
+
+ DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
+
+ /* Cannot get image from unviewable window */
+ if (pDrawable->type == DRAWABLE_WINDOW) {
+ WindowPtr pWindow = (WindowPtr)pDrawable;
+ if (!pWindow->viewable) {
+ while (!pWindow->viewable && pWindow->parent) {
+ sx += pWindow->origin.x - wBorderWidth(pWindow);
+ sx += pWindow->origin.y - wBorderWidth(pWindow);
+ pWindow = pWindow->parent;
+ }
+ if (!pWindow->viewable) {
+ return;
+ }
+ DMX_GCOPS_SET_DRAWABLE(&pWindow->drawable, draw);
+ }
+ }
+
+ img = XGetImage(dmxScreen->display, draw,
+ sx, sy, w, h, planeMask, format);
+ if (img) {
+ int len = img->bytes_per_line * img->height;
+ memmove(pdstLine, img->data, len);
+ XDestroyImage(img);
+ }
+ XSync(dmxScreen->display, False);
+}
+
+void dmxGetSpans(DrawablePtr pDrawable, int wMax,
+ DDXPointPtr ppt, int *pwidth, int nspans,
+ char *pdstStart)
+{
+ /* Error -- this should never happen! */
+}
diff --git a/xc/programs/Xserver/hw/dmx/dmxgcops.h b/xc/programs/Xserver/hw/dmx/dmxgcops.h
new file mode 100644
index 000000000..8c02db4b5
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxgcops.h
@@ -0,0 +1,93 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ *
+ */
+
+#ifndef DMXGCOPS_H
+#define DMXGCOPS_H
+
+extern void dmxFillSpans(DrawablePtr pDrawable, GCPtr pGC,
+ int nInit, DDXPointPtr pptInit, int *pwidthInit,
+ int fSorted);
+extern void dmxSetSpans(DrawablePtr pDrawable, GCPtr pGC,
+ char *psrc, DDXPointPtr ppt, int *pwidth, int nspans,
+ int fSorted);
+extern void dmxPutImage(DrawablePtr pDrawable, GCPtr pGC,
+ int depth, int x, int y, int w, int h,
+ int leftPad, int format, char *pBits);
+extern RegionPtr dmxCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int w, int h,
+ int dstx, int dsty);
+extern RegionPtr dmxCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int width, int height,
+ int dstx, int dsty, unsigned long bitPlane);
+extern void dmxPolyPoint(DrawablePtr pDrawable, GCPtr pGC,
+ int mode, int npt, DDXPointPtr pptInit);
+extern void dmxPolylines(DrawablePtr pDrawable, GCPtr pGC,
+ int mode, int npt, DDXPointPtr pptInit);
+extern void dmxPolySegment(DrawablePtr pDrawable, GCPtr pGC,
+ int nseg, xSegment *pSegs);
+extern void dmxPolyRectangle(DrawablePtr pDrawable, GCPtr pGC,
+ int nrects, xRectangle *pRects);
+extern void dmxPolyArc(DrawablePtr pDrawable, GCPtr pGC,
+ int narcs, xArc *parcs);
+extern void dmxFillPolygon(DrawablePtr pDrawable, GCPtr pGC,
+ int shape, int mode, int count, DDXPointPtr pPts);
+extern void dmxPolyFillRect(DrawablePtr pDrawable, GCPtr pGC,
+ int nrectFill, xRectangle *prectInit);
+extern void dmxPolyFillArc(DrawablePtr pDrawable, GCPtr pGC,
+ int narcs, xArc *parcs);
+extern int dmxPolyText8(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, int count, char *chars);
+extern int dmxPolyText16(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, int count, unsigned short *chars);
+extern void dmxImageText8(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, int count, char *chars);
+extern void dmxImageText16(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, int count, unsigned short *chars);
+extern void dmxImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr *ppci, pointer pglyphBase);
+extern void dmxPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr *ppci, pointer pglyphBase);
+extern void dmxPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDst,
+ int w, int h, int x, int y);
+
+extern void dmxGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h,
+ unsigned int format, unsigned long planeMask,
+ char *pdstLine);
+extern void dmxGetSpans(DrawablePtr pDrawable, int wMax,
+ DDXPointPtr ppt, int *pwidth, int nspans,
+ char *pdstStart);
+
+#endif /* DMXGCOPS_H */
diff --git a/xc/programs/Xserver/hw/dmx/dmxinit.c b/xc/programs/Xserver/hw/dmx/dmxinit.c
new file mode 100644
index 000000000..cbcaf553e
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxinit.c
@@ -0,0 +1,528 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ * David H. Dawes <dawes@xfree86.org>
+ *
+ */
+
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "globals.h"
+
+#include "dmx.h"
+#include "dmxlog.h"
+#include "dmxinput.h"
+#include "dmxscrinit.h"
+#include "dmxcursor.h"
+#include "dmxfont.h"
+#include "config/dmxconfig.h"
+#include "dmxcb.h"
+#include "dmxprop.h"
+
+#include "dixstruct.h"
+#include "panoramiXsrv.h"
+
+/* Global variables available to all Xserver/hw/dmx routines. */
+int dmxNumScreens;
+DMXScreenInfo *dmxScreens;
+
+int dmxNumInputs;
+DMXInputInfo *dmxInputs;
+
+int dmxShadowFB = FALSE;
+
+XErrorEvent dmxLastErrorEvent;
+Bool dmxErrorOccurred = FALSE;
+
+char *dmxFontPath = NULL;
+
+/* dmxErrorHandler catches errors that occur when calling one of the
+ * back-end servers. */
+static int dmxErrorHandler(Display *dpy, XErrorEvent *ev)
+{
+#define DMX_ERROR_BUF_SIZE 256
+ char buf[DMX_ERROR_BUF_SIZE];
+
+ dmxErrorOccurred = TRUE;
+ dmxLastErrorEvent = *ev;
+
+ XGetErrorText(dpy, ev->error_code, buf, DMX_ERROR_BUF_SIZE);
+ dmxLog(dmxWarning, "dmxErrorHandler: %s\n", buf);
+
+ return 0;
+}
+
+static void dmxOpenDisplay(DMXScreenInfo *dmxScreen)
+{
+ if (!(dmxScreen->display = XOpenDisplay(dmxScreen->name)))
+ dmxLog(dmxFatal,
+ "dmxOpenDisplay: Unable to open display %s\n",
+ dmxScreen->name);
+ dmxPropertyDisplay(dmxScreen);
+}
+
+static void dmxSetErrorHandler(DMXScreenInfo *dmxScreen)
+{
+ XSetErrorHandler(dmxErrorHandler);
+}
+
+static void dmxPrintScreenInfo(DMXScreenInfo *dmxScreen)
+{
+ XWindowAttributes attribs;
+ int ndepths = 0, *depths = NULL;
+ int i;
+ Display *dpy = dmxScreen->display;
+ Screen *s = DefaultScreenOfDisplay(dpy);
+ int scr = DefaultScreen(dpy);
+
+ XGetWindowAttributes(dpy, DefaultRootWindow(dpy), &attribs);
+ if (!(depths = XListDepths(dpy, scr, &ndepths))) ndepths = 0;
+
+ dmxLogOutput(dmxScreen, "Name of display: %s\n", DisplayString(dpy));
+ dmxLogOutput(dmxScreen, "Version number: %d.%d\n",
+ ProtocolVersion(dpy), ProtocolRevision(dpy));
+ dmxLogOutput(dmxScreen, "Vendor string: %s\n", ServerVendor(dpy));
+ if (!strstr(ServerVendor(dpy), "XFree86")) {
+ dmxLogOutput(dmxScreen, "Vendor release: %d\n", VendorRelease(dpy));
+ } else {
+ /* This code based on xdpyinfo.c */
+ int v = VendorRelease(dpy);
+ int major = -1, minor = -1, patch = -1, subpatch = -1;
+
+ if (v < 336)
+ major = v / 100, minor = (v / 10) % 10, patch = v % 10;
+ else if (v < 3900) {
+ major = v / 1000;
+ minor = (v / 100) % 10;
+ if (((v / 10) % 10) || (v % 10)) {
+ patch = (v / 10) % 10;
+ if (v % 10) subpatch = v % 10;
+ }
+ } else if (v < 40000000) {
+ major = v / 1000;
+ minor = (v / 10) % 10;
+ if (v % 10) patch = v % 10;
+ } else {
+ major = v / 10000000;
+ minor = (v / 100000) % 100;
+ patch = (v / 1000) % 100;
+ if (v % 1000) subpatch = v % 1000;
+ }
+ dmxLogOutput(dmxScreen, "Vendor release: %d (XFree86 version: %d.%d",
+ v, major, minor);
+ if (patch > 0) dmxLogAdditional(dmxScreen, ".%d", patch);
+ if (subpatch > 0) dmxLogAdditional(dmxScreen, ".%d", subpatch);
+ dmxLogAdditional(dmxScreen, ")\n");
+ }
+
+
+ dmxLogOutput(dmxScreen, "Dimensions: %dx%d pixels\n",
+ attribs.width, attribs.height);
+ dmxLogOutput(dmxScreen, "%d depths on screen %d: ", ndepths, scr);
+ for (i = 0; i < ndepths; i++)
+ dmxLogAdditional(dmxScreen, "%c%d", i ? ',' : ' ', depths[i]);
+ dmxLogAdditional(dmxScreen, "\n");
+ dmxLogOutput(dmxScreen, "Depth of root window: %d plane%s (%d)\n",
+ attribs.depth, attribs.depth == 1 ? "" : "s",
+ DisplayPlanes(dpy, scr));
+ dmxLogOutput(dmxScreen, "Number of colormaps: %d min, %d max\n",
+ MinCmapsOfScreen(s), MaxCmapsOfScreen(s));
+ dmxLogOutput(dmxScreen, "Options: backing-store %s, save-unders %s\n",
+ (DoesBackingStore (s) == NotUseful) ? "no" :
+ ((DoesBackingStore (s) == Always) ? "yes" : "when mapped"),
+ DoesSaveUnders (s) ? "yes" : "no");
+ dmxLogOutput(dmxScreen, "Window Manager running: %s\n",
+ (dmxScreen->WMRunningOnBE) ? "yes" : "no");
+
+ if (dmxScreen->WMRunningOnBE) {
+ dmxLogOutputWarning(dmxScreen,
+ "Window manager running "
+ "-- colormaps not supported\n");
+ }
+ XFree(depths);
+}
+
+static void dmxGetScreenAttribs(DMXScreenInfo *dmxScreen)
+{
+ XWindowAttributes attribs;
+ Display *dpy = dmxScreen->display;
+
+ XGetWindowAttributes(dpy, DefaultRootWindow(dpy), &attribs);
+
+ dmxScreen->displayWidth = attribs.width;
+ dmxScreen->displayHeight = attribs.height;
+
+ /* Fill in missing geometry information */
+ if (dmxScreen->xsign < 0) {
+ if (dmxScreen->width) {
+ dmxScreen->xoff = (attribs.width - dmxScreen->width
+ - dmxScreen->xoff);
+ } else {
+ dmxScreen->width = attribs.width - dmxScreen->xoff;
+ dmxScreen->xoff = 0;
+ }
+ }
+ if (dmxScreen->ysign < 0) {
+ if (dmxScreen->height) {
+ dmxScreen->yoff = (attribs.height - dmxScreen->height
+ - dmxScreen->yoff);
+ } else {
+ dmxScreen->height = attribs.height - dmxScreen->yoff;
+ dmxScreen->yoff = 0;
+ }
+ }
+ if (!dmxScreen->width)
+ dmxScreen->width = attribs.width - dmxScreen->xoff;
+ if (!dmxScreen->height)
+ dmxScreen->height = attribs.height - dmxScreen->yoff;
+
+ dmxScreen->depth = attribs.depth; /* FIXME: verify that this works
+ * always. In particular, this will
+ * work well for depth=16, will fail
+ * because of colormap issues at
+ * depth 8.
+ * More work needs to be done
+ * here. */
+
+ if (dmxScreen->depth <= 8) dmxScreen->bpp = 8;
+ else if (dmxScreen->depth <= 16) dmxScreen->bpp = 16;
+ else dmxScreen->bpp = 32;
+
+ dmxPrintScreenInfo(dmxScreen);
+ dmxLogOutput(dmxScreen, "%dx%d+%d+%d on %dx%d at depth=%d, bpp=%d\n",
+ dmxScreen->width, dmxScreen->height,
+ dmxScreen->xoff, dmxScreen->yoff,
+ dmxScreen->displayWidth, dmxScreen->displayHeight,
+ dmxScreen->depth, dmxScreen->bpp);
+ if (dmxScreen->depth != 16)
+ dmxLogOutputWarning(dmxScreen,
+ "Support for depth != 16 is not complete\n");
+}
+
+static void dmxGetVisualInfo(DMXScreenInfo *dmxScreen)
+{
+ int i;
+ XVisualInfo visinfo;
+
+ visinfo.screen = DefaultScreen(dmxScreen->display);
+ dmxScreen->visuals = XGetVisualInfo(dmxScreen->display,
+ VisualScreenMask,
+ &visinfo,
+ &dmxScreen->numVisuals);
+
+ visinfo.visualid =
+ XVisualIDFromVisual(DefaultVisual(dmxScreen->display,
+ DefaultScreen(dmxScreen->display)));
+ dmxScreen->defVisualIndex = 0;
+ for (i = 0; i < dmxScreen->numVisuals; i++)
+ if (visinfo.visualid == dmxScreen->visuals[i].visualid)
+ dmxScreen->defVisualIndex = i;
+
+ for (i = 0; i < dmxScreen->numVisuals; i++)
+ dmxLogVisual(dmxScreen, &dmxScreen->visuals[i],
+ (i == dmxScreen->defVisualIndex));
+
+}
+
+static void dmxGetColormaps(DMXScreenInfo *dmxScreen)
+{
+ int i;
+
+ dmxScreen->numDefColormaps = dmxScreen->numVisuals;
+ dmxScreen->defColormaps = xalloc(dmxScreen->numDefColormaps *
+ sizeof(*dmxScreen->defColormaps));
+
+ for (i = 0; i < dmxScreen->numDefColormaps; i++)
+ dmxScreen->defColormaps[i] =
+ XCreateColormap(dmxScreen->display,
+ DefaultRootWindow(dmxScreen->display),
+ dmxScreen->visuals[i].visual,
+ AllocNone);
+
+ dmxScreen->blackPixel = BlackPixel(dmxScreen->display,
+ DefaultScreen(dmxScreen->display));
+ dmxScreen->whitePixel = WhitePixel(dmxScreen->display,
+ DefaultScreen(dmxScreen->display));
+}
+
+static void dmxGetPixmapFormats(DMXScreenInfo *dmxScreen)
+{
+ dmxScreen->depths =
+ XListDepths(dmxScreen->display, DefaultScreen(dmxScreen->display),
+ &dmxScreen->numDepths);
+
+ dmxScreen->pixmapFormats =
+ XListPixmapFormats(dmxScreen->display, &dmxScreen->numPixmapFormats);
+}
+
+static Bool dmxSetPixmapFormats(ScreenInfo *pScreenInfo,
+ DMXScreenInfo *dmxScreen)
+{
+ PixmapFormatRec *format;
+ int i, j;
+
+ pScreenInfo->imageByteOrder = ImageByteOrder(dmxScreen->display);
+ pScreenInfo->bitmapScanlineUnit = BitmapUnit(dmxScreen->display);
+ pScreenInfo->bitmapScanlinePad = BitmapPad(dmxScreen->display);
+ pScreenInfo->bitmapBitOrder = BitmapBitOrder(dmxScreen->display);
+
+ pScreenInfo->numPixmapFormats = 0;
+ for (i = 0; i < dmxScreen->numPixmapFormats; i++)
+ for (j = 0; j < dmxScreen->numDepths; j++)
+ if ((dmxScreen->pixmapFormats[i].depth == 1) ||
+ (dmxScreen->pixmapFormats[i].depth == dmxScreen->depths[j])) {
+ format = &pScreenInfo->formats[pScreenInfo->numPixmapFormats];
+
+ format->depth =
+ dmxScreen->pixmapFormats[i].depth;
+ format->bitsPerPixel =
+ dmxScreen->pixmapFormats[i].bits_per_pixel;
+ format->scanlinePad =
+ dmxScreen->pixmapFormats[i].scanline_pad;
+
+ pScreenInfo->numPixmapFormats++;
+ break;
+ }
+
+ return TRUE;
+}
+
+static void dmxCheckForWM(DMXScreenInfo *dmxScreen)
+{
+ Status status;
+ XWindowAttributes xwa;
+
+ status = XGetWindowAttributes(dmxScreen->display,
+ DefaultRootWindow(dmxScreen->display),
+ &xwa);
+ dmxScreen->WMRunningOnBE =
+ (status &&
+ ((xwa.all_event_masks & SubstructureRedirectMask) ||
+ (xwa.all_event_masks & SubstructureNotifyMask)));
+}
+
+static void dmxDisplayInit(ScreenInfo *pScreenInfo, DMXScreenInfo *dmxScreen,
+ int argc, char *charv[])
+{
+ dmxOpenDisplay(dmxScreen);
+ dmxSetErrorHandler(dmxScreen);
+ dmxCheckForWM(dmxScreen);
+ dmxGetScreenAttribs(dmxScreen);
+ dmxGetVisualInfo(dmxScreen);
+ dmxGetColormaps(dmxScreen);
+ dmxGetPixmapFormats(dmxScreen);
+}
+
+void InitOutput(ScreenInfo *pScreenInfo, int argc, char *argv[])
+{
+ int i;
+ static unsigned long dmxGeneration = 0;
+
+ if (dmxGeneration != serverGeneration) {
+ dmxGeneration = serverGeneration;
+ dmxLog(dmxInfo, "Generation %lu\n", dmxGeneration);
+ for (i = 0; i < dmxNumScreens; i++) {
+ if (dmxScreens[i].display)
+ dmxLog(dmxWarning, "Display \"%s\" still open\n",
+ dmxScreens[i].name);
+ }
+ for (i = 0; i < dmxNumInputs; i++) dmxInputFree(&dmxInputs[i]);
+ if (dmxScreens) free(dmxScreens);
+ if (dmxInputs) free(dmxInputs);
+ dmxScreens = NULL;
+ dmxInputs = NULL;
+ dmxNumScreens = 0;
+ dmxNumInputs = 0;
+ }
+
+ /* ddxProcessArgument has been called at this point, but any data
+ * from the configuration file has not been applied. Do so, and be
+ * sure we have at least one back-end display. */
+ dmxConfigConfigure();
+ if (!dmxNumScreens)
+ dmxLog(dmxFatal, "InitOutput: no back-end displays found\n");
+ if (!dmxNumInputs)
+ dmxLog(dmxInfo, "InitOutput: no inputs found\n");
+
+ /* Open each display and gather information about it. */
+ for (i = 0; i < dmxNumScreens; i++)
+ dmxDisplayInit(pScreenInfo, &dmxScreens[i], argc, argv);
+
+ /* Register a Xinerama callback which will run from within
+ * PanoramiXCreateConnectionBlock. We can use the callback to
+ * determine if Xinerama is loaded and to check the visuals
+ * determined by PanoramiXConsolidate. */
+ XineramaRegisterConnectionBlockCallback(dmxConnectionBlockCallback);
+
+ /* Since we only have a single screen thus far, we only need to set
+ the pixmap formats to match that screen. FIXME: this isn't true.*/
+ if (!dmxSetPixmapFormats(pScreenInfo, &dmxScreens[0])) return;
+
+ /* FIXME: Might want to install a signal handler to allow cleaning
+ * up after unexpected signals. The DIX/OS layer already handles
+ * SIGINT and SIGTERM, so everything is OK for expected signals.
+ */
+
+ /* Tell dix layer about the backend displays */
+ for (i = 0; i < dmxNumScreens; i++) AddScreen(dmxScreenInit, argc, argv);
+
+ /* Compute origin information. */
+ dmxInitOrigins();
+
+ /* Compute overlap information. */
+ dmxInitOverlap();
+
+ /* Make sure there is a global width/height available */
+ dmxComputeWidthHeight();
+
+ /* FIXME: The following is temporarily placed here. When the DMX
+ * extension is available, it will be move there.
+ */
+ dmxInitFonts();
+
+ dmxLog(dmxInfo, "Shadow framebuffer support %s\n",
+ dmxShadowFB ? "enabled" : "disabled");
+}
+
+static void dmxSetDefaultFontPath(char *fp)
+{
+ if (dmxFontPath) {
+ int len;
+
+ len = strlen(dmxFontPath);
+ dmxFontPath = xrealloc(dmxFontPath, len+strlen(fp)+2);
+ dmxFontPath[len] = ',';
+ strcpy(&dmxFontPath[len+1], fp);
+ } else {
+ dmxFontPath = xalloc(strlen(fp)+1);
+ strcpy(dmxFontPath, fp);
+ }
+
+ defaultFontPath = dmxFontPath;
+}
+
+void AbortDDX(void)
+{
+ int i;
+
+ for (i=0; i < dmxNumScreens; i++) {
+ DMXScreenInfo *dmxScreen = &dmxScreens[i];
+
+ if (dmxScreen->display) XCloseDisplay(dmxScreen->display);
+ dmxScreen->display = NULL;
+ }
+}
+
+void ddxGiveUp(void)
+{
+ AbortDDX();
+}
+
+void OsVendorInit(void)
+{
+ return;
+}
+
+void OsVendorFatalError(void)
+{
+ return;
+}
+
+/* Process our command line arguments. */
+int ddxProcessArgument(int argc, char *argv[], int i)
+{
+ if (!strcmp(argv[i], "-display")) {
+ if (++i < argc) dmxConfigStoreDisplay(argv[i]);
+ return 2;
+ } else if (!strcmp(argv[i], "-inputfrom")) {
+ if (++i < argc) dmxConfigStoreInput(argv[i]);
+ return 2;
+ } else if (!strcmp(argv[i], "-noshadowfb")) {
+ dmxLog(dmxWarning,
+ "-noshadowfb has been deprecated "
+ "since it is now the default\n");
+ dmxShadowFB = FALSE;
+ return 1;
+ } else if (!strcmp(argv[i], "-nomulticursor")) {
+ dmxCursorNoMulti();
+ return 1;
+ } else if (!strcmp(argv[i], "-shadowfb")) {
+ dmxShadowFB = TRUE;
+ return 1;
+ } else if (!strcmp(argv[i], "-configfile")) {
+ if (++i < argc) dmxConfigStoreFile(argv[i]);
+ return 2;
+ } else if (!strcmp(argv[i], "-config")) {
+ if (++i < argc) dmxConfigStoreConfig(argv[i]);
+ return 2;
+ } else if (!strcmp(argv[i], "-fontpath")) {
+ if (++i < argc) dmxSetDefaultFontPath(argv[i]);
+ return 2;
+ }
+ return 0;
+}
+
+void ddxUseMsg(void)
+{
+ ErrorF("\n\nDevice Dependent Usage:\n");
+ ErrorF("-display string Specify the back-end display(s)\n");
+ ErrorF("-inputfrom string Specify input source\n");
+ ErrorF("-shadowfb Enable shadow frame buffer\n");
+ ErrorF("-configfile file Read from a configuration file\n");
+ ErrorF("-config config Select a specific configuration\n");
+ ErrorF("-nomulticursor Turn of multiple cursor support\n");
+ ErrorF("-fontpath Sets the default font path\n");
+ ErrorF("\n");
+ ErrorF(" If the -inputfrom string matches a -display string, then\n"
+ " input is taken from that backend display.\n\n");
+ ErrorF(" Otherwise, if the -inputfrom string specifies another X\n"
+ " display, then a console window will be created on that\n"
+ " display.\n\n");
+ ErrorF(" -inputfrom dummy specifies no input.\n");
+ ErrorF(" -inputfrom local specifies the use of a raw keyboard and\n"
+ " mouse:\n"
+ " -inputfrom local,kbd,ps2 will use a ps2 mouse\n"
+ " -inputfrom local,kbd,ms will use a serial mouse\n\n");
+ ErrorF(" Special Keys:\n");
+ ErrorF(" Ctrl-Alt-g Server grab/ungrab (console only)\n");
+ ErrorF(" Ctrl-Alt-f Fine (1-pixel) mouse mode (console only)\n");
+ ErrorF(" Ctrl-Alt-q Quit\n");
+ ErrorF(" Ctrl-Alt-F* Switch to VC (local only)\n");
+}
+
+CARD32 GetTimeInMillis(void)
+{
+ struct timeval tp;
+
+ gettimeofday(&tp, 0);
+ return tp.tv_sec * 1000 + tp.tv_usec / 1000;
+}
diff --git a/xc/programs/Xserver/hw/dmx/dmxinput.c b/xc/programs/Xserver/hw/dmx/dmxinput.c
new file mode 100644
index 000000000..a76c54a44
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxinput.c
@@ -0,0 +1,71 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * David H. Dawes <dawes@xfree86.org>
+ * Kevin E. Martin <kem@redhat.com>
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#include "inputstr.h"
+#include "input.h"
+
+#include "dmx.h"
+#include "dmxlog.h"
+#include "dmxinput.h"
+
+Bool LegalModifier(unsigned int key, DevicePtr pDev)
+{
+ return TRUE;
+}
+
+void InitInput(int argc, char **argv)
+{
+ int i;
+ DMXInputInfo *dmxInput;
+
+ if (!dmxNumInputs)
+ dmxLog(dmxFatal, "InitInput: no inputs specified\n");
+
+ for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++)
+ dmxInputInit(dmxInput);
+}
+
+void ProcessInputEvents()
+{
+ int i;
+ DMXInputInfo *dmxInput;
+
+ /* FIXME: if possible, don't poll every
+ * input */
+ for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++)
+ if (dmxInput->processInputEvents)
+ dmxInput->processInputEvents(dmxInput);
+}
diff --git a/xc/programs/Xserver/hw/dmx/dmxinput.h b/xc/programs/Xserver/hw/dmx/dmxinput.h
new file mode 100644
index 000000000..8c3187ca3
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxinput.h
@@ -0,0 +1,81 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * David H. Dawes <dawes@xfree86.org>
+ * Kevin E. Martin <kem@redhat.com>
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef DMXINPUT_H
+#define DMXINPUT_H
+
+struct _DMXInputInfo;
+
+typedef void (*ProcessInputEventsProc)(struct _DMXInputInfo *);
+
+typedef struct _DMXLocalInputInfo *DMXLocalInputInfoPtr;
+
+typedef enum {
+ DMX_NOSIGIO = 0,
+ DMX_USESIGIO,
+ DMX_ACTIVESIGIO
+} dmxSigioState;
+
+/* Typedef DMXInputInfo in dmx.h */
+struct _DMXInputInfo {
+ const char *name; /* Name from command line or config file */
+ int index; /* Index into dmxScreens global */
+
+
+ ProcessInputEventsProc processInputEvents;
+ DeviceIntPtr pKeyboard, pPointer;
+
+ /* Local input information */
+ dmxSigioState sigioState;
+ int sigioFdCount;
+ int sigioFd[DMX_MAX_SIGIO_FDS];
+ Bool sigioAdded[DMX_MAX_SIGIO_FDS];
+ int vt_switch_pending;
+ int vt_switched;
+ DMXLocalInputInfoPtr kbd, mou, gen;
+};
+
+/* Global variables available to all Xserver/hw/dmx routines. */
+extern int dmxNumInputs;
+extern DMXInputInfo *dmxInputs;
+
+/* These functions are defined in input/dmxinputinit.c, but are declared
+ * here so that hw/dmx does not have to include any files from
+ * hw/dmx/input. */
+extern void dmxInputInit(DMXInputInfo *dmxInput);
+extern void dmxInputFree(DMXInputInfo *dmxInput);
+
+#endif /* DMXINPUT_H */
diff --git a/xc/programs/Xserver/hw/dmx/dmxlog.c b/xc/programs/Xserver/hw/dmx/dmxlog.c
new file mode 100644
index 000000000..78368c9ae
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxlog.c
@@ -0,0 +1,256 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#include "dmx.h"
+#include "dmxlog.h"
+#include "dmxinput.h"
+
+/* This isn't declared in any header files. It should probably be in
+ * Xserver/include/os.h */
+extern void VFatalError(const char *msg, va_list args);
+
+static dmxLogLevel dmxCurrentLogLevel = dmxDebug;
+
+dmxLogLevel dmxSetLogLevel(dmxLogLevel newLevel)
+{
+ dmxLogLevel oldLevel = dmxCurrentLogLevel;
+ if (newLevel < dmxDebug) newLevel = dmxDebug;
+ if (newLevel > dmxFatal) newLevel = dmxFatal;
+ dmxCurrentLogLevel = newLevel;
+ return oldLevel;
+}
+
+dmxLogLevel dmxGetLogLevel(void)
+{
+ return dmxCurrentLogLevel;
+}
+
+#if 0
+void dmxOpenLogFile(const char *filename)
+{
+}
+
+void dmxCloseLogFile(void)
+{
+}
+#endif
+
+#ifdef DMX_LOG_STANDALONE
+void ErrorF(const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+}
+
+void VFatalError(const char *format, va_list args)
+{
+ vfprintf(stderr, format, args);
+ exit(1);
+}
+
+void VErrorF(const char *format, va_list args)
+{
+ vfprintf(stderr, format, args);
+}
+#endif
+
+static void dmxHeader(dmxLogLevel logLevel, DMXInputInfo *dmxInput,
+ DMXScreenInfo *dmxScreen)
+{
+ const char *type = "??";
+
+ switch (logLevel) {
+ case dmxDebug: type = ".."; break;
+ case dmxInfo: type = "II"; break;
+ case dmxWarning: type = "**"; break;
+ case dmxError: type = "!!"; break;
+ case dmxFatal: type = "Fatal Error"; break;
+ }
+
+ if (dmxInput && dmxScreen) {
+ ErrorF("(%s) dmx[i%d/%s;o%d/%s]: ", type,
+ dmxInput->index, dmxInput->name,
+ dmxScreen->index, dmxScreen->name);
+ } else if (dmxScreen) {
+ ErrorF("(%s) dmx[o%d/%s]: ", type,
+ dmxScreen->index, dmxScreen->name);
+ } else if (dmxInput) {
+ const char *pt = strchr(dmxInput->name, ',');
+ int len = pt ? pt-dmxInput->name : strlen(dmxInput->name);
+
+ ErrorF("(%s) dmx[i%d/%*.*s]: ", type,
+ dmxInput->index, len, len, dmxInput->name);
+ } else {
+ ErrorF("(%s) dmx: ", type);
+ }
+}
+
+static void dmxMessage(dmxLogLevel logLevel, const char *format, va_list args)
+{
+ if (logLevel == dmxFatal || logLevel >= dmxCurrentLogLevel) {
+ if (logLevel == dmxFatal) VFatalError(format, args);
+ else VErrorF(format, args);
+ }
+}
+
+void dmxLog(dmxLogLevel logLevel, const char *format, ...)
+{
+ va_list args;
+
+ dmxHeader(logLevel, NULL, NULL);
+ va_start(args, format);
+ dmxMessage(logLevel, format, args);
+ va_end(args);
+}
+
+#ifndef DMX_LOG_STANDALONE
+void dmxLogOutput(DMXScreenInfo *dmxScreen, const char *format, ...)
+{
+ va_list args;
+
+ dmxHeader(dmxInfo, NULL, dmxScreen);
+ va_start(args, format);
+ dmxMessage(dmxInfo, format, args);
+ va_end(args);
+}
+
+void dmxLogOutputWarning(DMXScreenInfo *dmxScreen, const char *format, ...)
+{
+ va_list args;
+
+ dmxHeader(dmxWarning, NULL, dmxScreen);
+ va_start(args, format);
+ dmxMessage(dmxWarning, format, args);
+ va_end(args);
+}
+
+void dmxLogInput(DMXInputInfo *dmxInput, const char *format, ...)
+{
+ va_list args;
+
+ dmxHeader(dmxInfo, dmxInput, NULL);
+ va_start(args, format);
+ dmxMessage(dmxInfo, format, args);
+ va_end(args);
+}
+
+void dmxLogAdditional(DMXScreenInfo *dmxScreen, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ dmxMessage(dmxInfo, format, args);
+ va_end(args);
+}
+
+void dmxLogArgs(dmxLogLevel logLevel, int argc, char **argv)
+{
+ int i;
+ for (i = 0; i < argc; i++)
+ dmxLog(logLevel, " Arg[%d] = \"%s\"\n", i, argv[i]);
+}
+
+void dmxLogVisual(DMXScreenInfo *dmxScreen, XVisualInfo *vi, int defaultVisual)
+{
+ const char *class = "Unknown";
+
+ switch (vi->class) {
+ case StaticGray: class = "StaticGray "; break;
+ case GrayScale: class = "GrayScale "; break;
+ case StaticColor: class = "StaticColor"; break;
+ case PseudoColor: class = "PseudoColor"; break;
+ case TrueColor: class = "TrueColor "; break;
+ case DirectColor: class = "DirectColor"; break;
+ }
+
+ if (dmxScreen) {
+ dmxLogOutput(dmxScreen,
+ "0x%02x %s %2db %db/rgb %3d 0x%04x 0x%04x 0x%04x%s\n",
+ vi->visualid, class, vi->depth, vi->bits_per_rgb,
+ vi->colormap_size,
+ vi->red_mask, vi->green_mask, vi->blue_mask,
+ defaultVisual ? " *" : "");
+ } else {
+ dmxLog(dmxInfo,
+ "0x%02x %s %2db %db/rgb %3d 0x%04x 0x%04x 0x%04x%s\n",
+ vi->visualid, class, vi->depth, vi->bits_per_rgb,
+ vi->colormap_size,
+ vi->red_mask, vi->green_mask, vi->blue_mask,
+ defaultVisual ? " *" : "");
+ }
+}
+#endif
+
+const char *dmxEventName(int type)
+{
+ switch (type) {
+ case KeyPress: return "KeyPress";
+ case KeyRelease: return "KeyRelease";
+ case ButtonPress: return "ButtonPress";
+ case ButtonRelease: return "ButtonRelease";
+ case MotionNotify: return "MotionNotify";
+ case EnterNotify: return "EnterNotify";
+ case LeaveNotify: return "LeaveNotify";
+ case FocusIn: return "FocusIn";
+ case FocusOut: return "FocusOut";
+ case KeymapNotify: return "KeymapNotify";
+ case Expose: return "Expose";
+ case GraphicsExpose: return "GraphicsExpose";
+ case NoExpose: return "NoExpose";
+ case VisibilityNotify: return "VisibilityNotify";
+ case CreateNotify: return "CreateNotify";
+ case DestroyNotify: return "DestroyNotify";
+ case UnmapNotify: return "UnmapNotify";
+ case MapNotify: return "MapNotify";
+ case MapRequest: return "MapRequest";
+ case ReparentNotify: return "ReparentNotify";
+ case ConfigureNotify: return "ConfigureNotify";
+ case ConfigureRequest: return "ConfigureRequest";
+ case GravityNotify: return "GravityNotify";
+ case ResizeRequest: return "ResizeRequest";
+ case CirculateNotify: return "CirculateNotify";
+ case CirculateRequest: return "CirculateRequest";
+ case PropertyNotify: return "PropertyNotify";
+ case SelectionClear: return "SelectionClear";
+ case SelectionRequest: return "SelectionRequest";
+ case SelectionNotify: return "SelectionNotify";
+ case ColormapNotify: return "ColormapNotify";
+ case ClientMessage: return "ClientMessage";
+ case MappingNotify: return "MappingNotify";
+ default: return "<unknown>";
+ }
+}
diff --git a/xc/programs/Xserver/hw/dmx/dmxlog.h b/xc/programs/Xserver/hw/dmx/dmxlog.h
new file mode 100644
index 000000000..6c0086936
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxlog.h
@@ -0,0 +1,65 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef _DMXLOG_H_
+#define _DMXLOG_H_
+
+/* Logging levels -- output is tunable with dmxSetLogLevel. */
+typedef enum {
+ dmxDebug,
+ dmxInfo,
+ dmxWarning,
+ dmxError,
+ dmxFatal
+} dmxLogLevel;
+
+/* Logging functions used by Xserver/hw/dmx routines. */
+extern dmxLogLevel dmxSetLogLevel(dmxLogLevel newLevel);
+extern dmxLogLevel dmxGetLogLevel(void);
+extern void dmxLog(dmxLogLevel logLevel, const char *format, ...);
+extern const char *dmxEventName(int type);
+
+#ifndef DMX_LOG_STANDALONE
+extern void dmxLogOutput(DMXScreenInfo *dmxScreen, const char *format, ...);
+extern void dmxLogOutputWarning(DMXScreenInfo *dmxScreen, const char *format,
+ ...);
+extern void dmxLogInput(DMXInputInfo *dmxInput, const char *format, ...);
+extern void dmxLogArgs(dmxLogLevel logLevel, int argc, char **argv);
+extern void dmxLogVisual(DMXScreenInfo *dmxScreen, XVisualInfo *vi,
+ int defaultVisual);
+extern void dmxLogAdditional(DMXScreenInfo *dmxScreen,
+ const char *format, ...);
+#endif
+
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/dmxpixmap.c b/xc/programs/Xserver/hw/dmx/dmxpixmap.c
new file mode 100644
index 000000000..209eed07d
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxpixmap.c
@@ -0,0 +1,190 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ *
+ */
+
+#include "dmx.h"
+#include "dmxpixmap.h"
+
+#include "pixmapstr.h"
+#include "servermd.h"
+
+Bool dmxInitPixmap(ScreenPtr pScreen)
+{
+#ifdef PIXPRIV
+ if (!AllocatePixmapPrivate(pScreen, dmxPixPrivateIndex,
+ sizeof(dmxPixPrivRec)))
+ return FALSE;
+
+ return TRUE;
+#else
+#error Must define PIXPRIV to compile DMX X server
+#endif
+}
+
+
+PixmapPtr dmxCreatePixmap(ScreenPtr pScreen, int width, int height, int depth)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ PixmapPtr pPixmap;
+ dmxPixPrivPtr pPixPriv;
+ int bpp;
+
+#if 0
+ DMX_UNWRAP(CreatePixmap, dmxScreen, pScreen);
+ if (pScreen->CreatePixmap)
+ ret = pScreen->CreatePixmap(pPixmap);
+#endif
+
+ /* Create pixmap on back-end server */
+ if (depth == 24) bpp = 32;
+ else bpp = depth;
+
+ pPixmap = AllocatePixmap(pScreen, 0);
+ if (!pPixmap)
+ return NullPixmap;
+
+ pPixmap->drawable.type = DRAWABLE_PIXMAP;
+ pPixmap->drawable.class = 0;
+ pPixmap->drawable.pScreen = pScreen;
+ pPixmap->drawable.depth = depth;
+ pPixmap->drawable.bitsPerPixel = bpp;
+ pPixmap->drawable.id = 0;
+ pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ pPixmap->drawable.x = 0;
+ pPixmap->drawable.y = 0;
+ pPixmap->drawable.width = width;
+ pPixmap->drawable.height = height;
+ pPixmap->devKind = PixmapBytePad(width, bpp);
+ pPixmap->refcnt = 1;
+
+ pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap);
+ if (width && height) {
+ pPixPriv->pixmap = XCreatePixmap(dmxScreen->display,
+ dmxScreen->window,
+ width, height, depth);
+ XSync(dmxScreen->display, False);
+ } else {
+ pPixPriv->pixmap = (Pixmap)0;
+ }
+
+#if 0
+ DMX_WRAP(CreatePixmap, dmxCreatePixmap, dmxScreen, pScreen);
+#endif
+
+ return pPixmap;
+}
+
+Bool dmxDestroyPixmap(PixmapPtr pPixmap)
+{
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap);
+ Bool ret = TRUE;
+
+#if 0
+ DMX_UNWRAP(DestroyPixmap, dmxScreen, pScreen);
+#endif
+
+ /* Destroy pixmap on back-end server */
+ if (--pPixmap->refcnt)
+ return TRUE;
+ if (pPixPriv->pixmap) {
+ XFreePixmap(dmxScreen->display, pPixPriv->pixmap);
+ XSync(dmxScreen->display, False);
+ }
+ xfree(pPixmap);
+
+#if 0
+ if (pScreen->DestroyPixmap)
+ ret = pScreen->DestroyPixmap(pPixmap);
+ DMX_WRAP(DestroyPixmap, dmxDestroyPixmap, dmxScreen, pScreen);
+#endif
+
+ return ret;
+}
+
+RegionPtr dmxBitmapToRegion(PixmapPtr pPixmap)
+{
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap);
+ XImage *ximage;
+ RegionPtr pReg, pTmpReg;
+ int x, y;
+ unsigned long previousPixel, currentPixel;
+ BoxRec Box;
+ Bool overlap;
+
+ ximage = XGetImage(dmxScreen->display, pPixPriv->pixmap, 0, 0,
+ pPixmap->drawable.width, pPixmap->drawable.height,
+ 1, XYPixmap);
+
+ pReg = REGION_CREATE(pScreen, NULL, 1);
+ pTmpReg = REGION_CREATE(pScreen, NULL, 1);
+ if(!pReg || !pTmpReg) return NullRegion;
+
+ for (y = 0; y < pPixmap->drawable.height; y++) {
+ Box.y1 = y;
+ Box.y2 = y + 1;
+ previousPixel = 0L;
+ for (x = 0; x < pPixmap->drawable.width; x++) {
+ currentPixel = XGetPixel(ximage, x, y);
+ if (previousPixel != currentPixel) {
+ if (previousPixel == 0L) {
+ /* left edge */
+ Box.x1 = x;
+ } else if (currentPixel == 0L) {
+ /* right edge */
+ Box.x2 = x;
+ REGION_RESET(pScreen, pTmpReg, &Box);
+ REGION_APPEND(pScreen, pReg, pTmpReg);
+ }
+ previousPixel = currentPixel;
+ }
+ }
+ if (previousPixel != 0L) {
+ /* right edge because of the end of pixmap */
+ Box.x2 = pPixmap->drawable.width;
+ REGION_RESET(pScreen, pTmpReg, &Box);
+ REGION_APPEND(pScreen, pReg, pTmpReg);
+ }
+ }
+
+ REGION_DESTROY(pScreen, pTmpReg);
+ XDestroyImage(ximage);
+
+ REGION_VALIDATE(pScreen, pReg, &overlap);
+
+ XSync(dmxScreen->display, False);
+ return(pReg);
+}
diff --git a/xc/programs/Xserver/hw/dmx/dmxpixmap.h b/xc/programs/Xserver/hw/dmx/dmxpixmap.h
new file mode 100644
index 000000000..e83abefbf
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxpixmap.h
@@ -0,0 +1,57 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ *
+ */
+
+#ifndef DMXPIXMAP_H
+#define DMXPIXMAP_H
+
+#include "pixmapstr.h"
+
+typedef struct _dmxPixPriv {
+ Pixmap pixmap;
+} dmxPixPrivRec, *dmxPixPrivPtr;
+
+
+extern Bool dmxInitPixmap(ScreenPtr pScreen);
+
+extern PixmapPtr dmxCreatePixmap(ScreenPtr pScreen,
+ int width, int height, int depth);
+extern Bool dmxDestroyPixmap(PixmapPtr pPixmap);
+extern RegionPtr dmxBitmapToRegion(PixmapPtr pPixmap);
+
+extern int dmxPixPrivateIndex;
+
+#define DMX_GET_PIXMAP_PRIV(_pPix) \
+ (dmxPixPrivPtr)(_pPix)->devPrivates[dmxPixPrivateIndex].ptr
+
+#endif /* DMXPIXMAP_H */
diff --git a/xc/programs/Xserver/hw/dmx/dmxprop.c b/xc/programs/Xserver/hw/dmx/dmxprop.c
new file mode 100644
index 000000000..8917b6845
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxprop.c
@@ -0,0 +1,217 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#include "dmx.h"
+#include "dmxprop.h"
+#include "dmxlog.h"
+#include <X11/Xmu/SysUtil.h>
+#include <X11/Xatom.h>
+
+#define DMX_ATOMNAME "DMX_NAME"
+#define DMX_IDENT "Xdmx"
+
+extern char *display;
+
+static int dmxPropertyErrorHandler(Display *dpy, XErrorEvent *ev)
+{
+ return 0;
+}
+
+static const unsigned char *dmxPropertyIdentifier(void)
+{
+ static char buf[128];
+ static int initialized = 0;
+ char hostname[256];
+
+ if (initialized++) return (unsigned char *)buf;
+
+ XmuGetHostname(hostname, sizeof(hostname));
+ XmuSnprintf(buf, sizeof(buf), "%s:%s:%s", DMX_IDENT, hostname, display);
+ return (unsigned char *)buf;
+}
+
+void *dmxPropertyIterate(DMXScreenInfo *start,
+ void *(*f)(DMXScreenInfo *dmxScreen, void *),
+ void *closure)
+{
+ DMXScreenInfo *pt;
+
+ if (!start->next) return f(start, closure);
+
+ for (pt = start->next; /* condition at end of loop */; pt = pt->next) {
+ void *retval;
+ if ((retval = f(pt, closure))) return retval;
+ if (pt == start) break;
+ }
+ return NULL;
+}
+
+/* Returns 0 if this is the only Xdmx session on the display; 1 otherwise. */
+static int dmxPropertyCheckOtherServers(DMXScreenInfo *dmxScreen, Atom atom)
+{
+ Display *dpy = dmxScreen->display;
+ XTextProperty tp;
+ XTextProperty tproot;
+ const char *pt;
+ int retcode = 0;
+ char **list = NULL;
+ int count = 0;
+ int i;
+ int (*dmxOldHandler)(Display *, XErrorEvent *);
+
+ if (!XGetTextProperty(dpy, RootWindow(dpy,0), &tproot, atom)
+ || !tproot.nitems) return 0;
+
+ /* Ignore BadWindow errors for this
+ * routine because the window id stored
+ * in the property might be old */
+ dmxOldHandler = XSetErrorHandler(dmxPropertyErrorHandler);
+ for (pt = (const char *)tproot.value; pt && *pt; pt = pt ? pt + 1 : NULL) {
+ if ((pt = strchr(pt, ','))) {
+ Window win = strtol(pt+1, NULL, 10);
+ if (XGetTextProperty(dpy, win, &tp, atom) && tp.nitems) {
+ if (!strncmp(tp.value, DMX_IDENT, strlen(DMX_IDENT))) {
+ int flag = 0;
+ for (i = 0; i < count; i++)
+ if (!strcmp(list[i], tp.value)) {
+ ++flag;
+ break;
+ }
+ if (flag) continue;
+ ++retcode;
+ dmxLogOutputWarning(dmxScreen,
+ "%s also running on %s\n",
+ tp.value, dmxScreen->name);
+ list = xrealloc(list, ++count * sizeof(*list));
+ list[count-1] = xalloc(tp.nitems + 1);
+ strcpy(list[count-1], tp.value);
+ }
+ }
+ }
+ }
+ XSetErrorHandler(dmxOldHandler);
+
+ for (i = 0; i < count; i++) xfree(list[i]);
+ xfree(list);
+ if (!retcode) dmxLog(dmxDebug, "No Xdmx server running on backend\n");
+ return retcode;
+}
+
+/* Returns NULL if this is the only Xdmx window on the display.
+ * Otherwise, returns a pointer to the dmxScreen of the other windows on
+ * the display. */
+static DMXScreenInfo *dmxPropertyCheckOtherWindows(DMXScreenInfo *dmxScreen,
+ Atom atom)
+{
+ Display *dpy = dmxScreen->display;
+ const unsigned char *id = dmxPropertyIdentifier();
+ XTextProperty tproot;
+ XTextProperty tp;
+ const char *pt;
+ int (*dmxOldHandler)(Display *, XErrorEvent *);
+
+ if (!XGetTextProperty(dpy, RootWindow(dpy,0), &tproot, atom)
+ || !tproot.nitems) return 0;
+
+ /* Ignore BadWindow errors for this
+ * routine because the window id stored
+ * in the property might be old */
+ dmxOldHandler = XSetErrorHandler(dmxPropertyErrorHandler);
+ for (pt = (const char *)tproot.value; pt && *pt; pt = pt ? pt + 1 : NULL) {
+ if ((pt = strchr(pt, ','))) {
+ Window win = strtol(pt+1, NULL, 10);
+ if (XGetTextProperty(dpy, win, &tp, atom) && tp.nitems) {
+ dmxLog(dmxDebug,"On %s/%lu: %s\n",
+ dmxScreen->name, win, tp.value);
+ if (!strncmp(tp.value, id, strlen(id))) {
+ int idx;
+
+ if (!(pt = strchr(tp.value, ','))) continue;
+ idx = strtol(pt+1, NULL, 10);
+ if (idx < 0 || idx >= dmxNumScreens) continue;
+ if (dmxScreens[idx].window != win) continue;
+ XSetErrorHandler(dmxOldHandler);
+ return &dmxScreens[idx];
+ }
+ }
+ }
+ }
+ XSetErrorHandler(dmxOldHandler);
+ return 0;
+}
+
+/* Returns 0 if this is the only Xdmx session on the display; 1 otherwise. */
+int dmxPropertyDisplay(DMXScreenInfo *dmxScreen)
+{
+ Atom atom;
+ const unsigned char *id = dmxPropertyIdentifier();
+ Display *dpy = dmxScreen->display;
+
+ atom = XInternAtom(dpy, DMX_ATOMNAME, False);
+ if (dmxPropertyCheckOtherServers(dmxScreen, atom)) {
+ dmxScreen->shared = 1;
+ return 1;
+ }
+ XChangeProperty(dpy, RootWindow(dpy,0), atom, XA_STRING, 8,
+ PropModeReplace, id, strlen((char *)id));
+ return 0;
+}
+
+void dmxPropertyWindow(DMXScreenInfo *dmxScreen)
+{
+ Atom atom;
+ const unsigned char *id = dmxPropertyIdentifier();
+ Display *dpy = dmxScreen->display;
+ Window win = dmxScreen->window;
+ DMXScreenInfo *other;
+ char buf[128];
+
+ atom = XInternAtom(dpy, DMX_ATOMNAME, False);
+ if ((other = dmxPropertyCheckOtherWindows(dmxScreen, atom))) {
+ DMXScreenInfo *tmp = dmxScreen->next;
+ dmxScreen->next = (other->next ? other->next : other);
+ other->next = (tmp ? tmp : dmxScreen);
+ dmxLog(dmxDebug, "%d/%s/%lu and %d/%s/%lu are on the same backend\n",
+ dmxScreen->index, dmxScreen->name, dmxScreen->window,
+ other->index, other->name, other->window);
+ }
+
+ XmuSnprintf(buf, sizeof(buf), ",%lu", win);
+ XChangeProperty(dpy, RootWindow(dpy,0), atom, XA_STRING, 8,
+ PropModeAppend, (unsigned char *)buf, strlen(buf));
+
+ XmuSnprintf(buf, sizeof(buf), "%s,%d", id, dmxScreen->index);
+ XChangeProperty(dpy, win, atom, XA_STRING, 8,
+ PropModeAppend, (unsigned char *)buf, strlen(buf));
+}
diff --git a/xc/programs/Xserver/hw/dmx/dmxprop.h b/xc/programs/Xserver/hw/dmx/dmxprop.h
new file mode 100644
index 000000000..b48f5b7d6
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxprop.h
@@ -0,0 +1,43 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef _DMXPROP_H_
+#define _DMXPROP_H_
+extern int dmxPropertyDisplay(DMXScreenInfo *dmxScreen);
+extern void dmxPropertyWindow(DMXScreenInfo *dmxScreen);
+extern void *dmxPropertyIterate(DMXScreenInfo *start,
+ void *(*f)(DMXScreenInfo *dmxScreen,
+ void *closure),
+ void *closure);
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/dmxscrinit.c b/xc/programs/Xserver/hw/dmx/dmxscrinit.c
new file mode 100644
index 000000000..581725ab1
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxscrinit.c
@@ -0,0 +1,445 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ * David H. Dawes <dawes@xfree86.org>
+ *
+ */
+
+#include "dmx.h"
+#include "dmxshadow.h"
+#include "dmxscrinit.h"
+#include "dmxcursor.h"
+#include "dmxgc.h"
+#include "dmxgcops.h"
+#include "dmxwindow.h"
+#include "dmxpixmap.h"
+#include "dmxfont.h"
+#include "dmxcmap.h"
+#include "dmxprop.h"
+
+#include "fb.h"
+#include "mipointer.h"
+#include "micmap.h"
+
+extern Bool dmxCloseScreen(int index, ScreenPtr pScreen);
+static Bool dmxSaveScreen(ScreenPtr pScreen, int what);
+
+static int dmxGeneration;
+static int dmxCursorGeneration[MAXSCREENS];
+
+int dmxGCPrivateIndex;
+int dmxWinPrivateIndex;
+int dmxPixPrivateIndex;
+int dmxFontPrivateIndex;
+int dmxScreenPrivateIndex;
+int dmxColormapPrivateIndex;
+
+Bool dmxScreenInit(int index, ScreenPtr pScreen, int argc, char *argv[])
+{
+ XSetWindowAttributes attribs;
+ XGCValues gcvals;
+ unsigned long mask;
+ int i, j;
+ DMXScreenInfo *dmxScreen = &dmxScreens[index];
+ int interval, preferBlanking, allowExposures;
+
+ if (dmxGeneration != serverGeneration) {
+ /* Allocate GC private index */
+ dmxGCPrivateIndex = AllocateGCPrivateIndex();
+ if (dmxGCPrivateIndex == -1)
+ return FALSE;
+
+ /* Allocate window private index */
+ dmxWinPrivateIndex = AllocateWindowPrivateIndex();
+ if (dmxWinPrivateIndex == -1)
+ return FALSE;
+
+#ifdef PIXPRIV
+ /* Allocate pixmap private index */
+ dmxPixPrivateIndex = AllocatePixmapPrivateIndex();
+ if (dmxPixPrivateIndex == -1)
+ return FALSE;
+#else
+#error Must define PIXPRIV to compile DMX X server
+#endif
+
+ /* Allocate font private index */
+ dmxFontPrivateIndex = AllocateFontPrivateIndex();
+ if (dmxFontPrivateIndex == -1)
+ return FALSE;
+
+ /* Allocate screen private index */
+ dmxScreenPrivateIndex = AllocateScreenPrivateIndex();
+ if (dmxScreenPrivateIndex == -1)
+ return False;
+
+ dmxGeneration = serverGeneration;
+ }
+
+ if (dmxShadowFB) {
+ dmxScreen->shadow = shadowAlloc(dmxScreen->width,
+ dmxScreen->height,
+ dmxScreen->bpp);
+ } else {
+ if (!dmxInitGC(pScreen)) return FALSE;
+ if (!dmxInitWindow(pScreen)) return FALSE;
+ if (!dmxInitPixmap(pScreen)) return FALSE;
+ }
+
+ /*
+ * Initalise the visual types. miSetVisualTypesAndMasks() requires
+ * that all of the types for each depth be collected together. It's
+ * intended for slightly different usage to what we would like here.
+ * Maybe a miAddVisualTypeAndMask() function will be added to make
+ * things easier here.
+ */
+ for (i = 0; i < dmxScreen->numDepths; i++) {
+ int depth;
+ int visuals = 0;
+ int bitsPerRgb = 0;
+ int preferredClass = -1;
+ Pixel redMask = 0;
+ Pixel greenMask = 0;
+ Pixel blueMask = 0;
+
+ depth = dmxScreen->depths[i];
+ for (j = 0; j < dmxScreen->numVisuals; j++) {
+ XVisualInfo *vi;
+
+ vi = &dmxScreen->visuals[j];
+ if (vi->depth == depth) {
+ /* Assume the masks are all the same. */
+ visuals |= (1 << vi->class);
+ bitsPerRgb = vi->bits_per_rgb;
+ redMask = vi->red_mask;
+ greenMask = vi->green_mask;
+ blueMask = vi->blue_mask;
+ if (j == dmxScreen->defVisualIndex) {
+ preferredClass = vi->class;
+ }
+ }
+ }
+ miSetVisualTypesAndMasks(depth, visuals, bitsPerRgb, preferredClass,
+ redMask, greenMask, blueMask);
+ }
+
+ fbScreenInit(pScreen,
+ dmxShadowFB ? dmxScreen->shadow : NULL,
+ dmxScreen->width,
+ dmxScreen->height,
+ 75, 75,
+ dmxScreen->width,
+ dmxScreen->bpp);
+ fbPictureInit(pScreen, 0, 0);
+
+ if (dmxShadowFB && !shadowInit(pScreen, dmxShadowUpdateProc, NULL))
+ return FALSE;
+
+ miInitializeBackingStore(pScreen);
+
+ if (dmxShadowFB) {
+ miDCInitialize(pScreen, &dmxPointerCursorFuncs);
+ } else {
+ if (dmxCursorGeneration[index] != serverGeneration) {
+ if (!(miPointerInitialize(pScreen,
+ &dmxPointerSpriteFuncs,
+ &dmxPointerCursorFuncs,
+ FALSE)))
+ return FALSE;
+
+ dmxCursorGeneration[index] = serverGeneration;
+ }
+ }
+
+ pScreen->mmWidth = DisplayWidthMM(dmxScreen->display,
+ DefaultScreen(dmxScreen->display));
+ pScreen->mmHeight = DisplayHeightMM(dmxScreen->display,
+ DefaultScreen(dmxScreen->display));
+
+ pScreen->whitePixel = dmxScreen->whitePixel;
+ pScreen->blackPixel = dmxScreen->blackPixel;
+
+ DMX_WRAP(CloseScreen, dmxCloseScreen, dmxScreen, pScreen);
+ DMX_WRAP(SaveScreen, dmxSaveScreen, dmxScreen, pScreen);
+
+ /* Disable the back end screen saver, and force a screen saver reset. */
+ XGetScreenSaver(dmxScreen->display, &dmxScreen->savedTimeout, &interval,
+ &preferBlanking, &allowExposures);
+ XSetScreenSaver(dmxScreen->display, 0, interval,
+ preferBlanking, allowExposures);
+ XResetScreenSaver(dmxScreen->display);
+ XSync(dmxScreen->display, False);
+
+ /* Create root window for screen */
+ mask = CWBackPixel | CWEventMask | CWColormap | CWOverrideRedirect;
+ attribs.background_pixel = dmxScreen->blackPixel;
+ attribs.event_mask = (KeyPressMask
+ | KeyReleaseMask
+ | ButtonPressMask
+ | ButtonReleaseMask
+ | EnterWindowMask
+ | LeaveWindowMask
+ | PointerMotionMask
+ | KeymapStateMask
+ | FocusChangeMask);
+ attribs.colormap = dmxScreen->defColormaps[0];
+ attribs.override_redirect = TRUE;
+
+ dmxScreen->window =
+ XCreateWindow(dmxScreen->display,
+ DefaultRootWindow(dmxScreen->display),
+ dmxScreen->xoff,
+ dmxScreen->yoff,
+ dmxScreen->width,
+ dmxScreen->height,
+ 0,
+ pScreen->rootDepth,
+ InputOutput,
+ dmxScreen->visuals[dmxScreen->defVisualIndex].visual,
+ mask,
+ &attribs);
+ dmxPropertyWindow(dmxScreen);
+
+ /*
+ * This turns off the cursor by defining a cursor with no visible
+ * components.
+ */
+ {
+ char noCursorData[] = {0, 0, 0, 0,
+ 0, 0, 0, 0};
+ Pixmap pixmap;
+ XColor color, tmp;
+
+ pixmap = XCreateBitmapFromData(dmxScreen->display, dmxScreen->window,
+ noCursorData, 8, 8);
+ XAllocNamedColor(dmxScreen->display, dmxScreen->defColormaps[0],
+ "black", &color, &tmp);
+ dmxScreen->noCursor = XCreatePixmapCursor(dmxScreen->display,
+ pixmap, pixmap,
+ &color, &color, 0, 0);
+ XDefineCursor(dmxScreen->display, dmxScreen->window,
+ dmxScreen->noCursor);
+
+ XFreePixmap(dmxScreen->display, pixmap);
+ }
+
+ XMapWindow(dmxScreen->display, dmxScreen->window);
+
+ mask = (GCFunction
+ | GCPlaneMask
+ | GCClipMask);
+ gcvals.function = GXcopy;
+ gcvals.plane_mask = AllPlanes;
+ gcvals.clip_mask = None;
+
+ dmxScreen->gc = XCreateGC(dmxScreen->display,
+ dmxScreen->window,
+ mask, &gcvals);
+
+ if (dmxShadowFB) {
+ dmxScreen->image =
+ XCreateImage(dmxScreen->display,
+ dmxScreen->visuals[dmxScreen->defVisualIndex].visual,
+ dmxScreen->depth,
+ ZPixmap,
+ 0,
+ (char *)dmxScreen->shadow,
+ dmxScreen->width, dmxScreen->height,
+ dmxScreen->bpp,
+ PixmapBytePad(dmxScreen->width, dmxScreen->bpp));
+ } else {
+ /* Wrap GC functions */
+ DMX_WRAP(CreateGC, dmxCreateGC, dmxScreen, pScreen);
+
+ /* Wrap Window functions */
+ DMX_WRAP(CreateWindow, dmxCreateWindow, dmxScreen, pScreen);
+ DMX_WRAP(DestroyWindow, dmxDestroyWindow, dmxScreen, pScreen);
+ DMX_WRAP(PositionWindow, dmxPositionWindow, dmxScreen, pScreen);
+ DMX_WRAP(ChangeWindowAttributes, dmxChangeWindowAttributes, dmxScreen,
+ pScreen);
+ DMX_WRAP(RealizeWindow, dmxRealizeWindow, dmxScreen, pScreen);
+ DMX_WRAP(UnrealizeWindow, dmxUnrealizeWindow, dmxScreen, pScreen);
+ DMX_WRAP(RestackWindow, dmxRestackWindow, dmxScreen, pScreen);
+ DMX_WRAP(WindowExposures, dmxWindowExposures, dmxScreen, pScreen);
+ DMX_WRAP(PaintWindowBackground, dmxPaintWindowBackground, dmxScreen,
+ pScreen);
+ DMX_WRAP(PaintWindowBorder, dmxPaintWindowBorder, dmxScreen, pScreen);
+ DMX_WRAP(CopyWindow, dmxCopyWindow, dmxScreen, pScreen);
+
+ DMX_WRAP(ResizeWindow, dmxResizeWindow, dmxScreen, pScreen);
+ DMX_WRAP(ReparentWindow, dmxReparentWindow, dmxScreen, pScreen);
+
+ DMX_WRAP(ChangeBorderWidth, dmxChangeBorderWidth, dmxScreen, pScreen);
+
+ /* Wrap Image functions */
+ DMX_WRAP(GetImage, dmxGetImage, dmxScreen, pScreen);
+ DMX_WRAP(GetSpans, dmxGetSpans, dmxScreen, pScreen);
+
+ /* Wrap Pixmap functions */
+ DMX_WRAP(CreatePixmap, dmxCreatePixmap, dmxScreen, pScreen);
+ DMX_WRAP(DestroyPixmap, dmxDestroyPixmap, dmxScreen, pScreen);
+ DMX_WRAP(BitmapToRegion, dmxBitmapToRegion, dmxScreen, pScreen);
+
+ /* Wrap Font functions */
+ DMX_WRAP(RealizeFont, dmxRealizeFont, dmxScreen, pScreen);
+ DMX_WRAP(UnrealizeFont, dmxUnrealizeFont, dmxScreen, pScreen);
+
+ /* Wrap Colormap functions */
+ DMX_WRAP(CreateColormap, dmxCreateColormap, dmxScreen, pScreen);
+ DMX_WRAP(DestroyColormap, dmxDestroyColormap, dmxScreen, pScreen);
+ DMX_WRAP(InstallColormap, dmxInstallColormap, dmxScreen, pScreen);
+ DMX_WRAP(StoreColors, dmxStoreColors, dmxScreen, pScreen);
+
+ /* Create default drawables (used during GC creation) */
+ for (i = 0; i < dmxScreen->numPixmapFormats; i++)
+ for (j = 0; j < dmxScreen->numDepths; j++)
+ if ((dmxScreen->pixmapFormats[i].depth == 1) ||
+ (dmxScreen->pixmapFormats[i].depth ==
+ dmxScreen->depths[j])) {
+ dmxScreen->defDrawables[i] = (Drawable)
+ XCreatePixmap(dmxScreen->display, dmxScreen->window,
+ 1, 1, dmxScreen->pixmapFormats[i].depth);
+ break;
+ }
+ }
+
+ if (!dmxCreateDefColormap(pScreen))
+ return FALSE;
+
+ return TRUE;
+}
+
+Bool dmxCloseScreen(int index, ScreenPtr pScreen)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[index];
+ int timeout, interval, preferBlanking, allowExposures;
+ int i;
+
+ /* Restore the back end screen saver state. */
+ XGetScreenSaver(dmxScreen->display, &timeout, &interval,
+ &preferBlanking, &allowExposures);
+ XSetScreenSaver(dmxScreen->display, dmxScreen->savedTimeout, interval,
+ preferBlanking, allowExposures);
+ XSync(dmxScreen->display, False);
+
+ /* Free the screen resources */
+ XUnmapWindow(dmxScreen->display, dmxScreen->window);
+ XDestroyWindow(dmxScreen->display, dmxScreen->window);
+ XFreeCursor(dmxScreen->display, dmxScreen->noCursor);
+ XFreeGC(dmxScreen->display, dmxScreen->gc);
+
+ if (dmxShadowFB) {
+ /* Free the shadow framebuffer */
+ xfree(dmxScreen->shadow);
+ XFree(dmxScreen->image);
+ } else {
+ /* Free the default drawables */
+ for (i = 0; i < dmxScreen->numPixmapFormats; i++)
+ XFreePixmap(dmxScreen->display, dmxScreen->defDrawables[i]);
+
+ /* Unwrap the pScreen functions */
+ DMX_UNWRAP(CreateGC, dmxScreen, pScreen);
+
+ DMX_UNWRAP(CreateWindow, dmxScreen, pScreen);
+ DMX_UNWRAP(DestroyWindow, dmxScreen, pScreen);
+ DMX_UNWRAP(PositionWindow, dmxScreen, pScreen);
+ DMX_UNWRAP(ChangeWindowAttributes, dmxScreen, pScreen);
+ DMX_UNWRAP(RealizeWindow, dmxScreen, pScreen);
+ DMX_UNWRAP(UnrealizeWindow, dmxScreen, pScreen);
+ DMX_UNWRAP(RestackWindow, dmxScreen, pScreen);
+ DMX_UNWRAP(WindowExposures, dmxScreen, pScreen);
+ DMX_UNWRAP(PaintWindowBackground, dmxScreen, pScreen);
+ DMX_UNWRAP(PaintWindowBorder, dmxScreen, pScreen);
+ DMX_UNWRAP(CopyWindow, dmxScreen, pScreen);
+
+ DMX_UNWRAP(ResizeWindow, dmxScreen, pScreen);
+ DMX_UNWRAP(ReparentWindow, dmxScreen, pScreen);
+
+ DMX_UNWRAP(ChangeBorderWidth, dmxScreen, pScreen);
+
+ DMX_UNWRAP(GetImage, dmxScreen, pScreen);
+ DMX_UNWRAP(GetSpans, dmxScreen, pScreen);
+
+ DMX_UNWRAP(CreatePixmap, dmxScreen, pScreen);
+ DMX_UNWRAP(DestroyPixmap, dmxScreen, pScreen);
+ DMX_UNWRAP(BitmapToRegion, dmxScreen, pScreen);
+
+ DMX_UNWRAP(RealizeFont, dmxScreen, pScreen);
+ DMX_UNWRAP(UnrealizeFont, dmxScreen, pScreen);
+
+ DMX_UNWRAP(CreateColormap, dmxScreen, pScreen);
+ DMX_UNWRAP(DestroyColormap, dmxScreen, pScreen);
+ DMX_UNWRAP(InstallColormap, dmxScreen, pScreen);
+ DMX_UNWRAP(StoreColors, dmxScreen, pScreen);
+ }
+
+ DMX_UNWRAP(SaveScreen, dmxScreen, pScreen);
+
+ /* Free resources allocated during initialization (in dmxinit.c) */
+ for (i = 0; i < dmxScreen->numDefColormaps; i++)
+ XFreeColormap(dmxScreen->display, dmxScreen->defColormaps[i]);
+ xfree(dmxScreen->defColormaps);
+
+ XFree(dmxScreen->visuals);
+ XFree(dmxScreen->depths);
+ XFree(dmxScreen->pixmapFormats);
+
+ XSync(dmxScreen->display, False);
+
+ if (dmxScreen->display) {
+ XCloseDisplay(dmxScreen->display);
+ dmxScreen->display = NULL;
+ }
+
+ DMX_UNWRAP(CloseScreen, dmxScreen, pScreen);
+ return pScreen->CloseScreen(index, pScreen);
+}
+
+static Bool
+dmxSaveScreen(ScreenPtr pScreen, int what)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+
+ switch (what) {
+ case SCREEN_SAVER_OFF:
+ case SCREEN_SAVER_FORCER:
+ XResetScreenSaver(dmxScreen->display);
+ XSync(dmxScreen->display, False);
+ break;
+ case SCREEN_SAVER_ON:
+ case SCREEN_SAVER_CYCLE:
+ XActivateScreenSaver(dmxScreen->display);
+ XSync(dmxScreen->display, False);
+ break;
+ }
+ return TRUE;
+}
+
diff --git a/xc/programs/Xserver/hw/dmx/dmxscrinit.h b/xc/programs/Xserver/hw/dmx/dmxscrinit.h
new file mode 100644
index 000000000..3c2cf7353
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxscrinit.h
@@ -0,0 +1,46 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ * David H. Dawes <dawes@xfree86.org>
+ *
+ */
+
+#ifndef DMXSCRINIT_H
+#define DMXSCRINIT_H
+
+#include "scrnintstr.h"
+
+extern int dmxScreenPrivateIndex;
+
+extern Bool dmxScreenInit(int index, ScreenPtr pScreen,
+ int argc, char *argv[]);
+
+#endif /* DMXSCRINIT_H */
diff --git a/xc/programs/Xserver/hw/dmx/dmxshadow.c b/xc/programs/Xserver/hw/dmx/dmxshadow.c
new file mode 100644
index 000000000..50b818ad2
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxshadow.c
@@ -0,0 +1,60 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ * David H. Dawes <dawes@xfree86.org>
+ *
+ */
+
+#include "dmx.h"
+#include "dmxshadow.h"
+
+void dmxShadowUpdateProc(ScreenPtr pScreen, shadowBufPtr pBuf)
+{
+ RegionPtr damage = &pBuf->damage;
+ int nbox = REGION_NUM_RECTS(damage);
+ BoxPtr pbox = REGION_RECTS(damage);
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+
+ while (nbox--) {
+ XPutImage(dmxScreen->display,
+ dmxScreen->window,
+ dmxScreen->gc,
+ dmxScreen->image,
+ pbox->x1, pbox->y1,
+ pbox->x1, pbox->y1,
+ pbox->x2 - pbox->x1,
+ pbox->y2 - pbox->y1);
+
+ pbox++;
+ }
+
+ XSync(dmxScreen->display, False);
+}
diff --git a/xc/programs/Xserver/hw/dmx/dmxshadow.h b/xc/programs/Xserver/hw/dmx/dmxshadow.h
new file mode 100644
index 000000000..78ef5e26d
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxshadow.h
@@ -0,0 +1,44 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ * David H. Dawes <dawes@xfree86.org>
+ *
+ */
+
+#ifndef DMXSHADOW_H
+#define DMXSHADOW_H
+
+#include "shadow.h"
+#include "scrnintstr.h"
+
+extern void dmxShadowUpdateProc(ScreenPtr pScreen, shadowBufPtr pBuf);
+
+#endif /* DMXSHADOW_H */
diff --git a/xc/programs/Xserver/hw/dmx/dmxvisual.c b/xc/programs/Xserver/hw/dmx/dmxvisual.c
new file mode 100644
index 000000000..8f0208612
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxvisual.c
@@ -0,0 +1,85 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ *
+ */
+
+#include "dmx.h"
+#include "dmxvisual.h"
+
+#include "scrnintstr.h"
+
+Visual *dmxLookupVisual(ScreenPtr pScreen, VisualPtr pVisual)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ int i;
+
+ for (i = 0; i < dmxScreen->numVisuals; i++) {
+ if (pVisual->class == dmxScreen->visuals[i].class &&
+ pVisual->bitsPerRGBValue == dmxScreen->visuals[i].bits_per_rgb &&
+ pVisual->ColormapEntries == dmxScreen->visuals[i].colormap_size &&
+ pVisual->nplanes == dmxScreen->visuals[i].depth &&
+ pVisual->redMask == dmxScreen->visuals[i].red_mask &&
+ pVisual->greenMask == dmxScreen->visuals[i].green_mask &&
+ pVisual->blueMask == dmxScreen->visuals[i].blue_mask) {
+ return dmxScreen->visuals[i].visual;
+ }
+ }
+
+ return NULL;
+}
+
+Visual *dmxLookupVisualFromID(ScreenPtr pScreen, VisualID vid)
+{
+ Visual *visual;
+ int i;
+
+ for (i = 0; i < pScreen->numVisuals; i++) {
+ if (pScreen->visuals[i].vid == vid) {
+ visual = dmxLookupVisual(pScreen, &pScreen->visuals[i]);
+ if (visual) return visual;
+ }
+ }
+
+ return NULL;
+}
+
+Colormap dmxColormapFromDefaultVisual(ScreenPtr pScreen, Visual *visual)
+{
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ int i;
+
+ for (i = 0; i < dmxScreen->numDefColormaps; i++)
+ if (visual == dmxScreen->visuals[i].visual)
+ return dmxScreen->defColormaps[i];
+
+ return None;
+}
diff --git a/xc/programs/Xserver/hw/dmx/dmxvisual.h b/xc/programs/Xserver/hw/dmx/dmxvisual.h
new file mode 100644
index 000000000..00fdb3021
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxvisual.h
@@ -0,0 +1,45 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ *
+ */
+
+#ifndef DMXVISUAL_H
+#define DMXVISUAL_H
+
+#include "scrnintstr.h"
+
+extern Visual *dmxLookupVisual(ScreenPtr pScreen, VisualPtr pVisual);
+extern Visual *dmxLookupVisualFromID(ScreenPtr pScreen, VisualID vid);
+extern Colormap dmxColormapFromDefaultVisual(ScreenPtr pScreen,
+ Visual *visual);
+
+#endif /* DMXVISUAL_H */
diff --git a/xc/programs/Xserver/hw/dmx/dmxwindow.c b/xc/programs/Xserver/hw/dmx/dmxwindow.c
new file mode 100644
index 000000000..23b6e48d1
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxwindow.c
@@ -0,0 +1,578 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ *
+ */
+
+#include "dmx.h"
+#include "dmxwindow.h"
+#include "dmxpixmap.h"
+#include "dmxcmap.h"
+#include "dmxvisual.h"
+
+#include "windowstr.h"
+
+Bool dmxInitWindow(ScreenPtr pScreen)
+{
+ if (!AllocateWindowPrivate(pScreen, dmxWinPrivateIndex,
+ sizeof(dmxWinPrivRec)))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+Bool dmxCreateWindow(WindowPtr pWindow)
+{
+ ScreenPtr pScreen = pWindow->drawable.pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
+ Bool ret = TRUE;
+ Window parent;
+ Visual *visual;
+ unsigned long mask;
+ XSetWindowAttributes attribs;
+ ColormapPtr pCmap;
+ dmxColormapPrivPtr pCmapPriv;
+
+ DMX_UNWRAP(CreateWindow, dmxScreen, pScreen);
+#if 0
+ if (pScreen->CreateWindow)
+ ret = pScreen->CreateWindow(pWindow);
+#endif
+
+ /* Create window on back-end server */
+ if (pWindow->drawable.class == InputOnly) {
+ dmxWinPrivPtr pParentPriv = DMX_GET_WINDOW_PRIV(pWindow->parent);
+ parent = pParentPriv->window;
+ visual = CopyFromParent;
+ mask = 0L;
+ } else {
+ mask = CWEventMask | CWBackingStore;
+ attribs.event_mask = ExposureMask;
+ attribs.backing_store = NotUseful;
+
+ if (pWindow->parent) {
+ /* Non-root windows */
+ dmxWinPrivPtr pParentPriv = DMX_GET_WINDOW_PRIV(pWindow->parent);
+
+ parent = pParentPriv->window;
+
+ if (pWindow->optional &&
+ pWindow->optional->visual != wVisual(pWindow->parent)) {
+
+ /* Find the matching visual */
+ visual = dmxLookupVisualFromID(pScreen, wVisual(pWindow));
+
+ /* Handle optional colormaps */
+ mask |= CWColormap;
+
+ if (pWindow->optional->colormap) {
+ pCmap = (ColormapPtr)LookupIDByType(wColormap(pWindow),
+ RT_COLORMAP);
+ pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap);
+ attribs.colormap = pCmapPriv->cmap;
+ } else {
+ attribs.colormap = dmxColormapFromDefaultVisual(pScreen,
+ visual);
+ }
+ } else {
+ visual = CopyFromParent;
+ }
+ } else {
+ /* Root window */
+ parent = dmxScreen->window; /* This is our root window */
+ visual = dmxScreen->visuals[dmxScreen->defVisualIndex].visual;
+
+ mask |= CWColormap;
+ pCmap = (ColormapPtr)LookupIDByType(wColormap(pWindow),
+ RT_COLORMAP);
+ pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap);
+ attribs.colormap = pCmapPriv->cmap;
+ }
+ }
+ pWinPriv->window = XCreateWindow(dmxScreen->display,
+ parent,
+ pWindow->origin.x - wBorderWidth(pWindow),
+ pWindow->origin.y - wBorderWidth(pWindow),
+ pWindow->drawable.width,
+ pWindow->drawable.height,
+ pWindow->borderWidth,
+ pWindow->drawable.depth,
+ pWindow->drawable.class,
+ visual,
+ mask,
+ &attribs);
+ XSync(dmxScreen->display, False);
+
+ DMX_WRAP(CreateWindow, dmxCreateWindow, dmxScreen, pScreen);
+
+ return ret;
+}
+
+Bool dmxDestroyWindow(WindowPtr pWindow)
+{
+ ScreenPtr pScreen = pWindow->drawable.pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ Bool ret = TRUE;
+ dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
+
+ DMX_UNWRAP(DestroyWindow, dmxScreen, pScreen);
+
+ /* Destroy window on back-end server */
+ XDestroyWindow(dmxScreen->display, pWinPriv->window);
+ XSync(dmxScreen->display, False);
+
+#if 0
+ if (pScreen->DestroyWindow)
+ ret = pScreen->DestroyWindow(pWindow);
+#endif
+ DMX_WRAP(DestroyWindow, dmxDestroyWindow, dmxScreen, pScreen);
+
+ return ret;
+}
+
+Bool dmxPositionWindow(WindowPtr pWindow, int x, int y)
+{
+ ScreenPtr pScreen = pWindow->drawable.pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ Bool ret = TRUE;
+ dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
+ unsigned int m;
+ XWindowChanges c;
+
+ DMX_UNWRAP(PositionWindow, dmxScreen, pScreen);
+#if 0
+ if (pScreen->PositionWindow)
+ ret = pScreen->PositionWindow(pWindow, x, y);
+#endif
+
+ /* Position window on back-end server */
+ m = CWX | CWY | CWWidth | CWHeight;
+ c.x = pWindow->origin.x - wBorderWidth(pWindow);
+ c.y = pWindow->origin.y - wBorderWidth(pWindow);
+ c.width = pWindow->drawable.width;
+ c.height = pWindow->drawable.height;
+ if (pWindow->drawable.class != InputOnly) {
+ m |= CWBorderWidth;
+ c.border_width = pWindow->borderWidth;
+ }
+
+ XConfigureWindow(dmxScreen->display, pWinPriv->window, m, &c);
+ XSync(dmxScreen->display, False);
+
+ DMX_WRAP(PositionWindow, dmxPositionWindow, dmxScreen, pScreen);
+
+ return ret;
+}
+
+Bool dmxChangeWindowAttributes(WindowPtr pWindow, unsigned long mask)
+{
+ ScreenPtr pScreen = pWindow->drawable.pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ Bool ret = TRUE;
+ dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
+ dmxPixPrivPtr pPixPriv;
+ XSetWindowAttributes attribs;
+
+ DMX_UNWRAP(ChangeWindowAttributes, dmxScreen, pScreen);
+#if 0
+ if (pScreen->ChangeWindowAttributes)
+ ret = pScreen->ChangeWindowAttributes(pWindow, mask);
+#endif
+
+ /* Change window attribs on back-end server */
+ if (mask & CWBackPixmap) {
+ switch (pWindow->backgroundState) {
+ case None:
+ attribs.background_pixmap = None;
+ break;
+
+ case ParentRelative:
+ attribs.background_pixmap = ParentRelative;
+ break;
+
+ case BackgroundPixmap:
+ pPixPriv = DMX_GET_PIXMAP_PRIV(pWindow->background.pixmap);
+ attribs.background_pixmap = pPixPriv->pixmap;
+ break;
+
+ case BackgroundPixel:
+ mask &= ~CWBackPixmap;
+ break;
+ }
+ }
+
+ if (mask & CWBackPixel) {
+ if (pWindow->backgroundState == BackgroundPixel)
+ attribs.background_pixel = pWindow->background.pixel;
+ else
+ mask &= ~CWBackPixel;
+ }
+
+ if (mask & CWBorderPixmap) {
+ if (pWindow->borderIsPixel)
+ mask &= ~CWBorderPixmap;
+ else {
+ pPixPriv = DMX_GET_PIXMAP_PRIV(pWindow->border.pixmap);
+ attribs.border_pixmap = pPixPriv->pixmap;
+ }
+ }
+
+ if (mask & CWBorderPixel) {
+ if (pWindow->borderIsPixel)
+ attribs.border_pixel = pWindow->border.pixel;
+ else
+ mask &= ~CWBorderPixel;
+ }
+
+ if (mask & CWBitGravity)
+ attribs.bit_gravity = pWindow->bitGravity;
+
+ if (mask & CWWinGravity)
+ mask &= ~CWWinGravity; /* Handled by dix */
+
+ if (mask & CWBackingStore)
+ mask &= ~CWBackingStore; /* Backing store not supported */
+
+ if (mask & CWBackingPlanes)
+ mask &= ~CWBackingPlanes; /* Backing store not supported */
+
+ if (mask & CWBackingPixel)
+ mask &= ~CWBackingPixel; /* Backing store not supported */
+
+ if (mask & CWOverrideRedirect)
+ attribs.override_redirect = pWindow->overrideRedirect;
+
+ if (mask & CWSaveUnder)
+ mask &= ~CWSaveUnder; /* Save unders not supported */
+
+ if (mask & CWEventMask)
+ mask &= ~CWEventMask; /* Events are handled by dix */
+
+ if (mask & CWDontPropagate)
+ mask &= ~CWDontPropagate; /* Events are handled by dix */
+
+ if (mask & CWColormap) {
+ ColormapPtr pCmap;
+ dmxColormapPrivPtr pCmapPriv;
+
+ pCmap = (ColormapPtr)LookupIDByType(wColormap(pWindow), RT_COLORMAP);
+ pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap);
+ attribs.colormap = pCmapPriv->cmap;
+ }
+
+ if (mask & CWCursor)
+ mask &= ~CWCursor; /* Handled by the cursor code */
+
+ if (mask) {
+ XChangeWindowAttributes(dmxScreen->display, pWinPriv->window,
+ mask, &attribs);
+ XSync(dmxScreen->display, False);
+ }
+
+ DMX_WRAP(ChangeWindowAttributes, dmxChangeWindowAttributes, dmxScreen,
+ pScreen);
+
+ return ret;
+}
+
+Bool dmxRealizeWindow(WindowPtr pWindow)
+{
+ ScreenPtr pScreen = pWindow->drawable.pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ Bool ret = TRUE;
+ dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
+
+ DMX_UNWRAP(RealizeWindow, dmxScreen, pScreen);
+#if 0
+ if (pScreen->RealizeWindow)
+ ret = pScreen->RealizeWindow(pWindow);
+#endif
+
+ /* Realize window on back-end server */
+ XMapWindow(dmxScreen->display, pWinPriv->window);
+ XSync(dmxScreen->display, False);
+
+ DMX_WRAP(RealizeWindow, dmxRealizeWindow, dmxScreen, pScreen);
+
+ return ret;
+}
+
+Bool dmxUnrealizeWindow(WindowPtr pWindow)
+{
+ ScreenPtr pScreen = pWindow->drawable.pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ Bool ret = TRUE;
+ dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
+
+ DMX_UNWRAP(UnrealizeWindow, dmxScreen, pScreen);
+#if 0
+ if (pScreen->UnrealizeWindow)
+ ret = pScreen->UnrealizeWindow(pWindow);
+#endif
+
+ /* Unrealize window on back-end server */
+ XUnmapWindow(dmxScreen->display, pWinPriv->window);
+ XSync(dmxScreen->display, False);
+
+ DMX_WRAP(UnrealizeWindow, dmxUnrealizeWindow, dmxScreen, pScreen);
+
+ return ret;
+}
+
+void dmxRestackWindow(WindowPtr pWindow, WindowPtr pOldNextSib)
+{
+ ScreenPtr pScreen = pWindow->drawable.pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
+ dmxWinPrivPtr pNextSibPriv;
+ WindowPtr pNextSib = pWindow->nextSib;
+ unsigned int m;
+ XWindowChanges c;
+
+
+ DMX_UNWRAP(RestackWindow, dmxScreen, pScreen);
+#if 0
+ if (pScreen->RestackWindow)
+ pScreen->RestackWindow(pWindow, pOldNextSib);
+#endif
+
+ if (pOldNextSib != pNextSib) {
+ /* Restack window on back-end server */
+
+ if (pNextSib == NullWindow) {
+ /* Window is at the bottom of the stack */
+ m = CWStackMode;
+ c.stack_mode = BottomIf;
+ XConfigureWindow(dmxScreen->display, pWinPriv->window, m, &c);
+ } else {
+ /* Window is at the top or in the middle of the stack */
+ pNextSibPriv = DMX_GET_WINDOW_PRIV(pNextSib);
+ m = CWStackMode | CWSibling;
+ c.sibling = pNextSibPriv->window;
+ c.stack_mode = Above;
+ XConfigureWindow(dmxScreen->display, pWinPriv->window, m, &c);
+ }
+
+ XSync(dmxScreen->display, False);
+ }
+
+ DMX_WRAP(RestackWindow, dmxRestackWindow, dmxScreen, pScreen);
+}
+
+static Bool dmxWindowExposurePredicate(Display *dpy, XEvent *ev, XPointer ptr)
+{
+ return (ev->type == Expose && ev->xexpose.window == *(Window *)ptr);
+}
+
+void dmxWindowExposures(WindowPtr pWindow, RegionPtr prgn,
+ RegionPtr other_exposed)
+{
+ ScreenPtr pScreen = pWindow->drawable.pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
+ XEvent ev;
+
+ DMX_UNWRAP(WindowExposures, dmxScreen, pScreen);
+
+ XSync(dmxScreen->display, False);
+
+ while (XCheckIfEvent(dmxScreen->display, &ev, dmxWindowExposurePredicate,
+ (char *)&pWinPriv->window)) {
+ /* Handle expose events -- this should not be necessary since
+ the base window in which the root window was created is
+ guaranteed to be on top (override_redirect), so we should
+ just swallow these events. If for some reason the window is
+ not on top, then we'd need to collect these events and send
+ them to the client later (e.g., during the block handler as
+ Xnest does). */
+ }
+
+#if 1
+ if (pScreen->WindowExposures)
+ pScreen->WindowExposures(pWindow, prgn, other_exposed);
+#endif
+ DMX_WRAP(WindowExposures, dmxWindowExposures, dmxScreen, pScreen);
+}
+
+void dmxPaintWindowBackground(WindowPtr pWindow, RegionPtr pRegion, int what)
+{
+ ScreenPtr pScreen = pWindow->drawable.pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
+ BoxPtr pBox;
+ int nBox;
+
+ DMX_UNWRAP(PaintWindowBackground, dmxScreen, pScreen);
+#if 0
+ if (pScreen->PaintWindowBackground)
+ pScreen->PaintWindowBackground(pWindow, pRegion, what);
+#endif
+
+ /* Paint window background on back-end server */
+ pBox = REGION_RECTS(pRegion);
+ nBox = REGION_NUM_RECTS(pRegion);
+ while (nBox--) {
+ XClearArea(dmxScreen->display, pWinPriv->window,
+ pBox->x1 - pWindow->drawable.x,
+ pBox->y1 - pWindow->drawable.y,
+ pBox->x2 - pBox->x1,
+ pBox->y2 - pBox->y1,
+ False);
+ pBox++;
+ }
+ XSync(dmxScreen->display, False);
+
+ DMX_WRAP(PaintWindowBackground, dmxPaintWindowBackground, dmxScreen, pScreen);
+}
+
+void dmxPaintWindowBorder(WindowPtr pWindow, RegionPtr pRegion, int what)
+{
+ ScreenPtr pScreen = pWindow->drawable.pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+
+ DMX_UNWRAP(PaintWindowBorder, dmxScreen, pScreen);
+#if 0
+ if (pScreen->PaintWindowBorder)
+ pScreen->PaintWindowBorder(pWindow, pRegion, what);
+#endif
+
+ /* Paint window border on back-end server */
+
+ DMX_WRAP(PaintWindowBorder, dmxPaintWindowBorder, dmxScreen, pScreen);
+}
+
+void dmxCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
+{
+ ScreenPtr pScreen = pWindow->drawable.pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
+ unsigned int m;
+ XWindowChanges c;
+
+ DMX_UNWRAP(CopyWindow, dmxScreen, pScreen);
+#if 0
+ if (pScreen->CopyWindow)
+ pScreen->CopyWindow(pWindow, ptOldOrg, prgnSrc);
+#endif
+
+ /* Move window on back-end server */
+ m = CWX | CWY | CWWidth | CWHeight;
+ c.x = pWindow->origin.x - wBorderWidth(pWindow);
+ c.y = pWindow->origin.y - wBorderWidth(pWindow);
+ c.width = pWindow->drawable.width;
+ c.height = pWindow->drawable.height;
+
+ XConfigureWindow(dmxScreen->display, pWinPriv->window, m, &c);
+ XSync(dmxScreen->display, False);
+
+ DMX_WRAP(CopyWindow, dmxCopyWindow, dmxScreen, pScreen);
+}
+
+void dmxResizeWindow(WindowPtr pWindow, int x, int y,
+ unsigned int w, unsigned int h, WindowPtr pSib)
+{
+ ScreenPtr pScreen = pWindow->drawable.pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
+ dmxWinPrivPtr pSibPriv;
+ unsigned int m;
+ XWindowChanges c;
+
+ if (pSib)
+ pSibPriv = DMX_GET_WINDOW_PRIV(pSib);
+
+ DMX_UNWRAP(ResizeWindow, dmxScreen, pScreen);
+#if 1
+ if (pScreen->ResizeWindow)
+ pScreen->ResizeWindow(pWindow, x, y, w, h, pSib);
+#endif
+
+ /* Handle resizing on back-end server */
+ m = CWX | CWY | CWWidth | CWHeight;
+ c.x = pWindow->origin.x - wBorderWidth(pWindow);
+ c.y = pWindow->origin.y - wBorderWidth(pWindow);
+ c.width = pWindow->drawable.width;
+ c.height = pWindow->drawable.height;
+
+ XConfigureWindow(dmxScreen->display, pWinPriv->window, m, &c);
+ XSync(dmxScreen->display, False);
+
+ DMX_WRAP(ResizeWindow, dmxResizeWindow, dmxScreen, pScreen);
+}
+
+void dmxReparentWindow(WindowPtr pWindow, WindowPtr pPriorParent)
+{
+ ScreenPtr pScreen = pWindow->drawable.pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
+ dmxWinPrivPtr pParentPriv = DMX_GET_WINDOW_PRIV(pWindow->parent);
+
+ DMX_UNWRAP(ReparentWindow, dmxScreen, pScreen);
+#if 0
+ if (pScreen->ReparentWindow)
+ pScreen->ReparentWindow(pWindow, pPriorParent);
+#endif
+
+ /* Handle reparenting on back-end server */
+ XReparentWindow(dmxScreen->display, pWinPriv->window,
+ pParentPriv->window,
+ pWindow->origin.x - wBorderWidth(pWindow),
+ pWindow->origin.x - wBorderWidth(pWindow));
+ XSync(dmxScreen->display, False);
+
+ DMX_WRAP(ReparentWindow, dmxReparentWindow, dmxScreen, pScreen);
+}
+
+void dmxChangeBorderWidth(WindowPtr pWindow, unsigned int width)
+{
+ ScreenPtr pScreen = pWindow->drawable.pScreen;
+ DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
+ dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
+ unsigned int m;
+ XWindowChanges c;
+
+ DMX_UNWRAP(ChangeBorderWidth, dmxScreen, pScreen);
+#if 1
+ if (pScreen->ChangeBorderWidth)
+ pScreen->ChangeBorderWidth(pWindow, width);
+#endif
+
+ /* Handle border width change on back-end server */
+ m = CWBorderWidth;
+ c.border_width = width;
+
+ XConfigureWindow(dmxScreen->display, pWinPriv->window, m, &c);
+ XSync(dmxScreen->display, False);
+
+ DMX_WRAP(ChangeBorderWidth, dmxChangeBorderWidth, dmxScreen, pScreen);
+}
diff --git a/xc/programs/Xserver/hw/dmx/dmxwindow.h b/xc/programs/Xserver/hw/dmx/dmxwindow.h
new file mode 100644
index 000000000..bf270e9a4
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/dmxwindow.h
@@ -0,0 +1,93 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Kevin E. Martin <kem@redhat.com>
+ *
+ */
+
+#ifndef DMXWINDOW_H
+#define DMXWINDOW_H
+
+#include "windowstr.h"
+
+typedef struct _dmxWinPriv {
+ Window window;
+} dmxWinPrivRec, *dmxWinPrivPtr;
+
+
+extern Bool dmxInitWindow(ScreenPtr pScreen);
+
+extern Bool dmxCreateWindow(WindowPtr pWindow);
+extern Bool dmxDestroyWindow(WindowPtr pWindow);
+extern Bool dmxPositionWindow(WindowPtr pWindow, int x, int y);
+extern Bool dmxChangeWindowAttributes(WindowPtr pWindow, unsigned long mask);
+extern Bool dmxRealizeWindow(WindowPtr pWindow);
+extern Bool dmxUnrealizeWindow(WindowPtr pWindow);
+extern void dmxRestackWindow(WindowPtr pWindow, WindowPtr pOldNextSib);
+extern void dmxWindowExposures(WindowPtr pWindow, RegionPtr prgn,
+ RegionPtr other_exposed);
+extern void dmxPaintWindowBackground(WindowPtr pWindow, RegionPtr pRegion,
+ int what);
+extern void dmxPaintWindowBorder(WindowPtr pWindow, RegionPtr pRegion,
+ int what);
+extern void dmxCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg,
+ RegionPtr prgnSrc);
+
+extern void dmxResizeWindow(WindowPtr pWindow, int x, int y,
+ unsigned int w, unsigned int h, WindowPtr pSib);
+extern void dmxReparentWindow(WindowPtr pWindow, WindowPtr pPriorParent);
+
+extern void dmxChangeBorderWidth(WindowPtr pWindow, unsigned int width);
+
+
+
+extern int dmxWinPrivateIndex;
+
+
+#define DMX_GET_WINDOW_PRIV(_pWin) \
+ (dmxWinPrivPtr)(_pWin)->devPrivates[dmxWinPrivateIndex].ptr
+
+#define DMX_WINDOW_FUNC_PROLOGUE(_pGC) \
+do { \
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(_pGC); \
+ DMX_UNWRAP(funcs, pGCPriv, (_pGC)); \
+ if (pGCPriv->ops) \
+ DMX_UNWRAP(ops, pGCPriv, (_pGC)); \
+} while (0)
+
+#define DMX_WINDOW_FUNC_EPILOGUE(_pGC) \
+do { \
+ dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(_pGC); \
+ DMX_WRAP(funcs, &dmxGCFuncs, pGCPriv, (_pGC)); \
+ if (pGCPriv->ops) \
+ DMX_WRAP(ops, &dmxGCOps, pGCPriv, (_pGC)); \
+} while (0)
+
+#endif /* DMXWINDOW_H */
diff --git a/xc/programs/Xserver/hw/dmx/doc/Imakefile b/xc/programs/Xserver/hw/dmx/doc/Imakefile
new file mode 100644
index 000000000..b8d805400
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/doc/Imakefile
@@ -0,0 +1,9 @@
+XCOMM $XFree86$
+
+#include <Server.tmpl>
+#include <lnxdoc.rules>
+
+all::
+
+LinuxDocTarget(dmx)
+
diff --git a/xc/programs/Xserver/hw/dmx/doc/Makefile.linux b/xc/programs/Xserver/hw/dmx/doc/Makefile.linux
new file mode 100644
index 000000000..299cb5200
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/doc/Makefile.linux
@@ -0,0 +1,31 @@
+# This is a temporary convenience Makefile that will be removed before
+# merging in to XFree86 tree.
+
+FILES = dmx.sgml
+
+TXT_FILES = $(FILES:.sgml=.txt)
+DVI_FILES = $(FILES:.sgml=.dvi)
+PS_FILES = $(FILES:.sgml=.ps)
+HTML_FILES = $(FILES:.sgml=.html)
+
+all: txt ps html
+
+txt: $(TXT_FILES)
+dvi: $(DVI_FILES)
+ps: $(PS_FILES)
+html: $(HTML_FILES)
+
+%.txt: %.sgml
+ sgml2txt $*
+
+%.dvi: %.sgml
+ sgml2latex --papersize=letter $*
+
+%.ps: %.sgml
+ sgml2latex --papersize=letter --output=ps $*
+
+%.html: %.sgml
+ sgml2html --split=0 $*
+
+clean:
+ rm -f $(TXT_FILES) $(DVI_FILES) $(PS_FILES) $(HTML_FILES)
diff --git a/xc/programs/Xserver/hw/dmx/doc/dmx.sgml b/xc/programs/Xserver/hw/dmx/doc/dmx.sgml
new file mode 100644
index 000000000..fdfcd164b
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/doc/dmx.sgml
@@ -0,0 +1,1419 @@
+<!DOCTYPE linuxdoc PUBLIC "-//XFree86//DTD linuxdoc//EN">
+ <article>
+
+ <!-- Title information -->
+ <title>Distributed multihead X design
+ <author>Kevin E. Martin, David H. Dawes, and Rickard E. Faith
+ <date>31 May 2002 (created 25 July 2001)
+ <abstract>
+ This document covers the motivation, background, design and
+ implementation of the distributed multihead X (DMX) system. It
+ is a living document and describes the current design and
+ implementation details of the DMX system. As the project
+ progresses, this document will be continually updated to reflect
+ the changes in the code and/or design. <it>Copyright 2001 by VA
+ Linux Systems, Inc., Fremont, California. Copyright 2001,2002
+ by Red Hat, Inc., Durham, North Carolina</it>
+ </abstract>
+
+ <!-- Table of contents -->
+ <toc>
+
+ <!-- Begin the document -->
+ <sect>Introduction
+
+<p>Current Open Source multihead solutions are limited to a single
+physical machine. A single X server controls multiple display devices,
+which can be arranged as independent heads or unified into a single
+desktop. These solutions are limited to the number of physical devices
+that can co-exist in a single machine (e.g., due to the number of
+AGP/PCI slots available for graphics cards). Thus, large tiled displays
+are not currently possible. This limitation will be solved by
+eliminating the requirement that the display devices reside in the same
+physical machine. This will be accomplished by developing a front-end
+proxy X server that will control multiple back-end X servers that make
+up the large display. These X servers can either run on the same or
+separate machines.
+
+<p>The overall structure of the distributed multihead X (DMX) project is
+as follows: A single front-end X server will act as a proxy to a set of
+back-end X servers, which handle all of the visible rendering. X
+clients will connect to the front-end server just as they normally would
+to a regular X server. To the client, everything appears as if they
+have a single large display; however, using an extension they can
+request the arrangement of the back-end server screens as well as other
+information that might be useful to them (e.g., for placement of pop-up
+windows, window alignments by the window manager, etc.). A
+configuration tool will be developed that will use this extension and
+will aid setup and arrangement of the DMX system.
+
+<p>DMX can be broken down into two main parts: input devices and
+rendering/windowing requests. Each of these are describe briefly below,
+and the rest of this design document will describe them in greater
+detail. When the project is complete, this design doc will be delivered
+with the final product documentation.
+
+<p>Input devices can be handled either in the front-end server or can be
+funneled through the front-end server from one (or more) or the back-end
+servers. If they are served by the front-end server, then they will be
+need to be connected directly to the system that runs the front-end
+server and cannot be in use by another X server running on that system.
+Basic devices, such as the mouse and keyboard, will be handled directly.
+Other devices will be processed by the XInput extension. Events will be
+passed back to the requesting client. For devices that control a
+cursor, the software or hardware cursor on the appropriate back-end
+server(s) will be enabled and positioned accordingly, while the cursors
+on the other back-end server(s) will be disabled.
+
+<p>Rendering requests will be accepted by the front-end server; however,
+rendering to visible windows will be broken down as needed and sent to
+the appropriate back-end server(s) via X11 library calls for actual
+rendering. The basic framework will follow a Xnest-style approach. GC
+state will be managed in the front-end server and sent to the
+appropriate back-end server(s) as required. Pixmap rendering will (at
+least initially) be handled by the front-end X server. Windowing
+requests (e.g., ordering, mapping, moving, etc.) will handled in the
+front-end server. If the request requires a visible change, the
+windowing operation will be translated into requests for the appropriate
+back-end server(s). Window state will be mirrored in the back-end
+server(s) as needed.
+
+
+<!-- ============================================================ -->
+<sect>Background
+
+<p>This section describes the existing Open Source architectures that
+can be used to handle multiple screens and upon which this development
+project is based.
+
+<sect1>Core input device handling
+
+<p>The following is a description of how core input devices are handled
+by an X server.
+
+<sect2>InitInput()
+
+<p>InitInput() is a DDX function that is called at the start of each
+server generation from the X server's main() function. Its purpose is
+to determine what input devices are connected to the X server, register
+them with the DIX and MI layers, and initialize the input event queue.
+InitInput() does not have a return value, but the X server will abort if
+either a core keyboard device or a core pointer device are not
+registered. Extended input (XInput) devices can also be registered in
+InitInput().
+
+<p>InitInput() usually has implementation specific code to determine
+which input devices are available. For each input device it will be
+using, it calls AddInputDevice():
+
+<descrip>
+<tag/AddInputDevice()/ This DIX function allocates the device structure,
+registers a callback function (which handles device init, close, on and
+off), and returns the input handle, which can be treated as opaque. It
+is called once for each input device.
+</descrip>
+
+<p>Once input handles for core keyboard and core pointer devices have
+been obtained from AddInputDevice(), they are registered as core devices
+by calling RegisterPointerDevice() and RegisterKeyboardDevice(). Each
+of these should be called once. If both core devices are not
+registered, then the X server will exit with a fatal error when it
+attempts to start the input devices in InitAndStartDevices(), which is
+called directly after InitInput() (see below).
+
+<descrip>
+<tag/Register{Pointer,Keyboard}Device()/ These DIX functions take a
+handle returned from AddInputDevice() and initialize the core input
+device fields in inputInfo, and initialize the input processing and grab
+functions for each core input device.
+</descrip>
+
+<p>The core pointer device is then registered with the miPointer code
+(which does the high level cursor handling). While this registration
+is not necessary for correct miPointer operation in the current XFree86
+code, it is still done mostly for compatibility reasons.
+
+<descrip>
+<tag/miRegisterPointerDevice()/ This MI function registers the core
+pointer's input handle with with the miPointer code.
+</descrip>
+
+<p>The final part of InitInput() is the initialization of the input
+event queue handling. In most cases, the event queue handling provided
+in the MI layer is used. The primary XFree86 X server uses its own
+event queue handling to support some special cases related to the XInput
+extension and the XFree86-specific DGA extension. For our purposes, the
+MI event queue handling should be suitable. It is initialized by
+calling mieqInit():
+
+<descrip>
+<tag/mieqInit()/ This MI function initializes the MI event queue for the
+core devices, and is passed the public component of the input handles
+for the two core devices.
+</descrip>
+
+<p>If a wakeup handler is required to deliver synchronous input
+events, it can be registered here by calling the DIX function
+RegisterBlockAndWakeupHandlers(). (See the devReadInput() description
+below.)
+
+<sect2>InitAndStartDevices()
+
+<p>InitAndStartDevices() is a DIX function that is called immediately
+after InitInput() from the X server's main() function. Its purpose is
+to initialize each input device that was registered with
+AddInputDevice(), enable each input device that was successfully
+initialized, and create the list of enabled input devices. Once each
+registered device is processed in this way, the list of enabled input
+devices is checked to make sure that both a core keyboard device and
+core pointer device were registered and successfully enabled. If not,
+InitAndStartDevices() returns failure, and results in the the X server
+exiting with a fatal error.
+
+<p>Each registered device is initialized by calling its callback
+(dev-&gt;deviceProc) with the DEVICE_INIT argument:
+
+<descrip>
+<tag/(*dev-&gt;deviceProc)(dev, DEVICE_INIT)/ This function initializes the
+device structs with core information relevant to the device.
+
+<p>For pointer devices, this means specifying the number of buttons,
+default button mapping, the function used to get motion events (usually
+miPointerGetMotionEvents()), the function used to change/control the
+core pointer motion parameters (acceleration and threshold), and the
+motion buffer size.
+
+<p>For keyboard devices, this means specifying the keycode range,
+default keycode to keysym mapping, default modifier mapping, and the
+functions used to sound the keyboard bell and modify/control the
+keyboard parameters (LEDs, bell pitch and duration, key click, which
+keys are auto-repeating, etc).
+</descrip>
+
+<p>Each initialized device is enabled by calling EnableDevice():
+
+<descrip>
+<tag/EnableDevice()/ EnableDevice() calls the device callback with
+DEVICE_ON:
+ <descrip>
+ <tag/(*dev-&gt;deviceProc)(dev, DEVICE_ON)/ This typically opens and
+ initializes the relevant physical device, and when appropriate,
+ registers the device's file descriptor (or equivalent) as a valid
+ input source.
+ </descrip>
+
+ <p>EnableDevice() then adds the device handle to the X server's
+ global list of enabled devices.
+</descrip>
+
+<p>InitAndStartDevices() then verifies that a valid core keyboard and
+pointer has been initialized and enabled. It returns failure if either
+are missing.
+
+<sect2>devReadInput()
+
+<p>Each device will have some function that gets called to read its
+physical input. These may be called in a number of different ways. In
+the case of synchronous I/O, they will be called from a DDX
+wakeup-handler that gets called after the server detects that new input is
+available. In the case of asynchronous I/O, they will be called from a
+(SIGIO) signal handler triggered when new input is available. This
+function should do at least two things: make sure that input events get
+enqueued, and make sure that the cursor gets moved for motion events
+(except if these are handled later by the driver's own event queue
+processing function, which cannot be done when using the MI event queue
+handling).
+
+<p>Events are queued by calling mieqEnqueue():
+
+<descrip>
+<tag/mieqEnqueue()/ This MI function is used to add input events to the
+event queue. It is simply passed the event to be queued.
+</descrip>
+
+<p>The cursor position should be updated when motion events are
+enqueued, by calling either miPointerAbsoluteCursor() or
+miPointerDeltaCursor():
+
+<descrip>
+<tag/miPointerAbsoluteCursor()/ This MI function is used to move the
+cursor to the absolute coordinates provided.
+<tag/miPointerDeltaCursor()/ This MI function is used to move the cursor
+relative to its current position.
+</descrip>
+
+<sect2>ProcessInputEvents()
+
+<p>ProcessInputEvents() is a DDX function that is called from the X
+server's main dispatch loop when new events are available in the input
+event queue. It typically processes the enqueued events, and updates
+the cursor/pointer position. It may also do other DDX-specific event
+processing.
+
+<p>Enqueued events are processed by mieqProcessInputEvents() and passed
+to the DIX layer for transmission to clients:
+
+<descrip>
+<tag/mieqProcessInputEvents()/ This function processes each event in the
+event queue, and passes it to the device's input processing function.
+The DIX layer provides default functions to do this processing, and they
+handle the task of getting the events passed back to the relevant
+clients.
+<tag/miPointerUpdate()/ This function resynchronized the cursor position
+with the new pointer position. It also takes care of moving the cursor
+between screens when needed in multi-head configurations.
+</descrip>
+
+
+<sect2>DisableDevice()
+
+<p>DisableDevice is a DIX function that removes an input device from the
+list of enabled devices. The result of this is that the device no
+longer generates input events. The device's data structures are kept in
+place, and disabling a device like this can be reversed by calling
+EnableDevice(). DisableDevice() may be called from the DDX when it is
+desirable to do so (e.g., the XFree86 server does this when VT
+switching). Except for special cases, this is not normally called for
+core input devices.
+
+<p>DisableDevice() calls the device's callback function with
+<tt/DEVICE_OFF/:
+
+<descrip>
+<tag/(*dev-&gt;deviceProc)(dev, DEVICE_OFF)/ This typically closes the
+relevant physical device, and when appropriate, unregisters the device's
+file descriptor (or equivalent) as a valid input source.
+</descrip>
+
+<p>DisableDevice() then removes the device handle from the X server's
+global list of enabled devices.
+
+
+<sect2>CloseDevice()
+
+<p>CloseDevice is a DIX function that removes an input device from the
+list of available devices. It disables input from the device and frees
+all data structures associated with the device. This function is
+usually called from CloseDownDevices(), which is called from main() at
+the end of each server generation to close all input devices.
+
+<p>CloseDevice() calls the device's callback function with
+<tt/DEVICE_CLOSE/:
+
+<descrip>
+<tag/(*dev-&gt;deviceProc)(dev, DEVICE_CLOSE)/ This typically closes the
+relevant physical device, and when appropriate, unregisters the device's
+file descriptor (or equivalent) as a valid input source. If any device
+specific data structures were allocated when the device was initialized,
+they are freed here.
+</descrip>
+
+<p>CloseDevice() then frees the data structures that were allocated
+for the device when it was registered/initialized.
+
+
+<sect2>LegalModifier()
+<!-- dmx/dmxinput.c - currently returns TRUE -->
+<p>LegalModifier() is a required DDX function that can be used to
+restrict which keys may be modifier keys. This seems to be present for
+historical reasons, so this function should simply return TRUE
+unconditionally.
+
+
+<sect1>Output handling
+
+<p>The following sections describe the main functions required to
+initialize, use and close the output device(s) for each screen in the X
+server.
+
+<sect2>InitOutput()
+
+<p>This DDX function is called near the start of each server generation
+from the X server's main() function. InitOutput()'s main purpose is to
+initialize each screen and fill in the global screenInfo structure for
+each screen. It is passed three arguments: a pointer to the screenInfo
+struct, which it is to initialize, and argc and argv from main(), which
+can be used to determine additional configuration information.
+
+<p>The primary tasks for this function are outlined below:
+
+<enum>
+ <item><bf/Parse configuration info:/ The first task of InitOutput()
+ is to parses any configuration information from the configuration
+ file. In addition to the XF86Config file, other configuration
+ information can be taken from the command line. The command line
+ options can be gathered either in InitOutput() or earlier in the
+ ddxProcessArgument() function, which is called by
+ ProcessCommandLine(). The configuration information determines the
+ characteristics of the screen(s). For example, in the XFree86 X
+ server, the XF86Config file specifies the monitor information, the
+ screen resolution, the graphics devices and slots in which they are
+ located, and, for Xinerama, the screens' layout.
+
+ <item><bf/Initialize screen info:/ The next task is to initialize
+ the screen-dependent internal data structures. For example, part of
+ what the XFree86 X server does is to allocate its screen and pixmap
+ private indices, probe for graphics devices, compare the probed
+ devices to the ones listed in the XF86Config file, and add the ones that
+ match to the internal xf86Screens&lsqb;&rsqb; structure.
+
+ <item><bf/Set pixmap formats:/ The next task is to initialize the
+ screenInfo's image byte order, bitmap bit order and bitmap scanline
+ unit/pad. The screenInfo's pixmap format's depth, bits per pixel
+ and scanline padding is also initialized at this stage.
+
+ <item><bf/Unify screen info:/ An optional task that might be done at
+ this stage is to compare all of the information from the various
+ screens and determines if they are compatible (i.e., if the set of
+ screens can be unified into a single desktop). This task has
+ potential to be useful to the DMX front-end server, if Xinerama's
+ PanoramiXConsolidate() function is not sufficient.
+</enum>
+
+<p>Once these tasks are complete, the valid screens are known and each
+of these screens can be initialized by calling AddScreen().
+
+<sect2>AddScreen()
+
+<p>This DIX function is called from InitOutput(), in the DDX layer, to
+add each new screen to the screenInfo structure. The DDX screen
+initialization function and command line arguments (i.e., argc and argv)
+are passed to it as arguments.
+
+<p>This function first allocates a new Screen structure and any privates
+that are required. It then initializes some of the fields in the Screen
+struct and sets up the pixmap padding information. Finally, it calls
+the DDX screen initialization function ScreenInit(), which is described
+below. It returns the number of the screen that were just added, or -1
+if there is insufficient memory to add the screen or if the DDX screen
+initialization fails.
+
+<sect2>ScreenInit()
+
+<p>This DDX function initializes the rest of the Screen structure with
+either generic or screen-specific functions (as necessary). It also
+fills in various screen attributes (e.g., width and height in
+millimeters, black and white pixel values).
+
+<p>The screen init function usually calls several functions to perform
+certain screen initialization functions. They are described below:
+
+<descrip>
+<tag/{mi,*fb}ScreenInit()/ The DDX layer's ScreenInit() function usually
+calls another layer's ScreenInit() function (e.g., miScreenInit() or
+fbScreenInit()) to initialize the fallbacks that the DDX driver does not
+specifically handle.
+
+<p>After calling another layer's ScreenInit() function, any
+screen-specific functions either wrap or replace the other layer's
+function pointers. If a function is to be wrapped, each of the old
+function pointers from the other layer are stored in a screen private
+area. Common functions to wrap are CloseScreen() and SaveScreen().
+
+<tag/miInitializeBackingStore()/ This MI function initializes the
+screen's backing storage functions, which are used to save areas of
+windows that are currently covered by other windows.
+
+<tag/miDCInitialize()/ This MI function initializes the MI cursor
+display structures and function pointers. If a hardware cursor is used,
+the DDX layer's ScreenInit() function will wrap additional screen and
+the MI cursor display function pointers.
+</descrip>
+
+<p>Another common task for ScreenInit() function is to initialize the
+output device state. For example, in the XFree86 X server, the
+ScreenInit() function saves the original state of the video card and
+then initializes the video mode of the graphics device.
+
+<sect2>CloseScreen()
+
+<p>This function restores any wrapped screen functions (and in
+particular the wrapped CloseScreen() function) and restores the state of
+the output device to its original state. It should also free any
+private data it created during the screen initialization.
+
+<sect2>GC operations
+
+<p>When the X server is requested to render drawing primitives, it does
+so by calling drawing functions through the graphics context's operation
+function pointer table (i.e., the GCOps functions). These functions
+render the basic graphics operations such as drawing rectangles, lines,
+text or copying pixmaps. Default routines are provided either by the MI
+layer, which draws indirectly through a simple span interface, or by the
+framebuffer layers (e.g., CFB, MFB, FB), which draw directly to a
+linearly mapped frame buffer.
+
+<p>To take advantage of special hardware on the graphics device,
+specific GCOps functions can be replaced by device specific code.
+However, many times the graphics devices can handle only a subset of the
+possible states of the GC, so during graphics context validation,
+appropriate routines are selected based on the state and capabilities of
+the hardware. For example, some graphics hardware can accelerate single
+pixel width lines with certain dash patterns. Thus, for dash patterns
+that are not supported by hardware or for width 2 or greater lines, the
+default routine is chosen during GC validation.
+
+<p>Note that some pointers to functions that draw to the screen are
+stored in the Screen structure. They include GetImage(), GetSpans(),
+PaintWindowBackground(), PaintWindowBorder(), CopyWindow() and
+RestoreAreas().
+
+<sect2>Xnest
+
+<p>The Xnest X server is a special proxy X server that relays the X
+protocol requests that it receives to a ``real'' X server that then
+processes the requests and displays the results, if applicable. To the X
+applications, Xnest appears as if it is a regular X server. However,
+Xnest is both server to the X application and client of the real X
+server, which will actually handle the requests.
+
+<p>The Xnest server implements all of the standard input and output
+initialization steps outlined above.
+
+<descrip>
+<tag/InitOutput()/ Xnest takes its configuration information from
+command line arguments via ddxProcessArguments(). This information
+includes the real X server display to connect to, its default visual
+class, the screen depth, the Xnest window's geometry, etc. Xnest then
+connects to the real X server and gathers visual, colormap, depth and
+pixmap information about that server's display, creates a window on that
+server, which will be used as the root window for Xnest.
+
+<p>Next, Xnest initializes its internal data structures and uses the
+data from the real X server's pixmaps to initialize its own pixmap
+formats. Finally, it calls AddScreen(xnestOpenScreen, argc, argv) to
+initialize each of its screens.
+
+<tag/ScreenInit()/ Xnest's ScreenInit() function is called
+xnestOpenScreen(). This function initializes its screen's depth and
+visual information, and then calls miScreenInit() to set up the default
+screen functions. It then calls miInitializeBackingStore() and
+miDCInitialize() to initialize backing store and the software cursor.
+Finally, it replaces many of the screen functions with its own
+functions that repackage and send the requests to the real X server to
+which Xnest is attached.
+
+<tag/CloseScreen()/ This function frees its internal data structure
+allocations. Since it replaces instead of wrapping screen functions,
+there are no function pointers to unwrap. This can potentially lead to
+problems during server regeneration.
+
+<tag/GC operations/ The GC operations in Xnest are very simple since
+they leave all of the drawing to the real X server to which Xnest is
+attached. Each of the GCOps takes the request and sends it to the
+real X server using standard Xlib calls. For example, the X
+application issues a XDrawLines() call. This function turns into a
+protocol request to Xnest, which calls the xnestPolylines() function
+through Xnest's GCOps function pointer table. The xnestPolylines()
+function is only a single line, which calls XDrawLines() using the same
+arguments that were passed into it. Other GCOps functions are very
+similar. Two exceptions to the simple GCOps functions described above
+are the image functions and the BLT operations.
+
+<p>The image functions, GetImage() and PutImage(), must use a temporary
+image to hold the image to be put of the image that was just grabbed
+from the screen while it is in transit to the real X server or the
+client. When the image has been transmitted, the temporary image is
+destroyed.
+
+<p>The BLT operations, CopyArea() and CopyPlane(), handle not only the
+copy function, which is the same as the simple cases described above,
+but also the graphics exposures that result when the GC's graphics
+exposure bit is set to True. Graphics exposures are handled in a helper
+function, xnestBitBlitHelper(). This function collects the exposure
+events from the real X server and, if any resulting in regions being
+exposed, then those regions are passed back to the MI layer so that it
+can generate exposure events for the X application.
+</descrip>
+
+<p>The Xnest server takes its input from the X server to which it is
+connected. When the mouse is in the Xnest server's window, keyboard and
+mouse events are received by the Xnest server, repackaged and sent back
+to any client that requests those events.
+
+<sect2>Shadow framebuffer
+
+<p>The most common type of framebuffer is a linear array memory that
+maps to the video memory on the graphics device. However, accessing
+that video memory over an I/O bus (e.g., ISA or PCI) can be slow. The
+shadow framebuffer layer allows the developer to keep the entire
+framebuffer in main memory and copy it back to video memory at regular
+intervals. It also has been extended to handle planar video memory and
+rotated framebuffers.
+
+<p>There are two main entry points to the shadow framebuffer code:
+
+<descrip>
+<tag/shadowAlloc(width, height, bpp)/ This function allocates the in
+memory copy of the framebuffer of size width*height*bpp. It returns a
+pointer to that memory, which will be used by the framebuffer
+ScreenInit() code during the screen's initialization.
+
+<tag/shadowInit(pScreen, updateProc, windowProc)/ This function
+initializes the shadow framebuffer layer. It wraps several screen
+drawing functions, and registers a block handler that will update the
+screen. The updateProc is a function that will copy the damaged regions
+to the screen, and the windowProc is a function that is used when the
+entire linear video memory range cannot be accessed simultaneously so
+that only a window into that memory is available (e.g., when using the
+VGA aperture).
+</descrip>
+
+<p>The shadow framebuffer code keeps track of the damaged area of each
+screen by calculating the bounding box of all drawing operations that
+have occurred since the last screen update. Then, when the block handler
+is next called, only the damaged portion of the screen is updated.
+
+<p>Note that since the shadow framebuffer is kept in main memory, all
+drawing operations are performed by the CPU and, thus, no accelerated
+hardware drawing operations are possible.
+
+
+<sect1>Xinerama
+
+<p>Xinerama is an X extension that allows multiple physical screens
+controlled by a single X server to appear as a single screen. Although
+the extension allows clients to find the physical screen layout via
+extension requests, it is completely transparent to clients at the core
+X11 protocol level. The original public implementation of Xinerama came
+from Digital/Compaq. XFree86 rewrote it, filling in some missing pieces
+and improving both X11 core protocol compliance and performance. The
+Xinerama extension will be passing through X.Org's standardization
+process in the near future, and the sample implementation will be based
+on this rewritten version.
+
+<p>The current implementation of Xinerama is based primarily in the DIX
+(device independent) and MI (machine independent) layers of the X
+server. With few exceptions the DDX layers do not need any changes to
+support Xinerama. X server extensions often do need modifications to
+provide full Xinerama functionality.
+
+<p>The following is a code-level description of how Xinerama functions.
+
+<p>Note: Because the Xinerama extension was originally called the
+PanoramiX extension, many of the Xinerama functions still have the
+PanoramiX prefix.
+
+<descrip>
+ <tag/PanoramiXExtensionInit()/ PanoramiXExtensionInit() is a
+ device-independent extension function that is called at the start of
+ each server generation from InitExtensions(), which is called from
+ the X server's main() function after all output devices have been
+ initialized, but before any input devices have been initialized.
+
+ <p>PanoramiXNumScreens is set to the number of physical screens. If
+ only one physical screen is present, the extension is disabled, and
+ PanoramiXExtensionInit() returns without doing anything else.
+
+ <p>The Xinerama extension is registered by calling AddExtension().
+
+ <p>A local per-screen array of data structures
+ (panoramiXdataPtr&lsqb;&rsqb;)
+ is allocated for each physical screen, and GC and Screen private
+ indexes are allocated, and both GC and Screen private areas are
+ allocated for each physical screen. These hold Xinerama-specific
+ per-GC and per-Screen data. Each screen's CreateGC and CloseScreen
+ functions are wrapped by XineramaCreateGC() and
+ XineramaCloseScreen() respectively. Some new resource classes are
+ created for Xinerama drawables and GCs, and resource types for
+ Xinerama windows, pixmaps and colormaps.
+
+ <p>A region (XineramaScreenRegions&lsqb;i&rsqb;) is initialized for each
+ physical screen, and single region (PanoramiXScreenRegion) is
+ initialized to be the union of the screen regions. The
+ panoramiXdataPtr&lsqb;&rsqb; array is also initialized with the size and
+ origin of each screen. The relative positioning information for the
+ physical screens is taken from the array
+ dixScreenOrigins&lsqb;&rsqb;, which
+ the DDX layer must initialize in InitOutput(). The bounds of the
+ combined screen is also calculated (PanoramiXPixWidth and
+ PanoramiXPixHeight).
+
+ <p>The DIX layer has a list of function pointers
+ (ProcVector&lsqb;&rsqb;) that
+ holds the entry points for the functions that process core protocol
+ requests. The requests that Xinerama must intercept and break up
+ into physical screen-specific requests are wrapped. The original
+ set is copied to SavedProcVector&lsqb;&rsqb;. The types of requests
+ intercepted are Window requests, GC requests, colormap requests,
+ drawing requests, and some geometry-related requests. This wrapping
+ allows the bulk of the protocol request processing to be handled
+ transparently to the DIX layer. Some operations cannot be dealt with
+ in this way and are handled with Xinerama-specific code within the
+ DIX layer.
+
+ <tag/PanoramiXConsolidate()/ PanoramiXConsolidate() is a
+ device-independent extension function that is called directly from
+ the X server's main() function after extensions and input/output
+ devices have been initialized, and before the root windows are
+ defined and initialized.
+
+ <p>This function finds the set of depths (PanoramiXDepths&lsqb;&rsqb;) and
+ visuals (PanoramiXVisuals&lsqb;&rsqb;)
+ common to all of the physical screens.
+ PanoramiXNumDepths is set to the number of common depths, and
+ PanoramiXNumVisuals is set to the number of common visuals.
+ Resources are created for the single root window and the default
+ colormap. Each of these resources has per-physical screen entries.
+
+ <tag/PanoramiXCreateConnectionBlock()/ PanoramiXConsolidate() is a
+ device-independent extension function that is called directly from
+ the X server's main() function after the per-physical screen root
+ windows are created. It is called instead of the standard DIX
+ CreateConnectionBlock() function. If this function returns FALSE,
+ the X server exits with a fatal error. This function will return
+ FALSE if no common depths were found in PanoramiXConsolidate().
+ With no common depths, Xinerama mode is not possible.
+
+ <p>The connection block holds the information that clients get when
+ they open a connection to the X server. It includes information
+ such as the supported pixmap formats, number of screens and the
+ sizes, depths, visuals, default colormap information, etc, for each
+ of the screens (much of information that <tt/xdpyinfo/ shows). The
+ connection block is initialized with the combined single screen
+ values that were calculated in the above two functions.
+
+ <p>The Xinerama extension allows the registration of connection
+ block callback functions. The purpose of these is to allow other
+ extensions to do processing at this point. These callbacks can be
+ registered by calling XineramaRegisterConnectionBlockCallback() from
+ the other extension's ExtensionInit() function. Each registered
+ connection block callback is called at the end of
+ PanoramiXCreateConnectionBlock().
+</descrip>
+
+<sect2>Xinerama-specific changes to the DIX code
+
+<p>There are a few types of Xinerama-specific changes within the DIX
+code. The main ones are described here.
+
+<p>Functions that deal with colormap or GC -related operations outside of
+the intercepted protocol requests have a test added to only do the
+processing for screen numbers > 0. This is because they are handled for
+the single Xinerama screen and the processing is done once for screen 0.
+
+<p>The handling of motion events does some coordinate translation between
+the physical screen's origin and screen zero's origin. Also, motion
+events must be reported relative to the composite screen origin rather
+than the physical screen origins.
+
+<p>There is some special handling for cursor, window and event processing
+that cannot (either not at all or not conveniently) be done via the
+intercepted protocol requests. A particular case is the handling of
+pointers moving between physical screens.
+
+<sect2>Xinerama-specific changes to the MI code
+
+<p>The only Xinerama-specific change to the MI code is in miSendExposures()
+to handle the coordinate (and window ID) translation for expose events.
+
+<sect2>Intercepted DIX core requests
+
+<p>Xinerama breaks up drawing requests for dispatch to each physical
+screen. It also breaks up windows into pieces for each physical screen.
+GCs are translated into per-screen GCs. Colormaps are replicated on
+each physical screen. The functions handling the intercepted requests
+take care of breaking the requests and repackaging them so that they can
+be passed to the standard request handling functions for each screen in
+turn. In addition, and to aid the repackaging, the information from
+many of the intercepted requests is used to keep up to date the
+necessary state information for the single composite screen. Requests
+(usually those with replies) that can be satisfied completely from this
+stored state information do not call the standard request handling
+functions.
+
+
+<!-- ============================================================ -->
+<sect>Development plan
+
+<p>This section describes the current development plan.
+
+<sect1>Bootstrap code
+
+<p>To allow for rapid development of the DMX server by multiple
+developers during the first development stage, the problem will be
+broken down into three tasks: the overall DMX framework, back-end
+rendering services and input device handling services. However, before
+the work begins on these tasks, a simple framework that each developer
+could use was implemented to bootstrap the development effort. This
+framework renders to a single back-end server and provides dummy input
+devices (i.e., the keyboard and mouse). The simple back-end rendering
+service was implemented using the shadow framebuffer support currently
+available in the XFree86 environment.
+
+<p>Using this bootstrapping framework, each developer has been able to
+work on each of the tasks listed above independently as follows: the
+framework will be extended to handle arbitrary back-end server
+configurations; the back-end rendering services will be transitioned to
+the more efficient Xnest-style implementation; and, an input device
+framework to handle various input devices via the input extension will
+be developed.
+
+<p>Status: The boot strap code is complete. <!-- August 2001 -->
+
+
+<sect1>Input device handling
+
+<p>An X server (including the front-end X server) requires two core
+input devices -- a keyboard and a pointer (mouse). These core devices
+are handled and required by the core X11 protocol. Additional types of
+input devices may be attached and utilized via the XInput extension.
+These are usually referred to as ``extended input devices''.
+
+<p>There are some options as to how the front-end X server gets its core
+input devices:
+
+<enum>
+ <item>The physical input devices (e.g., keyboard and mouse) can be
+ attached directly to the front-end X server. In this case, the
+ keyboard and mouse on the machine running the front-end X server
+ will be used. The front-end will have drivers to read the raw input
+ from those devices and convert it into the required X input events
+ (key press/release, pointer button press/release, pointer motion).
+ The front-end keyboard driver will keep track of keyboard properties
+ such as key and modifier mappings, autorepeat state, keyboard sound
+ and led state. Similarly the front-end pointer driver will keep
+ track if pointer properties such as the button mapping and movement
+ acceleration parameters. With this option, input is handled fully
+ in the front-end X server, and the back-end X servers are used in a
+ display-only mode.
+
+ <p>There are some options for how the input device support could be
+ implemented:
+
+ <enum>
+ <item>The XFree86 X server has modular input drivers that could
+ be adapted for this purpose. The mouse driver supports a wide
+ range of mouse types and interfaces, as well as a range of
+ Operating System platforms. The keyboard driver in XFree86 is
+ not currently as modular as the mouse driver, but could be made
+ so. The XFree86 X server also has a range of other input
+ drivers for extended input devices such as tablets and touch
+ screens.
+
+ <item>The <tt/kdrive/ X server in XFree86 has built-in drivers that
+ support PS/2 mice and keyboard under Linux. The mouse driver
+ can indirectly handle other mouse types if the Linux utility
+ <tt/gpm/ is used as to translate the native mouse protocol into
+ PS/2 mouse format. These drivers could be adapted and built in
+ to the front-end X server if this range of hardware and OS
+ support is sufficient.
+ </enum>
+
+ <item>The front-end can make use of the core input devices attached
+ to a single back-end X server. In this case, the front-end will get
+ the core input events from that back-end, and the keyboard and mouse
+ used to control the distributed X array will be physically connected
+ to that back-end. The keyboard and pointer state will also be
+ handled in that back-end, with the front-end simply acting as a
+ proxy for input-device related X requests.
+
+ <item>The front-end can make use of the core input devices attached
+ to one or more of the back-end X servers. This is like option 2,
+ except that the core input events from multiple back-ends are merged
+ into a single input event stream. This can work sanely when only a
+ single set of input devices is used at any given time. The keyboard
+ and pointer state will be handled in the front-end, with changes
+ propagated to the back-end servers as needed. This option can work
+ well when the keyboards and pointers on each back-end are the same.
+ When they are different (different numbers of buttons, different
+ keys, etc) there are issues to resolve in how the front-end exports
+ a single set of consistent core input devices.
+
+ <item>A variation on option 3 is to nominate one back-end X server
+ (or even the front-end X server) as providing the core input
+ devices, and allowing access to the core input devices on the other
+ back-ends as extended input devices. Among other things, this
+ would allow the current core devices to be switched at run time,
+ and it would allow XInput-aware applications to access the full
+ capabilities of each back-end's core input devices simultaneously.
+ The back-end X servers would not need to support the XInput
+ extension for this to work. The XFree86 implementation of the
+ XInput extension allows multiple extended input devices to generate
+ core input events, and leveraging this would be an option for
+ implementing option 3.
+
+ <item>The front-end server could create a console window that is
+ displayed on an X server independent of the back-end X servers.
+ This console window could display things like the physical screen
+ layout, and the front-end could get its core input events from events
+ delivered to the console window.
+
+</enum>
+
+<p>Although extended input devices are not specifically mentioned in the
+Distributed X requirements, option 4 above could be further extended to
+make extended input devices attached to back-end X servers visible,
+and/or to allow extended input devices to be attached to the front-end X
+server.
+
+<p>The bootstrap code (Xdmx) currently has dummy input devices. These
+do the necessary initialization to satisfy the X server's requirements
+for core pointer and keyboard devices, but no input events are ever
+generated.
+
+<p>The input device support in Xnest could be used to implement the
+input-from-back-end approach in the bootstrap code. The mouse and
+keyboard handling code from the <tt/kdrive/ X server in XFree86 would be a
+good starting point for implementing the input-from-front-end approach
+in the bootstrap code.
+
+<p>Input-related work required with the bootstrap code:
+
+<itemize>
+ <item>Evaluate using back-end input devices vs attaching the input
+ devices directly to the front-end:
+
+ <itemize>
+ <item>Implement back-end input in the bootstrap code.
+ <item>Implement front-end input in the bootstrap code.
+ <item>Evaluate both options with the bootstrap code extended to
+ drive more than one back-end.
+ </itemize>
+</itemize>
+
+<p>Status: The input code is complete. <!-- May 2002 -->
+
+
+<sect1>Output device handling
+
+<p>The output of the DMX system displays rendering and windowing
+requests across multiple screens. The screens are typically arranged in
+a grid such that together they represent a single large display.
+
+<p>The output section of the DMX code consists of two parts. The first
+is in the front-end proxy X server, which accept client connections,
+manages the windows and potentially renders primitives but does not
+actually display any of the drawing primitives. The second part is the
+back-end X server(s), which accept commands from the front-end server
+and display the results on their screens.
+
+<sect2>Initialization
+
+<p>The DMX front-end must first initialize its screens by connecting to
+each of the back-end X servers and collecting information about each of
+these screens. However, the information collected from the back-end X
+servers might be inconsistent. Handling these cases can be difficult
+and/or inefficient. For example, a two screen system has one back-end X
+server running at 16bpp while the second is running at 32bpp.
+Converting rendering requests (e.g., XPutImage() or XGetImage()
+requests) to the appropriate bit depth can be very time consuming.
+Analyzing these cases to determine how or even if it is possible to
+handle them is required. The current Xinerama code handles many of
+these cases (e.g., in PanoramiXConsolidate()) and will be used as a
+starting point. In general, the best solution is to use homogeneous X
+servers and display devices.
+
+<p>Once this screen consolidation is finished, the relative position of
+each back-end X server's screen in the unified screen is initialized. A
+full-screen window is opened on each of the back-end X servers, and the
+cursor on each screen is turned off.
+
+<sect2>Handling rendering requests
+
+<p>After initialization, X applications connect to the front-end server.
+There are two possible implementations of how rendering and windowing
+requests are handled in the DMX system:
+
+<enum>
+ <item>A shadow framebuffer is used in the front-end server as the
+ render target. In this option, all protocol requests are completely
+ handled in the front-end server. All state and resources are
+ maintained in the front-end including a shadow copy of the entire
+ framebuffer. The framebuffers attached to the back-end servers are
+ updated by XPutImage() calls with data taken directly from the
+ shadow framebuffer.
+
+ <p>This solution suffers from two main problems. First, it does not
+ take advantage of any accelerated hardware available in the system.
+ Second, the size of the XPutImage() calls can be quite large and
+ thus will be limited by the bandwidth available.
+
+ <item>Rendering requests are sent to each back-end server for
+ handling (as is done in the Xnest server described above). In this
+ option, certain protocol requests are handled in the front-end
+ server and certain requests are repackaged and then sent to the
+ back-end servers. The framebuffer is distributed across the
+ multiple back-end servers. Rendering to the framebuffer is handled
+ on each back-end and can take advantage of any acceleration
+ available on the back-end servers' graphics display device. State
+ is maintained both in the front and back-end servers.
+
+ <p>This solution suffers from two main drawbacks. First, protocol
+ requests are sent to all back-end servers -- even those that will
+ completely clip the rendering primitive -- which wastes bandwidth
+ and processing time. Second, state is maintained both in the front-
+ and back-end servers. These drawbacks are not as severe as in
+ option 1 (above) and can either be overcome through optimizations or
+ are acceptable. Therefore, this option will be used in the final
+ implementation.
+</enum>
+
+<p>Status: Both the shadow framebuffer and Xnest-style code is complete.
+<!-- May 2002 -->
+
+
+<sect1>Optimizing DMX
+
+<p>The simple Xnest-style solution described above sends the repackaged
+protocol requests to all back-end servers. Simple clipping tests in the
+front-end X server will be used to limit sending the repackaged protocol
+requests to only those back-end servers that will actually display the
+data.
+
+<p>In addition, each protocol request will be analyzed to determine if
+it is possible to break the request into smaller pieces at display
+boundaries. The initial ones to be analyzed are put and get image
+requests since they will require the greatest bandwidth to transmit data
+between the front and back-end servers. Other protocol requests will be
+analyzed and those that will benefit from breaking them into smaller
+requests will be implemented.
+
+<p>In the simple solution, BLT operations (e.g., XCopyArea() and window
+moves) that cross display boundaries require moving pixel data from
+possibly multiple back-end servers to the front-end server and then
+potentially to several back-end servers. This data movement is very
+inefficient and direct communication between back-end X servers could
+eliminate several extraneous data copies. An X server extension will be
+implemented and used by the front and back-end servers to allow back-end
+servers to directly send pixel data to each other under the direct
+control of the front-end server. This X extension is entirely optional
+and the DMX system will function without it; however, the performance of
+the system might degrade if the front and back-end servers do not
+implemented it.
+
+<p>Status: Not yet started.
+
+
+<sect1>Common X extension support
+
+<p>The XInput, XKeyboard and Shape X extensions are commonly used and
+support for them will be added to the DMX system. In addition, support
+for the Render extension (as well as the XTest extension mentioned
+above) will be added.
+
+<p>The XInput extension will be used to allow multiple and non-standard
+input devices to be accessed simultaneously. These input devices might
+be connected to either the front-end or back-end servers. The XKeyboard
+extension will allow much better keyboard mappings control. The Shape
+extension allows arbitrarily shaped windows and is commonly used by
+various window managers.
+
+<p>Status: Not yet started.
+
+
+<sect1>OpenGL support
+
+<p>OpenGL support using the Mesa code base exists in XFree86 release 4
+and later. Currently, the direct rendering infrastructure (DRI)
+provides accelerated OpenGL support for local clients and unaccelerated
+OpenGL support (i.e., software rendering) is provided for non-local
+clients.
+
+<p>The single head OpenGL support in XFree86 4.x will be extended to use
+the DMX system. When the front and back-end servers are on the same
+physical hardware, it is possible to use the DRI to directly render to
+the back-end servers. First, the existing DRI will be extended to
+support multiple display heads, and then to support the DMX system.
+OpenGL rendering requests will be direct rendering to each back-end X
+server. The DRI will request the screen layout (either from the
+existing Xinerama extension or a DMX-specific extension). Support for
+synchronized swap buffers will also be added (on hardware that supports
+it). Note that a single front-end server with a single back-end server
+on the same physical machine can emulate accelerated indirect rendering.
+
+<p>When the front and back-end servers are on different physical
+hardware or are using non-XFree86 4.x X servers, a mechanism to render
+primitives across the back-end servers will be provided. There are
+several options as to how this can be implemented.
+
+<enum>
+ <item>The existing OpenGL support in each back-end server can be
+ used by repackaging rendering primitives and sending them to each
+ back-end server. This option is similar to the unoptimized
+ Xnest-style approach mentioned above. Optimization of this solution
+ is beyond the scope of this project and is better suited to other
+ distributed rendering systems.
+
+ <item>Rendering to a pixmap in the front-end server using the
+ current XFree86 4.x code, and then displaying to the back-ends via
+ calls to XPutImage() is another option. This option is similar to
+ the shadow frame buffer approach mentioned above. It is slower and
+ bandwidth intensive, but has the advantage that the back-end servers
+ are not required to have OpenGL support.
+</enum>
+
+<p>These, and other, options will be investigated in this phase of the
+work.
+
+<p>Future work (outside the scope of the current project) could further
+extend this work to use a distributed rendering system such as
+Chromium/WireGL.
+
+<p>Status: Not yet started.
+
+
+<!-- ============================================================ -->
+<sect>Development Results
+
+<p>In this section the results of each phase of development are
+discussed.
+
+<sect1>Phase I
+
+<p>The initial development phase dealt with the basic implementation
+including the bootstrap code, which used the shadow framebuffer, and the
+unoptimized implementation, based on an Xnest-style implementation.
+
+<sect2>Scope
+
+<p>The goal of Phase I is to provide fundamental functionality that can
+act as a foundation for ongoing work:
+<enum>
+ <item>Develop the proxy X server
+ <itemize>
+ <item>The proxy X server will operate on the X11 protocol and
+ relay requests as necessary to correctly perform the request.
+ <item>Work will be based on the existing work for Xinerama and
+ Xnest.
+ <item>Input events and windowing operations are handled in the
+ proxy server and rendering requests are repackaged and sent to
+ each of the back-end servers for display.
+ <item>The multiple screen layout (including support for
+ overlapping screens) will be user configurable via a
+ configuration file or through the configuration tool.
+ </itemize>
+ <item>Develop graphical configuration tool
+ <itemize>
+ <item>There will be potentially a large number of X servers to
+ configure into a single display. The tool will allow the user
+ to specify which servers are involved in the configuration and
+ how they should be laid out.
+ </itemize>
+ <item>Pass the X Test Suite
+ <itemize>
+ <item>The X Test Suite covers the basic X11 operations. All
+ tests known to succeed must correctly operate in the distributed
+ X environment.
+ </itemize>
+</enum>
+
+<p>For this phase, the back-end X servers are assumed to be unmodified X
+servers that do not support any DMX-related protocol extensions; future
+optimization pathways are considered, but are not implemented; and the
+configuration tool is assumed to rely only on libraries in the X source
+tree (e.g., Xt).
+
+<sect2>Results
+
+<p>The proxy X server, Xdmx, was developed to distribute X11 protocol
+requests to the set of back-end X servers. It opens a window on each
+back-end server, which represents the part of the front-end's root
+window that is visible on that screen. It mirrors window, pixmap and
+other state in each back-end server. Drawing requests are sent to
+either windows or pixmaps on each back-end server. This code is based
+on Xnest and uses the existing Xinerama extension.
+
+<p>Input events can be taken from (1) devices attached to the back-end
+server, (2) core devices attached directly to the Xdmx server, or (3)
+from a ``console'' window on another X server. Events for these devices
+are gathered, processed and delivered to clients attached to the Xdmx
+server.
+
+<p>An intuitive configuration format was developed to help the user
+easily configure the multiple back-end X servers. It was defined (see
+grammar in Xdmx man page) and a parser was implemented that is used by
+the Xdmx server and by a standalone xdmxconfig utility. The parsing
+support was implemented such that it can be easily factored out of the X
+source tree for use with other tools (e.g., vdl). Support for
+converting legacy vdl-format configuration files to the DMX format is
+provided by the vdltodmx utility.
+
+<p>Originally, the configuration file was going to be a subsection of
+XFree86's XF86Config file, but that was not possible since Xdmx is a
+completely separate X server. Thus, a separate config file format was
+developed. In addition, a graphical configuration
+tool, xdmxconfig, was developed to allow the user to create and arrange
+the screens in the configuration file. The <bf/-configfile/ and <bf/-config/
+command-line options can be used to start Xdmx using a configuration
+file.
+
+<p>An extension that enables remote input testing is required for the X
+Test Suite to function. During this phase, this extension (XTEST) was
+implemented in the Xdmx server. The results from running the X Test
+Suite are described in detail below.
+
+<sect2>X Test Suite
+
+ <sect3> Introduction
+ <p>
+ The X Test Suite contains tests that verify Xlib functions
+ operate correctly. The test suite is designed to run on a
+ single X server; however, since X applications will not be
+ able to tell the difference between the DMX server and a
+ standard X server, the X Test Suite should also run on the
+ DMX server.
+ <p>
+ The Xdmx server was tested with the X Test Suite, and the
+ existing failures are noted in this section. To put these
+ results in perspective, we first discuss expected X Test
+ failures and how errors in underlying systems can impact
+ Xdmx test results.
+
+ <sect3>Expected Failures for a Single Head
+ <p>
+ A correctly implemented X server with a single screen is
+ expected to fail certain X Test tests. The following
+ well-known errors occur because of rounding error in the X
+ server code:
+ <verb>
+XDrawArc: Tests 42, 63, 66, 73
+XDrawArcs: Tests 45, 66, 69, 76
+ </verb>
+ <p>
+ The following failures occur because of the high-level X
+ server implementation:
+ <verb>
+XLoadQueryFont: Test 1
+XListFontsWithInfo: Tests 3, 4
+XQueryFont: Tests 1, 2
+ </verb>
+ <p>
+ The following test fails when running the X server as root
+ under Linux because of the way directory modes are
+ interpreted:
+ <verb>
+XWriteBitmapFile: Test 3
+ </verb>
+ <p>
+ Depending on the video card used for the back-end, other
+ failures may also occur because of bugs in the low-level
+ driver implementation. Over time, failures of this kind
+ are usually fixed by XFree86, but will show up in Xdmx
+ testing until then.
+
+ <sect3>Expected Failures for Xinerama
+ <p>
+ Xinerama fails several X Test Suite tests because of
+ design decisions made for the current implementation of
+ Xinerama. Over time, many of these errors will be
+ corrected by XFree86 and the group working on a new
+ Xinerama implementation. Therefore, Xdmx will also share
+ X Suite Test failures with Xinerama.
+ <p>
+ We may be able to fix or work-around some of these
+ failures at the Xdmx level, but this will require
+ additional exploration that was not part of Phase I.
+ <p>
+ Xinerama is constantly improving, and the list of
+ Xinerama-related failures depends on XFree86 version and
+ the underlying graphics hardware. We tested with a
+ variety of hardware, including nVidia, S3, ATI Radeon,
+ and Matrox G400 (in dual-head mode). The list below
+ includes only those failures that appear to be from the
+ Xinerama layer, and does not include failures listed in
+ the previous section, or failures that appear to be from
+ the low-level graphics driver itself:
+ <p>
+ These failures were noted with multiple Xinerama
+ configurations:
+ <verb>
+XCopyPlane: Tests 13, 22, 31 (well-known Xinerama implementation issue)
+XSetFontPath: Test 4
+XGetDefault: Test 5
+XMatchVisualInfo: Test 1
+ </verb>
+ <p>
+ These failures were noted only when using one dual-head
+ video card with a 4.2.99.x XFree86 server:
+ <verb>
+XListPixmapFormats: Test 1
+XDrawRectangles: Test 45
+ </verb>
+ <p>
+ These failures were noted only when using two video cards
+ from different vendors with a 4.1.99.x XFree86 server:
+ <verb>
+XChangeWindowAttributes: Test 32
+XCreateWindow: Test 30
+XDrawLine: Test 22
+XFillArc: Test 22
+XChangeKeyboardControl: Tests 9, 10
+XRebindKeysym: Test 1
+ </verb>
+
+ <sect3>Additional Failures from Xdmx
+ <p>
+ When running Xdmx, no unexpected failures were noted.
+ Since the Xdmx server is based on Xinerama, we expect to
+ have most of the Xinerama failures present in the Xdmx
+ server. Similarly, since the Xdmx server must rely on the
+ low-level device drivers on each back-end server, we also
+ expect that Xdmx will exhibit most of the back-end
+ failures. Here is a summary:
+ <verb>
+XListPixmapFormats: Test 1 (configuration dependent)
+XChangeWindowAttributes: Test 32
+XCreateWindow: Test 30
+XCopyPlane: Test 13, 22, 31
+XSetFontPath: Test 4
+XGetDefault: Test 5 (configuration dependent)
+XMatchVisualInfo: Test 1
+XRebindKeysym: Test 1 (configuration dependent)
+ </verb>
+ <p>
+ Note that this list is shorter than the combined list for
+ Xinerama because Xdmx uses different code paths to perform
+ some Xinerama operations. Further, some Xinerama failures
+ have been fixed in the XFree86 4.2.99.x CVS repository.
+
+ <sect3>Summary and Future Work
+ <p>
+ Running the X Test Suite on Xdmx does not produce any
+ failures that cannot be accounted for by the underlying
+ Xinerama subsystem used by the front-end or by the
+ low-level device-driver code running on the back-end X
+ servers. The Xdmx server therefore is as ``correct'' as
+ possible with respect to the standard set of X Test Suite
+ tests.
+ <p>
+ During the following phases, we will continue to verify
+ Xdmx correctness using the X Test Suite. We may also use
+ other tests suites or write additional tests that run
+ under the X Test Suite that specifically verify the
+ expected behavior of DMX.
+
+<sect2>Fonts
+
+<p>In Phase I, fonts are handled directly by both the front-end and the
+back-end servers, which is required since we must treat each back-end
+server during this phase as a ``black box''. What this requires is that
+<bf/the front- and back-end servers must share the exact same font
+path/. There are two ways to help make sure that all servers share the
+same font path:
+
+<enum>
+ <item>First, each server can be configured to use the same font
+ server. The font server, xfs, can be configured to serve fonts to
+ multiple X servers via TCP.
+
+ <item>Second, each server can be configured to use the same font
+ path and either those font paths can be copied to each back-end
+ machine or they can be mounted (e.g., via NFS) on each back-end
+ machine.
+</enum>
+
+<p>One additional concern is that a client program can set its own font
+path, and if it does so, then that font path must be available on each
+back-end machine.
+
+<p>The -fontpath command line option was added to allow users to
+initialize the font path of the front end server. This font path is
+propagated to each back-end server when the default font is loaded. If
+there are any problems, an error message is printed, which will describe
+the problem and list the current font path. For more information about
+setting the font path, see the -fontpath option description in the man
+page.
+
+<sect2>Performance
+
+<p>Phase I of development was not intended to optimize performance. Its
+focus was on completely and correctly handling the base X11 protocol in
+the Xdmx server. However, several insights were gained during Phase I,
+which are listed here for reference during the next phase of
+development.
+
+<enum>
+ <item>Calls to XSync() can slow down rendering since it requires a
+ complete round trip to and from a back-end server. This is
+ especially problematic when communicating over long haul networks.
+ <item>Sending drawing requests to only the screens that they overlap
+ should improve performance.
+</enum>
+
+<sect2>Pixmaps
+
+<p>Pixmaps were originally expected to be handled entirely in the
+front-end X server; however, it was found that this overly complicated
+the rendering code and would have required sending potentially large
+images to each back server that required them when copying from pixmap
+to screen. Thus, pixmap state is mirrored in the back-end server just
+as it is with regular window state. With this implementation, the same
+rendering code that draws to windows can be used to draw to pixmaps on
+the back-end server, and no large image transfers are required to copy
+from pixmap to window.
+
+<!-- ============================================================ -->
+<sect>Current issues
+
+<p>In this sections the current issues are outlined that require further
+investigation.
+
+<sect1>Fonts
+
+<p>The font path and glyphs need to be the same for the front-end and
+each of the back-end servers. Font glyphs could be sent to the back-end
+servers as necessary but this might consume a significant amount of
+available bandwidth during font rendering for clients that use many
+different fonts (e.g., Netscape). Initially, the font server (xfs) will
+be used to provide the fonts to both the front-end and back-end servers.
+Other possibilities will be investigated during development.
+
+<sect1>Zero width rendering primitives
+
+<p>To allow pixmap and on-screen rendering to be pixel perfect, all
+back-end servers must render zero width primitives exactly the same as
+the front-end renders the primitives to pixmaps. For those back-end
+servers that do not exactly match, zero width primitives will be
+automatically converted to one width primitives. This can be handled in
+the front-end server via the GC state.
+
+<sect1>DMX extension
+
+<p>The DMX extension will provide DMX-aware X clients with the screen
+information (clipping rectangle for each screen relative to the virtual
+screen) and window information (window IDs for each back-end window that
+corresponds to each DMX window). Allowing clients to access this
+information will permit them to directly render to those windows.
+
+<sect1>GLX support
+
+<p>The utility of the software rendered OpenGL support for non-local
+back-end servers is questionable. On modern graphics accelerators, it
+is likely that the back-end servers will have hardware accelerated
+OpenGL support. In general, OpenGL/GLX support is best left to another
+approach (e.g., Chromium); however, it might prove useful to support
+pushing a subset of primitives to the back-end servers, so that they can
+handle the rendering directly. We will investigate this possibility.
+These will include only those primitives that are output only, as there
+are a number of issues with the other primitives. These other
+primitives will be left unsupported and will either return errors or be
+turned into no-ops. If useful, then the software rendered OpenGL in the
+front-end server will not be implemented.
+
+<sect1>Output scaling
+
+<p>With very large tiled displays, it might be difficult to read the
+information on the standard X desktop. In particular, the cursor can be
+easily lost and fonts could be difficult to read. Automatic primitive
+scaling might be very useful. We will investigate the possibility of
+scaling the cursor and providing a set of alternate pre-scaled fonts to
+replace the standard fonts that many applications use (e.g., fixed).
+Other options for automatic scaling will also be investigated.
+
+<sect1>Per-screen colormaps
+
+<p>Each screen in the set of back-end X servers should be able to be
+adjusted via the configuration utility. This support is required to
+allow the back-end screens to be calibrated via custom gamma tables. On
+24-bit systems that support a DirectColor visual, this type of
+correction can be accommodated. One possible implementation would be to
+advertise to X client of the DMX server a TrueColor visual while using
+DirectColor visuals on the back-end servers to implement this type of
+color correction. Other options will be investigated.
+
+ </article>
+
+ <!-- Local Variables: -->
+ <!-- fill-column: 72 -->
+ <!-- End: -->
diff --git a/xc/programs/Xserver/hw/dmx/doc/dmx.txt b/xc/programs/Xserver/hw/dmx/doc/dmx.txt
new file mode 100644
index 000000000..1da6caa98
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/doc/dmx.txt
@@ -0,0 +1,1716 @@
+ Distributed multihead X design
+ Kevin E. Martin, David H. Dawes, and Rickard E. Faith
+
+ 31 May 2002 (created 25 July 2001)
+
+ This document covers the motivation, background, design and implemen-
+ tation of the distributed multihead X (DMX) system. It is a living
+ document and describes the current design and implementation details
+ of the DMX system. As the project progresses, this document will be
+ continually updated to reflect the changes in the code and/or design.
+ _C_o_p_y_r_i_g_h_t _2_0_0_1 _b_y _V_A _L_i_n_u_x _S_y_s_t_e_m_s_, _I_n_c_._, _F_r_e_m_o_n_t_, _C_a_l_i_f_o_r_n_i_a_. _C_o_p_y_-
+ _r_i_g_h_t _2_0_0_1_,_2_0_0_2 _b_y _R_e_d _H_a_t_, _I_n_c_._, _D_u_r_h_a_m_, _N_o_r_t_h _C_a_r_o_l_i_n_a
+
+ ______________________________________________________________________
+
+ Table of Contents
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1. Introduction
+
+ 2. Background
+
+ 2.1 Core input device handling
+ 2.1.1 InitInput()
+ 2.1.2 InitAndStartDevices()
+ 2.1.3 devReadInput()
+ 2.1.4 ProcessInputEvents()
+ 2.1.5 DisableDevice()
+ 2.1.6 CloseDevice()
+ 2.1.7 LegalModifier()
+ 2.2 Output handling
+ 2.2.1 InitOutput()
+ 2.2.2 AddScreen()
+ 2.2.3 ScreenInit()
+ 2.2.4 CloseScreen()
+ 2.2.5 GC operations
+ 2.2.6 Xnest
+ 2.2.7 Shadow framebuffer
+ 2.3 Xinerama
+ 2.3.1 Xinerama-specific changes to the DIX code
+ 2.3.2 Xinerama-specific changes to the MI code
+ 2.3.3 Intercepted DIX core requests
+
+ 3. Development plan
+
+ 3.1 Bootstrap code
+ 3.2 Input device handling
+ 3.3 Output device handling
+ 3.3.1 Initialization
+ 3.3.2 Handling rendering requests
+ 3.4 Optimizing DMX
+ 3.5 Common X extension support
+ 3.6 OpenGL support
+
+ 4. Development Results
+
+ 4.1 Phase I
+ 4.1.1 Scope
+ 4.1.2 Results
+ 4.1.3 X Test Suite
+ 4.1.3.1 Introduction
+ 4.1.3.2 Expected Failures for a Single Head
+ 4.1.3.3 Expected Failures for Xinerama
+ 4.1.3.4 Additional Failures from Xdmx
+ 4.1.3.5 Summary and Future Work
+ 4.1.4 Fonts
+ 4.1.5 Performance
+ 4.1.6 Pixmaps
+
+ 5. Current issues
+
+ 5.1 Fonts
+ 5.2 Zero width rendering primitives
+ 5.3 DMX extension
+ 5.4 GLX support
+ 5.5 Output scaling
+ 5.6 Per-screen colormaps
+
+
+ ______________________________________________________________________
+
+
+
+
+ 11.. IInnttrroodduuccttiioonn
+
+ Current Open Source multihead solutions are limited to a single
+ physical machine. A single X server controls multiple display
+ devices, which can be arranged as independent heads or unified into a
+ single desktop. These solutions are limited to the number of physical
+ devices that can co-exist in a single machine (e.g., due to the number
+ of AGP/PCI slots available for graphics cards). Thus, large tiled
+ displays are not currently possible. This limitation will be solved
+ by eliminating the requirement that the display devices reside in the
+ same physical machine. This will be accomplished by developing a
+ front-end proxy X server that will control multiple back-end X servers
+ that make up the large display. These X servers can either run on the
+ same or separate machines.
+
+
+ The overall structure of the distributed multihead X (DMX) project is
+ as follows: A single front-end X server will act as a proxy to a set
+ of back-end X servers, which handle all of the visible rendering. X
+ clients will connect to the front-end server just as they normally
+ would to a regular X server. To the client, everything appears as if
+ they have a single large display; however, using an extension they can
+ request the arrangement of the back-end server screens as well as
+ other information that might be useful to them (e.g., for placement of
+ pop-up windows, window alignments by the window manager, etc.). A
+ configuration tool will be developed that will use this extension and
+ will aid setup and arrangement of the DMX system.
+
+
+ DMX can be broken down into two main parts: input devices and
+ rendering/windowing requests. Each of these are describe briefly
+ below, and the rest of this design document will describe them in
+ greater detail. When the project is complete, this design doc will be
+ delivered with the final product documentation.
+
+
+ Input devices can be handled either in the front-end server or can be
+ funneled through the front-end server from one (or more) or the back-
+ end servers. If they are served by the front-end server, then they
+ will be need to be connected directly to the system that runs the
+ front-end server and cannot be in use by another X server running on
+ that system. Basic devices, such as the mouse and keyboard, will be
+ handled directly. Other devices will be processed by the XInput
+ extension. Events will be passed back to the requesting client. For
+ devices that control a cursor, the software or hardware cursor on the
+ appropriate back-end server(s) will be enabled and positioned
+ accordingly, while the cursors on the other back-end server(s) will be
+ disabled.
+
+
+ Rendering requests will be accepted by the front-end server; however,
+ rendering to visible windows will be broken down as needed and sent to
+ the appropriate back-end server(s) via X11 library calls for actual
+ rendering. The basic framework will follow a Xnest-style approach.
+ GC state will be managed in the front-end server and sent to the
+ appropriate back-end server(s) as required. Pixmap rendering will (at
+ least initially) be handled by the front-end X server. Windowing
+ requests (e.g., ordering, mapping, moving, etc.) will handled in the
+ front-end server. If the request requires a visible change, the
+ windowing operation will be translated into requests for the
+ appropriate back-end server(s). Window state will be mirrored in the
+ back-end server(s) as needed.
+
+
+
+
+ 22.. BBaacckkggrroouunndd
+
+ This section describes the existing Open Source architectures that can
+ be used to handle multiple screens and upon which this development
+ project is based.
+
+
+ 22..11.. CCoorree iinnppuutt ddeevviiccee hhaannddlliinngg
+
+ The following is a description of how core input devices are handled
+ by an X server.
+
+
+ 22..11..11.. IInniittIInnppuutt(())
+
+ InitInput() is a DDX function that is called at the start of each
+ server generation from the X server's main() function. Its purpose is
+ to determine what input devices are connected to the X server,
+ register them with the DIX and MI layers, and initialize the input
+ event queue. InitInput() does not have a return value, but the X
+ server will abort if either a core keyboard device or a core pointer
+ device are not registered. Extended input (XInput) devices can also
+ be registered in InitInput().
+
+
+ InitInput() usually has implementation specific code to determine
+ which input devices are available. For each input device it will be
+ using, it calls AddInputDevice():
+
+
+ AAddddIInnppuuttDDeevviiccee(())
+ This DIX function allocates the device structure, registers a
+ callback function (which handles device init, close, on and
+ off), and returns the input handle, which can be treated as
+ opaque. It is called once for each input device.
+
+
+ Once input handles for core keyboard and core pointer devices have
+ been obtained from AddInputDevice(), they are registered as core
+ devices by calling RegisterPointerDevice() and
+ RegisterKeyboardDevice(). Each of these should be called once. If
+ both core devices are not registered, then the X server will exit with
+ a fatal error when it attempts to start the input devices in
+ InitAndStartDevices(), which is called directly after InitInput() (see
+ below).
+
+
+ RReeggiisstteerr{{PPooiinntteerr,,KKeeyybbooaarrdd}}DDeevviiccee(())
+ These DIX functions take a handle returned from AddInputDevice()
+ and initialize the core input device fields in inputInfo, and
+ initialize the input processing and grab functions for each core
+ input device.
+
+
+ The core pointer device is then registered with the miPointer code
+ (which does the high level cursor handling). While this registration
+ is not necessary for correct miPointer operation in the current
+ XFree86 code, it is still done mostly for compatibility reasons.
+
+
+ mmiiRReeggiisstteerrPPooiinntteerrDDeevviiccee(())
+ This MI function registers the core pointer's input handle with
+ with the miPointer code.
+
+
+
+ The final part of InitInput() is the initialization of the input event
+ queue handling. In most cases, the event queue handling provided in
+ the MI layer is used. The primary XFree86 X server uses its own event
+ queue handling to support some special cases related to the XInput
+ extension and the XFree86-specific DGA extension. For our purposes,
+ the MI event queue handling should be suitable. It is initialized by
+ calling mieqInit():
+
+
+ mmiieeqqIInniitt(())
+ This MI function initializes the MI event queue for the core
+ devices, and is passed the public component of the input handles
+ for the two core devices.
+
+
+ If a wakeup handler is required to deliver synchronous input events,
+ it can be registered here by calling the DIX function
+ RegisterBlockAndWakeupHandlers(). (See the devReadInput() description
+ below.)
+
+
+ 22..11..22.. IInniittAAnnddSSttaarrttDDeevviicceess(())
+
+ InitAndStartDevices() is a DIX function that is called immediately
+ after InitInput() from the X server's main() function. Its purpose is
+ to initialize each input device that was registered with
+ AddInputDevice(), enable each input device that was successfully
+ initialized, and create the list of enabled input devices. Once each
+ registered device is processed in this way, the list of enabled input
+ devices is checked to make sure that both a core keyboard device and
+ core pointer device were registered and successfully enabled. If not,
+ InitAndStartDevices() returns failure, and results in the the X server
+ exiting with a fatal error.
+
+
+ Each registered device is initialized by calling its callback
+ (dev->deviceProc) with the DEVICE_INIT argument:
+
+
+ ((**ddeevv-->>ddeevviicceePPrroocc))((ddeevv,, DDEEVVIICCEE__IINNIITT))
+ This function initializes the device structs with core
+ information relevant to the device.
+
+
+ For pointer devices, this means specifying the number of
+ buttons, default button mapping, the function used to get motion
+ events (usually miPointerGetMotionEvents()), the function used
+ to change/control the core pointer motion parameters
+ (acceleration and threshold), and the motion buffer size.
+
+
+ For keyboard devices, this means specifying the keycode range,
+ default keycode to keysym mapping, default modifier mapping, and
+ the functions used to sound the keyboard bell and modify/control
+ the keyboard parameters (LEDs, bell pitch and duration, key
+ click, which keys are auto-repeating, etc).
+
+
+ Each initialized device is enabled by calling EnableDevice():
+
+
+ EEnnaabblleeDDeevviiccee(())
+ EnableDevice() calls the device callback with DEVICE_ON:
+
+ ((**ddeevv-->>ddeevviicceePPrroocc))((ddeevv,, DDEEVVIICCEE__OONN))
+ This typically opens and initializes the relevant physical
+ device, and when appropriate, registers the device's file
+ descriptor (or equivalent) as a valid input source.
+
+
+ EnableDevice() then adds the device handle to the X server's
+ global list of enabled devices.
+
+
+ InitAndStartDevices() then verifies that a valid core keyboard and
+ pointer has been initialized and enabled. It returns failure if
+ either are missing.
+
+
+ 22..11..33.. ddeevvRReeaaddIInnppuutt(())
+
+ Each device will have some function that gets called to read its
+ physical input. These may be called in a number of different ways.
+ In the case of synchronous I/O, they will be called from a DDX wakeup-
+ handler that gets called after the server detects that new input is
+ available. In the case of asynchronous I/O, they will be called from
+ a (SIGIO) signal handler triggered when new input is available. This
+ function should do at least two things: make sure that input events
+ get enqueued, and make sure that the cursor gets moved for motion
+ events (except if these are handled later by the driver's own event
+ queue processing function, which cannot be done when using the MI
+ event queue handling).
+
+
+ Events are queued by calling mieqEnqueue():
+
+
+ mmiieeqqEEnnqquueeuuee(())
+ This MI function is used to add input events to the event queue.
+ It is simply passed the event to be queued.
+
+
+ The cursor position should be updated when motion events are enqueued,
+ by calling either miPointerAbsoluteCursor() or miPointerDeltaCursor():
+
+
+ mmiiPPooiinntteerrAAbbssoolluutteeCCuurrssoorr(())
+ This MI function is used to move the cursor to the absolute
+ coordinates provided.
+
+ mmiiPPooiinntteerrDDeellttaaCCuurrssoorr(())
+ This MI function is used to move the cursor relative to its
+ current position.
+
+
+ 22..11..44.. PPrroocceessssIInnppuuttEEvveennttss(())
+
+ ProcessInputEvents() is a DDX function that is called from the X
+ server's main dispatch loop when new events are available in the input
+ event queue. It typically processes the enqueued events, and updates
+ the cursor/pointer position. It may also do other DDX-specific event
+ processing.
+
+
+ Enqueued events are processed by mieqProcessInputEvents() and passed
+ to the DIX layer for transmission to clients:
+
+
+ mmiieeqqPPrroocceessssIInnppuuttEEvveennttss(())
+ This function processes each event in the event queue, and
+ passes it to the device's input processing function. The DIX
+ layer provides default functions to do this processing, and they
+ handle the task of getting the events passed back to the
+ relevant clients.
+
+ mmiiPPooiinntteerrUUppddaattee(())
+ This function resynchronized the cursor position with the new
+ pointer position. It also takes care of moving the cursor
+ between screens when needed in multi-head configurations.
+
+
+
+ 22..11..55.. DDiissaabblleeDDeevviiccee(())
+
+ DisableDevice is a DIX function that removes an input device from the
+ list of enabled devices. The result of this is that the device no
+ longer generates input events. The device's data structures are kept
+ in place, and disabling a device like this can be reversed by calling
+ EnableDevice(). DisableDevice() may be called from the DDX when it is
+ desirable to do so (e.g., the XFree86 server does this when VT
+ switching). Except for special cases, this is not normally called for
+ core input devices.
+
+
+ DisableDevice() calls the device's callback function with DEVICE_OFF:
+
+
+ ((**ddeevv-->>ddeevviicceePPrroocc))((ddeevv,, DDEEVVIICCEE__OOFFFF))
+ This typically closes the relevant physical device, and when
+ appropriate, unregisters the device's file descriptor (or
+ equivalent) as a valid input source.
+
+
+ DisableDevice() then removes the device handle from the X server's
+ global list of enabled devices.
+
+
+
+ 22..11..66.. CClloosseeDDeevviiccee(())
+
+ CloseDevice is a DIX function that removes an input device from the
+ list of available devices. It disables input from the device and
+ frees all data structures associated with the device. This function
+ is usually called from CloseDownDevices(), which is called from main()
+ at the end of each server generation to close all input devices.
+
+
+ CloseDevice() calls the device's callback function with DEVICE_CLOSE:
+
+
+ ((**ddeevv-->>ddeevviicceePPrroocc))((ddeevv,, DDEEVVIICCEE__CCLLOOSSEE))
+ This typically closes the relevant physical device, and when
+ appropriate, unregisters the device's file descriptor (or
+ equivalent) as a valid input source. If any device specific
+ data structures were allocated when the device was initialized,
+ they are freed here.
+
+
+ CloseDevice() then frees the data structures that were allocated for
+ the device when it was registered/initialized.
+
+
+
+ 22..11..77.. LLeeggaallMMooddiiffiieerr(())
+
+ LegalModifier() is a required DDX function that can be used to
+ restrict which keys may be modifier keys. This seems to be present
+ for historical reasons, so this function should simply return TRUE
+ unconditionally.
+
+
+
+ 22..22.. OOuuttppuutt hhaannddlliinngg
+
+ The following sections describe the main functions required to
+ initialize, use and close the output device(s) for each screen in the
+ X server.
+
+
+ 22..22..11.. IInniittOOuuttppuutt(())
+
+ This DDX function is called near the start of each server generation
+ from the X server's main() function. InitOutput()'s main purpose is
+ to initialize each screen and fill in the global screenInfo structure
+ for each screen. It is passed three arguments: a pointer to the
+ screenInfo struct, which it is to initialize, and argc and argv from
+ main(), which can be used to determine additional configuration
+ information.
+
+
+ The primary tasks for this function are outlined below:
+
+
+ 1. PPaarrssee ccoonnffiigguurraattiioonn iinnffoo:: The first task of InitOutput() is to
+ parses any configuration information from the configuration file.
+ In addition to the XF86Config file, other configuration information
+ can be taken from the command line. The command line options can
+ be gathered either in InitOutput() or earlier in the
+ ddxProcessArgument() function, which is called by
+ ProcessCommandLine(). The configuration information determines the
+ characteristics of the screen(s). For example, in the XFree86 X
+ server, the XF86Config file specifies the monitor information, the
+ screen resolution, the graphics devices and slots in which they are
+ located, and, for Xinerama, the screens' layout.
+
+ 2. IInniittiiaalliizzee ssccrreeeenn iinnffoo:: The next task is to initialize the screen-
+ dependent internal data structures. For example, part of what the
+ XFree86 X server does is to allocate its screen and pixmap private
+ indices, probe for graphics devices, compare the probed devices to
+ the ones listed in the XF86Config file, and add the ones that match
+ to the internal xf86Screens[] structure.
+
+ 3. SSeett ppiixxmmaapp ffoorrmmaattss:: The next task is to initialize the screenInfo's
+ image byte order, bitmap bit order and bitmap scanline unit/pad.
+ The screenInfo's pixmap format's depth, bits per pixel and scanline
+ padding is also initialized at this stage.
+
+ 4. UUnniiffyy ssccrreeeenn iinnffoo:: An optional task that might be done at this
+ stage is to compare all of the information from the various screens
+ and determines if they are compatible (i.e., if the set of screens
+ can be unified into a single desktop). This task has potential to
+ be useful to the DMX front-end server, if Xinerama's
+ PanoramiXConsolidate() function is not sufficient.
+
+
+ Once these tasks are complete, the valid screens are known and each of
+ these screens can be initialized by calling AddScreen().
+
+
+ 22..22..22.. AAddddSSccrreeeenn(())
+
+ This DIX function is called from InitOutput(), in the DDX layer, to
+ add each new screen to the screenInfo structure. The DDX screen
+ initialization function and command line arguments (i.e., argc and
+ argv) are passed to it as arguments.
+
+
+ This function first allocates a new Screen structure and any privates
+ that are required. It then initializes some of the fields in the
+ Screen struct and sets up the pixmap padding information. Finally, it
+ calls the DDX screen initialization function ScreenInit(), which is
+ described below. It returns the number of the screen that were just
+ added, or -1 if there is insufficient memory to add the screen or if
+ the DDX screen initialization fails.
+
+
+ 22..22..33.. SSccrreeeennIInniitt(())
+
+ This DDX function initializes the rest of the Screen structure with
+ either generic or screen-specific functions (as necessary). It also
+ fills in various screen attributes (e.g., width and height in
+ millimeters, black and white pixel values).
+
+
+ The screen init function usually calls several functions to perform
+ certain screen initialization functions. They are described below:
+
+
+ {{mmii,,**ffbb}}SSccrreeeennIInniitt(())
+ The DDX layer's ScreenInit() function usually calls another
+ layer's ScreenInit() function (e.g., miScreenInit() or
+ fbScreenInit()) to initialize the fallbacks that the DDX driver
+ does not specifically handle.
+
+
+ After calling another layer's ScreenInit() function, any screen-
+ specific functions either wrap or replace the other layer's
+ function pointers. If a function is to be wrapped, each of the
+ old function pointers from the other layer are stored in a
+ screen private area. Common functions to wrap are CloseScreen()
+ and SaveScreen().
+
+
+ mmiiIInniittiiaalliizzeeBBaacckkiinnggSSttoorree(())
+ This MI function initializes the screen's backing storage
+ functions, which are used to save areas of windows that are
+ currently covered by other windows.
+
+
+ mmiiDDCCIInniittiiaalliizzee(())
+ This MI function initializes the MI cursor display structures
+ and function pointers. If a hardware cursor is used, the DDX
+ layer's ScreenInit() function will wrap additional screen and
+ the MI cursor display function pointers.
+
+
+ Another common task for ScreenInit() function is to initialize the
+ output device state. For example, in the XFree86 X server, the
+ ScreenInit() function saves the original state of the video card and
+ then initializes the video mode of the graphics device.
+
+
+ 22..22..44.. CClloosseeSSccrreeeenn(())
+
+ This function restores any wrapped screen functions (and in particular
+ the wrapped CloseScreen() function) and restores the state of the
+ output device to its original state. It should also free any private
+ data it created during the screen initialization.
+
+
+ 22..22..55.. GGCC ooppeerraattiioonnss
+
+ When the X server is requested to render drawing primitives, it does
+ so by calling drawing functions through the graphics context's
+ operation function pointer table (i.e., the GCOps functions). These
+ functions render the basic graphics operations such as drawing
+ rectangles, lines, text or copying pixmaps. Default routines are
+ provided either by the MI layer, which draws indirectly through a
+ simple span interface, or by the framebuffer layers (e.g., CFB, MFB,
+ FB), which draw directly to a linearly mapped frame buffer.
+
+
+ To take advantage of special hardware on the graphics device, specific
+ GCOps functions can be replaced by device specific code. However,
+ many times the graphics devices can handle only a subset of the
+ possible states of the GC, so during graphics context validation,
+ appropriate routines are selected based on the state and capabilities
+ of the hardware. For example, some graphics hardware can accelerate
+ single pixel width lines with certain dash patterns. Thus, for dash
+ patterns that are not supported by hardware or for width 2 or greater
+ lines, the default routine is chosen during GC validation.
+
+
+ Note that some pointers to functions that draw to the screen are
+ stored in the Screen structure. They include GetImage(), GetSpans(),
+ PaintWindowBackground(), PaintWindowBorder(), CopyWindow() and
+ RestoreAreas().
+
+
+ 22..22..66.. XXnneesstt
+
+ The Xnest X server is a special proxy X server that relays the X
+ protocol requests that it receives to a ``real'' X server that then
+ processes the requests and displays the results, if applicable. To
+ the X applications, Xnest appears as if it is a regular X server.
+ However, Xnest is both server to the X application and client of the
+ real X server, which will actually handle the requests.
+
+
+ The Xnest server implements all of the standard input and output
+ initialization steps outlined above.
+
+
+ IInniittOOuuttppuutt(())
+ Xnest takes its configuration information from command line
+ arguments via ddxProcessArguments(). This information includes
+ the real X server display to connect to, its default visual
+ class, the screen depth, the Xnest window's geometry, etc.
+ Xnest then connects to the real X server and gathers visual,
+ colormap, depth and pixmap information about that server's
+ display, creates a window on that server, which will be used as
+ the root window for Xnest.
+
+
+ Next, Xnest initializes its internal data structures and uses
+ the data from the real X server's pixmaps to initialize its own
+ pixmap formats. Finally, it calls AddScreen(xnestOpenScreen,
+ argc, argv) to initialize each of its screens.
+
+
+ SSccrreeeennIInniitt(())
+ Xnest's ScreenInit() function is called xnestOpenScreen(). This
+ function initializes its screen's depth and visual information,
+ and then calls miScreenInit() to set up the default screen
+ functions. It then calls miInitializeBackingStore() and
+ miDCInitialize() to initialize backing store and the software
+ cursor. Finally, it replaces many of the screen functions with
+ its own functions that repackage and send the requests to the
+ real X server to which Xnest is attached.
+
+
+ CClloosseeSSccrreeeenn(())
+ This function frees its internal data structure allocations.
+ Since it replaces instead of wrapping screen functions, there
+ are no function pointers to unwrap. This can potentially lead
+ to problems during server regeneration.
+
+
+ GGCC ooppeerraattiioonnss
+ The GC operations in Xnest are very simple since they leave all
+ of the drawing to the real X server to which Xnest is attached.
+ Each of the GCOps takes the request and sends it to the real X
+ server using standard Xlib calls. For example, the X
+ application issues a XDrawLines() call. This function turns
+ into a protocol request to Xnest, which calls the
+ xnestPolylines() function through Xnest's GCOps function pointer
+ table. The xnestPolylines() function is only a single line,
+ which calls XDrawLines() using the same arguments that were
+ passed into it. Other GCOps functions are very similar. Two
+ exceptions to the simple GCOps functions described above are the
+ image functions and the BLT operations.
+
+
+ The image functions, GetImage() and PutImage(), must use a
+ temporary image to hold the image to be put of the image that
+ was just grabbed from the screen while it is in transit to the
+ real X server or the client. When the image has been
+ transmitted, the temporary image is destroyed.
+
+
+ The BLT operations, CopyArea() and CopyPlane(), handle not only
+ the copy function, which is the same as the simple cases
+ described above, but also the graphics exposures that result
+ when the GC's graphics exposure bit is set to True. Graphics
+ exposures are handled in a helper function,
+ xnestBitBlitHelper(). This function collects the exposure
+ events from the real X server and, if any resulting in regions
+ being exposed, then those regions are passed back to the MI
+ layer so that it can generate exposure events for the X
+ application.
+
+
+ The Xnest server takes its input from the X server to which it is
+ connected. When the mouse is in the Xnest server's window, keyboard
+ and mouse events are received by the Xnest server, repackaged and sent
+ back to any client that requests those events.
+
+
+ 22..22..77.. SShhaaddooww ffrraammeebbuuffffeerr
+
+ The most common type of framebuffer is a linear array memory that maps
+ to the video memory on the graphics device. However, accessing that
+ video memory over an I/O bus (e.g., ISA or PCI) can be slow. The
+ shadow framebuffer layer allows the developer to keep the entire
+ framebuffer in main memory and copy it back to video memory at regular
+ intervals. It also has been extended to handle planar video memory
+ and rotated framebuffers.
+
+
+ There are two main entry points to the shadow framebuffer code:
+
+
+ sshhaaddoowwAAlllloocc((wwiiddtthh,, hheeiigghhtt,, bbpppp))
+ This function allocates the in memory copy of the framebuffer of
+ size width*height*bpp. It returns a pointer to that memory,
+ which will be used by the framebuffer ScreenInit() code during
+ the screen's initialization.
+
+
+ sshhaaddoowwIInniitt((ppSSccrreeeenn,, uuppddaatteePPrroocc,, wwiinnddoowwPPrroocc))
+ This function initializes the shadow framebuffer layer. It
+ wraps several screen drawing functions, and registers a block
+ handler that will update the screen. The updateProc is a
+ function that will copy the damaged regions to the screen, and
+ the windowProc is a function that is used when the entire linear
+ video memory range cannot be accessed simultaneously so that
+ only a window into that memory is available (e.g., when using
+ the VGA aperture).
+
+
+ The shadow framebuffer code keeps track of the damaged area of each
+ screen by calculating the bounding box of all drawing operations that
+ have occurred since the last screen update. Then, when the block
+ handler is next called, only the damaged portion of the screen is
+ updated.
+
+
+ Note that since the shadow framebuffer is kept in main memory, all
+ drawing operations are performed by the CPU and, thus, no accelerated
+ hardware drawing operations are possible.
+
+
+
+ 22..33.. XXiinneerraammaa
+
+ Xinerama is an X extension that allows multiple physical screens
+ controlled by a single X server to appear as a single screen.
+ Although the extension allows clients to find the physical screen
+ layout via extension requests, it is completely transparent to clients
+ at the core X11 protocol level. The original public implementation of
+ Xinerama came from Digital/Compaq. XFree86 rewrote it, filling in
+ some missing pieces and improving both X11 core protocol compliance
+ and performance. The Xinerama extension will be passing through
+ X.Org's standardization process in the near future, and the sample
+ implementation will be based on this rewritten version.
+
+
+ The current implementation of Xinerama is based primarily in the DIX
+ (device independent) and MI (machine independent) layers of the X
+ server. With few exceptions the DDX layers do not need any changes to
+ support Xinerama. X server extensions often do need modifications to
+ provide full Xinerama functionality.
+
+
+ The following is a code-level description of how Xinerama functions.
+
+
+ Note: Because the Xinerama extension was originally called the
+ PanoramiX extension, many of the Xinerama functions still have the
+ PanoramiX prefix.
+
+
+ PPaannoorraammiiXXEExxtteennssiioonnIInniitt(())
+ PanoramiXExtensionInit() is a device-independent extension
+ function that is called at the start of each server generation
+ from InitExtensions(), which is called from the X server's
+ main() function after all output devices have been initialized,
+ but before any input devices have been initialized.
+ PanoramiXNumScreens is set to the number of physical screens.
+ If only one physical screen is present, the extension is
+ disabled, and PanoramiXExtensionInit() returns without doing
+ anything else.
+
+
+ The Xinerama extension is registered by calling AddExtension().
+
+
+ A local per-screen array of data structures (panoramiXdataPtr[])
+ is allocated for each physical screen, and GC and Screen private
+ indexes are allocated, and both GC and Screen private areas are
+ allocated for each physical screen. These hold Xinerama-
+ specific per-GC and per-Screen data. Each screen's CreateGC and
+ CloseScreen functions are wrapped by XineramaCreateGC() and
+ XineramaCloseScreen() respectively. Some new resource classes
+ are created for Xinerama drawables and GCs, and resource types
+ for Xinerama windows, pixmaps and colormaps.
+
+
+ A region (XineramaScreenRegions[i]) is initialized for each
+ physical screen, and single region (PanoramiXScreenRegion) is
+ initialized to be the union of the screen regions. The
+ panoramiXdataPtr[] array is also initialized with the size and
+ origin of each screen. The relative positioning information for
+ the physical screens is taken from the array dixScreenOrigins[],
+ which the DDX layer must initialize in InitOutput(). The bounds
+ of the combined screen is also calculated (PanoramiXPixWidth and
+ PanoramiXPixHeight).
+
+
+ The DIX layer has a list of function pointers (ProcVector[])
+ that holds the entry points for the functions that process core
+ protocol requests. The requests that Xinerama must intercept
+ and break up into physical screen-specific requests are wrapped.
+ The original set is copied to SavedProcVector[]. The types of
+ requests intercepted are Window requests, GC requests, colormap
+ requests, drawing requests, and some geometry-related requests.
+ This wrapping allows the bulk of the protocol request processing
+ to be handled transparently to the DIX layer. Some operations
+ cannot be dealt with in this way and are handled with Xinerama-
+ specific code within the DIX layer.
+
+
+ PPaannoorraammiiXXCCoonnssoolliiddaattee(())
+ PanoramiXConsolidate() is a device-independent extension
+ function that is called directly from the X server's main()
+ function after extensions and input/output devices have been
+ initialized, and before the root windows are defined and
+ initialized.
+
+
+ This function finds the set of depths (PanoramiXDepths[]) and
+ visuals (PanoramiXVisuals[]) common to all of the physical
+ screens. PanoramiXNumDepths is set to the number of common
+ depths, and PanoramiXNumVisuals is set to the number of common
+ visuals. Resources are created for the single root window and
+ the default colormap. Each of these resources has per-physical
+ screen entries.
+
+
+ PPaannoorraammiiXXCCrreeaatteeCCoonnnneeccttiioonnBBlloocckk(())
+ PanoramiXConsolidate() is a device-independent extension
+ function that is called directly from the X server's main()
+ function after the per-physical screen root windows are created.
+ It is called instead of the standard DIX CreateConnectionBlock()
+ function. If this function returns FALSE, the X server exits
+ with a fatal error. This function will return FALSE if no
+ common depths were found in PanoramiXConsolidate(). With no
+ common depths, Xinerama mode is not possible.
+
+
+ The connection block holds the information that clients get when
+ they open a connection to the X server. It includes information
+ such as the supported pixmap formats, number of screens and the
+ sizes, depths, visuals, default colormap information, etc, for
+ each of the screens (much of information that xdpyinfo shows).
+ The connection block is initialized with the combined single
+ screen values that were calculated in the above two functions.
+
+
+ The Xinerama extension allows the registration of connection
+ block callback functions. The purpose of these is to allow
+ other extensions to do processing at this point. These
+ callbacks can be registered by calling
+ XineramaRegisterConnectionBlockCallback() from the other
+ extension's ExtensionInit() function. Each registered
+ connection block callback is called at the end of
+ PanoramiXCreateConnectionBlock().
+
+
+ 22..33..11.. XXiinneerraammaa--ssppeecciiffiicc cchhaannggeess ttoo tthhee DDIIXX ccooddee
+
+ There are a few types of Xinerama-specific changes within the DIX
+ code. The main ones are described here.
+
+
+ Functions that deal with colormap or GC -related operations outside of
+ the intercepted protocol requests have a test added to only do the
+ processing for screen numbers > 0. This is because they are handled
+ for the single Xinerama screen and the processing is done once for
+ screen 0.
+
+
+ The handling of motion events does some coordinate translation between
+ the physical screen's origin and screen zero's origin. Also, motion
+ events must be reported relative to the composite screen origin rather
+ than the physical screen origins.
+
+
+ There is some special handling for cursor, window and event processing
+ that cannot (either not at all or not conveniently) be done via the
+ intercepted protocol requests. A particular case is the handling of
+ pointers moving between physical screens.
+
+
+ 22..33..22.. XXiinneerraammaa--ssppeecciiffiicc cchhaannggeess ttoo tthhee MMII ccooddee
+
+ The only Xinerama-specific change to the MI code is in
+ miSendExposures() to handle the coordinate (and window ID) translation
+ for expose events.
+
+
+ 22..33..33.. IInntteerrcceepptteedd DDIIXX ccoorree rreeqquueessttss
+
+ Xinerama breaks up drawing requests for dispatch to each physical
+ screen. It also breaks up windows into pieces for each physical
+ screen. GCs are translated into per-screen GCs. Colormaps are
+ replicated on each physical screen. The functions handling the
+ intercepted requests take care of breaking the requests and
+ repackaging them so that they can be passed to the standard request
+ handling functions for each screen in turn. In addition, and to aid
+ the repackaging, the information from many of the intercepted requests
+ is used to keep up to date the necessary state information for the
+ single composite screen. Requests (usually those with replies) that
+ can be satisfied completely from this stored state information do not
+ call the standard request handling functions.
+
+
+
+ 33.. DDeevveellooppmmeenntt ppllaann
+
+ This section describes the current development plan.
+
+
+ 33..11.. BBoooottssttrraapp ccooddee
+
+ To allow for rapid development of the DMX server by multiple
+ developers during the first development stage, the problem will be
+ broken down into three tasks: the overall DMX framework, back-end
+ rendering services and input device handling services. However,
+ before the work begins on these tasks, a simple framework that each
+ developer could use was implemented to bootstrap the development
+ effort. This framework renders to a single back-end server and
+ provides dummy input devices (i.e., the keyboard and mouse). The
+ simple back-end rendering service was implemented using the shadow
+ framebuffer support currently available in the XFree86 environment.
+
+
+ Using this bootstrapping framework, each developer has been able to
+ work on each of the tasks listed above independently as follows: the
+ framework will be extended to handle arbitrary back-end server
+ configurations; the back-end rendering services will be transitioned
+ to the more efficient Xnest-style implementation; and, an input device
+ framework to handle various input devices via the input extension will
+ be developed.
+
+
+ Status: The boot strap code is complete.
+
+
+
+ 33..22.. IInnppuutt ddeevviiccee hhaannddlliinngg
+
+ An X server (including the front-end X server) requires two core input
+ devices -- a keyboard and a pointer (mouse). These core devices are
+ handled and required by the core X11 protocol. Additional types of
+ input devices may be attached and utilized via the XInput extension.
+ These are usually referred to as ``extended input devices''.
+
+
+ There are some options as to how the front-end X server gets its core
+ input devices:
+
+
+ 1. The physical input devices (e.g., keyboard and mouse) can be
+ attached directly to the front-end X server. In this case, the
+ keyboard and mouse on the machine running the front-end X server
+ will be used. The front-end will have drivers to read the raw
+ input from those devices and convert it into the required X input
+ events (key press/release, pointer button press/release, pointer
+ motion). The front-end keyboard driver will keep track of keyboard
+ properties such as key and modifier mappings, autorepeat state,
+ keyboard sound and led state. Similarly the front-end pointer
+ driver will keep track if pointer properties such as the button
+ mapping and movement acceleration parameters. With this option,
+ input is handled fully in the front-end X server, and the back-end
+ X servers are used in a display-only mode.
+ There are some options for how the input device support could be
+ implemented:
+
+
+ a. The XFree86 X server has modular input drivers that could be
+ adapted for this purpose. The mouse driver supports a wide
+ range of mouse types and interfaces, as well as a range of
+ Operating System platforms. The keyboard driver in XFree86 is
+ not currently as modular as the mouse driver, but could be made
+ so. The XFree86 X server also has a range of other input
+ drivers for extended input devices such as tablets and touch
+ screens.
+
+ b. The kdrive X server in XFree86 has built-in drivers that support
+ PS/2 mice and keyboard under Linux. The mouse driver can
+ indirectly handle other mouse types if the Linux utility gpm is
+ used as to translate the native mouse protocol into PS/2 mouse
+ format. These drivers could be adapted and built in to the
+ front-end X server if this range of hardware and OS support is
+ sufficient.
+
+
+ 2. The front-end can make use of the core input devices attached to a
+ single back-end X server. In this case, the front-end will get the
+ core input events from that back-end, and the keyboard and mouse
+ used to control the distributed X array will be physically
+ connected to that back-end. The keyboard and pointer state will
+ also be handled in that back-end, with the front-end simply acting
+ as a proxy for input-device related X requests.
+
+ 3. The front-end can make use of the core input devices attached to
+ one or more of the back-end X servers. This is like option 2,
+ except that the core input events from multiple back-ends are
+ merged into a single input event stream. This can work sanely when
+ only a single set of input devices is used at any given time. The
+ keyboard and pointer state will be handled in the front-end, with
+ changes propagated to the back-end servers as needed. This option
+ can work well when the keyboards and pointers on each back-end are
+ the same. When they are different (different numbers of buttons,
+ different keys, etc) there are issues to resolve in how the front-
+ end exports a single set of consistent core input devices.
+
+ 4. A variation on option 3 is to nominate one back-end X server (or
+ even the front-end X server) as providing the core input devices,
+ and allowing access to the core input devices on the other back-
+ ends as extended input devices. Among other things, this would
+ allow the current core devices to be switched at run time, and it
+ would allow XInput-aware applications to access the full
+ capabilities of each back-end's core input devices simultaneously.
+ The back-end X servers would not need to support the XInput
+ extension for this to work. The XFree86 implementation of the
+ XInput extension allows multiple extended input devices to generate
+ core input events, and leveraging this would be an option for
+ implementing option 3.
+
+ 5. The front-end server could create a console window that is
+ displayed on an X server independent of the back-end X servers.
+ This console window could display things like the physical screen
+ layout, and the front-end could get its core input events from
+ events delivered to the console window.
+
+
+ Although extended input devices are not specifically mentioned in the
+ Distributed X requirements, option 4 above could be further extended
+ to make extended input devices attached to back-end X servers visible,
+ and/or to allow extended input devices to be attached to the front-end
+ X server.
+
+
+ The bootstrap code (Xdmx) currently has dummy input devices. These do
+ the necessary initialization to satisfy the X server's requirements
+ for core pointer and keyboard devices, but no input events are ever
+ generated.
+
+
+ The input device support in Xnest could be used to implement the
+ input-from-back-end approach in the bootstrap code. The mouse and
+ keyboard handling code from the kdrive X server in XFree86 would be a
+ good starting point for implementing the input-from-front-end approach
+ in the bootstrap code.
+
+
+ Input-related work required with the bootstrap code:
+
+
+ +o Evaluate using back-end input devices vs attaching the input
+ devices directly to the front-end:
+
+
+ +o Implement back-end input in the bootstrap code.
+
+ +o Implement front-end input in the bootstrap code.
+
+ +o Evaluate both options with the bootstrap code extended to drive
+ more than one back-end.
+
+
+ Status: The input code is complete.
+
+
+
+ 33..33.. OOuuttppuutt ddeevviiccee hhaannddlliinngg
+
+ The output of the DMX system displays rendering and windowing requests
+ across multiple screens. The screens are typically arranged in a grid
+ such that together they represent a single large display.
+
+
+ The output section of the DMX code consists of two parts. The first
+ is in the front-end proxy X server, which accept client connections,
+ manages the windows and potentially renders primitives but does not
+ actually display any of the drawing primitives. The second part is
+ the back-end X server(s), which accept commands from the front-end
+ server and display the results on their screens.
+
+
+ 33..33..11.. IInniittiiaalliizzaattiioonn
+
+ The DMX front-end must first initialize its screens by connecting to
+ each of the back-end X servers and collecting information about each
+ of these screens. However, the information collected from the back-
+ end X servers might be inconsistent. Handling these cases can be
+ difficult and/or inefficient. For example, a two screen system has
+ one back-end X server running at 16bpp while the second is running at
+ 32bpp. Converting rendering requests (e.g., XPutImage() or
+ XGetImage() requests) to the appropriate bit depth can be very time
+ consuming. Analyzing these cases to determine how or even if it is
+ possible to handle them is required. The current Xinerama code
+ handles many of these cases (e.g., in PanoramiXConsolidate()) and will
+ be used as a starting point. In general, the best solution is to use
+ homogeneous X servers and display devices.
+
+ Once this screen consolidation is finished, the relative position of
+ each back-end X server's screen in the unified screen is initialized.
+ A full-screen window is opened on each of the back-end X servers, and
+ the cursor on each screen is turned off.
+
+
+ 33..33..22.. HHaannddlliinngg rreennddeerriinngg rreeqquueessttss
+
+ After initialization, X applications connect to the front-end server.
+ There are two possible implementations of how rendering and windowing
+ requests are handled in the DMX system:
+
+
+ 1. A shadow framebuffer is used in the front-end server as the render
+ target. In this option, all protocol requests are completely
+ handled in the front-end server. All state and resources are
+ maintained in the front-end including a shadow copy of the entire
+ framebuffer. The framebuffers attached to the back-end servers are
+ updated by XPutImage() calls with data taken directly from the
+ shadow framebuffer.
+
+
+ This solution suffers from two main problems. First, it does not
+ take advantage of any accelerated hardware available in the system.
+ Second, the size of the XPutImage() calls can be quite large and
+ thus will be limited by the bandwidth available.
+
+
+ 2. Rendering requests are sent to each back-end server for handling
+ (as is done in the Xnest server described above). In this option,
+ certain protocol requests are handled in the front-end server and
+ certain requests are repackaged and then sent to the back-end
+ servers. The framebuffer is distributed across the multiple back-
+ end servers. Rendering to the framebuffer is handled on each back-
+ end and can take advantage of any acceleration available on the
+ back-end servers' graphics display device. State is maintained
+ both in the front and back-end servers.
+
+
+ This solution suffers from two main drawbacks. First, protocol
+ requests are sent to all back-end servers -- even those that will
+ completely clip the rendering primitive -- which wastes bandwidth
+ and processing time. Second, state is maintained both in the
+ front- and back-end servers. These drawbacks are not as severe as
+ in option 1 (above) and can either be overcome through
+ optimizations or are acceptable. Therefore, this option will be
+ used in the final implementation.
+
+
+ Status: Both the shadow framebuffer and Xnest-style code is complete.
+
+
+
+ 33..44.. OOppttiimmiizziinngg DDMMXX
+
+ The simple Xnest-style solution described above sends the repackaged
+ protocol requests to all back-end servers. Simple clipping tests in
+ the front-end X server will be used to limit sending the repackaged
+ protocol requests to only those back-end servers that will actually
+ display the data.
+
+
+ In addition, each protocol request will be analyzed to determine if it
+ is possible to break the request into smaller pieces at display
+ boundaries. The initial ones to be analyzed are put and get image
+ requests since they will require the greatest bandwidth to transmit
+ data between the front and back-end servers. Other protocol requests
+ will be analyzed and those that will benefit from breaking them into
+ smaller requests will be implemented.
+
+
+ In the simple solution, BLT operations (e.g., XCopyArea() and window
+ moves) that cross display boundaries require moving pixel data from
+ possibly multiple back-end servers to the front-end server and then
+ potentially to several back-end servers. This data movement is very
+ inefficient and direct communication between back-end X servers could
+ eliminate several extraneous data copies. An X server extension will
+ be implemented and used by the front and back-end servers to allow
+ back-end servers to directly send pixel data to each other under the
+ direct control of the front-end server. This X extension is entirely
+ optional and the DMX system will function without it; however, the
+ performance of the system might degrade if the front and back-end
+ servers do not implemented it.
+
+
+ Status: Not yet started.
+
+
+
+ 33..55.. CCoommmmoonn XX eexxtteennssiioonn ssuuppppoorrtt
+
+ The XInput, XKeyboard and Shape X extensions are commonly used and
+ support for them will be added to the DMX system. In addition,
+ support for the Render extension (as well as the XTest extension
+ mentioned above) will be added.
+
+
+ The XInput extension will be used to allow multiple and non-standard
+ input devices to be accessed simultaneously. These input devices
+ might be connected to either the front-end or back-end servers. The
+ XKeyboard extension will allow much better keyboard mappings control.
+ The Shape extension allows arbitrarily shaped windows and is commonly
+ used by various window managers.
+
+
+ Status: Not yet started.
+
+
+
+ 33..66.. OOppeennGGLL ssuuppppoorrtt
+
+ OpenGL support using the Mesa code base exists in XFree86 release 4
+ and later. Currently, the direct rendering infrastructure (DRI)
+ provides accelerated OpenGL support for local clients and
+ unaccelerated OpenGL support (i.e., software rendering) is provided
+ for non-local clients.
+
+
+ The single head OpenGL support in XFree86 4.x will be extended to use
+ the DMX system. When the front and back-end servers are on the same
+ physical hardware, it is possible to use the DRI to directly render to
+ the back-end servers. First, the existing DRI will be extended to
+ support multiple display heads, and then to support the DMX system.
+ OpenGL rendering requests will be direct rendering to each back-end X
+ server. The DRI will request the screen layout (either from the
+ existing Xinerama extension or a DMX-specific extension). Support for
+ synchronized swap buffers will also be added (on hardware that
+ supports it). Note that a single front-end server with a single back-
+ end server on the same physical machine can emulate accelerated
+ indirect rendering.
+
+
+ When the front and back-end servers are on different physical hardware
+ or are using non-XFree86 4.x X servers, a mechanism to render
+ primitives across the back-end servers will be provided. There are
+ several options as to how this can be implemented.
+
+
+ 1. The existing OpenGL support in each back-end server can be used by
+ repackaging rendering primitives and sending them to each back-end
+ server. This option is similar to the unoptimized Xnest-style
+ approach mentioned above. Optimization of this solution is beyond
+ the scope of this project and is better suited to other distributed
+ rendering systems.
+
+ 2. Rendering to a pixmap in the front-end server using the current
+ XFree86 4.x code, and then displaying to the back-ends via calls to
+ XPutImage() is another option. This option is similar to the
+ shadow frame buffer approach mentioned above. It is slower and
+ bandwidth intensive, but has the advantage that the back-end
+ servers are not required to have OpenGL support.
+
+
+ These, and other, options will be investigated in this phase of the
+ work.
+
+
+ Future work (outside the scope of the current project) could further
+ extend this work to use a distributed rendering system such as
+ Chromium/WireGL.
+
+
+ Status: Not yet started.
+
+
+
+ 44.. DDeevveellooppmmeenntt RReessuullttss
+
+ In this section the results of each phase of development are
+ discussed.
+
+
+ 44..11.. PPhhaassee II
+
+ The initial development phase dealt with the basic implementation
+ including the bootstrap code, which used the shadow framebuffer, and
+ the unoptimized implementation, based on an Xnest-style
+ implementation.
+
+
+ 44..11..11.. SSccooppee
+
+ The goal of Phase I is to provide fundamental functionality that can
+ act as a foundation for ongoing work:
+
+ 1. Develop the proxy X server
+
+ +o The proxy X server will operate on the X11 protocol and relay
+ requests as necessary to correctly perform the request.
+
+ +o Work will be based on the existing work for Xinerama and Xnest.
+
+ +o Input events and windowing operations are handled in the proxy
+ server and rendering requests are repackaged and sent to each of
+ the back-end servers for display.
+
+ +o The multiple screen layout (including support for overlapping
+ screens) will be user configurable via a configuration file or
+ through the configuration tool.
+
+ 2. Develop graphical configuration tool
+
+ +o There will be potentially a large number of X servers to configure
+ into a single display. The tool will allow the user to specify
+ which servers are involved in the configuration and how they should
+ be laid out.
+
+ 3. Pass the X Test Suite
+
+ +o The X Test Suite covers the basic X11 operations. All tests known
+ to succeed must correctly operate in the distributed X environment.
+
+
+ For this phase, the back-end X servers are assumed to be unmodified X
+ servers that do not support any DMX-related protocol extensions;
+ future optimization pathways are considered, but are not implemented;
+ and the configuration tool is assumed to rely only on libraries in the
+ X source tree (e.g., Xt).
+
+
+ 44..11..22.. RReessuullttss
+
+ The proxy X server, Xdmx, was developed to distribute X11 protocol
+ requests to the set of back-end X servers. It opens a window on each
+ back-end server, which represents the part of the front-end's root
+ window that is visible on that screen. It mirrors window, pixmap and
+ other state in each back-end server. Drawing requests are sent to
+ either windows or pixmaps on each back-end server. This code is based
+ on Xnest and uses the existing Xinerama extension.
+
+
+ Input events can be taken from (1) devices attached to the back-end
+ server, (2) core devices attached directly to the Xdmx server, or (3)
+ from a ``console'' window on another X server. Events for these
+ devices are gathered, processed and delivered to clients attached to
+ the Xdmx server.
+
+
+ An intuitive configuration format was developed to help the user
+ easily configure the multiple back-end X servers. It was defined (see
+ grammar in Xdmx man page) and a parser was implemented that is used by
+ the Xdmx server and by a standalone xdmxconfig utility. The parsing
+ support was implemented such that it can be easily factored out of the
+ X source tree for use with other tools (e.g., vdl). Support for
+ converting legacy vdl-format configuration files to the DMX format is
+ provided by the vdltodmx utility.
+
+
+ Originally, the configuration file was going to be a subsection of
+ XFree86's XF86Config file, but that was not possible since Xdmx is a
+ completely separate X server. Thus, a separate config file format was
+ developed. In addition, a graphical configuration tool, xdmxconfig,
+ was developed to allow the user to create and arrange the screens in
+ the configuration file. The --ccoonnffiiggffiillee and --ccoonnffiigg command-line
+ options can be used to start Xdmx using a configuration file.
+
+
+ An extension that enables remote input testing is required for the X
+ Test Suite to function. During this phase, this extension (XTEST) was
+ implemented in the Xdmx server. The results from running the X Test
+ Suite are described in detail below.
+
+
+
+ 44..11..33..
+
+ XX TTeesstt SSuuiittee
+
+ 44..11..33..11..
+
+ IInnttrroodduuccttiioonn
+
+ The X Test Suite contains tests that verify Xlib functions operate
+ correctly. The test suite is designed to run on a single X server;
+ however, since X applications will not be able to tell the difference
+ between the DMX server and a standard X server, the X Test Suite
+ should also run on the DMX server.
+
+ The Xdmx server was tested with the X Test Suite, and the existing
+ failures are noted in this section. To put these results in
+ perspective, we first discuss expected X Test failures and how errors
+ in underlying systems can impact Xdmx test results.
+
+
+ 44..11..33..22..
+
+ EExxppeecctteedd FFaaiilluurreess ffoorr aa SSiinnggllee HHeeaadd
+
+ A correctly implemented X server with a single screen is expected to
+ fail certain X Test tests. The following well-known errors occur
+ because of rounding error in the X server code:
+
+ XDrawArc: Tests 42, 63, 66, 73
+ XDrawArcs: Tests 45, 66, 69, 76
+
+
+
+
+ The following failures occur because of the high-level X server
+ implementation:
+
+ XLoadQueryFont: Test 1
+ XListFontsWithInfo: Tests 3, 4
+ XQueryFont: Tests 1, 2
+
+
+
+
+ The following test fails when running the X server as root under Linux
+ because of the way directory modes are interpreted:
+
+ XWriteBitmapFile: Test 3
+
+
+
+
+ Depending on the video card used for the back-end, other failures may
+ also occur because of bugs in the low-level driver implementation.
+ Over time, failures of this kind are usually fixed by XFree86, but
+ will show up in Xdmx testing until then.
+
+
+ 44..11..33..33..
+
+ EExxppeecctteedd FFaaiilluurreess ffoorr XXiinneerraammaa
+
+ Xinerama fails several X Test Suite tests because of design decisions
+ made for the current implementation of Xinerama. Over time, many of
+ these errors will be corrected by XFree86 and the group working on a
+ new Xinerama implementation. Therefore, Xdmx will also share X Suite
+ Test failures with Xinerama.
+
+ We may be able to fix or work-around some of these failures at the
+ Xdmx level, but this will require additional exploration that was not
+ part of Phase I.
+
+ Xinerama is constantly improving, and the list of Xinerama-related
+ failures depends on XFree86 version and the underlying graphics
+ hardware. We tested with a variety of hardware, including nVidia, S3,
+ ATI Radeon, and Matrox G400 (in dual-head mode). The list below
+ includes only those failures that appear to be from the Xinerama
+ layer, and does not include failures listed in the previous section,
+ or failures that appear to be from the low-level graphics driver
+ itself:
+
+ These failures were noted with multiple Xinerama configurations:
+
+ XCopyPlane: Tests 13, 22, 31 (well-known Xinerama implementation issue)
+ XSetFontPath: Test 4
+ XGetDefault: Test 5
+ XMatchVisualInfo: Test 1
+
+
+
+
+ These failures were noted only when using one dual-head video card
+ with a 4.2.99.x XFree86 server:
+
+ XListPixmapFormats: Test 1
+ XDrawRectangles: Test 45
+
+
+
+
+ These failures were noted only when using two video cards from
+ different vendors with a 4.1.99.x XFree86 server:
+
+ XChangeWindowAttributes: Test 32
+ XCreateWindow: Test 30
+ XDrawLine: Test 22
+ XFillArc: Test 22
+ XChangeKeyboardControl: Tests 9, 10
+ XRebindKeysym: Test 1
+
+
+
+
+
+ 44..11..33..44..
+
+ AAddddiittiioonnaall FFaaiilluurreess ffrroomm XXddmmxx
+
+ When running Xdmx, no unexpected failures were noted. Since the Xdmx
+ server is based on Xinerama, we expect to have most of the Xinerama
+ failures present in the Xdmx server. Similarly, since the Xdmx server
+ must rely on the low-level device drivers on each back-end server, we
+ also expect that Xdmx will exhibit most of the back-end failures.
+ Here is a summary:
+
+
+
+
+
+
+
+
+ XListPixmapFormats: Test 1 (configuration dependent)
+ XChangeWindowAttributes: Test 32
+ XCreateWindow: Test 30
+ XCopyPlane: Test 13, 22, 31
+ XSetFontPath: Test 4
+ XGetDefault: Test 5 (configuration dependent)
+ XMatchVisualInfo: Test 1
+ XRebindKeysym: Test 1 (configuration dependent)
+
+
+
+
+ Note that this list is shorter than the combined list for Xinerama
+ because Xdmx uses different code paths to perform some Xinerama
+ operations. Further, some Xinerama failures have been fixed in the
+ XFree86 4.2.99.x CVS repository.
+
+
+ 44..11..33..55..
+
+ SSuummmmaarryy aanndd FFuuttuurree WWoorrkk
+
+ Running the X Test Suite on Xdmx does not produce any failures that
+ cannot be accounted for by the underlying Xinerama subsystem used by
+ the front-end or by the low-level device-driver code running on the
+ back-end X servers. The Xdmx server therefore is as ``correct'' as
+ possible with respect to the standard set of X Test Suite tests.
+
+ During the following phases, we will continue to verify Xdmx
+ correctness using the X Test Suite. We may also use other tests
+ suites or write additional tests that run under the X Test Suite that
+ specifically verify the expected behavior of DMX.
+
+
+ 44..11..44.. FFoonnttss
+
+ In Phase I, fonts are handled directly by both the front-end and the
+ back-end servers, which is required since we must treat each back-end
+ server during this phase as a ``black box''. What this requires is
+ that tthhee ffrroonntt-- aanndd bbaacckk--eenndd sseerrvveerrss mmuusstt sshhaarree tthhee eexxaacctt ssaammee ffoonntt
+ ppaatthh. There are two ways to help make sure that all servers share the
+ same font path:
+
+
+ 1. First, each server can be configured to use the same font server.
+ The font server, xfs, can be configured to serve fonts to multiple
+ X servers via TCP.
+
+ 2. Second, each server can be configured to use the same font path and
+ either those font paths can be copied to each back-end machine or
+ they can be mounted (e.g., via NFS) on each back-end machine.
+
+
+ One additional concern is that a client program can set its own font
+ path, and if it does so, then that font path must be available on each
+ back-end machine.
+
+
+ The -fontpath command line option was added to allow users to
+ initialize the font path of the front end server. This font path is
+ propagated to each back-end server when the default font is loaded.
+ If there are any problems, an error message is printed, which will
+ describe the problem and list the current font path. For more
+ information about setting the font path, see the -fontpath option
+ description in the man page.
+
+ 44..11..55.. PPeerrffoorrmmaannccee
+
+ Phase I of development was not intended to optimize performance. Its
+ focus was on completely and correctly handling the base X11 protocol
+ in the Xdmx server. However, several insights were gained during
+ Phase I, which are listed here for reference during the next phase of
+ development.
+
+
+ 1. Calls to XSync() can slow down rendering since it requires a
+ complete round trip to and from a back-end server. This is
+ especially problematic when communicating over long haul networks.
+
+ 2. Sending drawing requests to only the screens that they overlap
+ should improve performance.
+
+
+ 44..11..66.. PPiixxmmaappss
+
+ Pixmaps were originally expected to be handled entirely in the front-
+ end X server; however, it was found that this overly complicated the
+ rendering code and would have required sending potentially large
+ images to each back server that required them when copying from pixmap
+ to screen. Thus, pixmap state is mirrored in the back-end server just
+ as it is with regular window state. With this implementation, the
+ same rendering code that draws to windows can be used to draw to
+ pixmaps on the back-end server, and no large image transfers are
+ required to copy from pixmap to window.
+
+
+ 55.. CCuurrrreenntt iissssuueess
+
+ In this sections the current issues are outlined that require further
+ investigation.
+
+
+ 55..11.. FFoonnttss
+
+ The font path and glyphs need to be the same for the front-end and
+ each of the back-end servers. Font glyphs could be sent to the back-
+ end servers as necessary but this might consume a significant amount
+ of available bandwidth during font rendering for clients that use many
+ different fonts (e.g., Netscape). Initially, the font server (xfs)
+ will be used to provide the fonts to both the front-end and back-end
+ servers. Other possibilities will be investigated during development.
+
+
+ 55..22.. ZZeerroo wwiiddtthh rreennddeerriinngg pprriimmiittiivveess
+
+ To allow pixmap and on-screen rendering to be pixel perfect, all back-
+ end servers must render zero width primitives exactly the same as the
+ front-end renders the primitives to pixmaps. For those back-end
+ servers that do not exactly match, zero width primitives will be
+ automatically converted to one width primitives. This can be handled
+ in the front-end server via the GC state.
+
+
+ 55..33.. DDMMXX eexxtteennssiioonn
+
+ The DMX extension will provide DMX-aware X clients with the screen
+ information (clipping rectangle for each screen relative to the
+ virtual screen) and window information (window IDs for each back-end
+ window that corresponds to each DMX window). Allowing clients to
+ access this information will permit them to directly render to those
+ windows.
+
+ 55..44.. GGLLXX ssuuppppoorrtt
+
+ The utility of the software rendered OpenGL support for non-local
+ back-end servers is questionable. On modern graphics accelerators, it
+ is likely that the back-end servers will have hardware accelerated
+ OpenGL support. In general, OpenGL/GLX support is best left to
+ another approach (e.g., Chromium); however, it might prove useful to
+ support pushing a subset of primitives to the back-end servers, so
+ that they can handle the rendering directly. We will investigate this
+ possibility. These will include only those primitives that are output
+ only, as there are a number of issues with the other primitives.
+ These other primitives will be left unsupported and will either return
+ errors or be turned into no-ops. If useful, then the software
+ rendered OpenGL in the front-end server will not be implemented.
+
+
+ 55..55.. OOuuttppuutt ssccaalliinngg
+
+ With very large tiled displays, it might be difficult to read the
+ information on the standard X desktop. In particular, the cursor can
+ be easily lost and fonts could be difficult to read. Automatic
+ primitive scaling might be very useful. We will investigate the
+ possibility of scaling the cursor and providing a set of alternate
+ pre-scaled fonts to replace the standard fonts that many applications
+ use (e.g., fixed). Other options for automatic scaling will also be
+ investigated.
+
+
+ 55..66.. PPeerr--ssccrreeeenn ccoolloorrmmaappss
+
+ Each screen in the set of back-end X servers should be able to be
+ adjusted via the configuration utility. This support is required to
+ allow the back-end screens to be calibrated via custom gamma tables.
+ On 24-bit systems that support a DirectColor visual, this type of
+ correction can be accommodated. One possible implementation would be
+ to advertise to X client of the DMX server a TrueColor visual while
+ using DirectColor visuals on the back-end servers to implement this
+ type of color correction. Other options will be investigated.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xc/programs/Xserver/hw/dmx/input/Imakefile b/xc/programs/Xserver/hw/dmx/input/Imakefile
new file mode 100644
index 000000000..78af2ef42
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/Imakefile
@@ -0,0 +1,34 @@
+XCOMM $XFree86$
+
+#include <Server.tmpl>
+#include <lnxdoc.rules>
+
+RAWSRCS = lnx-keyboard.c lnx-ms.c lnx-ps2.c
+RAWOBJS = lnx-keyboard.o lnx-ms.o lnx-ps2.o
+
+DRVSRCS = dmxdummy.c dmxbackend.c dmxconsole.c dmxcommon.c
+DRVOBJS = dmxdummy.o dmxbackend.o dmxconsole.o dmxcommon.o
+
+DMXSRCS = dmxinputinit.c dmxarg.c dmxsigio.c dmxevents.c dmxxtest.c
+DMXOBJS = dmxinputinit.o dmxarg.o dmxsigio.o dmxevents.o dmxxtest.o
+
+SRCS = $(RAWSRCS) $(DRVSRCS) $(DMXSRCS)
+OBJS = $(RAWOBJS) $(DRVOBJS) $(DMXOBJS)
+
+INCLUDES = -I. -I.. -I$(XBUILDINCDIR) -I$(FONTINCSRC) -I../../../mi \
+ -I../../../include -I$(EXTINCSRC) -I$(SERVERSRC)/Xext
+
+DEFINES = $(OS_DEFINES) $(EXT_DEFINES)
+
+all:: $(OBJS)
+
+NormalProgramTarget(xbell,xbell.o,libdmxinput.a,$(XLIB),NullParameter)
+AllTarget(ProgramTargetName(xbell))
+
+LinkSourceFile(atKeynames.h,$(XF86COMSRC))
+LinkSourceFile(xf86Keymap.h,$(XF86COMSRC))
+
+NormalLibraryObjectRule()
+NormalLibraryTarget(dmxinput,$(OBJS))
+
+DependTarget()
diff --git a/xc/programs/Xserver/hw/dmx/input/TODO b/xc/programs/Xserver/hw/dmx/input/TODO
new file mode 100644
index 000000000..d38aa71c9
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/TODO
@@ -0,0 +1,18 @@
+Fri May 24 00:14:59 2002
+
+1) xset should work as expected. Done.
+
+ The raw mouse input is not accelerated.
+ Console mode isn't accelerated because this doesn't make sense.
+
+2) Allow multiple -inputfrom command line options to work as expected. Done.
+
+3) When screens overlap, only one cursor is displayed for the overlapped
+ region. This can't be fixed when the screens are on the same backend
+ display, since there is only one hardware cursor. however, this has
+ been fixed for the more common case of only one dmxScreen per backend
+ display. For testing, it can be disabled with -nomulticursor.
+
+4) The options line in the config file is processed once, just like the
+ command-line options. This needs to be documented, since it may be
+ unexpected. Done
diff --git a/xc/programs/Xserver/hw/dmx/input/dmxarg.c b/xc/programs/Xserver/hw/dmx/input/dmxarg.c
new file mode 100644
index 000000000..ebc50f543
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/dmxarg.c
@@ -0,0 +1,157 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#define DMX_ARG_TEST 0
+
+#include "dmxarg.h"
+#include <stdio.h>
+#include <string.h>
+#include "globals.h"
+
+#if DMX_ARG_TEST
+#include <stdlib.h>
+#endif
+
+struct _dmxArg {
+ int argc;
+ int argm;
+ const char **argv;
+};
+
+dmxArg dmxArgCreate(void)
+{
+ dmxArg a = malloc(sizeof(*a));
+ a->argc = 0;
+ a->argm = 2;
+ a->argv = malloc(a->argm * sizeof(*a->argv));
+ a->argv[0] = NULL;
+ return a;
+}
+
+void dmxArgFree(dmxArg a)
+{
+ int i;
+
+ for (i = 0; i < a->argc; i++) free((char *)a->argv[i]);
+ free(a->argv);
+ free(a);
+}
+
+void dmxArgAdd(dmxArg a, const char *string)
+{
+ if (a->argm <= a->argc + 2)
+ a->argv = realloc(a->argv, sizeof(*a->argv) * (a->argm *= 2));
+ a->argv[a->argc++] = strdup(string);
+ a->argv[a->argc] = NULL;
+}
+
+const char *dmxArgV(dmxArg a, int item)
+{
+ if (item < 0 || item >= a->argc) return NULL;
+ return a->argv[item];
+}
+
+int dmxArgC(dmxArg a)
+{
+ return a->argc;
+}
+
+dmxArg dmxArgParse(const char *string)
+{
+ char *tmp;
+ char *start, *pt;
+ dmxArg a = dmxArgCreate();
+ int done;
+
+ if (!string) return a;
+
+ tmp = malloc(strlen(string)+2);
+ strcpy(tmp, string);
+
+ for (start = pt = tmp, done = 0; !done && *pt; start = ++pt) {
+ for (;*pt && *pt != ','; pt++);
+ if (!*pt) done = 1;
+ *pt = '\0';
+ dmxArgAdd(a, start);
+ }
+ if (!done) dmxArgAdd(a, ""); /* Final comma */
+
+ free(tmp);
+ return a;
+}
+
+#if DMX_ARG_TEST
+static void dmxArgPrint(dmxArg a)
+{
+ int i;
+
+ printf(" argc = %d\n", dmxArgC(a));
+ for (i = 0; i < dmxArgC(a); i++)
+ printf(" argv[%d] = \"%s\"\n", i, dmxArgV(a, i));
+}
+
+static void dmxArgTest(const char *string)
+{
+ dmxArg a;
+
+ if (!string)
+ printf("Testing NULL\n");
+ else if (!strlen(string))
+ printf("Testing (empty)\n");
+ else
+ printf("Testing \"%s\"\n", string);
+
+ a = dmxArgParse(string);
+ dmxArgPrint(a);
+ dmxArgFree(a);
+}
+
+int main(void)
+{
+ dmxArgTest(NULL);
+ dmxArgTest("");
+ dmxArgTest(",");
+
+ dmxArgTest("a");
+ dmxArgTest("a,");
+ dmxArgTest(",a");
+
+ dmxArgTest("a,b");
+ dmxArgTest("a,b,");
+ dmxArgTest("a,b,,");
+ dmxArgTest("a,b,,c");
+
+ return 0;
+}
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/input/dmxarg.h b/xc/programs/Xserver/hw/dmx/input/dmxarg.h
new file mode 100644
index 000000000..2ec125da1
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/dmxarg.h
@@ -0,0 +1,47 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef _DMXARG_H_
+#define _DMXARG_H_
+
+typedef struct _dmxArg *dmxArg;
+
+extern dmxArg dmxArgCreate(void);
+extern void dmxArgFree(dmxArg a);
+extern void dmxArgAdd(dmxArg a, const char *string);
+extern const char *dmxArgV(dmxArg a, int item);
+extern int dmxArgC(dmxArg a);
+extern dmxArg dmxArgParse(const char *string);
+
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/input/dmxbackend.c b/xc/programs/Xserver/hw/dmx/input/dmxbackend.c
new file mode 100644
index 000000000..b0b27ee61
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/dmxbackend.c
@@ -0,0 +1,336 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * David H. Dawes <dawes@xfree86.org>
+ * Kevin E. Martin <kem@redhat.com>
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ */
+
+#define DMX_BACKEND_DEBUG 0
+
+/* Core devices on the back end X server -- like Xnest. */
+
+#include "inputstr.h"
+#include "input.h"
+#include "keysym.h"
+#include "mipointer.h"
+#include "mi.h"
+#include "scrnintstr.h"
+
+#include "dmxinputinit.h"
+#include "dmxevents.h"
+#include "dmxbackend.h"
+#include "dmxcommon.h"
+#include "dmxcursor.h"
+#include "dmxprop.h"
+
+#include "globals.h"
+
+#include "XInput.h"
+
+typedef struct _myPrivate {
+ DMX_COMMON_PRIVATE;
+ int myScreen;
+
+ int lastX;
+ int lastY;
+ int screen;
+} myPrivate;
+
+pointer dmxBackendCreatePrivate(DMXInputInfo *dmxInput)
+{
+ myPrivate *priv = xalloc(sizeof(*priv));
+ memset(priv, 0, sizeof(*priv));
+ priv->dmxInput = dmxInput;
+ return priv;
+}
+
+void dmxBackendDestroyPrivate(pointer private)
+{
+ if (private) xfree(private);
+}
+
+static void *dmxBackendTestScreen(DMXScreenInfo *dmxScreen, void *closure)
+{
+ int target = (int)closure;
+
+ if (dmxScreen->index == target) return dmxScreen;
+ return NULL;
+}
+
+/* Return non-zero if priv->screen and priv->myScreen are on the same
+ * physical backend display. */
+static int dmxBackendSameDisplay(myPrivate *priv)
+{
+ DMXScreenInfo *dmxScreen;
+
+ if (priv->screen == priv->myScreen) return 1;
+ if (priv->screen < 0 || priv->screen >= dmxNumScreens) return 0;
+ if ((dmxScreen = dmxPropertyIterate(priv->backendScreen,
+ dmxBackendTestScreen,
+ (void *)priv->screen))) {
+ return 1;
+ }
+ return 0;
+}
+
+static void *dmxBackendTestEvents(DMXScreenInfo *dmxScreen, void *closure)
+{
+ if (XPending(dmxScreen->display)) return dmxScreen;
+ return NULL;
+}
+
+static void *dmxBackendTestMotionEvent(DMXScreenInfo *dmxScreen, void *closure)
+{
+ XEvent N;
+
+ if (XPending(dmxScreen->display)) {
+ XPeekEvent(dmxScreen->display, &N);
+ if (N.type == MotionNotify) return dmxScreen;
+ }
+ return NULL;
+}
+
+static DMXScreenInfo *dmxBackendGetEvent(myPrivate *priv, XEvent *X)
+{
+ DMXScreenInfo *dmxScreen;
+
+ if ((dmxScreen = dmxPropertyIterate(priv->backendScreen,
+ dmxBackendTestEvents, NULL))) {
+ XNextEvent(dmxScreen->display, X);
+ return dmxScreen;
+ }
+ return NULL;
+}
+
+static DMXScreenInfo *dmxBackendPendingMotionEvent(myPrivate *priv)
+{
+ DMXScreenInfo *dmxScreen;
+
+ if ((dmxScreen = dmxPropertyIterate(priv->backendScreen,
+ dmxBackendTestMotionEvent, NULL))) {
+ return dmxScreen;
+ }
+ return NULL;
+}
+
+static void *dmxBackendTestWindow(DMXScreenInfo *dmxScreen, void *closure)
+{
+ Window win = (Window)closure;
+ if (dmxScreen->window == win) return dmxScreen;
+ return NULL;
+}
+
+static DMXScreenInfo *dmxBackendFindWindow(myPrivate *priv, Window win)
+{
+ return dmxPropertyIterate(priv->backendScreen,
+ dmxBackendTestWindow, (void *)win);
+}
+
+/* This routine is called from dmxAbsoluteMotion for each motion event. */
+void dmxBackendUpdatePosition(pointer private, int x, int y)
+{
+ GETONLYPRIVFROMPRIVATE;
+ int screen;
+ DMXScreenInfo *dmxScreen;
+
+#if DMX_BACKEND_DEBUG
+ dmxLog(dmxDebug, "dmxBackendUpdatePosition(,%d,%d)\n", x, y);
+#endif
+ if (priv->screen != (screen = miPointerCurrentScreen()->myNum)) {
+#if DMX_BACKEND_DEBUG
+ dmxLog(dmxDebug,
+ "dmxBackendUpdatePostion: Moved from screen %d to %d\n",
+ priv->screen, screen);
+#endif
+ priv->screen = screen;
+ dmxScreen = &dmxScreens[priv->screen];
+
+ if (dmxBackendSameDisplay(priv)) {
+ priv->myScreen = priv->screen;
+ } else {
+ priv->lastX = priv->width / 2;
+ priv->lastY = priv->height / 2;
+ XWarpPointer(priv->display, None, priv->window,
+ 0, 0, 0, 0, priv->lastX, priv->lastY);
+ XSync(priv->display, False);
+ }
+ }
+}
+
+void dmxBackendCollectEvents(pointer private)
+{
+ GETPRIVFROMPRIVATE;
+ XEvent X;
+ DMXScreenInfo *dmxScreen;
+ int enterred = 0;
+ int left = 0;
+
+ while ((dmxScreen = dmxBackendGetEvent(priv, &X))) {
+ switch (X.type) {
+ case EnterNotify:
+ if (enterred++) continue;
+#if DMX_BACKEND_DEBUG
+ dmxLog(dmxDebug,
+ "dmxBackendCollectEvents: Enter %lu\n", dmxScreen->window);
+#endif
+ XRaiseWindow(dmxScreen->display, dmxScreen->window);
+ XGrabPointer(dmxScreen->display, dmxScreen->window,
+ True, 0, GrabModeAsync, GrabModeAsync, None,
+ None, CurrentTime);
+ break;
+ case LeaveNotify:
+ if (left++) continue;
+#if DMX_BACKEND_DEBUG
+ dmxLog(dmxDebug,
+ "dmxBackendCollectEvents: Leave %lu\n", dmxScreen->window);
+#endif
+ XUngrabPointer(dmxScreen->display, CurrentTime);
+ break;
+ case MotionNotify:
+#if DMX_BACKEND_DEBUG
+ dmxLog(dmxDebug,
+ "dmxBackendCollectEvents: MotionNotify from screen %d:"
+ " %d %d win=%lu/%lu\n",
+ dmxScreen->index, X.xmotion.x, X.xmotion.y,
+ X.xmotion.window, dmxScreen->window);
+#endif
+
+ if (dmxBackendPendingMotionEvent(priv)) continue;
+ if (!(dmxScreen = dmxBackendFindWindow(priv, X.xmotion.window)))
+ dmxLog(dmxFatal,
+ "Event on non-existant window %lu\n", X.xmotion.window);
+ if (priv->screen == priv->myScreen) {
+ int newX = X.xmotion.x;
+ int newY = X.xmotion.y;
+
+ if (!newX) newX = -1;
+ if (newX == priv->width - 1) newX = priv->width;
+ if (!newY) newY = -1;
+ if (newY == priv->height - 1) newY = priv->height;
+ dmxAbsoluteMotion(dmxScreen->originX + newX,
+ dmxScreen->originY + newY);
+ } else {
+ dmxRelativeMotion(dmxScreen->originX
+ + priv->lastX - X.xmotion.x,
+ dmxScreen->originY
+ + priv->lastY - X.xmotion.y);
+ priv->lastX = X.xmotion.x;
+ priv->lastY = X.xmotion.y;
+ }
+ break;
+
+ default:
+ dmxEnqueueXEvent(dmxInput, &X);
+ break;
+ }
+ }
+}
+
+void dmxBackendProcessInput(pointer private)
+{
+ GETONLYPRIVFROMPRIVATE;
+
+ if (!dmxBackendSameDisplay(priv)
+ && (priv->lastX != priv->width / 2
+ || priv->lastY != priv->height / 2)) {
+ priv->lastX = priv->width / 2;
+ priv->lastY = priv->height / 2;
+ XWarpPointer(priv->display, None, priv->window,
+ 0, 0, 0, 0, priv->lastX, priv->lastY);
+ XSync(priv->display, False);
+ }
+}
+
+void dmxBackendInitialize(pointer private)
+{
+ GETPRIVFROMPRIVATE;
+ XExtensionVersion *ext;
+ XDeviceInfo *devices;
+ DMXScreenInfo *dmxScreen;
+ int num;
+ int i;
+
+ /* Fill in myPrivate */
+ for (i = 0,dmxScreen = &dmxScreens[0]; i<dmxNumScreens; i++,dmxScreen++) {
+ if (!strcmp(dmxInput->name, dmxScreen->name)) {
+ priv->display = dmxScreen->display;
+ priv->window = dmxScreen->window;
+ priv->width = dmxScreen->width;
+ priv->height = dmxScreen->height;
+ priv->backendScreen = dmxScreen;
+ break;
+ }
+ }
+ if (i >= dmxNumScreens)
+ dmxLog(dmxFatal,
+ "%s is not an existing backend display - cannot initialize\n",
+ dmxInput->name);
+
+ /* Finish dmxInput initialization using computed values or constants. */
+ priv->initPointerX = priv->width / 2;
+ priv->initPointerY = priv->height / 2;
+ priv->eventMask = (EnterWindowMask|LeaveWindowMask);
+ priv->myScreen = dmxScreen->index;
+ priv->lastX = priv->width / 2; /* FIXME? put cursor here? */
+ priv->lastY = priv->height / 2;
+ priv->screen = priv->myScreen;
+
+ /* Print out information about the XInput Extension. */
+ ext = XGetExtensionVersion(priv->display, INAME);
+ if (ext && ext != (XExtensionVersion *)NoSuchExtension) {
+ dmxLogInput(dmxInput, "%s version %d.%d\n",
+ INAME, ext->major_version, ext->minor_version);
+ devices = XListInputDevices(priv->display, &num);
+ if (num)
+ dmxLogInput(dmxInput, "Extended devices:\n");
+ for (i = 0; i < num; i++) {
+ const char *kind = "Unknown";
+ switch (devices[i].use) {
+ case IsXPointer: kind = "XPointer"; break;
+ case IsXKeyboard: kind = "XKeyboard"; break;
+ case IsXExtensionDevice: kind = "XExtensionDevice"; break;
+ }
+ dmxLogInput(dmxInput, " \"%s\": %s\n",
+ devices[i].name ? devices[i].name : "<noname>", kind);
+ }
+ XFreeDeviceList(devices);
+ }
+}
+
+int dmxBackendFunctions(pointer private, DMXFunctionType function)
+{
+ switch (function) {
+ case DMX_FUNCTION_TERMINATE:
+ return 1;
+ default:
+ return 0;
+ }
+}
diff --git a/xc/programs/Xserver/hw/dmx/input/dmxbackend.h b/xc/programs/Xserver/hw/dmx/input/dmxbackend.h
new file mode 100644
index 000000000..07c46194c
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/dmxbackend.h
@@ -0,0 +1,46 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef _DMXBACKEND_H_
+#define _DMXBACKEND_H_
+
+extern pointer dmxBackendCreatePrivate(DMXInputInfo *dmxInput);
+extern void dmxBackendDestroyPrivate(pointer private);
+extern void dmxBackendInitialize(pointer private);
+extern void dmxBackendCollectEvents(pointer private);
+extern void dmxBackendProcessInput(pointer private);
+extern int dmxBackendFunctions(pointer private, DMXFunctionType function);
+extern void dmxBackendUpdatePosition(pointer private, int x, int y);
+
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/input/dmxcommon.c b/xc/programs/Xserver/hw/dmx/input/dmxcommon.c
new file mode 100644
index 000000000..184a4c7eb
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/dmxcommon.c
@@ -0,0 +1,338 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * David H. Dawes <dawes@xfree86.org>
+ * Kevin E. Martin <kem@redhat.com>
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ */
+
+/* Core devices on the back end X server -- like Xnest. */
+
+#include "inputstr.h"
+#include "input.h"
+#include "keysym.h"
+#include "mipointer.h"
+#include "mi.h"
+#include "scrnintstr.h"
+
+#include "dmxinputinit.h"
+#include "dmxevents.h"
+#include "dmxcommon.h"
+#include "dmxconsole.h"
+#include "dmxprop.h"
+
+#include "globals.h"
+
+#include "XInput.h"
+
+typedef struct _myPrivate {
+ DMX_COMMON_PRIVATE;
+} myPrivate;
+
+static void dmxCommonKbdSetAR(Display *display,
+ unsigned char *old, unsigned char *new)
+{
+ XKeyboardControl kc;
+ XKeyboardState ks;
+ unsigned long mask = KBKey | KBAutoRepeatMode;
+ int i, j;
+
+ if (!old) {
+ XGetKeyboardControl(display, &ks);
+ old = (unsigned char *)ks.auto_repeats;
+ }
+
+ for (i = 1; i < 32; i++) {
+ if (!old || old[i] != new[i]) {
+ for (j = 0; j < 8; j++) {
+ if ((new[i] & (1 << j)) != (old[i] & (1 << j))) {
+ kc.key = i * 8 + j;
+ kc.auto_repeat_mode = ((new[i] & (1 << j))
+ ? AutoRepeatModeOn
+ : AutoRepeatModeOff);
+ XChangeKeyboardControl(display, mask, &kc);
+ }
+ }
+ }
+ }
+}
+
+static void dmxCommonKbdSetLeds(Display *display,
+ unsigned long old, unsigned long new)
+{
+ unsigned long change = old ^ new;
+ int i;
+ XKeyboardControl kc;
+ unsigned long mask = KBLed | KBLedMode;
+
+ if (!change) return;
+ for (i = 0; i < 32; i++) {
+ if (change & (1 << i)) {
+ kc.led = i + 1;
+ kc.led_mode = (new & (1 << i)) ? LedModeOn : LedModeOff;
+ XChangeKeyboardControl(display, mask, &kc);
+ }
+ }
+}
+
+void dmxCommonKbdSetCtrl(Display *display, KeybdCtrl *old, KeybdCtrl *new)
+{
+ XKeyboardControl kc;
+ unsigned long mask = KBKeyClickPercent | KBAutoRepeatMode;
+
+ if (!old
+ || old->click != new->click
+ || old->autoRepeat != new->autoRepeat) {
+
+ kc.key_click_percent = new->click;
+ kc.auto_repeat_mode = new->autoRepeat;
+
+ XChangeKeyboardControl(display, mask, &kc);
+ }
+
+ dmxCommonKbdSetLeds(display, old ? old->leds : ~new->leds, new->leds);
+ dmxCommonKbdSetAR(display, old ? old->autoRepeats : NULL,
+ new->autoRepeats);
+}
+
+void dmxCommonMouSetCtrl(Display *display, PtrCtrl *old, PtrCtrl *new)
+{
+ Bool do_accel, do_threshold;
+
+ if (!old
+ || old->num != new->num
+ || old->den != new->den
+ || old->threshold != new->threshold) {
+ do_accel = (new->num > 0 && new->den > 0);
+ do_threshold = (new->threshold > 0);
+ if (do_accel || do_threshold) {
+ XChangePointerControl(display, do_accel, do_threshold,
+ new->num, new->den, new->threshold);
+ }
+ }
+}
+
+void dmxCommonKbdCtrl(DevicePtr pDev, KeybdCtrl *ctrl)
+{
+ GETPRIVFROMPDEV;
+
+ if (!priv->backendScreen) dmxConsoleKbdSetCtrl(priv, ctrl);
+ else {
+ dmxCommonKbdSetCtrl(priv->display,
+ priv->kctrlset ? &priv->kctrl : NULL,
+ ctrl);
+ priv->kctrl = *ctrl;
+ priv->kctrlset = 1;
+ }
+}
+
+void dmxCommonMouCtrl(DevicePtr pDev, PtrCtrl *ctrl)
+{
+ GETPRIVFROMPDEV;
+
+ /* Don't set the acceleration for the
+ * console, because that should be
+ * controlled by the X server that the
+ * console is running on. Otherwise,
+ * the acceleration for the console
+ * window would be unexpected for the
+ * scale of the window. */
+ if (priv->backendScreen) {
+ dmxCommonMouSetCtrl(priv->display,
+ priv->mctrlset ? &priv->mctrl : NULL,
+ ctrl);
+ priv->mctrl = *ctrl;
+ priv->mctrlset = 1;
+ }
+}
+
+void dmxCommonKbdBell(DevicePtr pDev, int percent,
+ int volume, int pitch, int duration)
+{
+ GETPRIVFROMPDEV;
+ XKeyboardControl kc;
+ XKeyboardState ks;
+ unsigned long mask = KBBellPercent | KBBellPitch | KBBellDuration;
+
+ if (!priv->backendScreen) XGetKeyboardControl(priv->display, &ks);
+ kc.bell_percent = volume;
+ kc.bell_pitch = pitch;
+ kc.bell_duration = duration;
+ XChangeKeyboardControl(priv->display, mask, &kc);
+ XBell(priv->display, percent);
+ if (!priv->backendScreen) {
+ kc.bell_percent = ks.bell_percent;
+ kc.bell_pitch = ks.bell_pitch;
+ kc.bell_duration = ks.bell_duration;
+ XChangeKeyboardControl(priv->display, mask, &kc);
+ }
+}
+
+pointer dmxCommonKbdGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap)
+{
+ GETPRIVFROMPDEV;
+ int min_keycode;
+ int max_keycode;
+ int map_width;
+ KeySym *keyboard_mapping;
+ XModifierKeymap *modifier_mapping;
+ int i, j;
+
+ /* Compute pKeySyms */
+ XDisplayKeycodes(priv->display, &min_keycode, &max_keycode);
+ keyboard_mapping = XGetKeyboardMapping(priv->display,
+ min_keycode,
+ max_keycode - min_keycode + 1,
+ &map_width);
+ pKeySyms->minKeyCode = min_keycode;
+ pKeySyms->maxKeyCode = max_keycode;
+ pKeySyms->mapWidth = map_width;
+ pKeySyms->map = keyboard_mapping;
+
+
+ /* Compute pModMap */
+ modifier_mapping = XGetModifierMapping(priv->display);
+ for (i = 0; i < MAP_LENGTH; i++) pModMap[i] = 0;
+ for (j = 0; j < 8; j++) {
+ int max_keypermod = modifier_mapping->max_keypermod;
+
+ for (i = 0; i < max_keypermod; i++) {
+ CARD8 keycode = modifier_mapping->modifiermap[j*max_keypermod + i];
+ if (keycode) pModMap[keycode] |= 1 << j;
+ }
+ }
+ XFreeModifiermap(modifier_mapping);
+
+ return keyboard_mapping; /* High-level code frees with XFree */
+}
+
+int dmxCommonKbdOn(DevicePtr pDev)
+{
+ GETPRIVFROMPDEV;
+ priv->eventMask |= DMX_KEYBOARD_EVENT_MASK;
+ XSelectInput(priv->display, priv->window, priv->eventMask);
+ if (priv->backendScreen)
+ XSetInputFocus(priv->display, priv->window, RevertToPointerRoot,
+ CurrentTime);
+ return -1;
+}
+
+void dmxCommonKbdOff(DevicePtr pDev)
+{
+ GETPRIVFROMPDEV;
+ priv->eventMask &= ~DMX_KEYBOARD_EVENT_MASK;
+ XSelectInput(priv->display, priv->window, priv->eventMask);
+}
+
+void dmxCommonMouGetMap(DevicePtr pDev, unsigned char *map, int *nButtons)
+{
+ GETPRIVFROMPDEV;
+ int i;
+
+ *nButtons = XGetPointerMapping(priv->display, map, DMX_MAX_BUTTONS);
+ for (i = 0; i <= *nButtons; i++) map[i] = i;
+}
+
+static void *dmxCommonXSelect(DMXScreenInfo *dmxScreen, void *closure)
+{
+ myPrivate *priv = closure;
+ dmxLog(dmxDebug,"XSelectInput on display %p (win=%lu) 0x%08x\n",
+ dmxScreen->display, dmxScreen->window, priv->eventMask);
+ XSelectInput(dmxScreen->display, dmxScreen->window, priv->eventMask);
+ return NULL;
+}
+
+int dmxCommonMouOn(DevicePtr pDev)
+{
+ GETPRIVFROMPDEV;
+
+ if (!priv) return -1;
+ priv->eventMask |= DMX_POINTER_EVENT_MASK;
+ if (dmxShadowFB) {
+ XWarpPointer(priv->display, priv->window, priv->window,
+ 0, 0, 0, 0,
+ priv->initPointerX,
+ priv->initPointerY);
+ XSync(priv->display, False);
+ }
+ if (!priv->backendScreen)
+ XSelectInput(priv->display, priv->window, priv->eventMask);
+ else
+ dmxPropertyIterate(priv->backendScreen, dmxCommonXSelect, priv);
+
+ return -1;
+}
+
+void dmxCommonMouOff(DevicePtr pDev)
+{
+ GETPRIVFROMPDEV;
+
+ if (!priv) return;
+ priv->eventMask &= ~DMX_POINTER_EVENT_MASK;
+ if (!priv->backendScreen)
+ XSelectInput(priv->display, priv->window, priv->eventMask);
+ else
+ dmxPropertyIterate(priv->backendScreen, dmxCommonXSelect, priv);
+}
+
+static void *dmxCommonAddEnabledDevice(DMXScreenInfo *dmxScreen, void *closure)
+{
+ dmxLog(dmxDebug,"AddEnabledDevice on display %p (win=%lu)\n",
+ dmxScreen->display, dmxScreen->window);
+ AddEnabledDevice(XConnectionNumber(dmxScreen->display));
+ return NULL;
+}
+
+void dmxCommonEnableDevice(pointer private)
+{
+ GETONLYPRIVFROMPRIVATE;
+
+ if (!priv) return;
+ if (!priv->backendScreen)
+ AddEnabledDevice(XConnectionNumber(priv->display));
+ else
+ dmxPropertyIterate(priv->backendScreen,
+ dmxCommonAddEnabledDevice, NULL);
+
+}
+
+int dmxFindPointerScreen(int x, int y)
+{
+ int i;
+
+ for (i = 0; i < dmxNumScreens; i++) {
+ if (x >= dixScreenOrigins[i].x
+ && x < dixScreenOrigins[i].x + screenInfo.screens[i]->width
+ && y >= dixScreenOrigins[i].y
+ && y < dixScreenOrigins[i].y + screenInfo.screens[i]->height)
+ return i;
+ }
+ return -1;
+}
diff --git a/xc/programs/Xserver/hw/dmx/input/dmxcommon.h b/xc/programs/Xserver/hw/dmx/input/dmxcommon.h
new file mode 100644
index 000000000..bfb671c69
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/dmxcommon.h
@@ -0,0 +1,91 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef _DMXCOMMON_H_
+#define _DMXCOMMON_H_
+
+#define DMX_COMMON_PRIVATE \
+ Display *display; \
+ Window window; \
+ int width; \
+ int height; \
+ DMXInputInfo *dmxInput; \
+ int initPointerX; \
+ int initPointerY; \
+ long eventMask; \
+ KeybdCtrl kctrl; \
+ PtrCtrl mctrl; \
+ int kctrlset; \
+ int mctrlset; \
+ DMXScreenInfo *backendScreen
+
+#define GETONLYPRIVFROMPRIVATE myPrivate *priv = private
+
+#define GETPRIVFROMPRIVATE GETONLYPRIVFROMPRIVATE; \
+ DMXInputInfo *dmxInput = priv->dmxInput
+
+#define GETPRIVFROMPDEV DMXInputInfo *dmxInput = pDev->devicePrivate; \
+ myPrivate *priv = dmxInput->gen->private
+
+#define DMX_MAX_BUTTONS 256
+
+#define DMX_KEYBOARD_EVENT_MASK \
+ (KeyPressMask | KeyReleaseMask | KeymapStateMask)
+
+#define DMX_POINTER_EVENT_MASK \
+ (ButtonPressMask | ButtonReleaseMask | PointerMotionMask)
+
+extern pointer dmxCommonKbdGetMap(DevicePtr pDev,
+ KeySymsPtr pKeySyms, CARD8 *pModMap);
+extern void dmxCommonKbdCtrl(DevicePtr pDev, KeybdCtrl *ctrl);
+extern void dmxCommonKbdBell(DevicePtr pDev, int percent,
+ int volume, int pitch, int duration);
+extern int dmxCommonKbdOn(DevicePtr pDev);
+extern void dmxCommonKbdOff(DevicePtr pDev);
+extern Bool dmxCommonKbdLegalModifier(unsigned int key, DevicePtr pDev); /* FIXME */
+extern void dmxCommonMouGetMap(DevicePtr pDev,
+ unsigned char *map, int *nButtons);
+extern void dmxCommonMouCtrl(DevicePtr pDev, PtrCtrl *ctrl);
+extern int dmxCommonMouOn(DevicePtr pDev);
+extern void dmxCommonMouOff(DevicePtr pDev);
+extern void dmxCommonEnableDevice(pointer private);
+extern int dmxFindPointerScreen(int x, int y);
+
+ /* helper functions */
+extern void dmxCommonMouSetCtrl(Display *display,
+ PtrCtrl *old, PtrCtrl *new);
+extern void dmxCommonKbdSetCtrl(Display *display,
+ KeybdCtrl *old, KeybdCtrl *new);
+
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/input/dmxconsole.c b/xc/programs/Xserver/hw/dmx/input/dmxconsole.c
new file mode 100644
index 000000000..66cf2ff95
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/dmxconsole.c
@@ -0,0 +1,690 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * David H. Dawes <dawes@xfree86.org>
+ * Kevin E. Martin <kem@redhat.com>
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#define DMX_CONSOLE_DEBUG 0
+
+#include "X.h"
+#include "X11/cursorfont.h"
+
+#include "inputstr.h"
+#include "input.h"
+#include "mipointer.h"
+#include "mi.h"
+
+#include "dmxinputinit.h"
+#include "dmxevents.h"
+#include "dmxconsole.h"
+#include "dmxcommon.h"
+#include "dmxscrinit.h"
+
+#include "globals.h"
+
+#define CONSOLE_NUM 3
+#define CONSOLE_DEN 4
+#define DMX_CONSOLE_NAME "DMX Console"
+#define DMX_RES_NAME "Xdmx" /* FIXME -- use argv[0] */
+#define DMX_RES_CLASS "XDmx"
+#define CONSOLE_BG_COLOR "gray75"
+#define CONSOLE_FG_COLOR "black"
+#define CONSOLE_SCREEN_BG_COLOR "white"
+#define CONSOLE_SCREEN_FG_COLOR "black"
+#define CONSOLE_SCREEN_CUR_COLOR "red"
+
+typedef struct _myPrivate {
+ DMX_COMMON_PRIVATE;
+ int lastX;
+ int lastY;
+ int globalX;
+ int globalY;
+ int curX;
+ int curY;
+ double xScale;
+ double yScale;
+ XlibGC gc, gcRev, gcCur;
+ int grabbed, fine, entered;
+ Cursor cursorNormal, cursorGrabbed, cursorEmpty;
+ KeybdCtrl conkctrl, oldkctrl;
+ int conkctrlset;
+
+ CloseScreenProcPtr CloseScreen;
+ struct _myPrivate *next; /* for closing multiple consoles */
+} myPrivate;
+
+static int scalex(myPrivate *priv, int x)
+{
+ return (int)((x * priv->xScale) + .5);
+}
+
+static int scaley(myPrivate *priv, int y)
+{
+ return (int)((y * priv->yScale) + .5);
+}
+
+static int unscalex(myPrivate *priv, int x)
+{
+ return (int)((x / priv->xScale) + .5);
+}
+
+static int unscaley(myPrivate *priv, int y)
+{
+ return (int)((y / priv->yScale) + .5);
+}
+
+pointer dmxConsoleCreatePrivate(DMXInputInfo *dmxInput)
+{
+ myPrivate *priv = xalloc(sizeof(*priv));
+ memset(priv, 0, sizeof(*priv));
+ priv->dmxInput = dmxInput;
+ return priv;
+}
+
+void dmxConsoleDestroyPrivate(pointer private)
+{
+ if (private) xfree(private);
+}
+
+void dmxConsoleKbdSetCtrl(pointer private, KeybdCtrl *ctrl)
+{
+ GETONLYPRIVFROMPRIVATE;
+
+ if (!priv->entered) return;
+ dmxCommonKbdSetCtrl(priv->display,
+ priv->conkctrlset ? &priv->conkctrl : NULL,
+ ctrl);
+ priv->conkctrl = *ctrl;
+ priv->conkctrlset = 1;
+}
+
+static void dmxConsoleEnter(myPrivate *priv)
+{
+ XKeyboardState ks;
+ int i;
+
+ XGetKeyboardControl(priv->display, &ks);
+ priv->oldkctrl.click = ks.key_click_percent;
+ priv->oldkctrl.bell = ks.bell_percent;
+ priv->oldkctrl.bell_pitch = ks.bell_pitch;
+ priv->oldkctrl.bell_duration = ks.bell_duration;
+ priv->oldkctrl.leds = ks.led_mask;
+ priv->oldkctrl.autoRepeat = ks.global_auto_repeat;
+ for (i = 0; i < 32; i++)
+ priv->oldkctrl.autoRepeats[i] = ks.auto_repeats[i];
+
+ dmxConsoleKbdSetCtrl(priv, &priv->dmxInput->kbd->kctrl);
+}
+
+static void dmxConsoleLeave(myPrivate *priv)
+{
+ dmxCommonKbdSetCtrl(priv->display,
+ priv->conkctrlset ? &priv->conkctrl : NULL,
+ &priv->oldkctrl);
+ priv->conkctrl = priv->oldkctrl;
+ priv->conkctrlset = 1;
+}
+
+static void dmxConsoleDrawFineCursor(myPrivate *priv)
+{
+ int size = 6;
+ XDrawLine(priv->display, priv->window, priv->gcCur,
+ scalex(priv, priv->globalX) - size,
+ scaley(priv, priv->globalY),
+ scalex(priv, priv->globalX) + size,
+ scaley(priv, priv->globalY));
+ XDrawLine(priv->display, priv->window, priv->gcCur,
+ scalex(priv, priv->globalX),
+ scaley(priv, priv->globalY) - size,
+ scalex(priv, priv->globalX),
+ scaley(priv, priv->globalY) + size);
+ if (priv->grabbed) {
+ XDrawLine(priv->display, priv->window, priv->gcCur,
+ scalex(priv, priv->globalX) - (int)(size / 1.4),
+ scaley(priv, priv->globalY) - (int)(size / 1.4),
+ scalex(priv, priv->globalX) + (int)(size / 1.4),
+ scaley(priv, priv->globalY) + (int)(size / 1.4));
+ XDrawLine(priv->display, priv->window, priv->gcCur,
+ scalex(priv, priv->globalX) - (int)(size / 1.4),
+ scaley(priv, priv->globalY) + (int)(size / 1.4),
+ scalex(priv, priv->globalX) + (int)(size / 1.4),
+ scaley(priv, priv->globalY) - (int)(size / 1.4));
+ }
+}
+
+static void dmxConsoleDraw(myPrivate *priv, int updateCursor)
+{
+ Display *dsp = priv->display;
+ Window win = priv->window;
+ int i;
+
+ XFillRectangle(dsp, win, priv->gc, 0, 0,
+ scalex(priv, priv->width), scaley(priv, priv->height));
+
+ for (i = 0; i < dmxNumScreens; i++) {
+ XFillRectangle(dsp, win, priv->gcRev,
+ scalex(priv, dixScreenOrigins[i].x),
+ scaley(priv, dixScreenOrigins[i].y),
+ scalex(priv, screenInfo.screens[i]->width),
+ scaley(priv, screenInfo.screens[i]->height));
+ }
+ for (i = 0; i < dmxNumScreens; i++) {
+ XDrawRectangle(dsp, win, priv->gc,
+ scalex(priv, dixScreenOrigins[i].x),
+ scaley(priv, dixScreenOrigins[i].y),
+ scalex(priv, screenInfo.screens[i]->width),
+ scaley(priv, screenInfo.screens[i]->height));
+ }
+ if (priv->fine && updateCursor) dmxConsoleDrawFineCursor(priv);
+ XSync(dsp, False);
+}
+
+static void dmxConsoleClearCursor(myPrivate *priv, int x, int y)
+{
+ int cw = 14, ch = 14; /* Clear width and height */
+ XRectangle rects[1];
+
+ rects[0].x = scalex(priv, x) - cw/2;
+ rects[0].y = scaley(priv, y) - ch/2;
+ rects[0].width = cw;
+ rects[0].height = ch;
+ XSetClipRectangles(priv->display, priv->gc, 0, 0, rects, 1, Unsorted);
+ XSetClipRectangles(priv->display, priv->gcRev, 0, 0, rects, 1, Unsorted);
+ dmxConsoleDraw(priv, 0);
+ XSetClipMask(priv->display, priv->gc, None);
+ XSetClipMask(priv->display, priv->gcRev, None);
+}
+
+
+static void dmxConsoleUpdateFineCursor(myPrivate *priv)
+{
+ int leave = 0;
+
+ dmxConsoleClearCursor(priv, priv->globalX, priv->globalY);
+ dmxGetGlobalPosition(&priv->globalX, &priv->globalY);
+
+ priv->lastX = scalex(priv, priv->width / 2);
+ priv->lastY = scaley(priv, priv->height / 2);
+
+ /* Compute new warp position, which may be
+ outside the window */
+ if (priv->globalX < 1 || priv->globalX >= priv->width) {
+ if (priv->globalX < 1) priv->lastX = 0;
+ else priv->lastX = scalex(priv, priv->width);
+ priv->lastY = scaley(priv, priv->globalY);
+ ++leave;
+ }
+ if (priv->globalY < 1 || priv->globalY >= priv->height) {
+ if (priv->globalY < 1) priv->lastY = 0;
+ else priv->lastY = scaley(priv, priv->height);
+ priv->lastX = scalex(priv, priv->globalX);
+ ++leave;
+ }
+
+ /* Draw pseudo cursor in window */
+ dmxConsoleDrawFineCursor(priv);
+
+ XWarpPointer(priv->display, priv->window, priv->window,
+ 0, 0, 0, 0, priv->lastX, priv->lastY);
+ XSync(priv->display, False);
+
+ if (leave) {
+ XEvent X;
+ while (XCheckMaskEvent(priv->display, PointerMotionMask, &X)) {
+ if (X.type == MotionNotify) {
+ if (X.xmotion.x != priv->lastX
+ || X.xmotion.y != priv->lastY) {
+ dmxLog(dmxInfo,
+ "Ignoring motion to %d %d after leave from %d %d\n",
+ X.xmotion.x, X.xmotion.y, priv->lastX, priv->lastY);
+ }
+ } else {
+ dmxLog(dmxInfo, "Ignoring event (%d): %s ****************\n",
+ X.type, dmxEventName(X.type));
+ }
+ }
+ }
+#if DMX_CONSOLE_DEBUG
+ dmxLog(dmxDebug,
+ "dmxConsoleUpdateFindCursor: Warp %d %d on %d %d [%d %d]\n",
+ priv->lastX, priv->lastY,
+ scalex(priv, priv->width),
+ scaley(priv, priv->height),
+ priv->globalX, priv->globalY);
+#endif
+}
+
+static void dmxConsoleMoveAbsolute(myPrivate *priv, int x, int y)
+{
+ int tmpX, tmpY;
+
+ tmpX = unscalex(priv, x);
+ tmpY = unscalex(priv, y);
+#if DMX_CONSOLE_DEBUG
+ dmxLog(dmxDebug, "dmxConsoleMoveAbsolute(,%d,%d) %d %d =? %d %d\n",
+ x, y, tmpX, tmpY, priv->curX, priv->curY);
+#endif
+ if (tmpX == priv->curX && tmpY == priv->curY) return;
+ dmxAbsoluteMotionConfined(unscalex(priv, x), unscaley(priv, y));
+ /* dmxConsoleUpdatePosition gets called here by dmxAbsoluteMotion */
+}
+
+static void dmxConsoleMoveRelative(myPrivate *priv, int x, int y)
+{
+ /* Ignore the event generated from * warping back to middle */
+ if (x == priv->lastX && y == priv->lastY) return;
+ dmxRelativeMotion(priv->lastX - x, priv->lastY - y);
+ /* dmxConsoleUpdatePosition gets called here by dmxAbsoluteMotion */
+}
+
+/* This routine gets called from dmxAbsoluteMotion for each motion. */
+void dmxConsoleUpdatePosition(pointer private, int x, int y)
+{
+ GETONLYPRIVFROMPRIVATE;
+ int tmpX, tmpY;
+
+ tmpX = scalex(priv, x);
+ tmpY = scaley(priv, y);
+#if DMX_CONSOLE_DEBUG
+ dmxLog(dmxDebug, "dmxConsoleUpdatePosition(,%d,%d) new=%d,%d old=%d,%d\n",
+ x, y, tmpX, tmpY, priv->curX, priv->curY);
+#endif
+
+ if (priv->fine) dmxConsoleUpdateFineCursor(priv);
+ if (tmpX != priv->curX || tmpY != priv->curY) {
+ priv->curX = tmpX;
+ priv->curY = tmpY;
+ if (!priv->fine) {
+ XWarpPointer(priv->display, priv->window,
+ priv->window, 0, 0, 0, 0, tmpX, tmpY);
+ XSync(priv->display, False);
+ }
+ }
+}
+
+void dmxConsoleCollectEvents(pointer private)
+{
+ GETPRIVFROMPRIVATE;
+ Display *dsp = priv->display;
+ Window win = priv->window;
+ int width = priv->width;
+ int height = priv->height;
+ XEvent X, N;
+ XSetWindowAttributes attribs;
+ static int rInitialized = 0;
+ static Region r;
+ XRectangle rect;
+ static int raising = 0, raiseX, raiseY;
+
+ while (XPending(priv->display)) {
+ XNextEvent(priv->display, &X);
+ switch(X.type) {
+ case VisibilityNotify:
+ break;
+ case Expose:
+#if DMX_CONSOLE_DEBUG
+ dmxLog(dmxDebug,
+ "dmxConsoleCollectEvents: Expose #%d %d %d %d %d\n",
+ X.xexpose.count,
+ X.xexpose.x, X.xexpose.y,
+ X.xexpose.width, X.xexpose.height);
+#endif
+ if (!rInitialized++) r = XCreateRegion();
+ rect.x = X.xexpose.x;
+ rect.y = X.xexpose.y;
+ rect.width = X.xexpose.width;
+ rect.height = X.xexpose.height;
+ XUnionRectWithRegion(&rect, r, r);
+ if (X.xexpose.count == 0) {
+ XSetRegion(priv->display, priv->gc, r);
+ XSetRegion(priv->display, priv->gcRev, r);
+ dmxConsoleDraw(priv, 1);
+ XSetClipMask(priv->display, priv->gc, None);
+ XSetClipMask(priv->display, priv->gcRev, None);
+ XDestroyRegion(r);
+ rInitialized = 0;
+ }
+ break;
+ case ResizeRequest:
+#if DMX_CONSOLE_DEBUG
+ dmxLog(dmxDebug, "dmxConsoleCollectEvents: Resize %d %d\n",
+ X.xresizerequest.width, X.xresizerequest.height);
+#endif
+ priv->xScale = (double)X.xresizerequest.width / width;
+ priv->yScale = (double)X.xresizerequest.height / height;
+ attribs.override_redirect = True;
+ XChangeWindowAttributes(dsp, win, CWOverrideRedirect, &attribs);
+ XResizeWindow(dsp, win,
+ X.xresizerequest.width, X.xresizerequest.height);
+ dmxConsoleDraw(priv, 1);
+ attribs.override_redirect = False;
+ XChangeWindowAttributes(dsp, win, CWOverrideRedirect, &attribs);
+ break;
+ case LeaveNotify:
+ priv->entered = 0;
+ dmxConsoleLeave(priv);
+ break;
+ case EnterNotify:
+ priv->entered = 1;
+ dmxConsoleEnter(priv);
+ if (raising) {
+ raising = 0;
+ dmxConsoleMoveAbsolute(priv, raiseX, raiseY);
+ } else {
+ if (priv->fine) {
+ /* The raise will generate an event near the center,
+ * which is not where the cursor should be. So we
+ * save the real position, so the raise, and move
+ * the cursor here again after the raise generates
+ * the event. */
+ raising = 1;
+ raiseX = X.xmotion.x;
+ raiseY = X.xmotion.y;
+ XRaiseWindow(priv->display, priv->window);
+ }
+ dmxConsoleMoveAbsolute(priv, X.xmotion.x, X.xmotion.y);
+ }
+ break;
+ case MotionNotify:
+ if (priv->curX == X.xmotion.x && priv->curY == X.xmotion.y)
+ continue;
+ if (XPending(priv->display)) { /* do motion compression */
+ XPeekEvent(priv->display, &N);
+ if (N.type == MotionNotify) continue;
+ }
+#if DMX_CONSOLE_DEBUG
+ dmxLog(dmxDebug, "dmxConsoleCollectEvents: %d %d\n",
+ X.xmotion.x, X.xmotion.y);
+#endif
+ if (raising) {
+ raising = 0;
+ dmxConsoleMoveAbsolute(priv, raiseX, raiseY);
+ } else {
+ if (priv->fine)
+ dmxConsoleMoveRelative(priv, X.xmotion.x, X.xmotion.y);
+ else
+ dmxConsoleMoveAbsolute(priv, X.xmotion.x, X.xmotion.y);
+ }
+ break;
+ default:
+ dmxEnqueueXEvent(dmxInput, &X);
+ break;
+ }
+ }
+}
+
+static void dmxCloseConsole(myPrivate *priv)
+{
+ dmxLogInput(priv->dmxInput, "Closing\n");
+ if (priv->display) {
+ XFreeGC(priv->display, priv->gc);
+ XFreeGC(priv->display, priv->gcRev);
+ XCloseDisplay(priv->display);
+ }
+ priv->display = NULL;
+}
+
+static Bool dmxCloseConsoleScreen(int index, ScreenPtr pScreen)
+{
+ myPrivate *priv, *last;
+
+ for (last = priv = pScreen->devPrivates[dmxScreenPrivateIndex].ptr;
+ priv;
+ priv = priv->next) dmxCloseConsole(last = priv);
+
+ DMX_UNWRAP(CloseScreen, last, pScreen);
+ return pScreen->CloseScreen(index, pScreen);
+}
+
+static Cursor dmxConsoleCreateEmptyCursor(myPrivate *priv)
+{
+ char noCursorData[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ Pixmap pixmap;
+ Cursor cursor;
+ XColor color, tmpColor;
+
+ /* Create empty cursor for window */
+ pixmap = XCreateBitmapFromData(priv->display, priv->window,
+ noCursorData, 8, 8);
+ if (!XAllocNamedColor(priv->display,
+ DefaultColormap(priv->display,
+ DefaultScreen(priv->display)),
+ "black",
+ &color,
+ &tmpColor))
+ dmxLog(dmxFatal, "Cannot allocate color for cursor\n");
+ cursor = XCreatePixmapCursor(priv->display, pixmap, pixmap,
+ &color, &color, 0, 0);
+ XFreePixmap(priv->display, pixmap);
+ return cursor;
+}
+
+void dmxConsoleInitialize(pointer private)
+{
+ GETPRIVFROMPRIVATE;
+ int screen;
+ int i;
+ int consWidth, consHeight;
+ unsigned long mask;
+ XSetWindowAttributes attribs;
+ Display *dsp;
+ Window win;
+ XGCValues gcvals;
+ XColor color;
+ XClassHint class_hints;
+ unsigned long tmp;
+
+ if (!(dsp = priv->display = XOpenDisplay(dmxInput->name)))
+ dmxLog(dmxFatal, "dmxOpenConsole: cannot open console display %s\n",
+ dmxInput->name);
+
+ /* Private initialization using computed values or constants. */
+ priv->xScale = 1.0;
+ priv->yScale = 1.0;
+ priv->initPointerX = scalex(priv, priv->width / 2);
+ priv->initPointerY = scaley(priv, priv->height / 2);
+ priv->eventMask = (ButtonPressMask
+ | ButtonReleaseMask
+ | PointerMotionMask
+ | EnterWindowMask
+ | LeaveWindowMask
+ | KeyPressMask
+ | KeyReleaseMask
+ | ExposureMask
+ | ResizeRedirectMask);
+
+ /* Set up defaults */
+ screen = DefaultScreen(dsp);
+ consWidth = DisplayWidth(dsp, screen) * CONSOLE_NUM / CONSOLE_DEN;
+ consHeight = DisplayHeight(dsp, screen) * CONSOLE_NUM / CONSOLE_DEN;
+
+ for (i = 0; i < dmxNumScreens; i++) {
+ if (dixScreenOrigins[i].x+screenInfo.screens[i]->width > priv->width)
+ priv->width = dixScreenOrigins[i].x+screenInfo.screens[i]->width;
+
+ if (dixScreenOrigins[i].y+screenInfo.screens[i]->height > priv->height)
+ priv->height = dixScreenOrigins[i].y+screenInfo.screens[i]->height;
+ }
+
+ if ((double)consWidth / priv->width < (double)consHeight / priv->height)
+ priv->xScale = priv->yScale = (double)consWidth / priv->width;
+ else
+ priv->xScale = priv->yScale = (double)consHeight / priv->height;
+
+ consWidth = scalex(priv, priv->width);
+ consHeight = scaley(priv, priv->height);
+
+ mask = CWBackPixel | CWEventMask | CWColormap | CWOverrideRedirect;
+ attribs.colormap = DefaultColormap(dsp, screen);
+ if (XParseColor(dsp, attribs.colormap, CONSOLE_BG_COLOR, &color)
+ && XAllocColor(dsp, attribs.colormap, &color)) {
+ attribs.background_pixel = color.pixel;
+ } else
+ attribs.background_pixel = WhitePixel(dsp, screen);
+
+ attribs.event_mask = priv->eventMask;
+ attribs.override_redirect = FALSE;
+
+ win = priv->window = XCreateWindow(dsp,
+ RootWindow(dsp, screen),
+ 0, 0, consWidth, consHeight,
+ 0,
+ DefaultDepth(dsp, screen),
+ InputOutput,
+ DefaultVisual(dsp, screen),
+ mask, &attribs);
+
+ /* Set up properties */
+ XStoreName(dsp, win, DMX_CONSOLE_NAME);
+ class_hints.res_name = DMX_RES_NAME;
+ class_hints.res_class = DMX_RES_CLASS;
+ XSetClassHint(dsp, win, &class_hints);
+
+
+ /* Map the window */
+ XMapWindow(dsp, win);
+
+ /* Create cursors */
+ priv->cursorNormal = XCreateFontCursor(priv->display, XC_circle);
+ priv->cursorGrabbed = XCreateFontCursor(priv->display, XC_spider);
+ priv->cursorEmpty = dmxConsoleCreateEmptyCursor(priv);
+ XDefineCursor(priv->display, priv->window, priv->cursorNormal);
+
+ /* Create GC */
+ mask = (GCFunction | GCPlaneMask | GCClipMask | GCForeground |
+ GCBackground | GCLineWidth | GCLineStyle | GCCapStyle |
+ GCFillStyle);
+ gcvals.function = GXcopy;
+ gcvals.plane_mask = AllPlanes;
+ gcvals.clip_mask = None;
+ if (XParseColor(dsp, attribs.colormap, CONSOLE_SCREEN_FG_COLOR, &color)
+ && XAllocColor(dsp, attribs.colormap, &color)) {
+ gcvals.foreground = color.pixel;
+ } else
+ gcvals.foreground = BlackPixel(dsp, screen);
+ if (XParseColor(dsp, attribs.colormap, CONSOLE_SCREEN_BG_COLOR, &color)
+ && XAllocColor(dsp, attribs.colormap, &color)) {
+ gcvals.background = color.pixel;
+ } else
+ gcvals.background = WhitePixel(dsp, screen);
+ gcvals.line_width = 0;
+ gcvals.line_style = LineSolid;
+ gcvals.cap_style = CapNotLast;
+ gcvals.fill_style = FillSolid;
+
+ priv->gc = XCreateGC(dsp, win, mask, &gcvals);
+
+ tmp = gcvals.background;
+ gcvals.background = gcvals.foreground;
+ gcvals.foreground = tmp;
+ priv->gcRev = XCreateGC(dsp, win, mask, &gcvals);
+
+ gcvals.background = gcvals.foreground;
+ if (XParseColor(dsp, attribs.colormap, CONSOLE_SCREEN_CUR_COLOR, &color)
+ && XAllocColor(dsp, attribs.colormap, &color)) {
+ gcvals.foreground = color.pixel;
+ } else
+ gcvals.foreground = BlackPixel(dsp, screen);
+ priv->gcCur = XCreateGC(dsp, win, mask, &gcvals);
+
+ dmxConsoleDraw(priv, 1);
+
+ if (screenInfo.screens[0]->devPrivates[dmxScreenPrivateIndex].ptr)
+ priv->next = (screenInfo.screens[0]
+ ->devPrivates[dmxScreenPrivateIndex].ptr);
+ else
+ DMX_WRAP(CloseScreen, dmxCloseConsoleScreen,
+ priv, screenInfo.screens[0]);
+ screenInfo.screens[0]->devPrivates[dmxScreenPrivateIndex].ptr = priv;
+}
+
+int dmxConsoleFunctions(pointer private, DMXFunctionType function)
+{
+ GETONLYPRIVFROMPRIVATE;
+
+ switch (function) {
+ case DMX_FUNCTION_FINE:
+ if (priv->fine) {
+ priv->fine = 0;
+ dmxConsoleClearCursor(priv, priv->globalX, priv->globalY);
+ XDefineCursor(priv->display, priv->window,
+ priv->grabbed
+ ? priv->cursorGrabbed
+ : priv->cursorNormal);
+ XWarpPointer(priv->display, priv->window, priv->window,
+ 0, 0, 0, 0,
+ scalex(priv, priv->globalX),
+ scaley(priv, priv->globalY));
+ XSync(priv->display, False);
+ } else {
+ priv->fine = 1;
+ XRaiseWindow(priv->display, priv->window);
+ XDefineCursor(priv->display, priv->window, priv->cursorEmpty);
+ dmxConsoleUpdateFineCursor(priv);
+ }
+ return 1;
+ case DMX_FUNCTION_GRAB:
+ if (priv->grabbed) {
+ XUngrabKeyboard(priv->display, CurrentTime);
+ XUngrabPointer(priv->display, CurrentTime);
+ XDefineCursor(priv->display, priv->window,
+ priv->fine
+ ? priv->cursorEmpty
+ : priv->cursorNormal);
+ } else {
+ if (XGrabPointer(priv->display, priv->window, True,
+ 0, GrabModeAsync, GrabModeAsync, priv->window,
+ None, CurrentTime)) {
+ dmxLog(dmxError, "XGrabPointer failed\n");
+ return 0;
+ }
+ if (XGrabKeyboard(priv->display, priv->window, True,
+ GrabModeAsync, GrabModeAsync, CurrentTime)) {
+ dmxLog(dmxError, "XGrabKeyboard failed\n");
+ XUngrabPointer(priv->display, CurrentTime);
+ return 0;
+ }
+ XDefineCursor(priv->display, priv->window,
+ priv->fine
+ ? priv->cursorEmpty
+ : priv->cursorGrabbed);
+ }
+ priv->grabbed = !priv->grabbed;
+ if (priv->fine) dmxConsoleUpdateFineCursor(priv);
+ return 1;
+ case DMX_FUNCTION_TERMINATE:
+ return 1;
+ default:
+ return 0;
+ }
+}
diff --git a/xc/programs/Xserver/hw/dmx/input/dmxconsole.h b/xc/programs/Xserver/hw/dmx/input/dmxconsole.h
new file mode 100644
index 000000000..4091d0d79
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/dmxconsole.h
@@ -0,0 +1,46 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef _DMXCONSOLE_H_
+#define _DMXCONSOLE_H_
+
+extern pointer dmxConsoleCreatePrivate(DMXInputInfo *dmxInput);
+extern void dmxConsoleDestroyPrivate(pointer private);
+extern void dmxConsoleInitialize(pointer private);
+extern void dmxConsoleCollectEvents(pointer private);
+extern int dmxConsoleFunctions(pointer private, DMXFunctionType function);
+extern void dmxConsoleUpdatePosition(pointer private, int x, int y);
+extern void dmxConsoleKbdSetCtrl(pointer private, KeybdCtrl *ctrl);
+
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/input/dmxdummy.c b/xc/programs/Xserver/hw/dmx/input/dmxdummy.c
new file mode 100644
index 000000000..23838dde6
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/dmxdummy.c
@@ -0,0 +1,60 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#include "dmx.h"
+#define GC XlibGC
+#include <X11/Xlibint.h> /* For Xmalloc */
+#undef GC
+#include "dmxdummy.h"
+
+pointer dmxDummyKbdGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap)
+{
+ KeySym *keyboard_mapping = Xmalloc(sizeof(*keyboard_mapping));
+
+ keyboard_mapping[0] = NoSymbol;
+ pKeySyms->minKeyCode = 8;
+ pKeySyms->maxKeyCode = 8;
+ pKeySyms->mapWidth = 1;
+ pKeySyms->map = keyboard_mapping;
+
+ return keyboard_mapping; /* High-level code frees with XFree */
+}
+
+void dmxDummyMouGetMap(DevicePtr pDev, unsigned char *map, int *nButtons)
+{
+ *nButtons = 3;
+ map[0] = 1;
+ map[1] = 2;
+ map[2] = 3;
+}
diff --git a/xc/programs/Xserver/hw/dmx/input/dmxdummy.h b/xc/programs/Xserver/hw/dmx/input/dmxdummy.h
new file mode 100644
index 000000000..051d10fcf
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/dmxdummy.h
@@ -0,0 +1,42 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef _DMXDUMMY_H_
+#define _DMXDUMMY_H_
+
+extern pointer dmxDummyKbdGetMap(DevicePtr pDev,
+ KeySymsPtr pKeySyms, CARD8 *pModMap);
+extern void dmxDummyMouGetMap(DevicePtr pDev,
+ unsigned char *map, int *nButtons);
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/input/dmxevents.c b/xc/programs/Xserver/hw/dmx/input/dmxevents.c
new file mode 100644
index 000000000..4cdeec32e
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/dmxevents.c
@@ -0,0 +1,349 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#include "dmxinputinit.h"
+#include "dmxevents.h"
+#include "dmxcb.h"
+#include "keysym.h"
+#include "opaque.h"
+#include "inputstr.h"
+#include "mi.h"
+#include "mipointer.h"
+
+extern char dispatchException;
+static int dmxGlobalX, dmxGlobalY; /* Global cursor position */
+
+#define DMX_EVENTS_DEBUG 0
+
+static int dmxCheckFunctionKeys(DMXInputInfo *dmxInput, XEvent *X)
+{
+ unsigned int state = X->xkey.state;
+ KeySym keySym = XLookupKeysym(&X->xkey, 0);
+
+ if ((state & (ControlMask|Mod1Mask)) != (ControlMask|Mod1Mask)) return 0;
+
+ switch (keySym) {
+ case XK_g:
+ if (X->xkey.type == KeyPress) {
+ if (dmxInput->gen && dmxInput->gen->functions)
+ dmxInput->gen->functions(dmxInput->gen->private,
+ DMX_FUNCTION_GRAB);
+ }
+ return 1;
+ case XK_f:
+ if (X->xkey.type == KeyPress) {
+ if (dmxInput->gen && dmxInput->gen->functions)
+ dmxInput->gen->functions(dmxInput->gen->private,
+ DMX_FUNCTION_FINE);
+ }
+ return 1;
+ case XK_q:
+ if (X->xkey.type == KeyPress) {
+ if (dmxInput->gen && dmxInput->gen->functions) {
+ if (dmxInput->gen->functions(dmxInput->gen->private,
+ DMX_FUNCTION_TERMINATE)) {
+ dmxLog(dmxInfo, "User request for termination\n");
+ dispatchException |= DE_TERMINATE;
+ }
+ }
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+int dmxCheckSpecialKeys(pointer p,
+ xEvent *xE,
+ KeySym keySym,
+ unsigned short state)
+{
+ DMXInputInfo *dmxInput = p;
+ int vt = 0;
+
+#if DMX_EVENTS_DEBUG > 1
+ dmxLog(dmxDebug,
+ "dmxCheckSpecialKeys: scan=0x%02x %s keySym=0x%04x state=0x%04x\n",
+ xE->u.u.detail, xE->u.u.type == KeyPress ? "press" : "release",
+ keySym, state);
+#endif
+
+ if ((state & (ControlMask|Mod1Mask)) != (ControlMask|Mod1Mask)) return 0;
+
+ switch (keySym) {
+ case XK_F1:
+ case XK_F2:
+ case XK_F3:
+ case XK_F4:
+ case XK_F5:
+ case XK_F6:
+ case XK_F7:
+ case XK_F8:
+ case XK_F9:
+ case XK_F10:
+ vt = keySym - XK_F1 + 1;
+ break;
+
+ case XK_F11:
+ case XK_F12:
+ vt = keySym - XK_F11 + 11;
+ break;
+
+ case XK_q: /* To avoid confusion */
+ case XK_BackSpace:
+ case XK_Delete:
+ case XK_KP_Delete:
+ dmxLog(dmxInfo, "User request for termination\n");
+ dispatchException |= DE_TERMINATE;
+ return -1; /* Terminate */
+ break;
+ }
+
+ if (vt) {
+ dmxLog(dmxInfo, "Request to switch to VT %d\n", vt);
+ dmxInput->vt_switch_pending = vt;
+ return vt;
+ }
+
+ return 0; /* Do nothing */
+}
+
+void dmxEnqueueRawEvent(xEvent *xE)
+{
+#if DMX_EVENTS_DEBUG > 1
+ int x, y;
+
+ miPointerPosition(&x, &y);
+ dmxLog(dmxDebug, "dmxEnqueueRawEvent: Enqueuing 0x%0x @ %dx%d\n",
+ xE->u.u.detail, x, y);
+#endif
+#if XTESTEXT1
+ if (dmxXTestEvent(xE)) return;
+#endif
+
+ if (xE->u.u.type != MotionNotify) mieqEnqueue(xE);
+ else {
+ /* All MotionNotify events should be sent via dmxAbsoluteMotion
+ * and dmxRelativeMotion -- no input driver should build motion
+ * events by hand. */
+ dmxLog(dmxError,
+ "dmxEnqueueRawEvent: MotionNotify events not allowed here\n");
+ }
+}
+
+void dmxGetGlobalPosition(int *x, int *y)
+{
+ *x = dmxGlobalX;
+ *y = dmxGlobalY;
+}
+
+static DMXScreenInfo *dmxFindFirstScreen(int x, int y)
+{
+ int i;
+
+ for (i = 0; i < dmxNumScreens; i++) {
+ DMXScreenInfo *dmxScreen = &dmxScreens[i];
+ if (x >= dmxScreen->originX
+ && x < dmxScreen->originX + dmxScreen->width
+ && y >= dmxScreen->originY
+ && y < dmxScreen->originY + dmxScreen->height) {
+ return dmxScreen;
+ }
+ }
+ return NULL;
+}
+
+static void _dmxAbsoluteMotion(int x, int y, int delta)
+{
+ DMXScreenInfo *dmxScreen;
+ DMXInputInfo *dmxInput;
+ ScreenPtr pScreen;
+ int localX;
+ int localY;
+ int i;
+
+ if (dmxGlobalX == x && dmxGlobalY == y) return;
+
+#if DMX_EVENTS_DEBUG
+ dmxLog(dmxDebug,
+ "dmxAbsoluteMotion(%d,%d,%d) %d %d\n",
+ x, y, delta, dmxGlobalX, dmxGlobalY);
+#endif
+
+ dmxGlobalX = x;
+ dmxGlobalY = y;
+
+ if (dmxGlobalX < 0) dmxGlobalX = 0;
+ if (dmxGlobalY < 0) dmxGlobalY = 0;
+ if (dmxGlobalX >= dmxGlobalWidth) dmxGlobalX = dmxGlobalWidth + delta;
+ if (dmxGlobalY >= dmxGlobalHeight) dmxGlobalY = dmxGlobalHeight + delta;
+
+ if ((dmxScreen = dmxFindFirstScreen(dmxGlobalX, dmxGlobalY))) {
+ localX = dmxGlobalX - dmxScreen->originX;
+ localY = dmxGlobalY - dmxScreen->originY;
+ if ((pScreen = miPointerCurrentScreen())
+ && pScreen->myNum == dmxScreen->index) {
+ /* Screen is old screen */
+ miPointerAbsoluteCursor(localX, localY, GetTimeInMillis());
+ } else {
+ /* Screen is new */
+#if DMX_EVENTS_DEBUG
+ dmxLog(dmxDebug, "dmxAbsoluteMotion: %d %d %d\n",
+ dmxScreen->index, localX, localY);
+#endif
+ miPointerSetNewScreen(dmxScreen->index, localX, localY);
+ miPointerAbsoluteCursor(localX, localY, GetTimeInMillis());
+ }
+ miPointerPosition(&localX, &localY);
+
+ if ((pScreen = miPointerCurrentScreen())) {
+ dmxGlobalX = localX + dmxScreens[pScreen->myNum].originX;
+ dmxGlobalY = localY + dmxScreens[pScreen->myNum].originY;
+#if DMX_EVENTS_DEBUG
+ dmxLog(dmxDebug,
+ "dmxAbsoluteMotion: moved to %d %d on screen %d (%d %d)\n",
+ dmxGlobalX, dmxGlobalY,
+ dmxScreen ? dmxScreen->index : -1,
+ localX, localY);
+#endif
+ }
+ }
+ /* Send updates down to all input drivers */
+ for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) {
+ if (dmxInput->gen && dmxInput->gen->update_position)
+ dmxInput->gen->update_position(dmxInput->gen->private,
+ dmxGlobalX, dmxGlobalY);
+ }
+}
+
+void dmxAbsoluteMotion(int x, int y)
+{
+ _dmxAbsoluteMotion(x, y, 0);
+}
+
+void dmxAbsoluteMotionConfined(int x, int y)
+{
+ _dmxAbsoluteMotion(x, y, -1);
+}
+
+void dmxRelativeMotion(int x, int y)
+{
+#if DMX_EVENTS_DEBUG
+ dmxLog(dmxDebug, "dmxRelativeMotion: %d %d\n", x, y);
+#endif
+ dmxAbsoluteMotion(dmxGlobalX - x, dmxGlobalY - y);
+}
+
+void dmxMotion(int x, int y, int relative)
+{
+ if (relative) dmxRelativeMotion(x, y);
+ else dmxAbsoluteMotion(x, y);
+}
+
+static int dmxGetButtonMapping(DMXInputInfo *dmxInput, int button)
+{
+ ButtonClassPtr b = dmxInput->pPointer->button;
+
+ if (button > b->numButtons) { /* This shouldn't happen. */
+ dmxLog(dmxWarning, "Button %d pressed, but only %d buttons?!?\n",
+ button, b->numButtons);
+ return button;
+ }
+ return b->map[button];
+}
+
+void dmxEnqueueXEvent(DMXInputInfo *dmxInput, XEvent *X)
+{
+ xEvent x;
+
+ switch (X->type) {
+ case KeyPress:
+ if (dmxCheckFunctionKeys(dmxInput, X)) return;
+ x.u.u.type = KeyPress;
+ x.u.u.detail = X->xkey.keycode;
+ x.u.keyButtonPointer.time = GetTimeInMillis();
+ dmxEnqueueRawEvent(&x);
+ break;
+ case KeyRelease:
+ if (dmxCheckFunctionKeys(dmxInput, X)) return;
+ x.u.u.type = KeyRelease;
+ x.u.u.detail = X->xkey.keycode;
+ x.u.keyButtonPointer.time = GetTimeInMillis();
+ dmxEnqueueRawEvent(&x);
+ break;
+ case ButtonPress:
+ x.u.u.type = ButtonPress;
+ x.u.u.detail = dmxGetButtonMapping(dmxInput,
+ X->xbutton.button);
+ x.u.keyButtonPointer.time = GetTimeInMillis();
+ dmxEnqueueRawEvent(&x);
+ break;
+ case ButtonRelease:
+ x.u.u.type = ButtonRelease;
+ x.u.u.detail = dmxGetButtonMapping(dmxInput,
+ X->xbutton.button);
+ x.u.keyButtonPointer.time = GetTimeInMillis();
+ dmxEnqueueRawEvent(&x);
+ break;
+ case MotionNotify:
+ /* All MotionNotify events should be sent via dmxAbsoluteMotion
+ * and dmxRelativeMotion -- no input driver should build motion
+ * events by hand. */
+ dmxLog(dmxError, "dmxEnqueueXEvent: MotionNotify not allowed here\n");
+ dmxEnqueueRawEvent(&x);
+ break;
+
+ /* Always ignore these events */
+ case EnterNotify:
+ case LeaveNotify:
+ case KeymapNotify:
+ break;
+
+ default:
+#if 1 || DMX_EVENTS_DEBUG /* FIXME: remove 1 || */
+ if (X->type == Expose) {
+ dmxLogInput(dmxInput,
+ "Unhandled event (%d) on window %lu:"
+ " %s [%dx%d w=%d h=%d c=%d]\n",
+ X->type, X->xexpose.window, dmxEventName(X->type),
+ X->xexpose.x, X->xexpose.y,
+ X->xexpose.width, X->xexpose.height, X->xexpose.count);
+ } else {
+ dmxLogInput(dmxInput, "Unhandled event (%d): %s\n",
+ X->type, dmxEventName(X->type));
+ }
+#endif
+ break;
+ }
+}
diff --git a/xc/programs/Xserver/hw/dmx/input/dmxevents.h b/xc/programs/Xserver/hw/dmx/input/dmxevents.h
new file mode 100644
index 000000000..9a51cffb1
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/dmxevents.h
@@ -0,0 +1,49 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef _DMXEVENTS_H_
+#define _DMXEVENTS_H_
+extern void dmxAbsoluteMotion(int x, int y);
+extern void dmxAbsoluteMotionConfined(int x, int y);
+extern void dmxRelativeMotion(int x, int y);
+extern void dmxMotion(int x, int y, int relative);
+extern void dmxGetGlobalPosition(int *x, int *y);
+
+extern void dmxEnqueueRawEvent(xEvent *xE);
+extern void dmxEnqueueXEvent(DMXInputInfo *dmxInput, XEvent *X);
+extern int dmxCheckSpecialKeys(pointer dmxInput,
+ xEvent *xE,
+ KeySym keySym,
+ unsigned short state);
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/input/dmxinputinit.c b/xc/programs/Xserver/hw/dmx/input/dmxinputinit.c
new file mode 100644
index 000000000..cc65ab768
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/dmxinputinit.c
@@ -0,0 +1,558 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#include "inputstr.h"
+#include "input.h"
+#include "mipointer.h"
+#include "mi.h"
+
+#include "dmxinputinit.h"
+
+#include "dmxdummy.h"
+#include "dmxbackend.h"
+#include "dmxconsole.h"
+#include "dmxcommon.h"
+
+#include "lnx-keyboard.h"
+#include "lnx-ms.h"
+#include "lnx-ps2.h"
+
+#include "dmxsigio.h"
+#include "dmxarg.h"
+
+static DMXLocalInputInfoRec DMXDummyKbd = {
+ "dummy-kbd",
+ DMX_LOCAL_KEYBOARD,
+ NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL,
+ dmxDummyKbdGetMap,
+};
+
+static DMXLocalInputInfoRec DMXDummyMou = {
+ "common-mou",
+ DMX_LOCAL_MOUSE,
+ NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL,
+ dmxDummyMouGetMap
+};
+
+static DMXLocalInputInfoRec DMXCommonKbd = {
+ "common-kbd",
+ DMX_LOCAL_KEYBOARD,
+ NULL, NULL,
+ NULL,
+ dmxCommonKbdOn,
+ dmxCommonKbdOff,
+ NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL,
+ dmxCommonKbdGetMap,
+ dmxCommonKbdCtrl,
+ dmxCommonKbdBell
+};
+
+static DMXLocalInputInfoRec DMXCommonMou = {
+ "common-mou",
+ DMX_LOCAL_MOUSE,
+ NULL, NULL,
+ NULL,
+ dmxCommonMouOn,
+ dmxCommonMouOff,
+ NULL,
+ NULL, NULL, NULL,
+ NULL,
+ dmxCommonMouGetMap,
+ dmxCommonMouCtrl
+};
+
+static DMXLocalInputInfoRec DMXBackendGen = {
+ "backend-gen",
+ DMX_LOCAL_HIGHLEVEL,
+ NULL, NULL,
+ NULL, NULL, NULL,
+ dmxBackendUpdatePosition,
+ NULL, NULL, NULL,
+ NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ dmxBackendCreatePrivate,
+ dmxBackendDestroyPrivate,
+ dmxBackendInitialize,
+ dmxCommonEnableDevice,
+ dmxBackendCollectEvents,
+ dmxBackendProcessInput,
+ dmxBackendFunctions
+};
+
+static DMXLocalInputInfoRec DMXConsoleGen = {
+ "console-gen",
+ DMX_LOCAL_HIGHLEVEL,
+ NULL, NULL,
+ NULL, NULL, NULL,
+ dmxConsoleUpdatePosition,
+ NULL, NULL, NULL,
+ NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ dmxConsoleCreatePrivate,
+ dmxConsoleDestroyPrivate,
+ dmxConsoleInitialize,
+ dmxCommonEnableDevice,
+ dmxConsoleCollectEvents,
+ NULL,
+ dmxConsoleFunctions
+};
+
+static DMXLocalInputInfoRec DMXLocalDevices[] = {
+ {
+ "kbd",
+ DMX_LOCAL_KEYBOARD,
+ kbdLinuxCreatePrivate,
+ kbdLinuxDestroyPrivate,
+ kbdLinuxInit,
+ kbdLinuxOn,
+ kbdLinuxOff,
+ NULL,
+ kbdLinuxVTPreSwitch,
+ kbdLinuxVTPostSwitch,
+ kbdLinuxVTSwitch,
+ NULL, NULL, NULL,
+ kbdLinuxRead,
+ kbdLinuxGetMap,
+ kbdLinuxCtrl,
+ kbdLinuxBell
+ },
+ {
+ "ms",
+ DMX_LOCAL_MOUSE,
+ msLinuxCreatePrivate,
+ msLinuxDestroyPrivate,
+ msLinuxInit,
+ msLinuxOn,
+ msLinuxOff,
+ NULL,
+ msLinuxVTPreSwitch,
+ msLinuxVTPostSwitch,
+ NULL,
+ msLinuxRead,
+ msLinuxGetMap
+ },
+ {
+ "ps2",
+ DMX_LOCAL_MOUSE,
+ ps2LinuxCreatePrivate,
+ ps2LinuxDestroyPrivate,
+ ps2LinuxInit,
+ ps2LinuxOn,
+ ps2LinuxOff,
+ NULL,
+ ps2LinuxVTPreSwitch,
+ ps2LinuxVTPostSwitch,
+ NULL,
+ ps2LinuxRead,
+ ps2LinuxGetMap
+ },
+ { NULL } /* Must be last */
+};
+
+static void dmxChangePointerControl(DeviceIntPtr pDev, PtrCtrl *ctrl)
+{
+ int i;
+
+ for (i = 0; i < dmxNumInputs; i++) {
+ DMXInputInfo *dmxInput = &dmxInputs[i];
+ if (dmxInput->mou) {
+ dmxInput->mou->mctrl = *ctrl;
+ if (dmxInput->mou->mCtrl)
+ dmxInput->mou->mCtrl(&dmxInput->pPointer->public, ctrl);
+ }
+ }
+#if 0
+ DMXInputInfo *dmxInput = pDev->public.devicePrivate;
+ Display *dsp = dmxInput->gen->display;
+
+ dmxLogInput(dmxInput, "dmxChangePointerControl\n");
+
+ XChangePointerControl(dsp, True, True,
+ ctrl->num, ctrl->den, ctrl->threshold);
+#endif
+}
+
+static int dmxMouseOnOff(DeviceIntPtr pDevice, int what)
+{
+ DevicePtr pDev = &pDevice->public;
+ DMXInputInfo *dmxInput = pDev->devicePrivate;
+ unsigned char map[64];
+ int nButtons;
+ int fd;
+
+ switch (what) {
+ case DEVICE_INIT:
+ if (dmxInput->mou->init) dmxInput->mou->init(pDev);
+ dmxInput->mou->mGetmap(pDev, map, &nButtons);
+ if (!InitPointerDeviceStruct(pDev, map, nButtons,
+ miPointerGetMotionEvents,
+ dmxChangePointerControl,
+ miPointerGetMotionBufferSize()))
+ return BadImplementation;
+ break;
+ case DEVICE_ON:
+ if (dmxInput->mou->on && (fd = dmxInput->mou->on(pDev)) >= 0)
+ dmxSigioRegister(dmxInput, fd);
+ pDev->on = TRUE;
+ break;
+ case DEVICE_OFF:
+ case DEVICE_CLOSE:
+ dmxSigioUnregister(dmxInput);
+ if (dmxInput->mou->off) dmxInput->mou->off(pDev);
+ pDev->on = FALSE;
+ break;
+ }
+ return Success;
+}
+
+static void dmxKeyboardKbdCtrlProc(DeviceIntPtr pDevice, KeybdCtrl *ctrl)
+{
+ int i;
+
+ for (i = 0; i < dmxNumInputs; i++) {
+ DMXInputInfo *dmxInput = &dmxInputs[i];
+ if (dmxInput->kbd) {
+ dmxInput->kbd->kctrl = *ctrl;
+ if (dmxInput->kbd->kCtrl)
+ dmxInput->kbd->kCtrl(&dmxInput->pKeyboard->public, ctrl);
+ }
+ }
+}
+
+static void dmxKeyboardBellProc(int percent, DeviceIntPtr pDevice,
+ pointer ctrl, int unknown)
+{
+ int i;
+
+ for (i = 0; i < dmxNumInputs; i++) {
+ DMXInputInfo *di = &dmxInputs[i];
+ if (di->kbd && di->kbd->kBell)
+ di->kbd->kBell(&di->pKeyboard->public,
+ percent,
+ di->kbd->kctrl.bell,
+ di->kbd->kctrl.bell_pitch,
+ di->kbd->kctrl.bell_duration);
+ }
+}
+
+static int dmxKeyboardOnOff(DeviceIntPtr pDevice, int what)
+{
+ DevicePtr pDev = &pDevice->public;
+ DMXInputInfo *dmxInput = pDev->devicePrivate;
+ KeySymsRec keysyms;
+ CARD8 modmap[MAP_LENGTH];
+ int fd;
+ XPointer tmp;
+
+ if (!dmxInput->kbd) return BadImplementation;
+
+ switch (what) {
+ case DEVICE_INIT:
+ if (dmxInput->kbd->init) dmxInput->kbd->init(pDev);
+ tmp = dmxInput->kbd->kGetmap(pDev, &keysyms, modmap);
+ if (!InitKeyboardDeviceStruct(pDev, &keysyms, modmap,
+ dmxKeyboardBellProc,
+ dmxKeyboardKbdCtrlProc))
+ return BadImplementation;
+ if (tmp) XFree(tmp);
+ break;
+ case DEVICE_ON:
+ if (dmxInput->kbd->on && (fd = dmxInput->kbd->on(pDev)) >= 0)
+ dmxSigioRegister(dmxInput, fd);
+ pDev->on = TRUE;
+ break;
+ case DEVICE_OFF:
+ case DEVICE_CLOSE:
+ dmxSigioUnregister(dmxInput);
+ if (dmxInput->kbd->off) dmxInput->kbd->off(pDev);
+ pDev->on = FALSE;
+ break;
+ }
+ return Success;
+}
+
+static void dmxProcessInputEvents(DMXInputInfo *dmxInput)
+{
+ mieqProcessInputEvents();
+ miPointerUpdate();
+ if (dmxInput->gen && dmxInput->gen->process_input)
+ dmxInput->gen->process_input(dmxInput->gen->private);
+}
+
+static void dmxBlockHandler(pointer blockData, OSTimePtr pTimeout,
+ pointer pReadMask)
+{
+}
+
+static void dmxSwitchReturn(pointer p)
+{
+ DMXInputInfo *dmxInput = p;
+
+ dmxLog(dmxInfo, "Returning from VT %d\n", dmxInput->vt_switched);
+
+ if (!dmxInput->vt_switched)
+ dmxLog(dmxFatal, "dmxSwitchReturn called, but not switched\n");
+ dmxSigioEnableInput();
+ if (dmxInput->kbd && dmxInput->kbd->vt_post_switch)
+ dmxInput->kbd->vt_post_switch(dmxInput->kbd->private);
+ if (dmxInput->mou && dmxInput->mou->vt_post_switch)
+ dmxInput->mou->vt_post_switch(dmxInput->mou->private);
+ dmxInput->vt_switched = 0;
+}
+
+static void dmxWakeupHandler(pointer blockData, int result, pointer pReadMask)
+{
+ DMXInputInfo *dmxInput = blockData;
+
+ if (dmxInput->vt_switch_pending) {
+ dmxLog(dmxInfo, "Switching to VT %d\n", dmxInput->vt_switch_pending);
+ if (dmxInput->kbd && dmxInput->kbd->vt_pre_switch)
+ dmxInput->kbd->vt_pre_switch(dmxInput->kbd->private);
+ if (dmxInput->mou && dmxInput->mou->vt_pre_switch)
+ dmxInput->mou->vt_pre_switch(dmxInput->mou->private);
+ dmxInput->vt_switched = dmxInput->vt_switch_pending;
+ dmxInput->vt_switch_pending = 0;
+ if (dmxInput->kbd && dmxInput->kbd->vt_switch) {
+ dmxSigioDisableInput();
+ if (!dmxInput->kbd->vt_switch(dmxInput->kbd->private,
+ dmxInput->vt_switched,
+ dmxSwitchReturn,
+ dmxInput))
+ dmxSwitchReturn(dmxInput);
+ }
+ }
+
+ if (dmxInput->gen && dmxInput->gen->collect_events)
+ dmxInput->gen->collect_events(dmxInput->gen->private);
+}
+
+static DeviceIntPtr dmxAddKeyboard(DMXInputInfo *dmxInput)
+{
+ DeviceIntPtr pKeyboard;
+
+ pKeyboard = AddInputDevice(dmxKeyboardOnOff, TRUE);
+ pKeyboard->public.devicePrivate = dmxInput;
+
+ RegisterKeyboardDevice(pKeyboard);
+
+ if (dmxInput->kbd->create_private)
+ dmxInput->kbd->private = dmxInput->kbd->create_private(pKeyboard);
+ return pKeyboard;
+}
+
+static DeviceIntPtr dmxAddMouse(DMXInputInfo *dmxInput)
+{
+ DeviceIntPtr pPointer;
+
+ pPointer = AddInputDevice(dmxMouseOnOff, TRUE);
+ pPointer->public.devicePrivate = dmxInput;
+
+ RegisterPointerDevice(pPointer);
+ miRegisterPointerDevice(screenInfo.screens[0], pPointer);
+
+ if (dmxInput->mou->create_private)
+ dmxInput->mou->private = dmxInput->mou->create_private(pPointer);
+ return pPointer;
+}
+
+static DMXLocalInputInfoPtr dmxLookupLocal(const char *name)
+{
+ DMXLocalInputInfoPtr pt;
+
+ for (pt = &DMXLocalDevices[0]; pt->name; ++pt)
+ if (!strcmp(pt->name, name)) return pt;
+ return NULL;
+}
+
+static DMXLocalInputInfoPtr dmxInputCopyLocal(DMXLocalInputInfoPtr s)
+{
+ DMXLocalInputInfoPtr d = xalloc(sizeof(*d));
+ memcpy(d, s, sizeof(*d));
+ return d;
+}
+
+static void dmxPopulateLocal(DMXInputInfo *dmxInput, dmxArg a)
+{
+ int i;
+ int help = 0;
+ DMXLocalInputInfoRec *pt;
+
+ for (i = 1; i < dmxArgC(a); i++) {
+ const char *name = dmxArgV(a, i);
+ if ((pt = dmxLookupLocal(name))) {
+ switch (pt->type) {
+ case DMX_LOCAL_KEYBOARD:
+ dmxInput->kbd = dmxInputCopyLocal(pt);
+ break;
+ case DMX_LOCAL_MOUSE:
+ dmxInput->mou = dmxInputCopyLocal(pt);
+ break;
+ default:
+ break;
+ }
+ } else {
+ if (strlen(name))
+ dmxLog(dmxWarning,
+ "Could not find a driver called %s\n", name);
+ ++help;
+ }
+ }
+ if (help) {
+ dmxLog(dmxInfo, "Available local device drivers:\n");
+ for (pt = &DMXLocalDevices[0]; pt->name; ++pt) {
+ const char *type;
+ switch (pt->type) {
+ case DMX_LOCAL_KEYBOARD: type = "keyboard"; break;
+ case DMX_LOCAL_MOUSE: type = "pointer"; break;
+ default: type = "unknown"; break;
+ }
+ dmxLog(dmxInfo, " %s (%s)\n", pt->name, type);
+ }
+ }
+
+ if (!dmxInput->kbd)
+ dmxInput->kbd = dmxInputCopyLocal(
+ dmxLookupLocal(DMX_LOCAL_DEFAULT_KEYBOARD));
+ if (!dmxInput->mou)
+ dmxInput->mou = dmxInputCopyLocal(
+ dmxLookupLocal(DMX_LOCAL_DEFAULT_POINTER));
+
+ dmxLogInput(dmxInput, "Using local (raw) device drivers: %s, %s\n",
+ dmxInput->kbd->name, dmxInput->mou->name);
+}
+
+void dmxInputInit(DMXInputInfo *dmxInput)
+{
+ DeviceIntPtr pKeyboard = NULL, pPointer = NULL;
+ dmxArg a;
+ const char *name;
+
+ dmxLogInput(dmxInput, "Initializing...\n");
+ a = dmxArgParse(dmxInput->name);
+
+ name = dmxArgV(a, 0);
+
+ if (!strcmp(name, "local")) dmxPopulateLocal(dmxInput, a);
+ else if (!strcmp(name, "dummy")) {
+ dmxInput->mou = dmxInputCopyLocal(&DMXDummyMou);
+ dmxInput->kbd = dmxInputCopyLocal(&DMXDummyKbd);
+ dmxInput->gen = NULL;
+ dmxLogInput(dmxInput, "Using dummy input\n");
+ } else {
+ int i, found;
+
+ for (found = 0, i = 0; i < dmxNumScreens; i++) {
+ if (!strcmp(dmxScreens[i].name, dmxInput->name)) {
+ if (dmxScreens[i].shared)
+ dmxLog(dmxFatal,
+ "Cannot take input from shared backend (%s)\n",
+ dmxInput->name);
+ dmxInput->mou = dmxInputCopyLocal(&DMXCommonMou);
+ dmxInput->kbd = dmxInputCopyLocal(&DMXCommonKbd);
+ dmxInput->gen = dmxInputCopyLocal(&DMXBackendGen);
+ dmxLogInput(dmxInput,
+ "Using backend input from %s\n", dmxInput->name);
+ ++found;
+ break;
+ }
+ }
+ if (!found) {
+ dmxInput->mou = dmxInputCopyLocal(&DMXCommonMou);
+ dmxInput->kbd = dmxInputCopyLocal(&DMXCommonKbd);
+ dmxInput->gen = dmxInputCopyLocal(&DMXConsoleGen);
+ dmxLogInput(dmxInput,
+ "Using console input from %s\n", dmxInput->name);
+ }
+ }
+
+ dmxArgFree(a);
+
+ if (dmxInput->gen && dmxInput->gen->create_gen_private)
+ dmxInput->gen->private = dmxInput->gen->create_gen_private(dmxInput);
+ if (dmxInput->gen && dmxInput->gen->initialize)
+ dmxInput->gen->initialize(dmxInput->gen->private);
+
+ pKeyboard = dmxAddKeyboard(dmxInput);
+ pPointer = dmxAddMouse(dmxInput);
+
+ mieqInit(&pKeyboard->public, &pPointer->public);
+
+ dmxInput->processInputEvents = dmxProcessInputEvents;
+ dmxInput->pKeyboard = pKeyboard;
+ dmxInput->pPointer = pPointer;
+
+ RegisterBlockAndWakeupHandlers(dmxBlockHandler,
+ dmxWakeupHandler,
+ dmxInput);
+
+
+ if (dmxInput->gen && dmxInput->gen->enable_device)
+ dmxInput->gen->enable_device(dmxInput->gen->private);
+
+ dmxLogInput(dmxInput, "Keyboard: %s; Pointer: %s\n",
+ pKeyboard->name, pPointer->name);
+}
+
+static void dmxInputFreeLocal(DMXLocalInputInfoRec *local)
+{
+ if (!local) return;
+ if (local->destroy_private) local->destroy_private(local->private);
+ local->private = NULL;
+ xfree(local);
+}
+
+void dmxInputFree(DMXInputInfo *dmxInput)
+{
+ if (!dmxInput) return;
+
+ dmxInputFreeLocal(dmxInput->kbd);
+ dmxInputFreeLocal(dmxInput->mou);
+ dmxInputFreeLocal(dmxInput->gen);
+
+ dmxInput->pKeyboard = NULL; /* Freed in dix/devices.c::CloseDownDevices */
+ dmxInput->pPointer = NULL; /* Freed in dix/devices.c::CloseDownDevices */
+ dmxInput->kbd = NULL;
+ dmxInput->mou = NULL;
+ dmxInput->gen = NULL;
+}
diff --git a/xc/programs/Xserver/hw/dmx/input/dmxinputinit.h b/xc/programs/Xserver/hw/dmx/input/dmxinputinit.h
new file mode 100644
index 000000000..596a0267e
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/dmxinputinit.h
@@ -0,0 +1,142 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef _DMXINPUTINIT_H_
+#define _DMXINPUTINIT_H_
+
+#include "dmx.h"
+#include "dmxinput.h"
+#include "dmxlog.h"
+
+#define DMX_LOCAL_DEFAULT_KEYBOARD "kbd"
+#define DMX_LOCAL_DEFAULT_POINTER "ps2"
+
+typedef enum {
+ DMX_FUNCTION_GRAB,
+ DMX_FUNCTION_TERMINATE,
+ DMX_FUNCTION_FINE
+} DMXFunctionType;
+
+ /* Generic -- high-level */
+typedef pointer (*dmxCreateGenPrivateProcPtr)(DMXInputInfo *);
+typedef void (*dmxDestroyGenPrivateProcPtr)(pointer);
+typedef void (*dmxInitializeProcPtr)(pointer);
+typedef void (*dmxEnableDeviceProcPtr)(pointer);
+typedef void (*dmxCollectEventsProcPtr)(pointer);
+typedef void (*dmxProcessInputProcPtr)(pointer);
+typedef int (*dmxFunctionsProcPtr)(pointer, DMXFunctionType);
+typedef void (*dmxUpdatePositionProcPtr)(pointer, int x, int y);
+
+ /* Low-level */
+typedef pointer (*dmxCreatePrivateProcPtr)(DeviceIntPtr);
+typedef void (*dmxDestroyPrivateProcPtr)(pointer);
+
+typedef void (*dmxInitProcPtr)(DevicePtr);
+typedef int (*dmxOnProcPtr)(DevicePtr);
+typedef void (*dmxOffProcPtr)(DevicePtr);
+
+typedef void (*dmxVTPreSwitchProcPtr)(pointer); /* Turn I/O Off */
+typedef void (*dmxVTPostSwitchProcPtr)(pointer); /* Turn I/O On */
+typedef void (*dmxVTSwitchReturnProcPtr)(pointer);
+typedef int (*dmxVTSwitchProcPtr)(pointer, int vt,
+ dmxVTSwitchReturnProcPtr, pointer);
+
+typedef void (*dmxEnqueueProcPtr)(xEvent *);
+typedef void (*dmxMotionProcPtr)(int x, int y, int relative);
+typedef int (*dmxCheckSpecialProcPtr)(pointer,
+ xEvent *, KeySym, unsigned short);
+typedef void (*dmxKBReadProcPtr)(pointer,
+ dmxEnqueueProcPtr,
+ dmxCheckSpecialProcPtr,
+ pointer);
+typedef void (*dmxMReadProcPtr)(pointer, dmxEnqueueProcPtr,
+ dmxMotionProcPtr);
+
+typedef pointer (*dmxGetkbmapProcPtr)(DevicePtr, KeySymsPtr, CARD8 *);
+typedef void (*dmxGetmmapProcPtr)(DevicePtr, unsigned char *, int *);
+
+typedef void (*dmxKBCtrlProcPtr)(DevicePtr, KeybdCtrl *ctrl);
+typedef void (*dmxMCtrlProcPtr)(DevicePtr, PtrCtrl *ctrl);
+
+typedef void (*dmxKBBellProcPtr)(DevicePtr, int percent,
+ int volume, int pitch, int duration);
+
+typedef enum {
+ DMX_LOCAL_HIGHLEVEL,
+ DMX_LOCAL_KEYBOARD,
+ DMX_LOCAL_MOUSE,
+ DMX_LOCAL_OTHER
+} DMXLocalInputType;
+
+typedef struct _DMXLocalInputInfo {
+ const char *name;
+ DMXLocalInputType type;
+
+ /* Low-level (e.g., keyboard/mouse drivers) */
+ dmxCreatePrivateProcPtr create_private;
+ dmxDestroyPrivateProcPtr destroy_private;
+ dmxInitProcPtr init;
+ dmxOnProcPtr on;
+ dmxOffProcPtr off;
+ dmxUpdatePositionProcPtr update_position;
+ dmxVTPreSwitchProcPtr vt_pre_switch;
+ dmxVTPostSwitchProcPtr vt_post_switch;
+ dmxVTSwitchProcPtr vt_switch;
+
+ dmxMReadProcPtr mRead;
+ dmxGetmmapProcPtr mGetmap;
+ dmxMCtrlProcPtr mCtrl;
+
+ dmxKBReadProcPtr kRead;
+ dmxGetkbmapProcPtr kGetmap;
+ dmxKBCtrlProcPtr kCtrl;
+ dmxKBBellProcPtr kBell;
+
+ /* High-level (e.g., X server proxy) */
+ dmxCreateGenPrivateProcPtr create_gen_private;
+ dmxDestroyGenPrivateProcPtr destroy_gen_private;
+ dmxInitializeProcPtr initialize;
+ dmxEnableDeviceProcPtr enable_device;
+ dmxCollectEventsProcPtr collect_events;
+ dmxProcessInputProcPtr process_input;
+ dmxFunctionsProcPtr functions;
+
+ pointer private;
+ KeybdCtrl kctrl;
+ PtrCtrl mctrl;
+} DMXLocalInputInfoRec;
+
+extern void dmxLocalInitInput(DMXInputInfo *dmxInput);
+
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/input/dmxsigio.c b/xc/programs/Xserver/hw/dmx/input/dmxsigio.c
new file mode 100644
index 000000000..03ac3d5f3
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/dmxsigio.c
@@ -0,0 +1,202 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#include "dmxinputinit.h"
+#include "dmxsigio.h"
+#include "dmxevents.h"
+#include <signal.h>
+#include <unistd.h>
+#include <sys/fcntl.h>
+
+static int dmxFdCount = 0;
+static Bool dmxInputEnabled = TRUE;
+
+static void dmxSigioHandler(int sig)
+{
+ int i;
+ DMXInputInfo *dmxInput;
+
+ for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) {
+ if (dmxInput->sigioState == DMX_ACTIVESIGIO) {
+ if (dmxInput->kbd->kRead)
+ dmxInput->kbd->kRead(dmxInput->kbd->private,
+ dmxEnqueueRawEvent,
+ dmxCheckSpecialKeys,
+ dmxInput);
+ if (dmxInput->mou->mRead)
+ dmxInput->mou->mRead(dmxInput->mou->private,
+ dmxEnqueueRawEvent,
+ dmxMotion);
+ }
+ }
+}
+
+void dmxSigioBlock(void)
+{
+ sigset_t s;
+
+ sigemptyset(&s);
+ sigaddset(&s, SIGIO);
+ sigprocmask(SIG_BLOCK, &s, 0);
+}
+
+void dmxSigioUnblock(void)
+{
+ sigset_t s;
+
+ sigemptyset(&s);
+ sigaddset(&s, SIGIO);
+ sigprocmask(SIG_UNBLOCK, &s, 0);
+}
+
+static void dmxSigioHook(void)
+{
+ struct sigaction a;
+ sigset_t s;
+
+ memset(&a, 0, sizeof(a));
+ a.sa_handler = dmxSigioHandler;
+ sigemptyset(&a.sa_mask);
+ sigaddset(&a.sa_mask, SIGIO);
+ sigaddset(&a.sa_mask, SIGALRM);
+ sigaddset(&a.sa_mask, SIGVTALRM);
+ sigaction(SIGIO, &a, 0);
+
+ sigemptyset(&s);
+ sigprocmask(SIG_SETMASK, &s, 0);
+}
+
+static void dmxSigioUnhook(void)
+{
+ struct sigaction a;
+
+ memset (&a, 0, sizeof(a));
+ a.sa_handler = SIG_IGN;
+ sigemptyset(&a.sa_mask);
+ sigaction(SIGIO, &a, 0);
+}
+
+static void dmxSigioAdd(DMXInputInfo *dmxInput)
+{
+ int flags;
+ int i;
+
+ switch (dmxInput->sigioState) {
+ case DMX_NOSIGIO: return;
+ case DMX_USESIGIO: dmxInput->sigioState = DMX_ACTIVESIGIO; break;
+ case DMX_ACTIVESIGIO: return;
+ }
+
+ for (i = 0; i < dmxInput->sigioFdCount; i++) {
+ if (!dmxInput->sigioAdded[i]) {
+ int fd = dmxInput->sigioFd[i];
+
+ fcntl(fd, F_SETOWN, getpid());
+ flags = fcntl(fd, F_GETFL);
+ flags |= O_ASYNC|O_NONBLOCK;
+ fcntl(fd, F_SETFL, flags);
+
+ AddEnabledDevice(fd);
+ dmxInput->sigioAdded[i] = TRUE;
+
+ if (++dmxFdCount == 1) dmxSigioHook();
+ }
+ }
+}
+
+static void dmxSigioRemove(DMXInputInfo *dmxInput)
+{
+ int flags;
+ int i;
+
+ switch (dmxInput->sigioState) {
+ case DMX_NOSIGIO: return;
+ case DMX_USESIGIO: return;
+ case DMX_ACTIVESIGIO: dmxInput->sigioState = DMX_USESIGIO; break;
+ }
+
+ for (i = 0; i < dmxInput->sigioFdCount; i++) {
+ if (dmxInput->sigioAdded[i]) {
+ int fd = dmxInput->sigioFd[i];
+
+ dmxInput->sigioAdded[i] = FALSE;
+ RemoveEnabledDevice(fd);
+
+ flags = fcntl(fd, F_GETFL);
+ flags &= ~(O_ASYNC|O_NONBLOCK);
+ fcntl(fd, F_SETFL, flags);
+
+ if (!--dmxFdCount) dmxSigioUnhook();
+ }
+ }
+}
+
+void dmxSigioEnableInput(void)
+{
+ int i;
+ DMXInputInfo *dmxInput;
+
+ dmxInputEnabled = TRUE;
+ for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++)
+ dmxSigioAdd(dmxInput);
+}
+
+void dmxSigioDisableInput(void)
+{
+ int i;
+ DMXInputInfo *dmxInput;
+
+ dmxInputEnabled = FALSE;
+ for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++)
+ dmxSigioRemove(dmxInput);
+}
+
+void dmxSigioRegister(DMXInputInfo *dmxInput, int fd)
+{
+ dmxInput->sigioState = DMX_USESIGIO;
+ if (dmxInput->sigioFdCount >= DMX_MAX_SIGIO_FDS)
+ dmxLog(dmxFatal, "Too many SIGIO file descriptors (%d >= %d)\n",
+ dmxInput->sigioFdCount, DMX_MAX_SIGIO_FDS);
+
+ dmxInput->sigioFd[dmxInput->sigioFdCount++] = fd;
+ if (dmxInputEnabled) dmxSigioAdd(dmxInput);
+}
+
+void dmxSigioUnregister(DMXInputInfo *dmxInput)
+{
+ if (dmxInput->sigioState == DMX_NOSIGIO) return;
+ dmxSigioRemove(dmxInput);
+ dmxInput->sigioState = DMX_NOSIGIO;
+ dmxInput->sigioFdCount = 0;
+}
diff --git a/xc/programs/Xserver/hw/dmx/input/dmxsigio.h b/xc/programs/Xserver/hw/dmx/input/dmxsigio.h
new file mode 100644
index 000000000..d8830daab
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/dmxsigio.h
@@ -0,0 +1,43 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef _DMXSIGIO_H_
+#define _DMXSIGIO_H_
+extern void dmxSigioBlock(void);
+extern void dmxSigioUnblock(void);
+extern void dmxSigioEnableInput(void);
+extern void dmxSigioDisableInput(void);
+extern void dmxSigioRegister(DMXInputInfo *dmxInput, int fd);
+extern void dmxSigioUnregister(DMXInputInfo *dmxInput);
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/input/dmxxtest.c b/xc/programs/Xserver/hw/dmx/input/dmxxtest.c
new file mode 100644
index 000000000..3c6dee420
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/dmxxtest.c
@@ -0,0 +1,138 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ * See Xserver/Xext/xtest1.frags, Xserver/hw/hp/input/x_hil.c, and
+ * Xserver/hw/xfree86/common/xf86Evetns.c for examples from which this
+ * code was derived. This file serves to encapsulate all of the
+ * XTest-related symbols and functions to minimize clutter in the other
+ * files.
+ *
+ * Note that sufficient support for playback_on appears to be in
+ * Xserver/os/WaitFor.c, and so isn't handled here. FIXME?
+ *
+ */
+
+#ifdef XTESTEXT1
+#include "dmxinputinit.h"
+#include "mipointer.h"
+#include "xtestext1.h"
+#include "xtest1dd.h"
+#include "dmxxtest.h"
+#if 0
+#include "inputstr.h"
+#include "input.h"
+#include "mi.h"
+#include "keysym.h"
+#include "opaque.h"
+#include "inputstr.h"
+#endif
+
+extern int on_steal_input;
+extern KeyCode xtest_command_key;
+extern Bool XTestStealKeyData(unsigned keycode, int keystate,
+ int dev_type, int locx, int locy);
+extern void XTestStealMotionData(int dx, int dy, int dev_type,
+ int mx, int my);
+
+void dmxXTestValidKeyCode(KeyCode code)
+{
+ xtest_command_key = code;
+}
+
+int dmxXTestEvent(xEvent *xE)
+{
+ int x, y;
+ int dx, dy;
+
+ miPointerPosition(&x, &y);
+ switch (xE->u.u.type) {
+ case KeyPress:
+ case KeyRelease:
+ if (!on_steal_input
+ || XTestStealKeyData(xE->u.u.detail, xE->u.u.type,
+ XTestKEY_ACTION, x, y)) return 1;
+ break;
+ case MotionNotify:
+ if (on_steal_input) {
+ if (xE->u.keyButtonPointer.pad1) {
+ dx = xE->u.keyButtonPointer.rootX;
+ dy = xE->u.keyButtonPointer.rootY;
+ } else {
+ dx = xE->u.keyButtonPointer.rootX - x;
+ dy = xE->u.keyButtonPointer.rootY - y;
+ }
+ XTestStealMotionData(dx, dy, XTestMOTION_ACTION, x, y);
+ }
+ break;
+ }
+ return 0;
+}
+
+void XTestGenerateEvent(int dev_type, int keycode, int keystate,
+ int mousex, int mousey)
+{
+ xEvent x;
+
+ dmxLog(dmxDebug, "XTestGenerateEvent %d @ %d %d\n",
+ dev_type, keycode, mousex, mousey);
+ switch (dev_type) {
+ case XTestMOTION_ACTION:
+ x.u.u.type = (keystate == XTestKEY_UP) ? ButtonRelease : ButtonPress;
+ break;
+ case XTestKEY_ACTION:
+ default:
+ x.u.u.type = (keystate == XTestKEY_UP) ? KeyRelease : KeyPress;
+ break;
+ }
+ x.u.u.detail = keycode;
+ x.u.keyButtonPointer.rootX = mousex;
+ x.u.keyButtonPointer.rootY = mousey;
+ x.u.keyButtonPointer.time = GetTimeInMillis();
+ dmxEnqueueRawEvent(&x); /* FIXME: call mieqEnqueue directly? */
+}
+
+void XTestGetPointerPos(short *fmousex, short *fmousey)
+{
+ int x, y;
+
+ miPointerPosition(&x, &y);
+ *fmousex = x;
+ *fmousey = y;
+ dmxLog(dmxDebug, "XTestGetPointerPos %d %d\n", x, y);
+}
+
+void XTestJumpPointer(int jx, int jy, int dev_type)
+{
+ dmxLog(dmxDebug, "XTestJumpPointer %d %d\n", jx, jy);
+ miPointerAbsoluteCursor(jx, jy, GetTimeInMillis());
+}
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/input/dmxxtest.h b/xc/programs/Xserver/hw/dmx/input/dmxxtest.h
new file mode 100644
index 000000000..7133e8b3e
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/dmxxtest.h
@@ -0,0 +1,41 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef _DMXXTEST_H_
+#define _DMXXTEST_H_
+#ifdef XTESTEXT1
+extern void dmxXTestValidKeyCode(KeyCode code);
+extern int dmxXTestEvent(xEvent *xE);
+#endif
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/input/lnx-keyboard.c b/xc/programs/Xserver/hw/dmx/input/lnx-keyboard.c
new file mode 100644
index 000000000..33583aee6
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/lnx-keyboard.c
@@ -0,0 +1,966 @@
+/* $XFree86$ */
+/* Portions of this file were derived from the following files:
+ *
+ **********************************************************************
+ *
+ * xfree86/common/{xf86Io.c,xf86Kbd.c,xf86Events.c}
+ *
+ * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
+ *
+ * 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 Thomas Roell not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Thomas Roell makes no representations
+ * about the suitability of this software for any purpose. It is provided
+ * "as is" without express or implied warranty.
+ *
+ * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THOMAS ROELL 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.
+ *
+ **********************************************************************
+ *
+ * xfree86/common/xf86KbdLnx.c
+ *
+ * Linux version of keymapping setup. The kernel (since 0.99.14) has support
+ * for fully remapping the keyboard, but there are some differences between
+ * the Linux map and the SVR4 map (esp. in the extended keycodes). We also
+ * remove the restriction on what keycodes can be remapped.
+ * Orest Zborowski.
+ *
+ * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
+ *
+ * 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 Thomas Roell not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Thomas Roell makes no representations
+ * about the suitability of this software for any purpose. It is provided
+ * "as is" without express or implied warranty.
+ *
+ * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THOMAS ROELL 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.
+ *
+ **********************************************************************
+ *
+ * xfree86/os-support/linux/lnx_io.c
+ *
+ * Copyright 1992 by Orest Zborowski <obz@Kodak.com>
+ * Copyright 1993 by David Dawes <dawes@xfree86.org>
+ *
+ * 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 names of Orest Zborowski and David Dawes
+ * not be used in advertising or publicity pertaining to distribution of
+ * the software without specific, written prior permission. Orest Zborowski
+ * and David Dawes make no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * OREST ZBOROWSKI AND DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD
+ * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL OREST ZBOROWSKI OR DAVID DAWES 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.
+ *
+ */
+
+/*
+ * Copyright 2001 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#include "inputstr.h"
+#include "input.h"
+#include "Xos.h"
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/vt.h>
+#include <sys/kd.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "atKeynames.h"
+#include "xf86Keymap.h"
+#include <linux/keyboard.h>
+
+#define NUM_AT2LNX (sizeof(at2lnx) / sizeof(at2lnx[0]))
+#define NUM_STATE_ENTRIES (256/32)
+
+/*****************************************************************************/
+/* Define some macros to make it easier to move this file to another
+ * part of the Xserver tree. All calls to the dmx* layer are #defined
+ * here for the .c file. The .h file will also have to be edited. */
+#include "dmxinputinit.h"
+#include "lnx-keyboard.h"
+
+#define GETPRIV myPrivate *priv \
+ = ((DMXLocalInputInfoPtr) \
+ ((DMXInputInfo *) \
+ (pDev->devicePrivate))->kbd)->private
+
+#define LOG0(f) dmxLog(dmxDebug,f)
+#define LOG1(f,a) dmxLog(dmxDebug,f,a)
+#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b)
+#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c)
+#define FATAL0(f) dmxLog(dmxFatal,f)
+#define FATAL1(f,a) dmxLog(dmxFatal,f,a)
+#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b)
+#define ENQUEUEPROC dmxEnqueueProcPtr
+#define CHECKPROC dmxCheckSpecialProcPtr
+#define SWITCHRETPROC dmxVTSwitchReturnProcPtr
+#define MESSAGE "\033c\n\n\nDMX taking input from this console..."
+#define FINALMESSAGE "\033cDMX terminated."
+
+/* End of interface definitions. */
+/*****************************************************************************/
+
+typedef struct _myPrivate {
+ int fd;
+ int vtno;
+ int vtcurrent;
+ int kbdtrans;
+ struct termios kbdtty;
+ int kbdType;
+ CARD32 kbdState[NUM_STATE_ENTRIES];
+ CARD32 modState;
+ DeviceIntPtr pKeyboard;
+ unsigned char prefix;
+
+ int switched;
+ SWITCHRETPROC switch_return;
+ void *switch_return_data;
+
+ /* For bell */
+ int pitch;
+ unsigned long duration;
+} myPrivate;
+
+static myPrivate *PRIV = NULL;
+
+#undef SYSCALL
+#define SYSCALL(call) while(((call) == -1) && (errno == EINTR))
+
+static int kbdLinuxKeyDown(myPrivate *priv, xEvent *xE)
+{
+ CARD8 key = xE->u.u.detail;
+ CARD8 byte = key >> 5;
+ CARD32 bit = 1 << (key & 0x1f);
+
+ if (byte > NUM_STATE_ENTRIES) return 0;
+ return priv->kbdState[byte] & bit;
+}
+
+static void kbdLinuxKeyState(myPrivate *priv, xEvent *xE)
+{
+ CARD8 key = xE->u.u.detail;
+ CARD8 byte = key >> 5;
+ CARD32 bit = 1 << (key & 0x1f);
+
+ if (byte > NUM_STATE_ENTRIES) return;
+ if (xE->u.u.type == KeyPress) priv->kbdState[byte] |= bit;
+ else priv->kbdState[byte] &= ~bit;
+}
+
+static KeySym linux_to_x[256] = {
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ XK_BackSpace, XK_Tab, XK_Linefeed, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, XK_Escape,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ XK_space, XK_exclam, XK_quotedbl, XK_numbersign,
+ XK_dollar, XK_percent, XK_ampersand, XK_apostrophe,
+ XK_parenleft, XK_parenright, XK_asterisk, XK_plus,
+ XK_comma, XK_minus, XK_period, XK_slash,
+ XK_0, XK_1, XK_2, XK_3,
+ XK_4, XK_5, XK_6, XK_7,
+ XK_8, XK_9, XK_colon, XK_semicolon,
+ XK_less, XK_equal, XK_greater, XK_question,
+ XK_at, XK_A, XK_B, XK_C,
+ XK_D, XK_E, XK_F, XK_G,
+ XK_H, XK_I, XK_J, XK_K,
+ XK_L, XK_M, XK_N, XK_O,
+ XK_P, XK_Q, XK_R, XK_S,
+ XK_T, XK_U, XK_V, XK_W,
+ XK_X, XK_Y, XK_Z, XK_bracketleft,
+ XK_backslash, XK_bracketright,XK_asciicircum, XK_underscore,
+ XK_grave, XK_a, XK_b, XK_c,
+ XK_d, XK_e, XK_f, XK_g,
+ XK_h, XK_i, XK_j, XK_k,
+ XK_l, XK_m, XK_n, XK_o,
+ XK_p, XK_q, XK_r, XK_s,
+ XK_t, XK_u, XK_v, XK_w,
+ XK_x, XK_y, XK_z, XK_braceleft,
+ XK_bar, XK_braceright, XK_asciitilde, XK_BackSpace,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ XK_nobreakspace,XK_exclamdown, XK_cent, XK_sterling,
+ XK_currency, XK_yen, XK_brokenbar, XK_section,
+ XK_diaeresis, XK_copyright, XK_ordfeminine, XK_guillemotleft,
+ XK_notsign, XK_hyphen, XK_registered, XK_macron,
+ XK_degree, XK_plusminus, XK_twosuperior, XK_threesuperior,
+ XK_acute, XK_mu, XK_paragraph, XK_periodcentered,
+ XK_cedilla, XK_onesuperior, XK_masculine, XK_guillemotright,
+ XK_onequarter, XK_onehalf, XK_threequarters,XK_questiondown,
+ XK_Agrave, XK_Aacute, XK_Acircumflex, XK_Atilde,
+ XK_Adiaeresis, XK_Aring, XK_AE, XK_Ccedilla,
+ XK_Egrave, XK_Eacute, XK_Ecircumflex, XK_Ediaeresis,
+ XK_Igrave, XK_Iacute, XK_Icircumflex, XK_Idiaeresis,
+ XK_ETH, XK_Ntilde, XK_Ograve, XK_Oacute,
+ XK_Ocircumflex, XK_Otilde, XK_Odiaeresis, XK_multiply,
+ XK_Ooblique, XK_Ugrave, XK_Uacute, XK_Ucircumflex,
+ XK_Udiaeresis, XK_Yacute, XK_THORN, XK_ssharp,
+ XK_agrave, XK_aacute, XK_acircumflex, XK_atilde,
+ XK_adiaeresis, XK_aring, XK_ae, XK_ccedilla,
+ XK_egrave, XK_eacute, XK_ecircumflex, XK_ediaeresis,
+ XK_igrave, XK_iacute, XK_icircumflex, XK_idiaeresis,
+ XK_eth, XK_ntilde, XK_ograve, XK_oacute,
+ XK_ocircumflex, XK_otilde, XK_odiaeresis, XK_division,
+ XK_oslash, XK_ugrave, XK_uacute, XK_ucircumflex,
+ XK_udiaeresis, XK_yacute, XK_thorn, XK_ydiaeresis
+};
+
+/*
+ * Maps the AT keycodes to Linux keycodes
+ */
+static unsigned char at2lnx[NUM_KEYCODES] =
+{
+ 0x01, /* KEY_Escape */ 0x02, /* KEY_1 */
+ 0x03, /* KEY_2 */ 0x04, /* KEY_3 */
+ 0x05, /* KEY_4 */ 0x06, /* KEY_5 */
+ 0x07, /* KEY_6 */ 0x08, /* KEY_7 */
+ 0x09, /* KEY_8 */ 0x0a, /* KEY_9 */
+ 0x0b, /* KEY_0 */ 0x0c, /* KEY_Minus */
+ 0x0d, /* KEY_Equal */ 0x0e, /* KEY_BackSpace */
+ 0x0f, /* KEY_Tab */ 0x10, /* KEY_Q */
+ 0x11, /* KEY_W */ 0x12, /* KEY_E */
+ 0x13, /* KEY_R */ 0x14, /* KEY_T */
+ 0x15, /* KEY_Y */ 0x16, /* KEY_U */
+ 0x17, /* KEY_I */ 0x18, /* KEY_O */
+ 0x19, /* KEY_P */ 0x1a, /* KEY_LBrace */
+ 0x1b, /* KEY_RBrace */ 0x1c, /* KEY_Enter */
+ 0x1d, /* KEY_LCtrl */ 0x1e, /* KEY_A */
+ 0x1f, /* KEY_S */ 0x20, /* KEY_D */
+ 0x21, /* KEY_F */ 0x22, /* KEY_G */
+ 0x23, /* KEY_H */ 0x24, /* KEY_J */
+ 0x25, /* KEY_K */ 0x26, /* KEY_L */
+ 0x27, /* KEY_SemiColon */ 0x28, /* KEY_Quote */
+ 0x29, /* KEY_Tilde */ 0x2a, /* KEY_ShiftL */
+ 0x2b, /* KEY_BSlash */ 0x2c, /* KEY_Z */
+ 0x2d, /* KEY_X */ 0x2e, /* KEY_C */
+ 0x2f, /* KEY_V */ 0x30, /* KEY_B */
+ 0x31, /* KEY_N */ 0x32, /* KEY_M */
+ 0x33, /* KEY_Comma */ 0x34, /* KEY_Period */
+ 0x35, /* KEY_Slash */ 0x36, /* KEY_ShiftR */
+ 0x37, /* KEY_KP_Multiply */ 0x38, /* KEY_Alt */
+ 0x39, /* KEY_Space */ 0x3a, /* KEY_CapsLock */
+ 0x3b, /* KEY_F1 */ 0x3c, /* KEY_F2 */
+ 0x3d, /* KEY_F3 */ 0x3e, /* KEY_F4 */
+ 0x3f, /* KEY_F5 */ 0x40, /* KEY_F6 */
+ 0x41, /* KEY_F7 */ 0x42, /* KEY_F8 */
+ 0x43, /* KEY_F9 */ 0x44, /* KEY_F10 */
+ 0x45, /* KEY_NumLock */ 0x46, /* KEY_ScrollLock */
+ 0x47, /* KEY_KP_7 */ 0x48, /* KEY_KP_8 */
+ 0x49, /* KEY_KP_9 */ 0x4a, /* KEY_KP_Minus */
+ 0x4b, /* KEY_KP_4 */ 0x4c, /* KEY_KP_5 */
+ 0x4d, /* KEY_KP_6 */ 0x4e, /* KEY_KP_Plus */
+ 0x4f, /* KEY_KP_1 */ 0x50, /* KEY_KP_2 */
+ 0x51, /* KEY_KP_3 */ 0x52, /* KEY_KP_0 */
+ 0x53, /* KEY_KP_Decimal */ 0x54, /* KEY_SysReqest */
+ 0x00, /* 0x55 */ 0x56, /* KEY_Less */
+ 0x57, /* KEY_F11 */ 0x58, /* KEY_F12 */
+ 0x66, /* KEY_Home */ 0x67, /* KEY_Up */
+ 0x68, /* KEY_PgUp */ 0x69, /* KEY_Left */
+ 0x5d, /* KEY_Begin */ 0x6a, /* KEY_Right */
+ 0x6b, /* KEY_End */ 0x6c, /* KEY_Down */
+ 0x6d, /* KEY_PgDown */ 0x6e, /* KEY_Insert */
+ 0x6f, /* KEY_Delete */ 0x60, /* KEY_KP_Enter */
+ 0x61, /* KEY_RCtrl */ 0x77, /* KEY_Pause */
+ 0x63, /* KEY_Print */ 0x62, /* KEY_KP_Divide */
+ 0x64, /* KEY_AltLang */ 0x65, /* KEY_Break */
+ 0x00, /* KEY_LMeta */ 0x00, /* KEY_RMeta */
+ 0x7A, /* KEY_Menu/FOCUS_PF11*/0x00, /* 0x6e */
+ 0x7B, /* FOCUS_PF12 */ 0x00, /* 0x70 */
+ 0x00, /* 0x71 */ 0x00, /* 0x72 */
+ 0x59, /* FOCUS_PF2 */ 0x78, /* FOCUS_PF9 */
+ 0x00, /* 0x75 */ 0x00, /* 0x76 */
+ 0x5A, /* FOCUS_PF3 */ 0x5B, /* FOCUS_PF4 */
+ 0x5C, /* FOCUS_PF5 */ 0x5D, /* FOCUS_PF6 */
+ 0x5E, /* FOCUS_PF7 */ 0x5F, /* FOCUS_PF8 */
+ 0x7C, /* JAP_86 */ 0x79, /* FOCUS_PF10 */
+ 0x00, /* 0x7f */
+};
+
+pointer kbdLinuxCreatePrivate(DeviceIntPtr pKeyboard)
+{
+ myPrivate *priv = xalloc(sizeof(*priv));
+ memset(priv, 0, sizeof(*priv));
+ priv->fd = -1;
+ priv->pKeyboard = pKeyboard;
+ return priv;
+}
+
+void kbdLinuxDestroyPrivate(pointer priv)
+{
+ if (priv) xfree(priv);
+}
+
+void kbdLinuxBell(DevicePtr pDev, int percent,
+ int volume, int pitch, int duration)
+{
+ GETPRIV;
+
+ /* Note: we completely ignore the volume, since the ioctl interface
+ * does not provide a way to control it. If it did, the XBell
+ * manpage tells how the actual volume is a function of the percent
+ * and the (base) volume.
+ *
+ * I should note that all of the other PC-based bell drivers compute
+ * the duration for KDMKTONE as a function of the volume and the
+ * duration. For some drivers, the duration is only measured in
+ * msec if the volume is 50, and is scaled by the volume for other
+ * values. This seems confusing and possibly incorrect (the xset
+ * man page says that the bell will be "as closely as it can to the
+ * user's specifications" -- if we ignore the volume and set the
+ * duration correctly, then we'll get one parameter "wrong" -- but
+ * if we use the volume to scale the duration, then we'll get both
+ * parameters "wrong").
+ */
+
+ if (duration && pitch) {
+ ioctl(priv->fd,
+ KDMKTONE,
+ ((1193190 / pitch) & 0xffff) /* Low bits specify cycle time */
+ | (duration << 16)); /* High bits are duration in msec */
+ }
+}
+
+void kbdLinuxCtrl(DevicePtr pDev, KeybdCtrl *ctrl)
+{
+ GETPRIV;
+
+ ioctl(priv->fd, KDSETLED, ctrl->leds & 0x07);
+}
+
+Bool kbdLinuxLegalModifier(unsigned int key, DevicePtr pDev)
+{
+ return TRUE;
+}
+
+static int kbdLinuxGetFreeVTNumber(void)
+{
+ int fd = -1;
+ int vtno;
+ int i;
+ const char *tty0[] = { "/dev/tty0", "/dev/vc/0", NULL };
+
+ for (i = 0; tty0[i]; i++)
+ if ((fd = open(tty0[i], O_WRONLY, 0)) >= 0) break;
+ if (fd < 0)
+ FATAL1("kbdLinuxGetFreeVTNumber: Cannot open tty0 (%s)\n",
+ strerror(errno));
+ if (ioctl(fd, VT_OPENQRY, &vtno) < 0 || vtno < 0)
+ FATAL0("kbdLinuxGetFreeVTNumber: Cannot find a free VT\n");
+ return vtno;
+}
+
+static int kbdLinuxOpenVT(int vtno)
+{
+ int fd = -1;
+ int i;
+ const char *vcs[] = { "/dev/vc/%d", "/dev/tty%d", NULL };
+ char name[32];
+
+ for (i = 0; vcs[i]; i++) {
+ sprintf(name, vcs[i], vtno);
+ if ((fd = open(name, O_RDWR | O_NONBLOCK, 0)) >= 0) break;
+ }
+ if (fd < 0)
+ FATAL2("kbdLinuxOpenVT: Cannot open VT %d (%s)\n",
+ vtno, strerror(errno));
+ return fd;
+}
+
+static int kbdLinuxGetCurrentVTNumber(int fd)
+{
+ struct vt_stat vts;
+
+ if (!ioctl(fd, VT_GETSTATE, &vts)) return vts.v_active;
+ return -1;
+}
+
+static int kbdLinuxActivate(int fd, int vtno, int setSig);
+
+void kbdLinuxVTPreSwitch(pointer p)
+{
+}
+
+void kbdLinuxVTPostSwitch(pointer p)
+{
+}
+
+int kbdLinuxVTSwitch(pointer p, int vt,
+ void (*switch_return)(pointer),
+ pointer switch_return_data)
+{
+ myPrivate *priv = p;
+
+ if (priv->switched) FATAL0("kbdLinuxVTSwitch: already switched...\n");
+ if (priv->vtno == vt) return 0;
+
+ PRIV = priv;
+ priv->switched = 0; /* Will switch to 1 in handler */
+ priv->switch_return = switch_return;
+ priv->switch_return_data = switch_return_data;
+ kbdLinuxActivate(priv->fd, vt, 0);
+ return 1;
+}
+
+static void kbdLinuxVTSignalHandler(int sig)
+{
+ myPrivate *priv = PRIV;
+
+ signal(sig, kbdLinuxVTSignalHandler);
+ if (priv) {
+ ioctl(priv->fd, VT_RELDISP, VT_ACKACQ);
+ priv->switched = !priv->switched;
+ LOG2("kbdLinuxVTSignalHandler: got signal %d, switched = %d\n",
+ sig, priv->switched);
+ if (!priv->switched && priv->switch_return)
+ priv->switch_return(priv->switch_return_data);
+ }
+}
+
+static int kbdLinuxActivate(int fd, int vtno, int setSig)
+{
+ int result;
+ struct vt_mode VT;
+
+ SYSCALL(result = ioctl(fd, VT_ACTIVATE, vtno));
+ if (result) FATAL0("kbdLinuxActivate: VT_ACTIVATE failed\n");
+ SYSCALL(result = ioctl(fd, VT_WAITACTIVE, vtno));
+ if (result) FATAL0("kbdLinuxActivate: VT_WAITACTIVE failed\n");
+ if (setSig) {
+ SYSCALL(result = ioctl(fd, VT_GETMODE, &VT));
+ if (result < 0) FATAL0("kbdLinuxActivate: VT_GETMODE failed\n");
+ VT.mode = VT_PROCESS;
+ VT.relsig = SIGUSR1;
+ VT.acqsig = SIGUSR1;
+ if (ioctl(fd, VT_SETMODE, &VT))
+ FATAL0("kbdLinuxActivate: VT_SETMODE VT_PROCESS failed\n");
+ signal(SIGUSR1, kbdLinuxVTSignalHandler);
+ }
+ return Success;
+}
+
+static void kbdLinuxOpenConsole(DevicePtr pDev)
+{
+ GETPRIV;
+ char *msg = MESSAGE;
+
+ if (priv->fd >= 0) return;
+ priv->vtno = kbdLinuxGetFreeVTNumber();
+ priv->fd = kbdLinuxOpenVT(priv->vtno);
+ priv->vtcurrent = kbdLinuxGetCurrentVTNumber(priv->fd);
+ LOG2("kbdLinuxOpenConsole: current VT %d; using free VT %d\n",
+ priv->vtcurrent, priv->vtno);
+ kbdLinuxActivate(priv->fd, priv->vtno, 1);
+ ioctl(priv->fd, KDSETMODE, KD_GRAPHICS); /* To turn off gpm */
+ if (msg) write(priv->fd, msg, strlen(msg));
+}
+
+static void kbdLinuxCloseConsole(DevicePtr pDev)
+{
+ GETPRIV;
+ struct vt_mode VT;
+ char *msg = FINALMESSAGE;
+
+ if (priv->fd < 0) return;
+
+ ioctl(priv->fd, KDSETMODE, KD_TEXT);
+ if (msg) write(priv->fd, msg, strlen(msg));
+ if (ioctl(priv->fd, VT_GETMODE, &VT) != -1) {
+ VT.mode = VT_AUTO;
+ ioctl(priv->fd, VT_SETMODE, &VT);
+ }
+
+ LOG1("kbdLinuxCloseConsole: switching to VT %d\n", priv->vtcurrent);
+ if (priv->vtcurrent >= 0) kbdLinuxActivate(priv->fd, priv->vtcurrent, 0);
+
+ close(priv->fd);
+ priv->fd = -1;
+}
+
+void kbdLinuxInit(DevicePtr pDev)
+{
+ GETPRIV;
+
+ if (priv->fd <= 0) kbdLinuxOpenConsole(pDev);
+
+ ioctl(priv->fd, KDGKBMODE, &priv->kbdtrans);
+ if (tcgetattr(priv->fd, &priv->kbdtty) < 0)
+ FATAL1("kbdLinuxInit: tcgetattr failed (%s)\n", strerror(errno));
+}
+
+#if 0
+/* FIXME: delete */
+static int kbdLinuxModIgnore(myPrivate *priv, xEvent *xE, KeySym keySym)
+{
+ int mask = 0;
+ int old, new;
+
+ switch (keySym) {
+ case XK_Num_Lock: mask = (1 << 0); break;
+ case XK_Scroll_Lock: mask = (1 << 1); break;
+ case XK_Shift_Lock: mask = (1 << 2); break;
+ case XK_Caps_Lock: mask = (1 << 3); break;
+ }
+
+ old = priv->modState & mask;
+ if (xE->u.u.type == KeyPress) priv->modState |= mask;
+ else priv->modState &= ~mask;
+ new = priv->modState & mask;
+
+ if (old == new || xE->u.u.type == KeyRelease) return 1;
+ return 0;
+}
+#endif
+
+
+static int kbdLinuxPrefix0Mapping(unsigned char *scanCode)
+{
+ /* Table from xfree86/common/xf86Events.c */
+ switch (*scanCode) {
+ case KEY_KP_7: *scanCode = KEY_Home; break; /* curs home */
+ case KEY_KP_8: *scanCode = KEY_Up; break; /* curs up */
+ case KEY_KP_9: *scanCode = KEY_PgUp; break; /* curs pgup */
+ case KEY_KP_4: *scanCode = KEY_Left; break; /* curs left */
+ case KEY_KP_5: *scanCode = KEY_Begin; break; /* curs begin */
+ case KEY_KP_6: *scanCode = KEY_Right; break; /* curs right */
+ case KEY_KP_1: *scanCode = KEY_End; break; /* curs end */
+ case KEY_KP_2: *scanCode = KEY_Down; break; /* curs down */
+ case KEY_KP_3: *scanCode = KEY_PgDown; break; /* curs pgdown */
+ case KEY_KP_0: *scanCode = KEY_Insert; break; /* curs insert */
+ case KEY_KP_Decimal: *scanCode = KEY_Delete; break; /* curs delete */
+ case KEY_Enter: *scanCode = KEY_KP_Enter; break; /* keypad enter */
+ case KEY_LCtrl: *scanCode = KEY_RCtrl; break; /* right ctrl */
+ case KEY_KP_Multiply: *scanCode = KEY_Print; break; /* print */
+ case KEY_Slash: *scanCode = KEY_KP_Divide; break; /* keyp divide */
+ case KEY_Alt: *scanCode = KEY_AltLang; break; /* right alt */
+ case KEY_ScrollLock: *scanCode = KEY_Break; break; /* curs break */
+ case 0x5b: *scanCode = KEY_LMeta; break;
+ case 0x5c: *scanCode = KEY_RMeta; break;
+ case 0x5d: *scanCode = KEY_Menu; break;
+ case KEY_F3: *scanCode = KEY_F13; break;
+ case KEY_F4: *scanCode = KEY_F14; break;
+ case KEY_F5: *scanCode = KEY_F15; break;
+ case KEY_F6: *scanCode = KEY_F16; break;
+ case KEY_F7: *scanCode = KEY_F17; break;
+ case KEY_KP_Plus: *scanCode = KEY_KP_DEC; break;
+ /*
+ * Ignore virtual shifts (E0 2A, E0 AA, E0 36, E0 B6)
+ */
+ case 0x2A:
+ case 0x36:
+ return 1;
+ default:
+ /*
+ * "Internet" keyboards are generating lots of new codes.
+ * Let them pass. There is little consistency between them,
+ * so don't bother with symbolic names at this level.
+ */
+ scanCode += 0x78;
+ }
+ return 0;
+}
+
+static int kbdLinuxPrefixMapping(myPrivate *priv, unsigned char *scanCode)
+{
+ int pressed = *scanCode & 0x80;
+ unsigned char code = *scanCode & 0x7f;
+
+ /* If we don't have a prefix, check for one */
+ if (!priv->prefix) {
+ switch (code) {
+ case KEY_Prefix0:
+ case KEY_Prefix1:
+ priv->prefix = code;
+ return 1;
+ }
+ return 0; /* No change */
+ }
+
+ /* We have a prefix from the last scanCode */
+ switch (priv->prefix) {
+ case KEY_Prefix0:
+ priv->prefix = 0;
+ if (kbdLinuxPrefix0Mapping(&code)) return 1; /* Skip sequence */
+ break;
+ case KEY_Prefix1:
+ priv->prefix = (code = KEY_LCtrl) ? KEY_LCtrl : 0;
+ return 1; /* Use new prefix */
+ case KEY_LCtrl:
+ priv->prefix = 0;
+ if (code != KEY_NumLock) return 1; /* Skip sequence*/
+ code = KEY_Pause;
+ break;
+ }
+
+ *scanCode = code | (pressed ? 0x80 : 0x00);
+ return 0; /* Use old scanCode */
+}
+
+static void kbdLinuxConvert(myPrivate *priv,
+ unsigned char scanCode,
+ dmxEnqueueProcPtr enqueue,
+ dmxCheckSpecialProcPtr checkspecial,
+ pointer data)
+{
+ KeySymsPtr pKeySyms = &priv->pKeyboard->key->curKeySyms;
+ unsigned short state = priv->pKeyboard->key->state;
+ KeySym keySym = NoSymbol;
+ int keyCode;
+ xEvent xE;
+ int switching;
+
+ /* Do special PC/AT prefix mapping -- may change scanCode! */
+ if (kbdLinuxPrefixMapping(priv, &scanCode)) return;
+
+ /* Set up xEvent information */
+ xE.u.keyButtonPointer.time = GetTimeInMillis();
+ xE.u.u.type = (scanCode & 0x80) ? KeyRelease : KeyPress;
+ xE.u.u.detail = keyCode = (scanCode & 0x7f) + MIN_KEYCODE;
+
+ /* Handle repeats */
+
+ if (keyCode >= pKeySyms->minKeyCode && keyCode <= pKeySyms->maxKeyCode) {
+ keySym = pKeySyms->map[(keyCode - pKeySyms->minKeyCode)
+ * pKeySyms->mapWidth];
+#if 0
+ switch (keySym) {
+ case XK_Num_Lock:
+ case XK_Scroll_Lock:
+ case XK_Shift_Lock:
+ case XK_Caps_Lock:
+ /* Ignore releases and all but first press */
+ if (kbdLinuxModIgnore(priv, &xE, keySym)) return;
+ if (kbdLinuxKeyDown(priv, &xE)) xE.u.u.type = KeyRelease;
+ else xE.u.u.type = KeyPress;
+ break;
+ }
+#endif
+
+ /* If key is already down, ignore or autorepeat */
+ if (xE.u.u.type == KeyPress && kbdLinuxKeyDown(priv, &xE)) {
+ KbdFeedbackClassRec *feed = priv->pKeyboard->kbdfeed;
+
+ /* No auto-repeat? */
+ if ((feed && !feed->ctrl.autoRepeat)
+ || priv->pKeyboard->key->modifierMap[keyCode]
+ || (feed
+ && !(feed->ctrl.autoRepeats[keyCode >> 3]
+ & (1 << (keyCode & 7))))) return; /* Ignore */
+
+ /* Do auto-repeat */
+ xE.u.u.type = KeyRelease;
+ enqueue(&xE);
+ xE.u.u.type = KeyPress;
+ }
+
+ /* If key is already up, ignore */
+ if (xE.u.u.type == KeyRelease && !kbdLinuxKeyDown(priv, &xE)) return;
+ }
+
+ switching = 0;
+ if (checkspecial) switching = checkspecial(data, &xE, keySym, state);
+ if (!switching) {
+ if (enqueue) enqueue(&xE);
+ kbdLinuxKeyState(priv, &xE); /* Update our state bitmap */
+ }
+}
+
+void kbdLinuxRead(pointer p,
+ ENQUEUEPROC enqueue,
+ CHECKPROC checkspecial,
+ pointer data)
+{
+ myPrivate *priv = p;
+ unsigned char buf[256];
+ unsigned char *pt;
+ int n;
+
+ while ((n = read(priv->fd, buf, sizeof(buf))) > 0)
+ for (pt = buf; n; --n, ++pt)
+ kbdLinuxConvert(priv, *pt, enqueue, checkspecial, data);
+}
+
+int kbdLinuxOn(DevicePtr pDev)
+{
+ GETPRIV;
+ struct termios nTty;
+
+ ioctl(priv->fd, KDSKBMODE, K_RAW);
+
+ nTty = priv->kbdtty;
+ nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP);
+ nTty.c_oflag = 0;
+ nTty.c_cflag = CREAD | CS8;
+ nTty.c_lflag = 0;
+ nTty.c_cc[VTIME] = 0;
+ nTty.c_cc[VMIN] = 1;
+ cfsetispeed(&nTty, B9600);
+ cfsetospeed(&nTty, B9600);
+ if (tcsetattr(priv->fd, TCSANOW, &nTty) < 0)
+ FATAL1("kbdLinuxOn: tcsetattr failed (%s)\n", strerror(errno));
+ return priv->fd;
+}
+
+void kbdLinuxOff(DevicePtr pDev)
+{
+ GETPRIV;
+
+ ioctl(priv->fd, KDSKBMODE, priv->kbdtrans);
+ tcsetattr(priv->fd, TCSANOW, &priv->kbdtty);
+ kbdLinuxCloseConsole(pDev);
+}
+
+
+static void kbdLinuxReadKernelMapping(int fd, KeySymsPtr pKeySyms,
+ CARD8 *pModMap)
+{
+ KeySym *k;
+ int i;
+ int maxkey;
+ static unsigned char tbl[GLYPHS_PER_KEY] = {
+ 0, /* unshifted */
+ 1, /* shifted */
+ 0, /* modeswitch unshifted */
+ 0 /* modeswitch shifted */
+ };
+
+ /*
+ * Read the mapping from the kernel.
+ * Since we're still using the XFree86 scancode->AT keycode mapping
+ * routines, we need to convert the AT keycodes to Linux keycodes,
+ * then translate the Linux keysyms into X keysyms.
+ *
+ * First, figure out which tables to use for the modeswitch columns
+ * above, from the XF86Config fields.
+ */
+ tbl[2] = 8; /* alt */
+ tbl[3] = tbl[2] | 1;
+
+ k = map+GLYPHS_PER_KEY;
+ maxkey = NUM_AT2LNX;
+
+ for (i = 0; i < maxkey; ++i) {
+ struct kbentry kbe;
+ int j;
+
+ kbe.kb_index = at2lnx[i];
+
+ for (j = 0; j < GLYPHS_PER_KEY; ++j, ++k) {
+ unsigned short kval;
+
+ *k = NoSymbol;
+
+ kbe.kb_table = tbl[j];
+ if (kbe.kb_index == 0 || ioctl(fd, KDGKBENT, &kbe)) continue;
+
+ kval = KVAL(kbe.kb_value);
+ switch (KTYP(kbe.kb_value)) {
+ case KT_LATIN:
+ case KT_LETTER: *k = linux_to_x[kval]; break;
+ case KT_FN:
+ if (kval <= 19) *k = XK_F1 + kval;
+ else switch (kbe.kb_value) {
+ case K_FIND: *k = XK_Home; /* or XK_Find */ break;
+ case K_INSERT: *k = XK_Insert; break;
+ case K_REMOVE: *k = XK_Delete; break;
+ case K_SELECT: *k = XK_End; /* or XK_Select */ break;
+ case K_PGUP: *k = XK_Prior; break;
+ case K_PGDN: *k = XK_Next; break;
+ case K_HELP: *k = XK_Help; break;
+ case K_DO: *k = XK_Execute; break;
+ case K_PAUSE: *k = XK_Pause; break;
+ case K_MACRO: *k = XK_Menu; break;
+ default: break;
+ }
+ break;
+ case KT_SPEC:
+ switch (kbe.kb_value) {
+ case K_ENTER: *k = XK_Return; break;
+ case K_BREAK: *k = XK_Break; break;
+ case K_CAPS: *k = XK_Caps_Lock; break;
+ case K_NUM: *k = XK_Num_Lock; break;
+ case K_HOLD: *k = XK_Scroll_Lock; break;
+ case K_COMPOSE: *k = XK_Multi_key; break;
+ default: break;
+ }
+ break;
+ case KT_PAD:
+ switch (kbe.kb_value) {
+ case K_PPLUS: *k = XK_KP_Add; break;
+ case K_PMINUS: *k = XK_KP_Subtract; break;
+ case K_PSTAR: *k = XK_KP_Multiply; break;
+ case K_PSLASH: *k = XK_KP_Divide; break;
+ case K_PENTER: *k = XK_KP_Enter; break;
+ case K_PCOMMA: *k = XK_KP_Separator; break;
+ case K_PDOT: *k = XK_KP_Decimal; break;
+ case K_PPLUSMINUS: *k = XK_KP_Subtract; break;
+ default: if (kval <= 9) *k = XK_KP_0 + kval; break;
+ }
+ break;
+ case KT_DEAD:
+ /* KT_DEAD keys are for accelerated diacritical creation. */
+ switch (kbe.kb_value) {
+ case K_DGRAVE: *k = XK_dead_grave; break;
+ case K_DACUTE: *k = XK_dead_acute; break;
+ case K_DCIRCM: *k = XK_dead_circumflex; break;
+ case K_DTILDE: *k = XK_dead_tilde; break;
+ case K_DDIERE: *k = XK_dead_diaeresis; break;
+ }
+ break;
+ case KT_CUR:
+ switch (kbe.kb_value) {
+ case K_DOWN: *k = XK_Down; break;
+ case K_LEFT: *k = XK_Left; break;
+ case K_RIGHT: *k = XK_Right; break;
+ case K_UP: *k = XK_Up; break;
+ }
+ break;
+ case KT_SHIFT:
+ switch (kbe.kb_value) {
+ case K_ALTGR: *k = XK_Alt_R; break;
+ case K_ALT:
+ *k = (kbe.kb_index == 0x64 ? XK_Alt_R : XK_Alt_L);
+ break;
+ case K_CTRL:
+ *k = (kbe.kb_index == 0x61 ? XK_Control_R : XK_Control_L);
+ break;
+ case K_CTRLL: *k = XK_Control_L; break;
+ case K_CTRLR: *k = XK_Control_R; break;
+ case K_SHIFT:
+ *k = (kbe.kb_index == 0x36 ? XK_Shift_R : XK_Shift_L);
+ break;
+ case K_SHIFTL: *k = XK_Shift_L; break;
+ case K_SHIFTR: *k = XK_Shift_R; break;
+ default: break;
+ }
+ break;
+ case KT_ASCII:
+ /* KT_ASCII keys accumulate a 3 digit decimal number that
+ * gets emitted when the shift state changes. We can't
+ * emulate that.
+ */
+ break;
+ case KT_LOCK:
+ if (kbe.kb_value == K_SHIFTLOCK) *k = XK_Shift_Lock;
+ break;
+ default: break;
+ }
+ }
+
+ if (k[-1] == k[-2]) k[-1] = NoSymbol;
+ if (k[-2] == k[-3]) k[-2] = NoSymbol;
+ if (k[-3] == k[-4]) k[-3] = NoSymbol;
+ if (k[-4] == k[-2] && k[-3] == k[-1]) k[-2] = k[-1] = NoSymbol;
+ if (k[-1] == k[-4] && k[-2] == k[-3]
+ && k[-2] == NoSymbol) k[-1] = NoSymbol;
+ }
+}
+
+pointer kbdLinuxGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap)
+{
+ GETPRIV;
+ KeySym *k;
+ char type;
+ int i;
+
+ kbdLinuxReadKernelMapping(priv->fd, pKeySyms, pModMap);
+
+ /* compute the modifier map */
+ for (i = 0; i < MAP_LENGTH; i++)
+ pModMap[i] = NoSymbol; /* make sure it is restored */
+
+ for (k = map, i = MIN_KEYCODE; i < NUM_KEYCODES + MIN_KEYCODE; i++, k += 4)
+ switch(*k) {
+ case XK_Shift_L:
+ case XK_Shift_R: pModMap[i] = ShiftMask; break;
+ case XK_Control_L:
+ case XK_Control_R: pModMap[i] = ControlMask; break;
+ case XK_Caps_Lock: pModMap[i] = LockMask; break;
+ case XK_Alt_L:
+ case XK_Alt_R: pModMap[i] = AltMask; break;
+ case XK_Num_Lock: pModMap[i] = NumLockMask; break;
+ case XK_Scroll_Lock: pModMap[i] = ScrollLockMask; break;
+ case XK_Kana_Lock:
+ case XK_Kana_Shift: pModMap[i] = KanaMask; break;
+ case XK_Mode_switch: pModMap[i] = AltLangMask; break;
+ }
+
+ priv->kbdType = (ioctl(priv->fd, KDGKBTYPE, &type) < 0) ? KB_101 : type;
+
+ pKeySyms->map = map;
+ pKeySyms->mapWidth = GLYPHS_PER_KEY;
+ pKeySyms->minKeyCode = MIN_KEYCODE;
+ pKeySyms->maxKeyCode = MAX_KEYCODE;
+ return NULL;
+}
+
diff --git a/xc/programs/Xserver/hw/dmx/input/lnx-keyboard.h b/xc/programs/Xserver/hw/dmx/input/lnx-keyboard.h
new file mode 100644
index 000000000..7fcd7544e
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/lnx-keyboard.h
@@ -0,0 +1,63 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef _KBD_LINUX_H_
+#define _KBD_LINUX_H_
+
+extern pointer kbdLinuxCreatePrivate(DeviceIntPtr pKeyboard);
+extern void kbdLinuxDestroyPrivate(pointer private);
+
+extern void kbdLinuxInit(DevicePtr pDev);
+extern int kbdLinuxOn(DevicePtr pDev);
+extern void kbdLinuxOff(DevicePtr pDev);
+
+extern void kbdLinuxVTPreSwitch(pointer p);
+extern void kbdLinuxVTPostSwitch(pointer p);
+extern int kbdLinuxVTSwitch(pointer p, int vt,
+ dmxVTSwitchReturnProcPtr switch_return,
+ pointer switch_return_data);
+
+extern void kbdLinuxRead(pointer priv,
+ dmxEnqueueProcPtr enqueue,
+ dmxCheckSpecialProcPtr checkspecial,
+ pointer data);
+
+extern pointer kbdLinuxGetMap(DevicePtr pDev,
+ KeySymsPtr pKeySyms, CARD8 *pModMap);
+extern void kbdLinuxCtrl(DevicePtr pDev, KeybdCtrl *ctrl);
+extern void kbdLinuxBell(DevicePtr pDev, int percent,
+ int volume, int pitch, int duration);
+
+extern Bool kbdLinuxLegalModifier(unsigned int key, DevicePtr pDev);
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/input/lnx-ms.c b/xc/programs/Xserver/hw/dmx/input/lnx-ms.c
new file mode 100644
index 000000000..de292ef0e
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/lnx-ms.c
@@ -0,0 +1,282 @@
+/* $XFree86$ */
+/* Portions of this file were derived from the following files:
+ *
+ **********************************************************************
+ *
+ * Xserver/hw/kdrive/linux/ms.c
+ *
+ * Copyright (c) 2001 by Juliusz Chroboczek
+ * Copyright (c) 1999 by Keith Packard
+ *
+ * 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 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 2001 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#include "inputstr.h"
+#include "Xos.h"
+#include <errno.h>
+#include <termios.h>
+#include <unistd.h>
+
+/*****************************************************************************/
+/* Define some macros to make it easier to move this file to another
+ * part of the Xserver tree. All calls to the dmx* layer are #defined
+ * here for the .c file. The .h file will also have to be edited. */
+#include "dmxinputinit.h"
+#include "lnx-ms.h"
+
+#define GETPRIV myPrivate *priv \
+ = ((DMXLocalInputInfoPtr) \
+ ((DMXInputInfo *) \
+ (pDev->devicePrivate))->mou)->private
+
+#define LOG0(f) dmxLog(dmxDebug,f)
+#define LOG1(f,a) dmxLog(dmxDebug,f,a)
+#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b)
+#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c)
+#define FATAL0(f) dmxLog(dmxFatal,f)
+#define FATAL1(f,a) dmxLog(dmxFatal,f,a)
+#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b)
+#define ENQUEUEPROC dmxEnqueueProcPtr
+#define MOTIONPROC dmxMotionProcPtr
+
+/* End of interface definitions. */
+/*****************************************************************************/
+
+typedef struct _myPrivate {
+ DeviceIntPtr pMouse;
+ int fd;
+ struct termios tty;
+ enum {
+ button1 = 0x0001,
+ button2 = 0x0002,
+ button3 = 0x0004,
+ button4 = 0x0008,
+ button5 = 0x0010
+ } buttons;
+} myPrivate;
+
+static int msLinuxReadBytes(int fd, unsigned char *buf, int len, int min)
+{
+ int n, tot;
+ fd_set set;
+ struct timeval tv;
+
+ tot = 0;
+ while (len) {
+ n = read(fd, buf, len);
+ if (n > 0) {
+ tot += n;
+ buf += n;
+ len -= n;
+ }
+ if (tot % min == 0) break;
+ FD_ZERO(&set);
+ FD_SET(fd, &set);
+ tv.tv_sec = 0;
+ tv.tv_usec = 100 * 1000;
+ n = select(fd + 1, &set, 0, 0, &tv);
+ if (n <= 0) break;
+ }
+ return tot;
+}
+
+static void msLinuxButton(myPrivate *priv, ENQUEUEPROC enqueue, xEvent *xE,
+ int buttons)
+{
+
+#define PRESS(b) \
+ do { \
+ xE->u.u.type = ButtonPress; \
+ xE->u.u.detail = priv->pMouse->button->map[b]; \
+ enqueue(xE); \
+ } while (0)
+
+#define RELEASE(b) \
+ do { \
+ xE->u.u.type = ButtonRelease; \
+ xE->u.u.detail = priv->pMouse->button->map[b]; \
+ enqueue(xE); \
+ } while (0)
+
+ if ((buttons & button1) && !(priv->buttons & button1)) PRESS(1);
+ if (!(buttons & button1) && (priv->buttons & button1)) RELEASE(1);
+
+ if ((buttons & button2) && !(priv->buttons & button2)) PRESS(2);
+ if (!(buttons & button2) && (priv->buttons & button2)) RELEASE(2);
+
+ if ((buttons & button3) && !(priv->buttons & button3)) PRESS(3);
+ if (!(buttons & button3) && (priv->buttons & button3)) RELEASE(3);
+
+ if ((buttons & button4) && !(priv->buttons & button4)) PRESS(4);
+ if (!(buttons & button4) && (priv->buttons & button4)) RELEASE(4);
+
+ if ((buttons & button5) && !(priv->buttons & button5)) PRESS(5);
+ if (!(buttons & button5) && (priv->buttons & button5)) RELEASE(5);
+
+ priv->buttons = buttons;
+}
+
+void msLinuxRead(pointer p, ENQUEUEPROC enqueue, MOTIONPROC motion)
+{
+ myPrivate *priv = p;
+ unsigned char buf[3 * 200];
+ unsigned char *b;
+ int n;
+ int dx, dy;
+ xEvent xE;
+
+ while ((n = msLinuxReadBytes(priv->fd, buf, sizeof(buf), 3)) > 0) {
+ b = buf;
+ while (n >= 3) {
+ dx = (char)(((b[0] & 0x03) << 6) | (b[1] & 0x3f));
+ dy = (char)(((b[0] & 0x0c) << 4) | (b[2] & 0x3f));
+
+ motion(-dx, -dy, 1);
+ msLinuxButton(priv, enqueue, &xE,
+ (((b[0] & 0x10) ? button3 : 0)
+ | ((b[0] & 0x20) ? button1 : 0)));
+ n -= 3;
+ b += 3;
+ }
+ }
+}
+
+void msLinuxInit(DevicePtr pDev)
+{
+ GETPRIV;
+ char *names[] = { "/dev/serialmouse", "/dev/mouse", NULL };
+ int i;
+
+ if (priv->fd >=0) return;
+
+ for (i = 0; names[i]; i++) {
+ if ((priv->fd = open(names[i], O_RDWR | O_NONBLOCK, 0)) >= 0) break;
+ }
+ if (priv->fd < 0)
+ FATAL1("msLinuxInit: Cannot open mouse port (%s)\n",
+ strerror(errno));
+
+ if (!isatty(priv->fd))
+ FATAL1("msLinuxInit: Mouse port %s is not a tty\n", names[i]);
+
+ if (tcgetattr(priv->fd, &priv->tty) < 0)
+ FATAL1("msLinuxInit: tcgetattr failed (%s)\n", strerror(errno));
+
+ write(priv->fd, "*n", 2); /* 1200 baud */
+ usleep(100000);
+}
+
+int msLinuxOn(DevicePtr pDev)
+{
+ GETPRIV;
+ struct termios nTty;
+
+ if (priv->fd < 0) msLinuxInit(pDev);
+
+ nTty = priv->tty;
+ nTty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR
+ | IGNCR | ICRNL | IXON | IXOFF);
+ nTty.c_oflag &= ~OPOST;
+ nTty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+ nTty.c_cflag &= ~(CSIZE | PARENB);
+ nTty.c_cflag |= CS8 | CLOCAL | CSTOPB;
+ nTty.c_cc[VTIME] = 0;
+ nTty.c_cc[VMIN] = 1;
+ cfsetispeed (&nTty, B1200);
+ cfsetospeed (&nTty, B1200);
+ if (tcsetattr(priv->fd, TCSANOW, &nTty) < 0)
+ FATAL1("msLinuxInit: tcsetattr failed (%s)\n", strerror(errno));
+ write(priv->fd, "*V", 2); /* 2 button 3 byte protocol */
+ return priv->fd;
+}
+
+void msLinuxOff(DevicePtr pDev)
+{
+ GETPRIV;
+
+ tcsetattr(priv->fd, TCSANOW, &priv->tty);
+ close(priv->fd);
+ priv->fd = -1;
+}
+
+void msLinuxGetMap(DevicePtr pDev, unsigned char *map, int *nButtons)
+{
+ int i;
+
+ if (nButtons) *nButtons = 3;
+ if (map) for (i = 0; i <= *nButtons; i++) map[i] = i;
+}
+
+void msLinuxVTPreSwitch(pointer p)
+{
+}
+
+void msLinuxVTPostSwitch(pointer p)
+{
+}
+
+pointer msLinuxCreatePrivate(DeviceIntPtr pMouse)
+{
+ myPrivate *priv = xalloc(sizeof(*priv));
+ memset(priv, 0, sizeof(*priv));
+ priv->fd = -1;
+ priv->pMouse = pMouse;
+ return priv;
+}
+
+void msLinuxDestroyPrivate(pointer priv)
+{
+ if (priv) xfree(priv);
+}
diff --git a/xc/programs/Xserver/hw/dmx/input/lnx-ms.h b/xc/programs/Xserver/hw/dmx/input/lnx-ms.h
new file mode 100644
index 000000000..785e90b7a
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/lnx-ms.h
@@ -0,0 +1,52 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef _LNX_MS_H_
+#define _LNX_MS_H_
+
+extern pointer msLinuxCreatePrivate(DeviceIntPtr pMouse);
+extern void msLinuxDestroyPrivate(pointer priv);
+extern void msLinuxRead(pointer p,
+ dmxEnqueueProcPtr enqueue,
+ dmxMotionProcPtr motion);
+extern void msLinuxInit(DevicePtr pDev);
+extern int msLinuxOn(DevicePtr pDev);
+extern void msLinuxOff(DevicePtr pDev);
+extern void msLinuxGetMap(DevicePtr pDev,
+ unsigned char *map, int *nButtons);
+extern void msLinuxCtrl(DevicePtr pDev, PtrCtrl *ctrl);
+extern void msLinuxVTPreSwitch(pointer p);
+extern void msLinuxVTPostSwitch(pointer p);
+
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/input/lnx-ps2.c b/xc/programs/Xserver/hw/dmx/input/lnx-ps2.c
new file mode 100644
index 000000000..98d03b8c1
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/lnx-ps2.c
@@ -0,0 +1,253 @@
+/* $XFree86$ */
+/* Portions of this file were derived from the following files:
+ *
+ **********************************************************************
+ *
+ * Xserver/hw/kdrive/linux/ps2.c
+ *
+ * Copyright (c) 1999 by Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*
+ * Copyright 2001 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#include "inputstr.h"
+#include "Xos.h"
+#include <errno.h>
+#include <termios.h>
+#include <unistd.h>
+
+/*****************************************************************************/
+/* Define some macros to make it easier to move this file to another
+ * part of the Xserver tree. All calls to the dmx* layer are #defined
+ * here for the .c file. The .h file will also have to be edited. */
+#include "dmxinputinit.h"
+#include "lnx-ps2.h"
+
+#define GETPRIV myPrivate *priv \
+ = ((DMXLocalInputInfoPtr) \
+ ((DMXInputInfo *) \
+ (pDev->devicePrivate))->mou)->private
+
+#define LOG0(f) dmxLog(dmxDebug,f)
+#define LOG1(f,a) dmxLog(dmxDebug,f,a)
+#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b)
+#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c)
+#define FATAL0(f) dmxLog(dmxFatal,f)
+#define FATAL1(f,a) dmxLog(dmxFatal,f,a)
+#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b)
+#define ENQUEUEPROC dmxEnqueueProcPtr
+#define MOTIONPROC dmxMotionProcPtr
+
+/* End of interface definitions. */
+/*****************************************************************************/
+
+typedef struct _myPrivate {
+ DeviceIntPtr pMouse;
+ int fd;
+ enum {
+ button1 = 0x0001,
+ button2 = 0x0002,
+ button3 = 0x0004,
+ button4 = 0x0008,
+ button5 = 0x0010
+ } buttons;
+} myPrivate;
+
+static int ps2LinuxReadBytes(int fd, unsigned char *buf, int len, int min)
+{
+ int n, tot;
+ fd_set set;
+ struct timeval tv;
+
+ tot = 0;
+ while (len) {
+ n = read(fd, buf, len);
+ if (n > 0) {
+ tot += n;
+ buf += n;
+ len -= n;
+ }
+ if (tot % min == 0) break;
+ FD_ZERO(&set);
+ FD_SET(fd, &set);
+ tv.tv_sec = 0;
+ tv.tv_usec = 100 * 1000;
+ n = select(fd + 1, &set, 0, 0, &tv);
+ if (n <= 0) break;
+ }
+ return tot;
+}
+
+static void ps2LinuxButton(myPrivate *priv, ENQUEUEPROC enqueue, xEvent *xE,
+ int buttons)
+{
+
+#define PRESS(b) \
+ do { \
+ xE->u.u.type = ButtonPress; \
+ xE->u.u.detail = priv->pMouse->button->map[b]; \
+ enqueue(xE); \
+ } while (0)
+
+#define RELEASE(b) \
+ do { \
+ xE->u.u.type = ButtonRelease; \
+ xE->u.u.detail = priv->pMouse->button->map[b]; \
+ enqueue(xE); \
+ } while (0)
+
+ if ((buttons & button1) && !(priv->buttons & button1)) PRESS(1);
+ if (!(buttons & button1) && (priv->buttons & button1)) RELEASE(1);
+
+ if ((buttons & button2) && !(priv->buttons & button2)) PRESS(2);
+ if (!(buttons & button2) && (priv->buttons & button2)) RELEASE(2);
+
+ if ((buttons & button3) && !(priv->buttons & button3)) PRESS(3);
+ if (!(buttons & button3) && (priv->buttons & button3)) RELEASE(3);
+
+ if ((buttons & button4) && !(priv->buttons & button4)) PRESS(4);
+ if (!(buttons & button4) && (priv->buttons & button4)) RELEASE(4);
+
+ if ((buttons & button5) && !(priv->buttons & button5)) PRESS(5);
+ if (!(buttons & button5) && (priv->buttons & button5)) RELEASE(5);
+
+ priv->buttons = buttons;
+}
+
+void ps2LinuxRead(pointer p, ENQUEUEPROC enqueue, MOTIONPROC motion)
+{
+ myPrivate *priv = p;
+ unsigned char buf[3 * 200];
+ unsigned char *b;
+ int n;
+ int dx, dy;
+ xEvent xE;
+
+ while ((n = ps2LinuxReadBytes(priv->fd, buf, sizeof(buf), 3)) > 0) {
+ b = buf;
+ while (n >= 3) {
+ dx = b[1] - ((b[0] & 0x10) ? 256 : 0);
+ dy = -b[2] + ((b[0] & 0x20) ? 256 : 0);
+
+ motion(-dx, -dy, 1);
+ ps2LinuxButton(priv, enqueue, &xE,
+ (((b[0] & 4) ? button2 : 0)
+ | ((b[0] & 2) ? button3 : 0)
+ | ((b[0] & 1) ? button1 : 0)));
+ n -= 3;
+ b += 3;
+ }
+ }
+}
+
+void ps2LinuxInit(DevicePtr pDev)
+{
+ GETPRIV;
+ char *names[] = { "/dev/mouse", "/dev/psaux", NULL };
+ int i;
+
+ if (priv->fd >=0) return;
+
+ for (i = 0; names[i]; i++) {
+ if ((priv->fd = open(names[i], O_RDWR | O_NONBLOCK, 0)) >= 0) break;
+ }
+ if (priv->fd < 0)
+ FATAL1("ps2LinuxInit: Cannot open mouse port (%s)\n",
+ strerror(errno));
+}
+
+int ps2LinuxOn(DevicePtr pDev)
+{
+ GETPRIV;
+
+ if (priv->fd < 0) ps2LinuxInit(pDev);
+ return priv->fd;
+}
+
+void ps2LinuxOff(DevicePtr pDev)
+{
+ GETPRIV;
+
+ close(priv->fd);
+ priv->fd = -1;
+}
+
+void ps2LinuxGetMap(DevicePtr pDev, unsigned char *map, int *nButtons)
+{
+ int i;
+
+ if (nButtons) *nButtons = 3;
+ if (map) for (i = 0; i <= *nButtons; i++) map[i] = i;
+}
+
+void ps2LinuxVTPreSwitch(pointer p)
+{
+}
+
+void ps2LinuxVTPostSwitch(pointer p)
+{
+}
+
+pointer ps2LinuxCreatePrivate(DeviceIntPtr pMouse)
+{
+ myPrivate *priv = xalloc(sizeof(*priv));
+ memset(priv, 0, sizeof(*priv));
+ priv->fd = -1;
+ priv->pMouse = pMouse;
+ return priv;
+}
+
+void ps2LinuxDestroyPrivate(pointer priv)
+{
+ if (priv) xfree(priv);
+}
diff --git a/xc/programs/Xserver/hw/dmx/input/lnx-ps2.h b/xc/programs/Xserver/hw/dmx/input/lnx-ps2.h
new file mode 100644
index 000000000..f6df3af7c
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/lnx-ps2.h
@@ -0,0 +1,51 @@
+/* $XFree86$ */
+/*
+ * Copyright 2001 Red Hat Inc., Durham, North Carolina.
+ *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+#ifndef _LNX_PS2_H_
+#define _LNX_PS2_H_
+
+extern pointer ps2LinuxCreatePrivate(DeviceIntPtr pMouse);
+extern void ps2LinuxDestroyPrivate(pointer priv);
+extern void ps2LinuxRead(pointer p, dmxEnqueueProcPtr enqueue,
+ dmxMotionProcPtr motion);
+extern void ps2LinuxInit(DevicePtr pDev);
+extern int ps2LinuxOn(DevicePtr pDev);
+extern void ps2LinuxOff(DevicePtr pDev);
+extern void ps2LinuxGetMap(DevicePtr pDev,
+ unsigned char *map, int *nButtons);
+extern void ps2LinuxCtrl(DevicePtr pDev, PtrCtrl *ctrl);
+extern void ps2LinuxVTPreSwitch(pointer p);
+extern void ps2LinuxVTPostSwitch(pointer p);
+
+#endif
diff --git a/xc/programs/Xserver/hw/dmx/input/xbell.c b/xc/programs/Xserver/hw/dmx/input/xbell.c
new file mode 100644
index 000000000..67493f73b
--- /dev/null
+++ b/xc/programs/Xserver/hw/dmx/input/xbell.c
@@ -0,0 +1,68 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <X11/Xlib.h>
+
+static void pkc(XKeyboardControl *kc, unsigned long vm)
+{
+ if (vm&KBKeyClickPercent)
+ printf(" key_click_percent = %d\n", kc->key_click_percent);
+ if (vm&KBBellPercent)
+ printf(" bell_percent = %d\n", kc->bell_percent);
+ if (vm&KBBellPitch)
+ printf(" bell_pitch = %d\n", kc->bell_pitch);
+ if (vm&KBBellDuration)
+ printf(" bell_duration = %d\n", kc->bell_duration);
+ if (vm&KBLed)
+ printf(" led = 0x%x\n", kc->led);
+ if (vm&KBLedMode)
+ printf(" led_mode = %d\n", kc->led_mode);
+ if (vm&KBKey)
+ printf(" key = %d\n", kc->key);
+ if (vm&KBAutoRepeatMode)
+ printf(" auto_repeat_mode = %d\n", kc->auto_repeat_mode);
+}
+
+static void pks(XKeyboardState *ks)
+{
+ printf(" key_click_percent = %d\n", ks->key_click_percent);
+ printf(" bell_percent = %d\n", ks->bell_percent);
+ printf(" bell_pitch = %u\n", ks->bell_pitch);
+ printf(" bell_duration = %u\n", ks->bell_duration);
+ printf(" led_mask = 0x%lx\n", ks->led_mask);
+ printf(" global_auto_repeat = %d\n", ks->global_auto_repeat);
+}
+
+int main(int argc, char **argv)
+{
+ Display *display = XOpenDisplay(NULL);
+ XKeyboardControl kc;
+ XKeyboardState ks;
+ unsigned long vm;
+ int percent;
+
+ if (argc != 5) {
+ printf("Usage: xbell percent baseVolume pitch duration\n");
+ return 1;
+ }
+
+ vm = (KBBellPercent
+ | KBBellPitch
+ | KBBellDuration);
+ percent = atoi(argv[1]);
+ kc.bell_percent = atoi(argv[2]);
+ kc.bell_pitch = atoi(argv[3]);
+ kc.bell_duration = atoi(argv[4]);
+
+ printf("Setting:\n");
+ pkc(&kc, vm);
+ XChangeKeyboardControl(display, vm, &kc);
+
+ printf("Have:\n");
+ XGetKeyboardControl(display, &ks);
+ pks(&ks);
+
+ XBell(display, 100);
+
+ XCloseDisplay(display);
+ return 0;
+}