diff options
author | faith <faith> | 2002-06-04 06:27:24 +0000 |
---|---|---|
committer | faith <faith> | 2002-06-04 06:27:24 +0000 |
commit | 8d5933791ef8c25b816e3a946ae44c7f2575af91 (patch) | |
tree | 5e5ef580ca3434ee620bf0a00bb0416a8c617065 | |
parent | 37d6f977b9eadad5c0e6f853aca28f520bcb5413 (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
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->deviceProc) with the DEVICE_INIT argument: + +<descrip> +<tag/(*dev->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->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->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->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[] 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[]) + 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[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). + + <p>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. + + <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[]) 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. + + <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; +} |