From: Adam Tkac Date: Fri, 21 Mar 2008 18:56:48 +0000 (+0000) Subject: - moved Xvnc sources to unix/xserver/hw/vnc directory to affect current X tree X-Git-Tag: v0.0.90~384^2~49 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=4c0427ffb370b5020a6f82456106774b6711ddd4;p=tigervnc.git - moved Xvnc sources to unix/xserver/hw/vnc directory to affect current X tree - replaced unix/xc.patch by unix/xserver.patch - completely deleted unneded unix/xc subtree (sources are in unix/xserver/hw/vnc) git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/branches/1.5-xserver@2439 3789f03b-4d11-0410-bbf8-ca57d06f2519 --- diff --git a/unix/xc.patch b/unix/xc.patch deleted file mode 100644 index a5927b95..00000000 --- a/unix/xc.patch +++ /dev/null @@ -1,67 +0,0 @@ -diff -bcr xc.org/programs/Xserver/Imakefile xc/programs/Xserver/Imakefile -*** xc.org/programs/Xserver/Imakefile 2004-12-15 20:22:53.000000000 +0100 ---- xc/programs/Xserver/Imakefile 2005-02-14 14:23:21.000000000 +0100 -*************** -*** 128,134 **** - LIBREGEX = RegexLibrary - - #if DoLoadableServer -! LIBCWRAPPER = os/libcwrapper.o - #endif - - #if BuildXprint ---- 128,134 ---- - LIBREGEX = RegexLibrary - - #if DoLoadableServer -! LIBCWRAPPER = os/libcwrapper.o os/libos.a - #endif - - #if BuildXprint -*************** -*** 414,419 **** ---- 414,430 ---- - #define ServerToInstall Xsun - #endif - #endif /* XsunServer */ -+ XCOMM -+ XCOMM X VNC server -+ XCOMM -+ FBSUBDIR = fb -+ XVNCDDXDIR = vnc/Xvnc -+ XVNCDIRS = $(STDDIRS) $(FBSUBDIR) miext/damage $(XVNCDDXDIR) $(DEPDIRS) -+ XVNCLIBS = PreFbLibs vnc/Xvnc/LibraryTargetName(xvnc) FbPostFbLibs -+ XVNCOBJS = $(XVNCDDXDIR)/stubs.o $(XVNCDDXDIR)/miinitext.o -+ XVNCSYSLIBS = $(FONTLIBS) $(SYSLIBS) -+ ServerTarget(Xvnc,$(XVNCDIRS),$(XVNCOBJS), \ -+ $(LIBCWRAPPER) $(XVNCLIBS) $(LOADABLEEXTS),$(XVNCSYSLIBS)) - - - #if defined(Xsun24Server) && Xsun24Server -diff -bcr xc.org/programs/Xserver/mi/miinitext.c xc/programs/Xserver/mi/miinitext.c -*** xc.org/programs/Xserver/mi/miinitext.c 2004-12-13 06:48:41.000000000 +0100 ---- xc/programs/Xserver/mi/miinitext.c 2005-02-11 16:47:34.000000000 +0100 -*************** -*** 286,291 **** ---- 286,294 ---- - #ifdef MITMISC - extern void MITMiscExtensionInit(INITARGS); - #endif -+ #ifdef VNCEXT -+ extern void vncExtensionInit(INITARGS); -+ #endif - #ifdef XIDLE - extern void XIdleExtensionInit(INITARGS); - #endif -*************** -*** 587,592 **** ---- 590,598 ---- - #ifdef MITMISC - if (!noMITMiscExtension) MITMiscExtensionInit(); - #endif -+ #ifdef VNCEXT -+ vncExtensionInit(); -+ #endif - #ifdef XIDLE - if (!noXIdleExtension) XIdleExtensionInit(); - #endif diff --git a/unix/xc/config/cf/host.def b/unix/xc/config/cf/host.def deleted file mode 100644 index 2de89af0..00000000 --- a/unix/xc/config/cf/host.def +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/unix/xc/config/cf/vnc.def b/unix/xc/config/cf/vnc.def deleted file mode 100644 index b7660a58..00000000 --- a/unix/xc/config/cf/vnc.def +++ /dev/null @@ -1,38 +0,0 @@ -#define BuildServersOnly YES -#define BuildFonts NO -#define BuildClients NO -#define BuildDocs NO -#define BuildPexExt NO -#define BuildNls NO -#define BuildXIE NO -#define BuildGlxExt YES -#define GlxBuiltInXMesa YES -#define XnestServer YES -#define XF86Server NO -#define XprtServer NO -#define BuildXFree86ConfigTools NO - -#ifdef SunArchitecture -#define ProjectRoot /usr/openwin -#define HasGcc3 YES -#endif - -#define HasFreetype2 NO -#define BuildVNCExt YES -#define VNCExtDefines -DVNCEXT -#define SiteExtensionDefines VNCExtDefines -#define SiteExtensionDirs vnc - -#define VncUnixDir $(TOP)/.. -#define VncCommonDir VncUnixDir/../common -#define VncExtLibs VncCommonDir/rfb/librfb.a \ - VncCommonDir/Xregion/libXregion.a \ - VncCommonDir/network/libnetwork.a \ - VncCommonDir/rdr/librdr.a \ - VncCommonDir/jpeg/build/libjpeg.a - -#define SiteExtensionLibs vnc/LibraryTargetName(vnc) VncExtLibs - -#define ServerTarget(server,subdirs,objects,libs,syslibs) @@\ -CCLINK = $(CXXENVSETUP) $(CXX) @@\ -ServerTargetWithFlags(server,subdirs,objects,libs,syslibs,$(_NOOP_)) diff --git a/unix/xc/programs/Xserver/Xvnc.man b/unix/xc/programs/Xserver/Xvnc.man deleted file mode 100644 index 94a2786c..00000000 --- a/unix/xc/programs/Xserver/Xvnc.man +++ /dev/null @@ -1,284 +0,0 @@ -.TH Xvnc 1 "17 Apr 2006" "TightVNC" "Virtual Network Computing" -.SH NAME -Xvnc \- the X VNC server -.SH SYNOPSIS -.B Xvnc -.RI [ options ] -.RI : display# -.SH DESCRIPTION -.B Xvnc -is the X VNC (Virtual Network Computing) server. It is based on a standard X -server, but it has a "virtual" screen rather than a physical one. X -applications display themselves on it as if it were a normal X display, but -they can only be accessed via a VNC viewer - see \fBvncviewer\fP(1). - -So Xvnc is really two servers in one. To the applications it is an X server, -and to the remote VNC users it is a VNC server. By convention we have arranged -that the VNC server display number will be the same as the X server display -number, which means you can use eg. snoopy:2 to refer to display 2 on machine -"snoopy" in both the X world and the VNC world. - -The best way of starting \fBXvnc\fP is via the \fBvncserver\fP script. This -sets up the environment appropriately and runs some X applications to get you -going. See the manual page for \fBvncserver\fP(1) for more information. - -.SH OPTIONS -.B Xvnc -takes lots of options - running \fBXvnc -help\fP gives a list. Many of these -are standard X server options, which are described in the \fBXserver\fP(1) -manual page. In addition to options which can only be set via the -command-line, there are also "parameters" which can be set both via the -command-line and through the \fBvncconfig\fP(1) program. - -.TP -.B \-geometry \fIwidth\fPx\fIheight\fP -Specify the size of the desktop to be created. Default is 1024x768. - -.TP -.B \-depth \fIdepth\fP -Specify the pixel depth in bits of the desktop to be created. Default is 16, -other possible values are 8, 15, and 24 - anything else is likely to cause -strange behaviour by applications. - -.TP -.B \-pixelformat \fIformat\fP -Specify pixel format for server to use (BGRnnn or RGBnnn). The default for -depth 8 is BGR233 (meaning the most significant two bits represent blue, the -next three green, and the least significant three represent red), the default -for depth 16 is RGB565 and for depth 24 is RGB888. - -.TP -.B \-cc 3 -As an alternative to the default TrueColor visual, this allows you to run an -Xvnc server with a PseudoColor visual (i.e. one which uses a color map or -palette), which can be useful for running some old X applications which only -work on such a display. Values other than 3 (PseudoColor) and 4 (TrueColor) -for the \-cc option may result in strange behaviour, and PseudoColor desktops -must be 8 bits deep (i.e. \fB-depth 8\fP). - -.TP -.B \-inetd -This significantly changes Xvnc's behaviour so that it can be launched from -inetd. See the section below on usage with inetd. - -.TP -.B \-help -List all the options and parameters - -.SH PARAMETERS -VNC parameters can be set both via the command-line and through the -\fBvncconfig\fP(1) program, and with a VNC-enabled XFree86 server via Options -entries in the XF86Config file. - -Parameters can be turned on with -\fIparam\fP or off with --\fIparam\fP=0. Parameters which take a value can be specified as --\fIparam\fP \fIvalue\fP. Other valid forms are \fIparam\fP\fB=\fP\fIvalue\fP --\fIparam\fP=\fIvalue\fP --\fIparam\fP=\fIvalue\fP. Parameter names are -case-insensitive. - -.TP -.B \-desktop \fIdesktop-name\fP -Each desktop has a name which may be displayed by the viewer. It defaults to -"x11". - -.TP -.B \-rfbport \fIport\fP -Specifies the TCP port on which Xvnc listens for connections from viewers (the -protocol used in VNC is called RFB - "remote framebuffer"). The default is -5900 plus the display number. - -.TP -.B \-rfbwait \fItime\fP, \-ClientWaitTimeMillis \fItime\fP - -Time in milliseconds to wait for a viewer which is blocking Xvnc. This is -necessary because Xvnc is single-threaded and sometimes blocks until the viewer -has finished sending or receiving a message - note that this does not mean an -update will be aborted after this time. Default is 20000 (20 seconds). - -.TP -.B \-httpd \fIdirectory\fP -Run a mini-HTTP server which serves files from the given directory. Normally -the directory will contain the classes for the Java viewer. In addition, files -with a .vnc extension will have certain substitutions made so that a single -installation of the Java VNC viewer can be served by separate instances of -Xvnc. - -.TP -.B \-httpPort \fIport\fP -Specifies the port on which the mini-HTTP server runs. Default is 5800 plus -the display number. - -.TP -.B \-rfbauth \fIpasswd-file\fP, \-PasswordFile \fIpasswd-file\fP -Specifies the file containing the password used to authenticate viewers. The -file is accessed each time a connection comes in, so it can be changed on the -fly via \fBvncpasswd\fP(1). - -.TP -.B \-deferUpdate \fItime\fP -Xvnc uses a "deferred update" mechanism which enhances performance in many -cases. After any change to the framebuffer, Xvnc waits for this number of -milliseconds (default 40) before sending an update to any waiting clients. This -means that more changes tend to get coalesced together in a single -update. Setting it to 0 results in the same behaviour as earlier versions of -Xvnc, where the first change to the framebuffer causes an immediate update to -any waiting clients. - -.TP -.B \-SendCutText -Send clipboard changes to clients (default is on). Note that you must also run -\fBvncconfig\fP(1) to get the clipboard to work. - -.TP -.B \-AcceptCutText -Accept clipboard updates from clients (default is on). Note that you must also -run \fBvncconfig\fP(1) to get the clipboard to work. - -.TP -.B \-AcceptPointerEvents -Accept pointer press and release events from clients (default is on). - -.TP -.B \-AcceptKeyEvents -Accept key press and release events from clients (default is on). - -.TP -.B \-DisconnectClients -Disconnect existing clients if an incoming connection is non-shared (default is -on). If \fBDisconnectClients\fP is false, then a new non-shared connection will -be refused while there is a client active. When combined with -\fBNeverShared\fP this means only one client is allowed at a time. - -.TP -.B \-NeverShared -Never treat incoming connections as shared, regardless of the client-specified -setting (default is off). - -.TP -.B \-AlwaysShared -Always treat incoming connections as shared, regardless of the client-specified -setting (default is off). - -.TP -.B \-Protocol3.3 -Always use protocol version 3.3 for backwards compatibility with badly-behaved -clients (default is off). - -.TP -.B \-CompareFB -Perform pixel comparison on framebuffer to reduce unnecessary updates (default -is on). - -.TP -.B \-SecurityTypes \fIsec-types\fP -Specify which security schemes to use separated by commas. At present only -"None" and "VncAuth" are supported. The default is "VncAuth" - note that if -you want a server which does not require a password, you must set this -parameter to "None". - -.TP -.B \-IdleTimeout \fIseconds\fP -The number of seconds after which an idle VNC connection will be dropped -(default is 0, which means that idle connections will never be dropped). - -.TP -.B \-QueryConnect -Prompts the user of the desktop to explicitly accept or reject incoming -connections. This is most useful when using the vnc.so module or -\fBx0vncserver\fP(1) program to access an existing X desktop via VNC. - -The \fBvncconfig\fP(1) program must be running on the desktop in order for -QueryConnect to be supported by the \fBvnc.so\fP(1) module or -\fBXvnc\fP(1) program. The \fBx0vncserver\fP(1) program does not require -\fBvncconfig\fP(1) to be running. - -.TP -.B \-localhost -Only allow connections from the same machine. Useful if you use SSH and want to -stop non-SSH connections from any other hosts. See the guide to using VNC with -SSH on the web site. - -.TP -.B \-log \fIlogname\fP:\fIdest\fP:\fIlevel\fP -Configures the debug log settings. \fIdest\fP can currently be \fBstderr\fP or -\fBstdout\fP, and \fIlevel\fP is between 0 and 100, 100 meaning most verbose -output. \fIlogname\fP is usually \fB*\fP meaning all, but you can target a -specific source file if you know the name of its "LogWriter". Default is -\fB*:stderr:30\fP. - -.TP -.B \-RemapKeys \fImapping -Sets up a keyboard mapping. -.I mapping -is a comma-separated string of character mappings, each of the form -.IR char -> char , -or -.IR char <> char , -where -.I char -is a hexadecimal keysym. For example, to exchange the " and @ symbols you would specify the following: -.IP "" 10 -RemapKeys=0x22<>0x40 - -.SH USAGE WITH INETD -By configuring the \fBinetd\fP(1) service appropriately, Xvnc can be launched -on demand when a connection comes in, rather than having to be started -manually. When given the \fB-inetd\fP option, instead of listening for TCP -connections on a given port it uses its standard input and standard output. -There are two modes controlled by the wait/nowait entry in the inetd.conf file. - -In the nowait mode, Xvnc uses its standard input and output directly as the -connection to a viewer. It never has a listening socket, so cannot accept -further connections from viewers (it can however connect out to listening -viewers by use of the vncconfig program). Further viewer connections to the -same TCP port result in inetd spawning off a new Xvnc to deal with each -connection. When the connection to the viewer dies, the Xvnc and any -associated X clients die. This behaviour is most useful when combined with the -XDMCP options -query and -once. An typical example in inetd.conf might be (all -on one line): - -5950 stream tcp nowait nobody /usr/local/bin/Xvnc Xvnc -inetd -query -localhost -once securitytypes=none - -In this example a viewer connection to :50 will result in a new Xvnc for that -connection which should display the standard XDM login screen on that machine. -Because the user needs to login via XDM, it is usually OK to accept connections -without a VNC password in this case. - -In the wait mode, when the first connection comes in, inetd gives the listening -socket to Xvnc. This means that for a given TCP port, there is only ever one -Xvnc at a time. Further viewer connections to the same port are accepted by -the same Xvnc in the normal way. Even when the original connection is broken, -the Xvnc will continue to run. If this is used with the XDMCP options -query -and -once, the Xvnc and associated X clients will die when the user logs out of -the X session in the normal way. It is important to use a VNC password in this -case. A typical entry in inetd.conf might be: - -5951 stream tcp wait james /usr/local/bin/Xvnc Xvnc -inetd -query localhost -once passwordFile=/home/james/.vnc/passwd - -In fact typically, you would have one entry for each user who uses VNC -regularly, each of whom has their own dedicated TCP port which they use. In -this example, when user "james" connects to :51, he enters his VNC password, -then gets the XDM login screen where he logs in in the normal way. However, -unlike the previous example, if he disconnects, the session remains persistent, -and when he reconnects he will get the same session back again. When he logs -out of the X session, the Xvnc will die, but of course a new one will be -created automatically the next time he connects. - -.SH SEE ALSO -.BR vncconfig (1), -.BR vncpasswd (1), -.BR vncserver (1), -.BR vncviewer (1), -.BR Xserver (1), -.BR inetd (1) -.br -http://www.tightvnc.com - -.SH AUTHOR -Tristan Richardson, RealVNC Ltd. - -VNC was originally developed by the RealVNC team while at Olivetti -Research Ltd / AT&T Laboratories Cambridge. TightVNC additions were -implemented by Constantin Kaplinsky. Many other people participated in -development, testing and support. diff --git a/unix/xc/programs/Xserver/vnc/Imakefile b/unix/xc/programs/Xserver/vnc/Imakefile deleted file mode 100644 index d2607599..00000000 --- a/unix/xc/programs/Xserver/vnc/Imakefile +++ /dev/null @@ -1,45 +0,0 @@ -XCOMM CDEBUGFLAGS = -g -XCOMM CXXDEBUGFLAGS = -g - - VNCUNIXDIR = VncUnixDir - VNCCOMMONDIR = VncCommonDir - VNCINCLUDE = -I$(VNCCOMMONDIR) -I$(VNCUNIXDIR)/vncconfig - -#define CplusplusSource - -#if DoLoadableServer -#define IHaveSubdirs -#endif - -#include - -#if DoLoadableServer - MODULE_SUBDIRS = module -#endif - SRCS = vncExtInit.cc vncHooks.cc XserverDesktop.cc - OBJS = vncExtInit.o vncHooks.o XserverDesktop.o - INCLUDES = -I../include -I$(EXTINCSRC) -I$(XINCLUDESRC) -I$(FONTINCSRC) \ - -I../render $(VNCINCLUDE) -#if defined(XFree86Version) && XFree86Version >= 4000 - VNCDEFINES = -DGC_HAS_COMPOSITE_CLIP -#endif -#if defined(ProjectX) && (ProjectX >= 604) - VNCDEFINES = -DGC_HAS_COMPOSITE_CLIP -#endif - DEFINES = $(STD_DEFINES) $(VNCDEFINES) -UXFree86LOADER - -#define IHaveSubdirs -SUBDIRS = Xvnc $(MODULE_SUBDIRS) - -NormalLibraryTarget(vnc,$(OBJS)) -LintLibraryTarget(vnc,$(SRCS)) -NormalLintTarget($(SRCS)) - -NormalLibraryObjectRule() -NormalCplusplusObjectRule() - - -MakeSubdirs($(SUBDIRS)) -DependSubdirs($(SUBDIRS)) - -DependTarget() diff --git a/unix/xc/programs/Xserver/vnc/RegionHelper.h b/unix/xc/programs/Xserver/vnc/RegionHelper.h deleted file mode 100644 index 61dc89ff..00000000 --- a/unix/xc/programs/Xserver/vnc/RegionHelper.h +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -#ifndef __REGIONHELPER_H__ -#define __REGIONHELPER_H__ - -// RegionHelper is a class which helps in using X server regions by -// automatically freeing them in the destructor. It also fixes a problem with -// REGION_INIT when given an empty rectangle. - -// REGION_NULL was introduced in the Xorg tree as the way to initialise an -// empty region. If it's not already defined do it the old way. Note that the -// old way causes a segfault in the new tree... -#ifndef REGION_NULL -#define REGION_NULL(pScreen,pReg) REGION_INIT(pScreen,pReg,NullBox,0) -#endif - -class RegionHelper { -public: - - // constructor from a single rect - RegionHelper(ScreenPtr pScreen_, BoxPtr rect, int size) - : pScreen(pScreen_), reg(0) - { - init(rect, size); - } - - // constructor from an existing X server region - RegionHelper(ScreenPtr pScreen_, RegionPtr pRegion) - : pScreen(pScreen_), reg(®Rec) - { - REGION_NULL(pScreen, reg); - REGION_COPY(pScreen, reg, pRegion); - } - - // constructor from an array of rectangles - RegionHelper(ScreenPtr pScreen_, int nrects, xRectanglePtr rects, - int ctype=CT_NONE) - : pScreen(pScreen_) - { - reg = RECTS_TO_REGION(pScreen, nrects, rects, ctype); - } - - // constructor for calling init() later - RegionHelper(ScreenPtr pScreen_) : pScreen(pScreen_), reg(0) { - } - - void init(BoxPtr rect, int size) { - reg = ®Rec; - if (!rect || (rect && (rect->x2 == rect->x1 || rect->y2 == rect->y1))) { - REGION_NULL(pScreen, reg); - } else { - REGION_INIT(pScreen, reg, rect, size); - } - } - - // destructor frees as appropriate - ~RegionHelper() { - if (reg == ®Rec) { - REGION_UNINIT(pScreen, reg); - } else if (reg) { - REGION_DESTROY(pScreen, reg); - } - } - ScreenPtr pScreen; - RegionRec regRec; - RegionPtr reg; -}; - -#endif diff --git a/unix/xc/programs/Xserver/vnc/XserverDesktop.cc b/unix/xc/programs/Xserver/vnc/XserverDesktop.cc deleted file mode 100644 index 9e5ea0f7..00000000 --- a/unix/xc/programs/Xserver/vnc/XserverDesktop.cc +++ /dev/null @@ -1,1147 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -// -// XserverDesktop.cxx -// - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "XserverDesktop.h" -#include "vncExtInit.h" - -extern "C" { -#define public c_public -#define class c_class - - // windowTable is in globals.h in XFree 4, but not in XFree 3 unfortunately -extern WindowPtr *WindowTable; -extern char *display; - -#include "inputstr.h" -#include "servermd.h" -#include "colormapst.h" -#include "resource.h" -#include "cursorstr.h" -#include "windowstr.h" -#define XK_CYRILLIC -#include "keysym.h" -#undef public -#undef class -} - -using namespace rfb; -using namespace network; - -static LogWriter vlog("XserverDesktop"); - -rfb::IntParameter deferUpdateTime("DeferUpdate", - "Time in milliseconds to defer updates",40); - -rfb::BoolParameter alwaysSetDeferUpdateTimer("AlwaysSetDeferUpdateTimer", - "Always reset the defer update timer on every change",false); - -IntParameter queryConnectTimeout("QueryConnectTimeout", - "Number of seconds to show the Accept Connection dialog before " - "rejecting the connection", - 10); - -static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col); - -static rdr::U8 reverseBits[] = { - 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, - 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, - 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, - 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, - 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, - 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, - 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, - 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, - 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, - 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, - 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, - 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, - 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, - 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, - 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, - 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, - 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, - 0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, - 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, - 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, - 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, - 0x3f, 0xbf, 0x7f, 0xff -}; - - -class FileHTTPServer : public rfb::HTTPServer { -public: - FileHTTPServer(XserverDesktop* d) : desktop(d) {} - virtual ~FileHTTPServer() {} - - virtual rdr::InStream* getFile(const char* name, const char** contentType, - int* contentLength, time_t* lastModified) - { - if (name[0] != '/' || strstr(name, "..") != 0) { - vlog.info("http request was for invalid file name"); - return 0; - } - - if (strcmp(name, "/") == 0) name = "/index.vnc"; - - CharArray httpDirStr(httpDir.getData()); - CharArray fname(strlen(httpDirStr.buf)+strlen(name)+1); - sprintf(fname.buf, "%s%s", httpDirStr.buf, name); - int fd = open(fname.buf, O_RDONLY); - if (fd < 0) return 0; - rdr::InStream* is = new rdr::FdInStream(fd, -1, 0, true); - *contentType = guessContentType(name, *contentType); - if (strlen(name) > 4 && strcasecmp(&name[strlen(name)-4], ".vnc") == 0) { - is = new rdr::SubstitutingInStream(is, desktop, 20); - *contentType = "text/html"; - } else { - struct stat st; - if (fstat(fd, &st) == 0) { - *contentLength = st.st_size; - *lastModified = st.st_mtime; - } - } - return is; - } - - XserverDesktop* desktop; -}; - - -XserverDesktop::XserverDesktop(ScreenPtr pScreen_, - network::TcpListener* listener_, - network::TcpListener* httpListener_, - const char* name, void* fbptr) - : pScreen(pScreen_), deferredUpdateTimer(0), dummyTimer(0), - server(0), httpServer(0), - listener(listener_), httpListener(httpListener_), - cmap(0), deferredUpdateTimerSet(false), - grabbing(false), ignoreHooks_(false), directFbptr(fbptr != 0), - oldButtonMask(0), - queryConnectId(0) -{ - int i; - format.depth = pScreen->rootDepth; - for (i = 0; i < screenInfo.numPixmapFormats; i++) { - if (screenInfo.formats[i].depth == format.depth) { - format.bpp = screenInfo.formats[i].bitsPerPixel; - break; - } - } - if (i == screenInfo.numPixmapFormats) { - fprintf(stderr,"no pixmap format for root depth???\n"); - abort(); - } - format.bigEndian = (screenInfo.imageByteOrder == MSBFirst); - - VisualPtr vis; - for (i = 0; i < pScreen->numVisuals; i++) { - if (pScreen->visuals[i].vid == pScreen->rootVisual) { - vis = &pScreen->visuals[i]; - break; - } - } - if (i == pScreen->numVisuals) { - fprintf(stderr,"no visual rec for root visual???\n"); - abort(); - } - format.trueColour = (vis->c_class == TrueColor); - if (!format.trueColour && format.bpp != 8) - throw rfb::Exception("X server uses unsupported visual"); - format.redShift = ffs(vis->redMask) - 1; - format.greenShift = ffs(vis->greenMask) - 1; - format.blueShift = ffs(vis->blueMask) - 1; - format.redMax = vis->redMask >> format.redShift; - format.greenMax = vis->greenMask >> format.greenShift; - format.blueMax = vis->blueMask >> format.blueShift; - - width_ = pScreen->width; - height_ = pScreen->height; - if (fbptr) - data = (rdr::U8*)fbptr; - else - data = new rdr::U8[pScreen->width * pScreen->height * (format.bpp/8)]; - colourmap = this; - - serverReset(pScreen); - - server = new VNCServerST(name, this); - server->setPixelBuffer(this); - server->setQueryConnectionHandler(this); - - if (httpListener) - httpServer = new FileHTTPServer(this); -} - -XserverDesktop::~XserverDesktop() -{ - if (!directFbptr) - delete [] data; - TimerFree(deferredUpdateTimer); - TimerFree(dummyTimer); - delete httpServer; - delete server; -} - -void XserverDesktop::serverReset(ScreenPtr pScreen_) -{ - pScreen = pScreen_; - XID* ids = new XID[pScreen->maxInstalledCmaps]; - int nmaps = (*pScreen->ListInstalledColormaps)(pScreen, ids); - cmap = (ColormapPtr)LookupIDByType(ids[0], RT_COLORMAP); - delete [] ids; -} - -char* XserverDesktop::substitute(const char* varName) -{ - if (strcmp(varName, "$$") == 0) { - return rfb::strDup("$"); - } - if (strcmp(varName, "$PORT") == 0) { - char* str = new char[10]; - sprintf(str, "%d", listener ? listener->getMyPort() : 0); - return str; - } - if (strcmp(varName, "$WIDTH") == 0) { - char* str = new char[10]; - sprintf(str, "%d", width()); - return str; - } - if (strcmp(varName, "$HEIGHT") == 0) { - char* str = new char[10]; - sprintf(str, "%d", height()); - return str; - } - if (strcmp(varName, "$APPLETWIDTH") == 0) { - char* str = new char[10]; - sprintf(str, "%d", width()); - return str; - } - if (strcmp(varName, "$APPLETHEIGHT") == 0) { - char* str = new char[10]; - sprintf(str, "%d", height() + 32); - return str; - } - if (strcmp(varName, "$DESKTOP") == 0) { - return rfb::strDup(server->getName()); - } - if (strcmp(varName, "$DISPLAY") == 0) { - struct utsname uts; - uname(&uts); - char* str = new char[256]; - strncat(str, uts.nodename, 240); - strcat(str, ":"); - strncat(str, display, 10); - return str; - } - if (strcmp(varName, "$USER") == 0) { - struct passwd* user = getpwuid(getuid()); - return rfb::strDup(user ? user->pw_name : "?"); - } - return 0; -} - -rfb::VNCServerST::queryResult -XserverDesktop::queryConnection(network::Socket* sock, - const char* userName, - char** reason) { - if (queryConnectId) { - *reason = strDup("Another connection is currently being queried."); - return rfb::VNCServerST::REJECT; - } - queryConnectAddress.replaceBuf(sock->getPeerAddress()); - if (!userName) - userName = "(anonymous)"; - queryConnectUsername.replaceBuf(strDup(userName)); - queryConnectId = sock; - vncQueryConnect(this, sock); - return rfb::VNCServerST::PENDING; -} - - -void XserverDesktop::setColormap(ColormapPtr cmap_) -{ - if (cmap != cmap_) { - cmap = cmap_; - setColourMapEntries(0, 0); - } -} - -void XserverDesktop::setColourMapEntries(ColormapPtr pColormap, int ndef, - xColorItem* pdef) -{ - if (cmap != pColormap || ndef <= 0) return; - - int first = pdef[0].pixel; - int n = 1; - - for (int i = 1; i < ndef; i++) { - if (first + n == pdef[i].pixel) { - n++; - } else { - setColourMapEntries(first, n); - first = pdef[i].pixel; - n = 1; - } - } - setColourMapEntries(first, n); -} - -void XserverDesktop::setColourMapEntries(int firstColour, int nColours) -{ - try { - server->setColourMapEntries(firstColour, nColours); - } catch (rdr::Exception& e) { - vlog.error("XserverDesktop::setColourMapEntries: %s",e.str()); - } -} - -void XserverDesktop::bell() -{ - server->bell(); -} - -void XserverDesktop::serverCutText(const char* str, int len) -{ - try { - server->serverCutText(str, len); - } catch (rdr::Exception& e) { - vlog.error("XserverDesktop::serverCutText: %s",e.str()); - } -} - -void XserverDesktop::setCursor(CursorPtr cursor) -{ - try { - int w = cursor->bits->width; - int h = cursor->bits->height; - rdr::U8* cursorData = new rdr::U8[w * h * (getPF().bpp / 8)]; - - xColorItem fg, bg; - fg.red = cursor->foreRed; - fg.green = cursor->foreGreen; - fg.blue = cursor->foreBlue; - FakeAllocColor(cmap, &fg); - bg.red = cursor->backRed; - bg.green = cursor->backGreen; - bg.blue = cursor->backBlue; - FakeAllocColor(cmap, &bg); - FakeFreeColor(cmap, fg.pixel); - FakeFreeColor(cmap, bg.pixel); - - int xMaskBytesPerRow = BitmapBytePad(w); - - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - int byte = y * xMaskBytesPerRow + x / 8; -#if (BITMAP_BIT_ORDER == MSBFirst) - int bit = 7 - x % 8; -#else - int bit = x % 8; -#endif - switch (getPF().bpp) { - case 8: - ((rdr::U8*)cursorData)[y * w + x] - = (cursor->bits->source[byte] & (1 << bit)) ? fg.pixel : bg.pixel; - break; - case 16: - ((rdr::U16*)cursorData)[y * w + x] - = (cursor->bits->source[byte] & (1 << bit)) ? fg.pixel : bg.pixel; - break; - case 32: - ((rdr::U32*)cursorData)[y * w + x] - = (cursor->bits->source[byte] & (1 << bit)) ? fg.pixel : bg.pixel; - break; - } - } - } - - int rfbMaskBytesPerRow = (w + 7) / 8; - - rdr::U8* cursorMask = new rdr::U8[rfbMaskBytesPerRow * h]; - - for (int j = 0; j < h; j++) { - for (int i = 0; i < rfbMaskBytesPerRow; i++) -#if (BITMAP_BIT_ORDER == MSBFirst) - cursorMask[j * rfbMaskBytesPerRow + i] - = cursor->bits->mask[j * xMaskBytesPerRow + i]; -#else - cursorMask[j * rfbMaskBytesPerRow + i] - = reverseBits[cursor->bits->mask[j * xMaskBytesPerRow + i]]; -#endif - } - - server->setCursor(cursor->bits->width, cursor->bits->height, - Point(cursor->bits->xhot, cursor->bits->yhot), - cursorData, cursorMask); - server->tryUpdate(); - delete [] cursorData; - delete [] cursorMask; - } catch (rdr::Exception& e) { - vlog.error("XserverDesktop::setCursor: %s",e.str()); - } -} - -static void printRegion(RegionPtr reg) -{ - int nrects = REGION_NUM_RECTS(reg); - - fprintf(stderr,"Region num rects %2d extents %3d,%3d %3dx%3d\n",nrects, - (REGION_EXTENTS(pScreen,reg))->x1, - (REGION_EXTENTS(pScreen,reg))->y1, - (REGION_EXTENTS(pScreen,reg))->x2-(REGION_EXTENTS(pScreen,reg))->x1, - (REGION_EXTENTS(pScreen,reg))->y2-(REGION_EXTENTS(pScreen,reg))->y1); - - for (int i = 0; i < nrects; i++) { - fprintf(stderr," rect %3d,%3d %3dx%3d\n", - REGION_RECTS(reg)[i].x1, - REGION_RECTS(reg)[i].y1, - REGION_RECTS(reg)[i].x2-REGION_RECTS(reg)[i].x1, - REGION_RECTS(reg)[i].y2-REGION_RECTS(reg)[i].y1); - } -} - -CARD32 XserverDesktop::deferredUpdateTimerCallback(OsTimerPtr timer, - CARD32 now, pointer arg) -{ - XserverDesktop* desktop = (XserverDesktop*)arg; - desktop->deferredUpdateTimerSet = false; - try { - desktop->server->tryUpdate(); - } catch (rdr::Exception& e) { - vlog.error("XserverDesktop::deferredUpdateTimerCallback: %s",e.str()); - } - return 0; -} - -void XserverDesktop::deferUpdate() -{ - if (deferUpdateTime != 0) { - if (!deferredUpdateTimerSet || alwaysSetDeferUpdateTimer) { - deferredUpdateTimerSet = true; - deferredUpdateTimer = TimerSet(deferredUpdateTimer, 0, - deferUpdateTime, - deferredUpdateTimerCallback, this); - } - } else { - server->tryUpdate(); - } -} - -void XserverDesktop::add_changed(RegionPtr reg) -{ - if (ignoreHooks_) return; - if (grabbing) return; - try { - rfb::Region rfbReg; - rfbReg.setExtentsAndOrderedRects((ShortRect*)REGION_EXTENTS(pScreen, reg), - REGION_NUM_RECTS(reg), - (ShortRect*)REGION_RECTS(reg)); - server->add_changed(rfbReg); - deferUpdate(); - } catch (rdr::Exception& e) { - vlog.error("XserverDesktop::add_changed: %s",e.str()); - } -} - -void XserverDesktop::add_copied(RegionPtr dst, int dx, int dy) -{ - if (ignoreHooks_) return; - if (grabbing) return; - try { - rfb::Region rfbReg; - rfbReg.setExtentsAndOrderedRects((ShortRect*)REGION_EXTENTS(pScreen, dst), - REGION_NUM_RECTS(dst), - (ShortRect*)REGION_RECTS(dst)); - server->add_copied(rfbReg, rfb::Point(dx, dy)); - deferUpdate(); - } catch (rdr::Exception& e) { - vlog.error("XserverDesktop::add_copied: %s",e.str()); - } -} - -void XserverDesktop::positionCursor() -{ - if (!cursorPos.equals(oldCursorPos)) { - oldCursorPos = cursorPos; - (*pScreen->SetCursorPosition) (pScreen, cursorPos.x, cursorPos.y, FALSE); - server->setCursorPos(cursorPos); - server->tryUpdate(); - } -} - -void XserverDesktop::blockHandler(fd_set* fds) -{ - try { - ScreenPtr screenWithCursor = GetCurrentRootWindow()->drawable.pScreen; - if (screenWithCursor == pScreen) { - int x, y; - GetSpritePosition(&x, &y); - if (x != cursorPos.x || y != cursorPos.y) { - cursorPos = oldCursorPos = Point(x, y); - server->setCursorPos(cursorPos); - server->tryUpdate(); - } - } - - if (listener) - FD_SET(listener->getFd(), fds); - if (httpListener) - FD_SET(httpListener->getFd(), fds); - - std::list sockets; - server->getSockets(&sockets); - std::list::iterator i; - for (i = sockets.begin(); i != sockets.end(); i++) { - int fd = (*i)->getFd(); - if ((*i)->isShutdown()) { - vlog.debug("client gone, sock %d",fd); - server->removeSocket(*i); - vncClientGone(fd); - delete (*i); - } else { - FD_SET(fd, fds); - } - } - if (httpServer) { - httpServer->getSockets(&sockets); - for (i = sockets.begin(); i != sockets.end(); i++) { - int fd = (*i)->getFd(); - if ((*i)->isShutdown()) { - vlog.debug("http client gone, sock %d",fd); - httpServer->removeSocket(*i); - delete (*i); - } else { - FD_SET(fd, fds); - } - } - } - } catch (rdr::Exception& e) { - vlog.error("XserverDesktop::blockHandler: %s",e.str()); - } -} - -static CARD32 dummyTimerCallback(OsTimerPtr timer, CARD32 now, pointer arg) { - return 0; -} - -void XserverDesktop::wakeupHandler(fd_set* fds, int nfds) -{ - try { - if (nfds >= 1) { - - if (listener) { - if (FD_ISSET(listener->getFd(), fds)) { - FD_CLR(listener->getFd(), fds); - Socket* sock = listener->accept(); - server->addSocket(sock); - vlog.debug("new client, sock %d",sock->getFd()); - } - } - - if (httpListener) { - if (FD_ISSET(httpListener->getFd(), fds)) { - FD_CLR(httpListener->getFd(), fds); - Socket* sock = httpListener->accept(); - httpServer->addSocket(sock); - vlog.debug("new http client, sock %d",sock->getFd()); - } - } - - std::list sockets; - server->getSockets(&sockets); - std::list::iterator i; - for (i = sockets.begin(); i != sockets.end(); i++) { - int fd = (*i)->getFd(); - if (FD_ISSET(fd, fds)) { - FD_CLR(fd, fds); - server->processSocketEvent(*i); - } - } - - if (httpServer) { - httpServer->getSockets(&sockets); - for (i = sockets.begin(); i != sockets.end(); i++) { - int fd = (*i)->getFd(); - if (FD_ISSET(fd, fds)) { - FD_CLR(fd, fds); - httpServer->processSocketEvent(*i); - } - } - } - - positionCursor(); - } - - int timeout = server->checkTimeouts(); - if (timeout > 0) { - // set a dummy timer just so we are guaranteed be called again next time. - dummyTimer = TimerSet(dummyTimer, 0, timeout, - dummyTimerCallback, 0); - } - - } catch (rdr::Exception& e) { - vlog.error("XserverDesktop::wakeupHandler: %s",e.str()); - } -} - -void XserverDesktop::addClient(Socket* sock, bool reverse) -{ - vlog.debug("new client, sock %d reverse %d",sock->getFd(),reverse); - server->addSocket(sock, reverse); -} - -void XserverDesktop::disconnectClients() -{ - vlog.debug("disconnecting all clients"); - return server->closeClients("Disconnection from server end"); -} - - -int XserverDesktop::getQueryTimeout(void* opaqueId, - const char** address, - const char** username) -{ - if (opaqueId && queryConnectId == opaqueId) { - vlog.info("address=%s, username=%s, timeout=%d", - queryConnectAddress.buf, queryConnectUsername.buf, - (int)queryConnectTimeout); - if (address) *address = queryConnectAddress.buf; - if (username) *username = queryConnectUsername.buf; - return queryConnectTimeout; - } - return 0; -} - -void XserverDesktop::approveConnection(void* opaqueId, bool accept, - const char* rejectMsg) -{ - if (queryConnectId == opaqueId) { - server->approveConnection((network::Socket*)opaqueId, accept, rejectMsg); - queryConnectId = 0; - } -} - -/////////////////////////////////////////////////////////////////////////// -// -// SDesktop callbacks - - -void XserverDesktop::pointerEvent(const Point& pos, int buttonMask) -{ - xEvent ev; - DevicePtr dev = LookupPointerDevice(); - - // SetCursorPosition seems to be very expensive (at least on XFree86 3.3.6 - // for S3), so we delay calling it until positionCursor() is called at the - // end of processing a load of RFB. - //(*pScreen->SetCursorPosition) (pScreen, pos.x, pos.y, FALSE); - - NewCurrentScreen(pScreen, pos.x, pos.y); - - ev.u.u.type = MotionNotify; - ev.u.u.detail = 0; - ev.u.keyButtonPointer.rootX = pos.x; - ev.u.keyButtonPointer.rootY = pos.y; - ev.u.keyButtonPointer.time = GetTimeInMillis(); - - if (!pos.equals(cursorPos)) - (*dev->processInputProc)(&ev, (DeviceIntPtr)dev, 1); - - for (int i = 0; i < 5; i++) { - if ((buttonMask ^ oldButtonMask) & (1<processInputProc)(&ev, (DeviceIntPtr)dev, 1); - } - } - - cursorPos = pos; - oldButtonMask = buttonMask; -} - -void XserverDesktop::clientCutText(const char* str, int len) -{ - vncClientCutText(str, len); -} - -void XserverDesktop::grabRegion(const rfb::Region& region) -{ - if (directFbptr) return; - if (!pScreen->GetImage) { - vlog.error("VNC error: pScreen->GetImage == 0"); - return; - } - - grabbing = true; - - int bytesPerPixel = format.bpp/8; - int bytesPerRow = pScreen->width * bytesPerPixel; - - std::vector rects; - std::vector::iterator i; - region.get_rects(&rects); - for (i = rects.begin(); i != rects.end(); i++) { - for (int y = i->tl.y; y < i->br.y; y++) { - (*pScreen->GetImage) ((DrawablePtr)WindowTable[pScreen->myNum], - i->tl.x, y, i->width(), 1, - ZPixmap, (unsigned long)~0L, - ((char*)data - + y * bytesPerRow + i->tl.x * bytesPerPixel)); - } - } - grabbing = false; -} - -void XserverDesktop::lookup(int index, int* r, int* g, int* b) -{ - if ((cmap->c_class | DynamicClass) == DirectColor) { - VisualPtr v = cmap->pVisual; - *r = cmap->red [(index & v->redMask ) >> v->offsetRed ].co.local.red; - *g = cmap->green[(index & v->greenMask) >> v->offsetGreen].co.local.green; - *b = cmap->blue [(index & v->blueMask ) >> v->offsetBlue ].co.local.blue; - } else { - EntryPtr pent; - pent = (EntryPtr)&cmap->red[index]; - if (pent->fShared) { - *r = pent->co.shco.red->color; - *g = pent->co.shco.green->color; - *b = pent->co.shco.blue->color; - } else { - *r = pent->co.local.red; - *g = pent->co.local.green; - *b = pent->co.local.blue; - } - } -} - -// -// Keyboard handling -// - -#define IS_PRESSED(keyc, keycode) \ - ((keyc)->down[(keycode) >> 3] & (1 << ((keycode) & 7))) - -// ModifierState is a class which helps simplify generating a "fake" press -// or release of shift, ctrl, alt, etc. An instance of the class is created -// for every modifier which may need to be pressed or released. Then either -// press() or release() may be called to make sure that the corresponding keys -// are in the right state. The destructor of the class automatically reverts -// to the previous state. Each modifier may have multiple keys associated with -// it, so in the case of a fake release, this may involve releasing more than -// one key. - -class ModifierState { -public: - ModifierState(DeviceIntPtr dev_, int modIndex_) - : dev(dev_), modIndex(modIndex_), nKeys(0), keys(0), pressed(false) - { - } - ~ModifierState() { - for (int i = 0; i < nKeys; i++) - generateXKeyEvent(keys[i], !pressed); - delete [] keys; - } - void press() { - KeyClassPtr keyc = dev->key; - if (!(keyc->state & (1<modifierKeyMap[modIndex * keyc->maxKeysPerModifier], - true); - pressed = true; - } - } - void release() { - KeyClassPtr keyc = dev->key; - if (keyc->state & (1<maxKeysPerModifier; k++) { - int keycode - = keyc->modifierKeyMap[modIndex * keyc->maxKeysPerModifier + k]; - if (keycode && IS_PRESSED(keyc, keycode)) - tempKeyEvent(keycode, false); - } - } - } -private: - void tempKeyEvent(int keycode, bool down) { - if (keycode) { - if (!keys) keys = new int[dev->key->maxKeysPerModifier]; - keys[nKeys++] = keycode; - generateXKeyEvent(keycode, down); - } - } - void generateXKeyEvent(int keycode, bool down) { - xEvent ev; - ev.u.u.type = down ? KeyPress : KeyRelease; - ev.u.u.detail = keycode; - ev.u.keyButtonPointer.time = GetTimeInMillis(); - (*dev->c_public.processInputProc)(&ev, dev, 1); - vlog.debug("fake keycode %d %s", keycode, down ? "down" : "up"); - } - DeviceIntPtr dev; - int modIndex; - int nKeys; - int* keys; - bool pressed; -}; - - -// altKeysym is a table of alternative keysyms which have the same meaning. - -struct altKeysym_t { - KeySym a, b; -}; - -altKeysym_t altKeysym[] = { - { XK_Shift_L, XK_Shift_R }, - { XK_Control_L, XK_Control_R }, - { XK_Meta_L, XK_Meta_R }, - { XK_Alt_L, XK_Alt_R }, - { XK_Super_L, XK_Super_R }, - { XK_Hyper_L, XK_Hyper_R }, - { XK_KP_Space, XK_space }, - { XK_KP_Tab, XK_Tab }, - { XK_KP_Enter, XK_Return }, - { XK_KP_F1, XK_F1 }, - { XK_KP_F2, XK_F2 }, - { XK_KP_F3, XK_F3 }, - { XK_KP_F4, XK_F4 }, - { XK_KP_Home, XK_Home }, - { XK_KP_Left, XK_Left }, - { XK_KP_Up, XK_Up }, - { XK_KP_Right, XK_Right }, - { XK_KP_Down, XK_Down }, - { XK_KP_Page_Up, XK_Page_Up }, - { XK_KP_Page_Down, XK_Page_Down }, - { XK_KP_End, XK_End }, - { XK_KP_Begin, XK_Begin }, - { XK_KP_Insert, XK_Insert }, - { XK_KP_Delete, XK_Delete }, - { XK_KP_Equal, XK_equal }, - { XK_KP_Multiply, XK_asterisk }, - { XK_KP_Add, XK_plus }, - { XK_KP_Separator, XK_comma }, - { XK_KP_Subtract, XK_minus }, - { XK_KP_Decimal, XK_period }, - { XK_KP_Divide, XK_slash }, - { XK_KP_0, XK_0 }, - { XK_KP_1, XK_1 }, - { XK_KP_2, XK_2 }, - { XK_KP_3, XK_3 }, - { XK_KP_4, XK_4 }, - { XK_KP_5, XK_5 }, - { XK_KP_6, XK_6 }, - { XK_KP_7, XK_7 }, - { XK_KP_8, XK_8 }, - { XK_KP_9, XK_9 }, -}; - -// keyEvent() - work out the best keycode corresponding to the keysym sent by -// the viewer. This is non-trivial because we can't assume much about the -// local keyboard layout. We must also find out which column of the keyboard -// mapping the keysym is in, and alter the shift state appropriately. Column 0 -// means both shift and "mode_switch" (AltGr) must be released, column 1 means -// shift must be pressed and mode_switch released, column 2 means shift must be -// released and mode_switch pressed, and column 3 means both shift and -// mode_switch must be pressed. - -void XserverDesktop::keyEvent(rdr::U32 keysym, bool down) -{ - if (keysym == XK_Caps_Lock) { - vlog.debug("Ignoring caps lock"); - return; - } - DeviceIntPtr dev = (DeviceIntPtr)LookupKeyboardDevice(); - KeyClassPtr keyc = dev->key; - KeySymsPtr keymap = &keyc->curKeySyms; - - // find which modifier Mode_switch is on. - int modeSwitchMapIndex = 0; - for (int i = 3; i < 8; i++) { - for (int k = 0; k < keyc->maxKeysPerModifier; k++) { - int keycode = keyc->modifierKeyMap[i * keyc->maxKeysPerModifier + k]; - for (int j = 0; j < keymap->mapWidth; j++) { - if (keycode != 0 && - keymap->map[(keycode - keymap->minKeyCode) - * keymap->mapWidth + j] == XK_Mode_switch) - { - modeSwitchMapIndex = i; - break; - } - } - } - } - - int col = 0; - if (keyc->state & (1<state & (1<state & (1<maxKeyCode; kc >= keymap->minKeyCode; kc--) { - if (!keymap->map[(kc - keymap->minKeyCode) * keymap->mapWidth]) { - keymap->map[(kc - keymap->minKeyCode) * keymap->mapWidth] = keysym; - col = 0; - SendMappingNotify(MappingKeyboard, kc, 1, serverClient); - vlog.info("Added unknown keysym 0x%x to keycode %d",keysym,kc); - break; - } - } - if (kc < keymap->minKeyCode) { - vlog.info("Keyboard mapping full - ignoring unknown keysym 0x%x",keysym); - return; - } - } - - // See if it's a modifier key. If so, then don't do any auto-repeat, because - // the X server will translate each press into a release followed by a press. - for (int i = 0; i < 8; i++) { - for (int k = 0; k < keyc->maxKeysPerModifier; k++) { - if (kc == keyc->modifierKeyMap[i * keyc->maxKeysPerModifier + k] && - IS_PRESSED(keyc,kc) && down) - return; - } - } - - ModifierState shift(dev, ShiftMapIndex); - ModifierState modeSwitch(dev, modeSwitchMapIndex); - if (down) { - if (col & 1) - shift.press(); - else - shift.release(); - if (modeSwitchMapIndex) { - if (col & 2) - modeSwitch.press(); - else - modeSwitch.release(); - } - } - vlog.debug("keycode %d %s", kc, down ? "down" : "up"); - xEvent ev; - ev.u.u.type = down ? KeyPress : KeyRelease; - ev.u.u.detail = kc; - ev.u.keyButtonPointer.time = GetTimeInMillis(); - (*dev->c_public.processInputProc)(&ev, dev, 1); -} - - -void XConvertCase(KeySym sym, KeySym *lower, KeySym *upper) -{ - *lower = sym; - *upper = sym; - switch(sym >> 8) { - case 0: /* Latin 1 */ - if ((sym >= XK_A) && (sym <= XK_Z)) - *lower += (XK_a - XK_A); - else if ((sym >= XK_a) && (sym <= XK_z)) - *upper -= (XK_a - XK_A); - else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) - *lower += (XK_agrave - XK_Agrave); - else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis)) - *upper -= (XK_agrave - XK_Agrave); - else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn)) - *lower += (XK_oslash - XK_Ooblique); - else if ((sym >= XK_oslash) && (sym <= XK_thorn)) - *upper -= (XK_oslash - XK_Ooblique); - break; - case 1: /* Latin 2 */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym == XK_Aogonek) - *lower = XK_aogonek; - else if (sym >= XK_Lstroke && sym <= XK_Sacute) - *lower += (XK_lstroke - XK_Lstroke); - else if (sym >= XK_Scaron && sym <= XK_Zacute) - *lower += (XK_scaron - XK_Scaron); - else if (sym >= XK_Zcaron && sym <= XK_Zabovedot) - *lower += (XK_zcaron - XK_Zcaron); - else if (sym == XK_aogonek) - *upper = XK_Aogonek; - else if (sym >= XK_lstroke && sym <= XK_sacute) - *upper -= (XK_lstroke - XK_Lstroke); - else if (sym >= XK_scaron && sym <= XK_zacute) - *upper -= (XK_scaron - XK_Scaron); - else if (sym >= XK_zcaron && sym <= XK_zabovedot) - *upper -= (XK_zcaron - XK_Zcaron); - else if (sym >= XK_Racute && sym <= XK_Tcedilla) - *lower += (XK_racute - XK_Racute); - else if (sym >= XK_racute && sym <= XK_tcedilla) - *upper -= (XK_racute - XK_Racute); - break; - case 2: /* Latin 3 */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym >= XK_Hstroke && sym <= XK_Hcircumflex) - *lower += (XK_hstroke - XK_Hstroke); - else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex) - *lower += (XK_gbreve - XK_Gbreve); - else if (sym >= XK_hstroke && sym <= XK_hcircumflex) - *upper -= (XK_hstroke - XK_Hstroke); - else if (sym >= XK_gbreve && sym <= XK_jcircumflex) - *upper -= (XK_gbreve - XK_Gbreve); - else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex) - *lower += (XK_cabovedot - XK_Cabovedot); - else if (sym >= XK_cabovedot && sym <= XK_scircumflex) - *upper -= (XK_cabovedot - XK_Cabovedot); - break; - case 3: /* Latin 4 */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym >= XK_Rcedilla && sym <= XK_Tslash) - *lower += (XK_rcedilla - XK_Rcedilla); - else if (sym >= XK_rcedilla && sym <= XK_tslash) - *upper -= (XK_rcedilla - XK_Rcedilla); - else if (sym == XK_ENG) - *lower = XK_eng; - else if (sym == XK_eng) - *upper = XK_ENG; - else if (sym >= XK_Amacron && sym <= XK_Umacron) - *lower += (XK_amacron - XK_Amacron); - else if (sym >= XK_amacron && sym <= XK_umacron) - *upper -= (XK_amacron - XK_Amacron); - break; - case 6: /* Cyrillic */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE) - *lower -= (XK_Serbian_DJE - XK_Serbian_dje); - else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze) - *upper += (XK_Serbian_DJE - XK_Serbian_dje); - else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN) - *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu); - else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign) - *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu); - break; - case 7: /* Greek */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent) - *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); - else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent && - sym != XK_Greek_iotaaccentdieresis && - sym != XK_Greek_upsilonaccentdieresis) - *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); - else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA) - *lower += (XK_Greek_alpha - XK_Greek_ALPHA); - else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega && - sym != XK_Greek_finalsmallsigma) - *upper -= (XK_Greek_alpha - XK_Greek_ALPHA); - break; - } -} - -static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col) -{ - register int per = keymap->mapWidth; - register KeySym *syms; - KeySym lsym, usym; - - if ((col < 0) || ((col >= per) && (col > 3)) || - (keycode < keymap->minKeyCode) || (keycode > keymap->maxKeyCode)) - return NoSymbol; - - syms = &keymap->map[(keycode - keymap->minKeyCode) * per]; - if (col < 4) { - if (col > 1) { - while ((per > 2) && (syms[per - 1] == NoSymbol)) - per--; - if (per < 3) - col -= 2; - } - if ((per <= (col|1)) || (syms[col|1] == NoSymbol)) { - XConvertCase(syms[col&~1], &lsym, &usym); - if (!(col & 1)) - return lsym; - // I'm commenting out this logic because it's incorrect even though it - // was copied from the Xlib sources. The X protocol book quite clearly - // states that where a group consists of element 1 being a non-alphabetic - // keysym and element 2 being NoSymbol that you treat the second element - // as being the same as the first. This also tallies with the behaviour - // produced by the installed Xlib on my linux box (I believe this is - // because it uses some XKB code rather than the original Xlib code - - // compare XKBBind.c with KeyBind.c in lib/X11). - // else if (usym == lsym) - // return NoSymbol; - else - return usym; - } - } - return syms[col]; -} - -// KeysymToKeycode() - find the keycode and column corresponding to the given -// keysym. The value of col passed in should be the column determined from the -// current shift state. If the keysym can be found in that column we prefer -// that to finding it in a different column (which would require fake events to -// alter the shift state). - -static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col) -{ - register int i, j; - - j = *col; - for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) { - if (KeyCodetoKeySym(keymap, i, j) == ks) - return i; - } - - for (j = 0; j < keymap->mapWidth; j++) { - for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) { - if (KeyCodetoKeySym(keymap, i, j) == ks) { - *col = j; - return i; - } - } - } - return 0; -} diff --git a/unix/xc/programs/Xserver/vnc/XserverDesktop.h b/unix/xc/programs/Xserver/vnc/XserverDesktop.h deleted file mode 100644 index 880acc21..00000000 --- a/unix/xc/programs/Xserver/vnc/XserverDesktop.h +++ /dev/null @@ -1,130 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -// -// XserverDesktop.h -// - -#ifndef __XSERVERDESKTOP_H__ -#define __XSERVERDESKTOP_H__ - -#include -#include -#include -#include -#include -#include - -extern "C" { -#define class c_class; -#include -#include -#undef class -} - -namespace rfb { - class VNCServerST; -} - -namespace network { class TcpListener; class Socket; } - -class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer, - public rfb::ColourMap, public rdr::Substitutor, - public rfb::VNCServerST::QueryConnectionHandler { -public: - - XserverDesktop(ScreenPtr pScreen, network::TcpListener* listener, - network::TcpListener* httpListener_, - const char* name, void* fbptr); - virtual ~XserverDesktop(); - - // methods called from X server code - void serverReset(ScreenPtr pScreen); - void setColormap(ColormapPtr cmap); - void setColourMapEntries(ColormapPtr pColormap, int ndef, xColorItem* pdef); - void bell(); - void serverCutText(const char* str, int len); - void setCursor(CursorPtr cursor); - void add_changed(RegionPtr reg); - void add_copied(RegionPtr dst, int dx, int dy); - void positionCursor(); - void ignoreHooks(bool b) { ignoreHooks_ = b; } - void blockHandler(fd_set* fds); - void wakeupHandler(fd_set* fds, int nfds); - void addClient(network::Socket* sock, bool reverse); - void disconnectClients(); - - // QueryConnect methods called from X server code - // getQueryTimeout() - // Returns the timeout associated with a particular - // connection, identified by an opaque Id passed to the - // X code earlier. Also optionally gets the address and - // name associated with that connection. - // Returns zero if the Id is not recognised. - int getQueryTimeout(void* opaqueId, - const char** address=0, - const char** username=0); - - // approveConnection() - // Used by X server code to supply the result of a query. - void approveConnection(void* opaqueId, bool accept, - const char* rejectMsg=0); - - // rfb::SDesktop callbacks - virtual void pointerEvent(const rfb::Point& pos, int buttonMask); - virtual void keyEvent(rdr::U32 key, bool down); - virtual void clientCutText(const char* str, int len); - virtual rfb::Point getFbSize() { return rfb::Point(width(), height()); } - - // rfb::PixelBuffer callbacks - virtual void grabRegion(const rfb::Region& r); - - // rfb::ColourMap callbacks - virtual void lookup(int index, int* r, int* g, int* b); - - // rdr::Substitutor callback - virtual char* substitute(const char* varName); - - // rfb::VNCServerST::QueryConnectionHandler callback - virtual rfb::VNCServerST::queryResult queryConnection(network::Socket* sock, - const char* userName, - char** reason); - -private: - void setColourMapEntries(int firstColour, int nColours); - static CARD32 deferredUpdateTimerCallback(OsTimerPtr timer, CARD32 now, - pointer arg); - void deferUpdate(); - ScreenPtr pScreen; - OsTimerPtr deferredUpdateTimer, dummyTimer; - rfb::VNCServerST* server; - rfb::HTTPServer* httpServer; - network::TcpListener* listener; - network::TcpListener* httpListener; - ColormapPtr cmap; - bool deferredUpdateTimerSet; - bool grabbing; - bool ignoreHooks_; - bool directFbptr; - int oldButtonMask; - rfb::Point cursorPos, oldCursorPos; - - void* queryConnectId; - rfb::CharArray queryConnectAddress; - rfb::CharArray queryConnectUsername; -}; -#endif diff --git a/unix/xc/programs/Xserver/vnc/Xvnc/Imakefile b/unix/xc/programs/Xserver/vnc/Xvnc/Imakefile deleted file mode 100644 index 57db6716..00000000 --- a/unix/xc/programs/Xserver/vnc/Xvnc/Imakefile +++ /dev/null @@ -1,95 +0,0 @@ - - VNCCOMMONDIR = VncCommonDir - VNCINCLUDE = -I$(VNCCOMMONDIR) - VNCLIBS = VncExtLibs - -#if defined(XFree86Version) && XFree86Version < 4000 - VNCDEFINES = -DNO_INIT_BACKING_STORE -#endif - -#define CplusplusSource - -#include - -#if HasShm -SHMDEF = -DHAS_SHM -#endif - -XCOMM add more architectures here as we discover them -#if defined(HPArchitecture) || \ - (defined(SparcArchitecture) && !defined(LynxOSArchitecture)) || \ - SystemV4 || \ - defined(OSF1Architecture) || \ - defined(i386BsdArchitecture) || \ - defined(LinuxArchitecture) || \ - defined(DarwinArchitecture) -MMAPDEF = -DHAS_MMAP -#endif - -#ifdef XVendorString -VENDORSTRING = XVendorString -#else -VENDORSTRING = "unknown" -#endif - -#ifdef XVendorRelease -VENDORRELEASE = XVendorRelease -#else -VENDORRELEASE = 0 -#endif - - VENDOR_STRING = -DVENDOR_STRING=\"$(VENDORSTRING)\" - VENDOR_RELEASE = -DVENDOR_RELEASE="$(VENDORRELEASE)" - -#ifdef OS2Architecture -SRCS1 = os2_stubs.c -OBJS1 = os2_stubs.o -#endif - -FBINCLUDE = -I../../fb - -SRCSA = xvnc.cc stubs.c $(SRCS1) miinitext.c $(SRCS2) - -OBJSA = xvnc.o stubs.o $(OBJS1) miinitext.o $(OBJS2) - -INCLUDES = -I. -I.. -I$(XBUILDINCDIR) -I$(FONTINCSRC) \ - $(FBINCLUDE) -I../../mfb -I../../mi -I../../include -I../../os \ - -I$(EXTINCSRC) -I$(XINCLUDESRC) -I$(SERVERSRC)/render $(VNCINCLUDE) - -DEFINES = $(OS_DEFINES) $(SHMDEF) $(MMAPDEF) $(FB_DEFINES) \ - $(VENDOR_STRING) $(VENDOR_RELEASE) $(STD_DEFINES) ServerOSDefines \ - $(VNCDEFINES) -UXFree86LOADER - -#if defined(XFree86Version) || defined(XorgVersion) -/* - * Make sure XINPUT, XF86VidTune, etc arent defined for the miinitext.o - * used by Xvnc - */ -EXT_DEFINES = ExtensionDefines -UXF86VIDMODE -UXFreeXDGA -UXF86MISC -UXF86DRI -#endif - - -SRCS = $(SRCSA) $(SRCSB) $(SRCSC) -OBJS = $(OBJSA) $(OBJSB) $(OBJSC) - -NormalLibraryObjectRule() -NormalLibraryTarget(xvnc,$(OBJS) buildtime.o) - -#ifdef OS2Architecture -LinkSourceFile(os2_stubs.c,../xfree86/os-support/os2) -SpecialCObjectRule(os2_stubs,$(ICONFIGFILES),-DOS2NULLSELECT) -#endif - -#ifdef HasGcc -NO_OPERATOR_NAMES = -fno-operator-names -#endif -LinkSourceFile(stubs.c,../../Xi) -SpecialCplusplusObjectRule(xvnc,$(ICONFIGFILES) xvnc,$(EXT_DEFINES) $(NO_OPERATOR_NAMES)) - -LinkSourceFile(miinitext.c,$(SERVERSRC)/mi) -SpecialCObjectRule(miinitext,$(ICONFIGFILES),$(EXT_DEFINES) $(PAN_DEFINES) -DNO_MODULE_EXTS $(EXT_MODULE_DEFINES) -UXFree86LOADER) - -/* InstallManPage(Xvfb,$(MANDIR)) */ -DependTarget() - -buildtime.o: $(OBJS) ../LibraryTargetName(vnc) $(VNCLIBS) diff --git a/unix/xc/programs/Xserver/vnc/Xvnc/buildtime.c b/unix/xc/programs/Xserver/vnc/Xvnc/buildtime.c deleted file mode 100644 index 3f4c3690..00000000 --- a/unix/xc/programs/Xserver/vnc/Xvnc/buildtime.c +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -char buildtime[] = __DATE__ " " __TIME__; diff --git a/unix/xc/programs/Xserver/vnc/Xvnc/xvnc.cc b/unix/xc/programs/Xserver/vnc/Xvnc/xvnc.cc deleted file mode 100644 index 5daf663d..00000000 --- a/unix/xc/programs/Xserver/vnc/Xvnc/xvnc.cc +++ /dev/null @@ -1,1472 +0,0 @@ -/* Copyright (c) 1993 X Consortium - Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice 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 X CONSORTIUM 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 X Consortium 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 X Consortium. - -*/ - -#include -#include -#include -#include -#include "vncExtInit.h" - -extern "C" { -#define class c_class -#define public c_public -#define xor c_xor -#define and c_and -#ifdef WIN32 -#include -#endif -#include -#include "X11/X.h" -#define NEED_EVENTS -#include "X11/Xproto.h" -#include "X11/Xos.h" -#include "scrnintstr.h" -#include "servermd.h" -#include "fb.h" -#include "mi.h" -#include "mibstore.h" -#include "colormapst.h" -#include "gcstruct.h" -#include "input.h" -#include "mipointer.h" -#define new New -#include "micmap.h" -#undef new -#include -#ifdef HAS_MMAP -#include -#ifndef MAP_FILE -#define MAP_FILE 0 -#endif -#endif /* HAS_MMAP */ -#include -#include -#ifndef WIN32 -#include -#endif -#include -#ifdef HAS_SHM -#include -#include -#endif /* HAS_SHM */ -#include "dix.h" -#include "miline.h" -#include "inputstr.h" -#include "keysym.h" - extern int defaultColorVisualClass; - extern char buildtime[]; -#undef class -#undef public -#undef xor -#undef and -} - -#define XVNCVERSION "TightVNC 1.5 series" -#define XVNCCOPYRIGHT ("Copyright (C) 2002-2005 RealVNC Ltd.\n" \ - "Copyright (C) 2000-2006 Constantin Kaplinsky\n" \ - "Copyright (C) 2004-2006 Peter Astrand, Cendio AB\n" \ - "See http://www.tightvnc.com for information on TightVNC.\n") - - -extern char *display; -extern int monitorResolution; - -#define VFB_DEFAULT_WIDTH 1024 -#define VFB_DEFAULT_HEIGHT 768 -#define VFB_DEFAULT_DEPTH 16 -#define VFB_DEFAULT_WHITEPIXEL 0xffff -#define VFB_DEFAULT_BLACKPIXEL 0 -#define VFB_DEFAULT_LINEBIAS 0 -#define XWD_WINDOW_NAME_LEN 60 - -typedef struct -{ - int scrnum; - int width; - int paddedBytesWidth; - int paddedWidth; - int height; - int depth; - int bitsPerPixel; - int sizeInBytes; - int ncolors; - char *pfbMemory; - XWDColor *pXWDCmap; - XWDFileHeader *pXWDHeader; - Pixel blackPixel; - Pixel whitePixel; - unsigned int lineBias; - CloseScreenProcPtr closeScreen; - -#ifdef HAS_MMAP - int mmap_fd; - char mmap_file[MAXPATHLEN]; -#endif - -#ifdef HAS_SHM - int shmid; -#endif - - Bool pixelFormatDefined; - Bool rgbNotBgr; - int redBits, greenBits, blueBits; - -} vfbScreenInfo, *vfbScreenInfoPtr; - -static int vfbNumScreens; -static vfbScreenInfo vfbScreens[MAXSCREENS]; -static Bool vfbPixmapDepths[33]; -#ifdef HAS_MMAP -static char *pfbdir = NULL; -#endif -typedef enum { NORMAL_MEMORY_FB, SHARED_MEMORY_FB, MMAPPED_FILE_FB } fbMemType; -static fbMemType fbmemtype = NORMAL_MEMORY_FB; -static char needswap = 0; -static int lastScreen = -1; -static Bool Render = TRUE; - -static bool displaySpecified = false; -static bool wellKnownSocketsCreated = false; -static char displayNumStr[16]; - -#define swapcopy16(_dst, _src) \ - if (needswap) { CARD16 _s = _src; cpswaps(_s, _dst); } \ - else _dst = _src; - -#define swapcopy32(_dst, _src) \ - if (needswap) { CARD32 _s = _src; cpswapl(_s, _dst); } \ - else _dst = _src; - - -static void -vfbInitializePixmapDepths(void) -{ - int i; - vfbPixmapDepths[1] = TRUE; /* always need bitmaps */ - for (i = 2; i <= 32; i++) - vfbPixmapDepths[i] = FALSE; -} - -static void -vfbInitializeDefaultScreens(void) -{ - int i; - - for (i = 0; i < MAXSCREENS; i++) - { - vfbScreens[i].scrnum = i; - vfbScreens[i].width = VFB_DEFAULT_WIDTH; - vfbScreens[i].height = VFB_DEFAULT_HEIGHT; - vfbScreens[i].depth = VFB_DEFAULT_DEPTH; - vfbScreens[i].blackPixel = VFB_DEFAULT_BLACKPIXEL; - vfbScreens[i].whitePixel = VFB_DEFAULT_WHITEPIXEL; - vfbScreens[i].lineBias = VFB_DEFAULT_LINEBIAS; - vfbScreens[i].pixelFormatDefined = FALSE; - vfbScreens[i].pfbMemory = NULL; - } - vfbNumScreens = 1; -} - -static int -vfbBitsPerPixel(int depth) -{ - if (depth == 1) return 1; - else if (depth <= 8) return 8; - else if (depth <= 16) return 16; - else return 32; -} - - -extern "C" { - - void ddxGiveUp() - { - int i; - - /* clean up the framebuffers */ - - switch (fbmemtype) - { -#ifdef HAS_MMAP - case MMAPPED_FILE_FB: - for (i = 0; i < vfbNumScreens; i++) - { - if (-1 == unlink(vfbScreens[i].mmap_file)) - { - perror("unlink"); - ErrorF("unlink %s failed, errno %d", - vfbScreens[i].mmap_file, errno); - } - } - break; -#else /* HAS_MMAP */ - case MMAPPED_FILE_FB: - break; -#endif /* HAS_MMAP */ - -#ifdef HAS_SHM - case SHARED_MEMORY_FB: - for (i = 0; i < vfbNumScreens; i++) - { - if (-1 == shmdt((char *)vfbScreens[i].pXWDHeader)) - { - perror("shmdt"); - ErrorF("shmdt failed, errno %d", errno); - } - } - break; -#else /* HAS_SHM */ - case SHARED_MEMORY_FB: - break; -#endif /* HAS_SHM */ - - case NORMAL_MEMORY_FB: - for (i = 0; i < vfbNumScreens; i++) - { - Xfree(vfbScreens[i].pXWDHeader); - } - break; - } -} - -void -AbortDDX() -{ - ddxGiveUp(); -} - -#ifdef __DARWIN__ -void -DarwinHandleGUI(int argc, char *argv[]) -{ -} - -void GlxExtensionInit(); -void GlxWrapInitVisuals(void *procPtr); - -void -DarwinGlxExtensionInit() -{ - GlxExtensionInit(); -} - -void -DarwinGlxWrapInitVisuals( - void *procPtr) -{ - GlxWrapInitVisuals(procPtr); -} -#endif - -void -OsVendorInit() -{ -} - -void -OsVendorFatalError() -{ -} - -void ddxBeforeReset(void) -{ - return; -} - -void -ddxUseMsg() -{ - ErrorF("\nXvnc %s - built %s\n%s", XVNCVERSION, buildtime, XVNCCOPYRIGHT); - ErrorF("Underlying X server release %d, %s\n\n", VENDOR_RELEASE, - VENDOR_STRING); - ErrorF("-screen scrn WxHxD set screen's width, height, depth\n"); - ErrorF("-pixdepths list-of-int support given pixmap depths\n"); -#ifdef RENDER - ErrorF("+/-render turn on/off RENDER extension support" - "(default on)\n"); -#endif - ErrorF("-linebias n adjust thin line pixelization\n"); - ErrorF("-blackpixel n pixel value for black\n"); - ErrorF("-whitepixel n pixel value for white\n"); - -#ifdef HAS_MMAP - ErrorF("-fbdir directory put framebuffers in mmap'ed files in directory\n"); -#endif - -#ifdef HAS_SHM - ErrorF("-shmem put framebuffers in shared memory\n"); -#endif - - ErrorF("-geometry WxH set screen 0's width, height\n"); - ErrorF("-depth D set screen 0's depth\n"); - ErrorF("-pixelformat fmt set pixel format (rgbNNN or bgrNNN)\n"); - ErrorF("-inetd has been launched from inetd\n"); - ErrorF("\nVNC parameters:\n"); - - fprintf(stderr,"\n" - "Parameters can be turned on with - or off with -=0\n" - "Parameters which take a value can be specified as " - "- \n" - "Other valid forms are = -= " - "--=\n" - "Parameter names are case-insensitive. The parameters are:\n\n"); - rfb::Configuration::listParams(79, 14); - } -} - -/* ddxInitGlobals - called by |InitGlobals| from os/util.c */ -void ddxInitGlobals(void) -{ -} - -static -bool displayNumFree(int num) -{ - try { - network::TcpListener l(6000+num); - } catch (rdr::Exception& e) { - return false; - } - char file[256]; - sprintf(file, "/tmp/.X%d-lock", num); - if (access(file, F_OK) == 0) return false; - sprintf(file, "/tmp/.X11-unix/X%d", num); - if (access(file, F_OK) == 0) return false; - sprintf(file, "/usr/spool/sockets/X11/%d", num); - if (access(file, F_OK) == 0) return false; - return true; -} - -int -ddxProcessArgument(int argc, char *argv[], int i) -{ - static Bool firstTime = TRUE; - - if (firstTime) - { - vfbInitializeDefaultScreens(); - vfbInitializePixmapDepths(); - firstTime = FALSE; - rfb::initStdIOLoggers(); - rfb::LogWriter::setLogParams("*:stderr:30"); - } - - if (argv[i][0] == ':') - displaySpecified = true; - - if (strcmp (argv[i], "-screen") == 0) /* -screen n WxHxD */ - { - int screenNum; - if (i + 2 >= argc) UseMsg(); - screenNum = atoi(argv[i+1]); - if (screenNum < 0 || screenNum >= MAXSCREENS) - { - ErrorF("Invalid screen number %d\n", screenNum); - UseMsg(); - } - if (3 != sscanf(argv[i+2], "%dx%dx%d", - &vfbScreens[screenNum].width, - &vfbScreens[screenNum].height, - &vfbScreens[screenNum].depth)) - { - ErrorF("Invalid screen configuration %s\n", argv[i+2]); - UseMsg(); - } - - if (screenNum >= vfbNumScreens) - vfbNumScreens = screenNum + 1; - lastScreen = screenNum; - return 3; - } - - if (strcmp (argv[i], "-pixdepths") == 0) /* -pixdepths list-of-depth */ - { - int depth, ret = 1; - - if (++i >= argc) UseMsg(); - while ((i < argc) && (depth = atoi(argv[i++])) != 0) - { - if (depth < 0 || depth > 32) - { - ErrorF("Invalid pixmap depth %d\n", depth); - UseMsg(); - } - vfbPixmapDepths[depth] = TRUE; - ret++; - } - return ret; - } - - if (strcmp (argv[i], "+render") == 0) /* +render */ - { - Render = TRUE; - return 1; - } - - if (strcmp (argv[i], "-render") == 0) /* -render */ - { - Render = FALSE; - return 1; - } - - if (strcmp (argv[i], "-blackpixel") == 0) /* -blackpixel n */ - { - Pixel pix; - if (++i >= argc) UseMsg(); - pix = atoi(argv[i]); - if (-1 == lastScreen) - { - int i; - for (i = 0; i < MAXSCREENS; i++) - { - vfbScreens[i].blackPixel = pix; - } - } - else - { - vfbScreens[lastScreen].blackPixel = pix; - } - return 2; - } - - if (strcmp (argv[i], "-whitepixel") == 0) /* -whitepixel n */ - { - Pixel pix; - if (++i >= argc) UseMsg(); - pix = atoi(argv[i]); - if (-1 == lastScreen) - { - int i; - for (i = 0; i < MAXSCREENS; i++) - { - vfbScreens[i].whitePixel = pix; - } - } - else - { - vfbScreens[lastScreen].whitePixel = pix; - } - return 2; - } - - if (strcmp (argv[i], "-linebias") == 0) /* -linebias n */ - { - unsigned int linebias; - if (++i >= argc) UseMsg(); - linebias = atoi(argv[i]); - if (-1 == lastScreen) - { - int i; - for (i = 0; i < MAXSCREENS; i++) - { - vfbScreens[i].lineBias = linebias; - } - } - else - { - vfbScreens[lastScreen].lineBias = linebias; - } - return 2; - } - -#ifdef HAS_MMAP - if (strcmp (argv[i], "-fbdir") == 0) /* -fbdir directory */ - { - if (++i >= argc) UseMsg(); - pfbdir = argv[i]; - fbmemtype = MMAPPED_FILE_FB; - return 2; - } -#endif /* HAS_MMAP */ - -#ifdef HAS_SHM - if (strcmp (argv[i], "-shmem") == 0) /* -shmem */ - { - fbmemtype = SHARED_MEMORY_FB; - return 1; - } -#endif - - if (strcmp(argv[i], "-geometry") == 0) - { - if (++i >= argc) UseMsg(); - if (sscanf(argv[i],"%dx%d",&vfbScreens[0].width, - &vfbScreens[0].height) != 2) { - ErrorF("Invalid geometry %s\n", argv[i]); - UseMsg(); - } - return 2; - } - - if (strcmp(argv[i], "-depth") == 0) - { - if (++i >= argc) UseMsg(); - vfbScreens[0].depth = atoi(argv[i]); - return 2; - } - - if (strcmp(argv[i], "-pixelformat") == 0) - { - char rgbbgr[4]; - int bits1, bits2, bits3; - if (++i >= argc) UseMsg(); - if (sscanf(argv[i], "%3s%1d%1d%1d", rgbbgr,&bits1,&bits2,&bits3) < 4) { - ErrorF("Invalid pixel format %s\n", argv[i]); - UseMsg(); - } - -#define SET_PIXEL_FORMAT(vfbScreen) \ - (vfbScreen).pixelFormatDefined = TRUE; \ - (vfbScreen).depth = bits1 + bits2 + bits3; \ - (vfbScreen).greenBits = bits2; \ - if (strcasecmp(rgbbgr, "bgr") == 0) { \ - (vfbScreen).rgbNotBgr = FALSE; \ - (vfbScreen).redBits = bits3; \ - (vfbScreen).blueBits = bits1; \ - } else if (strcasecmp(rgbbgr, "rgb") == 0) { \ - (vfbScreen).rgbNotBgr = TRUE; \ - (vfbScreen).redBits = bits1; \ - (vfbScreen).blueBits = bits3; \ - } else { \ - ErrorF("Invalid pixel format %s\n", argv[i]); \ - UseMsg(); \ - } - - if (-1 == lastScreen) - { - int i; - for (i = 0; i < MAXSCREENS; i++) - { - SET_PIXEL_FORMAT(vfbScreens[i]); - } - } - else - { - SET_PIXEL_FORMAT(vfbScreens[lastScreen]); - } - - return 2; - } - - if (strcmp(argv[i], "-inetd") == 0) - { - dup2(0,3); - vncInetdSock = 3; - close(2); - - if (!displaySpecified) { - int port = network::TcpSocket::getSockPort(vncInetdSock); - int displayNum = port - 5900; - if (displayNum < 0 || displayNum > 99 || !displayNumFree(displayNum)) { - for (displayNum = 1; displayNum < 100; displayNum++) - if (displayNumFree(displayNum)) break; - - if (displayNum == 100) - FatalError("Xvnc error: no free display number for -inetd"); - } - - display = displayNumStr; - sprintf(displayNumStr, "%d", displayNum); - } - - return 1; - } - - if (rfb::Configuration::setParam(argv[i])) - return 1; - - if (argv[i][0] == '-' && i+1 < argc) { - if (rfb::Configuration::setParam(&argv[i][1], argv[i+1])) - return 2; - } - - return 0; -} - -#ifdef DDXTIME /* from ServerOSDefines */ -CARD32 -GetTimeInMillis() -{ - struct timeval tp; - - X_GETTIMEOFDAY(&tp); - return(tp.tv_sec * 1000) + (tp.tv_usec / 1000); -} -#endif - -static ColormapPtr InstalledMaps[MAXSCREENS]; - -static int -vfbListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps) -{ - /* By the time we are processing requests, we can guarantee that there - * is always a colormap installed */ - *pmaps = InstalledMaps[pScreen->myNum]->mid; - return (1); -} - - -static void -vfbInstallColormap(ColormapPtr pmap) -{ - int index = pmap->pScreen->myNum; - ColormapPtr oldpmap = InstalledMaps[index]; - - if (pmap != oldpmap) - { - int entries; - XWDFileHeader *pXWDHeader; - XWDColor *pXWDCmap; - VisualPtr pVisual; - Pixel * ppix; - xrgb * prgb; - xColorItem *defs; - int i; - - if(oldpmap != (ColormapPtr)None) - WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid); - /* Install pmap */ - InstalledMaps[index] = pmap; - WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid); - - entries = pmap->pVisual->ColormapEntries; - pXWDHeader = vfbScreens[pmap->pScreen->myNum].pXWDHeader; - pXWDCmap = vfbScreens[pmap->pScreen->myNum].pXWDCmap; - pVisual = pmap->pVisual; - - swapcopy32(pXWDHeader->visual_class, pVisual->c_class); - swapcopy32(pXWDHeader->red_mask, pVisual->redMask); - swapcopy32(pXWDHeader->green_mask, pVisual->greenMask); - swapcopy32(pXWDHeader->blue_mask, pVisual->blueMask); - swapcopy32(pXWDHeader->bits_per_rgb, pVisual->bitsPerRGBValue); - swapcopy32(pXWDHeader->colormap_entries, pVisual->ColormapEntries); - - ppix = (Pixel *)ALLOCATE_LOCAL(entries * sizeof(Pixel)); - prgb = (xrgb *)ALLOCATE_LOCAL(entries * sizeof(xrgb)); - defs = (xColorItem *)ALLOCATE_LOCAL(entries * sizeof(xColorItem)); - - for (i = 0; i < entries; i++) ppix[i] = i; - /* XXX truecolor */ - QueryColors(pmap, entries, ppix, prgb); - - for (i = 0; i < entries; i++) { /* convert xrgbs to xColorItems */ - defs[i].pixel = ppix[i] & 0xff; /* change pixel to index */ - defs[i].red = prgb[i].red; - defs[i].green = prgb[i].green; - defs[i].blue = prgb[i].blue; - defs[i].flags = DoRed|DoGreen|DoBlue; - } - (*pmap->pScreen->StoreColors)(pmap, entries, defs); - - DEALLOCATE_LOCAL(ppix); - DEALLOCATE_LOCAL(prgb); - DEALLOCATE_LOCAL(defs); - } -} - -static void -vfbUninstallColormap(ColormapPtr pmap) -{ - ColormapPtr curpmap = InstalledMaps[pmap->pScreen->myNum]; - - if(pmap == curpmap) - { - if (pmap->mid != pmap->pScreen->defColormap) - { - curpmap = (ColormapPtr) LookupIDByType(pmap->pScreen->defColormap, - RT_COLORMAP); - (*pmap->pScreen->InstallColormap)(curpmap); - } - } -} - -static void -vfbStoreColors(ColormapPtr pmap, int ndef, xColorItem *pdefs) -{ - XWDColor *pXWDCmap; - int i; - - if (pmap != InstalledMaps[pmap->pScreen->myNum]) - { - return; - } - - pXWDCmap = vfbScreens[pmap->pScreen->myNum].pXWDCmap; - - if ((pmap->pVisual->c_class | DynamicClass) == DirectColor) - { - return; - } - - for (i = 0; i < ndef; i++) - { - if (pdefs[i].flags & DoRed) - { - swapcopy16(pXWDCmap[pdefs[i].pixel].red, pdefs[i].red); - } - if (pdefs[i].flags & DoGreen) - { - swapcopy16(pXWDCmap[pdefs[i].pixel].green, pdefs[i].green); - } - if (pdefs[i].flags & DoBlue) - { - swapcopy16(pXWDCmap[pdefs[i].pixel].blue, pdefs[i].blue); - } - } -} - -static Bool -vfbSaveScreen(ScreenPtr pScreen, int on) -{ - return TRUE; -} - -#ifdef HAS_MMAP - -/* this flushes any changes to the screens out to the mmapped file */ -static void -vfbBlockHandler(pointer blockData, OSTimePtr pTimeout, pointer pReadmask) -{ - int i; - - for (i = 0; i < vfbNumScreens; i++) - { -#ifdef MS_ASYNC - if (-1 == msync((caddr_t)vfbScreens[i].pXWDHeader, - (size_t)vfbScreens[i].sizeInBytes, MS_ASYNC)) -#else - /* silly NetBSD and who else? */ - if (-1 == msync((caddr_t)vfbScreens[i].pXWDHeader, - (size_t)vfbScreens[i].sizeInBytes)) -#endif - { - perror("msync"); - ErrorF("msync failed, errno %d", errno); - } - } -} - - -static void -vfbWakeupHandler(pointer blockData, int result, pointer pReadmask) -{ -} - - -static void -vfbAllocateMmappedFramebuffer(vfbScreenInfoPtr pvfb) -{ -#define DUMMY_BUFFER_SIZE 65536 - char dummyBuffer[DUMMY_BUFFER_SIZE]; - int currentFileSize, writeThisTime; - - sprintf(pvfb->mmap_file, "%s/Xvfb_screen%d", pfbdir, pvfb->scrnum); - if (-1 == (pvfb->mmap_fd = open(pvfb->mmap_file, O_CREAT|O_RDWR, 0666))) - { - perror("open"); - ErrorF("open %s failed, errno %d", pvfb->mmap_file, errno); - return; - } - - /* Extend the file to be the proper size */ - - bzero(dummyBuffer, DUMMY_BUFFER_SIZE); - for (currentFileSize = 0; - currentFileSize < pvfb->sizeInBytes; - currentFileSize += writeThisTime) - { - writeThisTime = min(DUMMY_BUFFER_SIZE, - pvfb->sizeInBytes - currentFileSize); - if (-1 == write(pvfb->mmap_fd, dummyBuffer, writeThisTime)) - { - perror("write"); - ErrorF("write %s failed, errno %d", pvfb->mmap_file, errno); - return; - } - } - - /* try to mmap the file */ - - pvfb->pXWDHeader = (XWDFileHeader *)mmap((caddr_t)NULL, pvfb->sizeInBytes, - PROT_READ|PROT_WRITE, - MAP_FILE|MAP_SHARED, - pvfb->mmap_fd, 0); - if (-1 == (long)pvfb->pXWDHeader) - { - perror("mmap"); - ErrorF("mmap %s failed, errno %d", pvfb->mmap_file, errno); - pvfb->pXWDHeader = NULL; - return; - } - - if (!RegisterBlockAndWakeupHandlers(vfbBlockHandler, vfbWakeupHandler, - NULL)) - { - pvfb->pXWDHeader = NULL; - } -} -#endif /* HAS_MMAP */ - - -#ifdef HAS_SHM -static void -vfbAllocateSharedMemoryFramebuffer(vfbScreenInfoPtr pvfb) -{ - /* create the shared memory segment */ - - pvfb->shmid = shmget(IPC_PRIVATE, pvfb->sizeInBytes, IPC_CREAT|0777); - if (pvfb->shmid < 0) - { - perror("shmget"); - ErrorF("shmget %d bytes failed, errno %d", pvfb->sizeInBytes, errno); - return; - } - - /* try to attach it */ - - pvfb->pXWDHeader = (XWDFileHeader *)shmat(pvfb->shmid, 0, 0); - if (-1 == (long)pvfb->pXWDHeader) - { - perror("shmat"); - ErrorF("shmat failed, errno %d", errno); - pvfb->pXWDHeader = NULL; - return; - } - - ErrorF("screen %d shmid %d\n", pvfb->scrnum, pvfb->shmid); -} -#endif /* HAS_SHM */ - - -static char * -vfbAllocateFramebufferMemory(vfbScreenInfoPtr pvfb) -{ - if (pvfb->pfbMemory) return pvfb->pfbMemory; /* already done */ - - pvfb->sizeInBytes = pvfb->paddedBytesWidth * pvfb->height; - - /* Calculate how many entries in colormap. This is rather bogus, because - * the visuals haven't even been set up yet, but we need to know because we - * have to allocate space in the file for the colormap. The number 10 - * below comes from the MAX_PSEUDO_DEPTH define in cfbcmap.c. - */ - - if (pvfb->depth <= 10) - { /* single index colormaps */ - pvfb->ncolors = 1 << pvfb->depth; - } - else - { /* decomposed colormaps */ - int nplanes_per_color_component = pvfb->depth / 3; - if (pvfb->depth % 3) nplanes_per_color_component++; - pvfb->ncolors = 1 << nplanes_per_color_component; - } - - /* add extra bytes for XWDFileHeader, window name, and colormap */ - - pvfb->sizeInBytes += SIZEOF(XWDheader) + XWD_WINDOW_NAME_LEN + - pvfb->ncolors * SIZEOF(XWDColor); - - pvfb->pXWDHeader = NULL; - switch (fbmemtype) - { -#ifdef HAS_MMAP - case MMAPPED_FILE_FB: vfbAllocateMmappedFramebuffer(pvfb); break; -#else - case MMAPPED_FILE_FB: break; -#endif - -#ifdef HAS_SHM - case SHARED_MEMORY_FB: vfbAllocateSharedMemoryFramebuffer(pvfb); break; -#else - case SHARED_MEMORY_FB: break; -#endif - - case NORMAL_MEMORY_FB: - pvfb->pXWDHeader = (XWDFileHeader *)Xalloc(pvfb->sizeInBytes); - break; - } - - if (pvfb->pXWDHeader) - { - pvfb->pXWDCmap = (XWDColor *)((char *)pvfb->pXWDHeader - + SIZEOF(XWDheader) + XWD_WINDOW_NAME_LEN); - pvfb->pfbMemory = (char *)(pvfb->pXWDCmap + pvfb->ncolors); - - return pvfb->pfbMemory; - } - else - return NULL; -} - -static void -vfbWriteXWDFileHeader(ScreenPtr pScreen) -{ - vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum]; - XWDFileHeader *pXWDHeader = pvfb->pXWDHeader; - char hostname[XWD_WINDOW_NAME_LEN]; - unsigned long swaptest = 1; - int i; - - needswap = *(char *) &swaptest; - - pXWDHeader->header_size = (char *)pvfb->pXWDCmap - (char *)pvfb->pXWDHeader; - pXWDHeader->file_version = XWD_FILE_VERSION; - - pXWDHeader->pixmap_format = ZPixmap; - pXWDHeader->pixmap_depth = pvfb->depth; - pXWDHeader->pixmap_height = pXWDHeader->window_height = pvfb->height; - pXWDHeader->xoffset = 0; - pXWDHeader->byte_order = IMAGE_BYTE_ORDER; - pXWDHeader->bitmap_bit_order = BITMAP_BIT_ORDER; -#ifndef INTERNAL_VS_EXTERNAL_PADDING - pXWDHeader->pixmap_width = pXWDHeader->window_width = pvfb->width; - pXWDHeader->bitmap_unit = BITMAP_SCANLINE_UNIT; - pXWDHeader->bitmap_pad = BITMAP_SCANLINE_PAD; -#else - pXWDHeader->pixmap_width = pXWDHeader->window_width = pvfb->paddedWidth; - pXWDHeader->bitmap_unit = BITMAP_SCANLINE_UNIT_PROTO; - pXWDHeader->bitmap_pad = BITMAP_SCANLINE_PAD_PROTO; -#endif - pXWDHeader->bits_per_pixel = pvfb->bitsPerPixel; - pXWDHeader->bytes_per_line = pvfb->paddedBytesWidth; - pXWDHeader->ncolors = pvfb->ncolors; - - /* visual related fields are written when colormap is installed */ - - pXWDHeader->window_x = pXWDHeader->window_y = 0; - pXWDHeader->window_bdrwidth = 0; - - /* write xwd "window" name: Xvfb hostname:server.screen */ - - if (-1 == gethostname(hostname, sizeof(hostname))) - hostname[0] = 0; - else - hostname[XWD_WINDOW_NAME_LEN-1] = 0; - sprintf((char *)(pXWDHeader+1), "Xvfb %s:%s.%d", hostname, display, - pScreen->myNum); - - /* write colormap pixel slot values */ - - for (i = 0; i < pvfb->ncolors; i++) - { - pvfb->pXWDCmap[i].pixel = i; - } - - /* byte swap to most significant byte first */ - - if (needswap) - { - SwapLongs((CARD32 *)pXWDHeader, SIZEOF(XWDheader)/4); - for (i = 0; i < pvfb->ncolors; i++) - { - register char n; - swapl(&pvfb->pXWDCmap[i].pixel, n); - } - } -} - - -static Bool -vfbCursorOffScreen (ScreenPtr *ppScreen, int *x, int *y) -{ - return FALSE; -} - -static void -vfbCrossScreen (ScreenPtr pScreen, Bool entering) -{ -} - -static Bool vfbRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) { - return TRUE; -} - -static Bool vfbUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) { - return TRUE; -} - -static void vfbSetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y) -{ -} - -static void vfbMoveCursor(ScreenPtr pScreen, int x, int y) -{ -} - -static miPointerSpriteFuncRec vfbPointerSpriteFuncs = { - vfbRealizeCursor, - vfbUnrealizeCursor, - vfbSetCursor, - vfbMoveCursor -}; - -static miPointerScreenFuncRec vfbPointerCursorFuncs = { - vfbCursorOffScreen, - vfbCrossScreen, - miPointerWarpCursor -}; - -static Bool -vfbCloseScreen(int index, ScreenPtr pScreen) -{ - vfbScreenInfoPtr pvfb = &vfbScreens[index]; - int i; - - pScreen->CloseScreen = pvfb->closeScreen; - - /* - * XXX probably lots of stuff to clean. For now, - * clear InstalledMaps[] so that server reset works correctly. - */ - for (i = 0; i < MAXSCREENS; i++) - InstalledMaps[i] = NULL; - - return pScreen->CloseScreen(index, pScreen); -} - -static Bool -vfbScreenInit(int index, ScreenPtr pScreen, int argc, char **argv) -{ - vfbScreenInfoPtr pvfb = &vfbScreens[index]; - int dpi = 100; - int ret; - char *pbits; - - if (monitorResolution) dpi = monitorResolution; - - pvfb->paddedBytesWidth = PixmapBytePad(pvfb->width, pvfb->depth); - pvfb->bitsPerPixel = vfbBitsPerPixel(pvfb->depth); - pvfb->paddedWidth = pvfb->paddedBytesWidth * 8 / pvfb->bitsPerPixel; - pbits = vfbAllocateFramebufferMemory(pvfb); - if (!pbits) return FALSE; - vncFbptr[index] = pbits; - - defaultColorVisualClass - = (pvfb->bitsPerPixel > 8) ? TrueColor : PseudoColor; - - ret = fbScreenInit(pScreen, pbits, pvfb->width, pvfb->height, - dpi, dpi, pvfb->paddedWidth, pvfb->bitsPerPixel); - -#ifdef RENDER - if (ret && Render) - fbPictureInit (pScreen, 0, 0); -#endif - - if (!ret) return FALSE; - - /* miInitializeBackingStore(pScreen); */ - - /* - * Circumvent the backing store that was just initialised. This amounts - * to a truely bizarre way of initialising SaveDoomedAreas and friends. - */ - - pScreen->InstallColormap = vfbInstallColormap; - pScreen->UninstallColormap = vfbUninstallColormap; - pScreen->ListInstalledColormaps = vfbListInstalledColormaps; - - pScreen->SaveScreen = vfbSaveScreen; - pScreen->StoreColors = vfbStoreColors; - - miPointerInitialize(pScreen, &vfbPointerSpriteFuncs, &vfbPointerCursorFuncs, - FALSE); - - vfbWriteXWDFileHeader(pScreen); - - pScreen->blackPixel = pvfb->blackPixel; - pScreen->whitePixel = pvfb->whitePixel; - - if (!pvfb->pixelFormatDefined && pvfb->depth == 16) { - pvfb->pixelFormatDefined = TRUE; - pvfb->rgbNotBgr = TRUE; - pvfb->blueBits = pvfb->redBits = 5; - pvfb->greenBits = 6; - } - - if (pvfb->pixelFormatDefined) { - VisualPtr vis = pScreen->visuals; - for (int i = 0; i < pScreen->numVisuals; i++) { - if (pvfb->rgbNotBgr) { - vis->offsetBlue = 0; - vis->blueMask = (1 << pvfb->blueBits) - 1; - vis->offsetGreen = pvfb->blueBits; - vis->greenMask = ((1 << pvfb->greenBits) - 1) << vis->offsetGreen; - vis->offsetRed = vis->offsetGreen + pvfb->greenBits; - vis->redMask = ((1 << pvfb->redBits) - 1) << vis->offsetRed; - } else { - vis->offsetRed = 0; - vis->redMask = (1 << pvfb->redBits) - 1; - vis->offsetGreen = pvfb->redBits; - vis->greenMask = ((1 << pvfb->greenBits) - 1) << vis->offsetGreen; - vis->offsetBlue = vis->offsetGreen + pvfb->greenBits; - vis->blueMask = ((1 << pvfb->blueBits) - 1) << vis->offsetBlue; - } - vis++; - } - } - - ret = fbCreateDefColormap(pScreen); - - miSetZeroLineBias(pScreen, pvfb->lineBias); - - pvfb->closeScreen = pScreen->CloseScreen; - pScreen->CloseScreen = vfbCloseScreen; - -#ifndef NO_INIT_BACKING_STORE - miInitializeBackingStore(pScreen); - pScreen->backingStoreSupport = Always; -#endif - - return ret; - -} /* end vfbScreenInit */ - - -static void vfbClientStateChange(CallbackListPtr*, pointer, pointer) { - dispatchException &= ~DE_RESET; -} - -void -InitOutput(ScreenInfo *screenInfo, int argc, char **argv) -{ - ErrorF("\nXvnc %s - built %s\n%s", XVNCVERSION, buildtime, XVNCCOPYRIGHT); - ErrorF("Underlying X server release %d, %s\n\n", VENDOR_RELEASE, - VENDOR_STRING); - int i; - int NumFormats = 0; - - /* initialize pixmap formats */ - - /* must have a pixmap depth to match every screen depth */ - for (i = 0; i < vfbNumScreens; i++) - { - vfbPixmapDepths[vfbScreens[i].depth] = TRUE; - } - - /* RENDER needs a good set of pixmaps. */ - if (Render) { - vfbPixmapDepths[1] = TRUE; - vfbPixmapDepths[4] = TRUE; - vfbPixmapDepths[8] = TRUE; -/* vfbPixmapDepths[15] = TRUE; */ - vfbPixmapDepths[16] = TRUE; - vfbPixmapDepths[24] = TRUE; - vfbPixmapDepths[32] = TRUE; - } - - for (i = 1; i <= 32; i++) - { - if (vfbPixmapDepths[i]) - { - if (NumFormats >= MAXFORMATS) - FatalError ("MAXFORMATS is too small for this server\n"); - screenInfo->formats[NumFormats].depth = i; - screenInfo->formats[NumFormats].bitsPerPixel = vfbBitsPerPixel(i); - screenInfo->formats[NumFormats].scanlinePad = BITMAP_SCANLINE_PAD; - NumFormats++; - } - } - - screenInfo->imageByteOrder = IMAGE_BYTE_ORDER; - screenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; - screenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD; - screenInfo->bitmapBitOrder = BITMAP_BIT_ORDER; - screenInfo->numPixmapFormats = NumFormats; - - /* initialize screens */ - - for (i = 0; i < vfbNumScreens; i++) - { - if (-1 == AddScreen(vfbScreenInit, argc, argv)) - { - FatalError("Couldn't add screen %d", i); - } - } - - if (!AddCallback(&ClientStateCallback, vfbClientStateChange, 0)) { - FatalError("AddCallback failed\n"); - } -} /* end InitOutput */ - -#ifdef DPMSExtension -extern "C" { -#if NeedFunctionPrototypes - void DPMSSet(CARD16 level) -#else - void DPMSSet(level) - CARD16 level; -#endif - { - return; - } - - Bool DPMSSupported() - { - return FALSE; - } -} -#endif - -/* this is just to get the server to link on AIX */ -#ifdef AIXV3 -int SelectWaitTime = 10000; /* usec */ -#endif - -Bool LegalModifier(unsigned int key, DevicePtr pDev) -{ - return TRUE; -} - -void ProcessInputEvents() -{ - mieqProcessInputEvents(); - miPointerUpdate(); -} - -/* Fairly standard US PC Keyboard */ - -#define VFB_MIN_KEY 8 -#define VFB_MAX_KEY 255 -#define VFB_MAP_LEN (VFB_MAX_KEY - VFB_MIN_KEY + 1) -#define KEYSYMS_PER_KEY 2 -KeySym keyboardMap[VFB_MAP_LEN * KEYSYMS_PER_KEY] = { - NoSymbol, NoSymbol, - XK_Escape, NoSymbol, - XK_1, XK_exclam, - XK_2, XK_at, - XK_3, XK_numbersign, - XK_4, XK_dollar, - XK_5, XK_percent, - XK_6, XK_asciicircum, - XK_7, XK_ampersand, - XK_8, XK_asterisk, - XK_9, XK_parenleft, - XK_0, XK_parenright, - XK_minus, XK_underscore, - XK_equal, XK_plus, - XK_BackSpace, NoSymbol, - XK_Tab, NoSymbol, - XK_q, XK_Q, - XK_w, XK_W, - XK_e, XK_E, - XK_r, XK_R, - XK_t, XK_T, - XK_y, XK_Y, - XK_u, XK_U, - XK_i, XK_I, - XK_o, XK_O, - XK_p, XK_P, - XK_bracketleft, XK_braceleft, - XK_bracketright, XK_braceright, - XK_Return, NoSymbol, - XK_Control_L, NoSymbol, - XK_a, XK_A, - XK_s, XK_S, - XK_d, XK_D, - XK_f, XK_F, - XK_g, XK_G, - XK_h, XK_H, - XK_j, XK_J, - XK_k, XK_K, - XK_l, XK_L, - XK_semicolon, XK_colon, - XK_apostrophe, XK_quotedbl, - XK_grave, XK_asciitilde, - XK_Shift_L, NoSymbol, - XK_backslash, XK_bar, - XK_z, XK_Z, - XK_x, XK_X, - XK_c, XK_C, - XK_v, XK_V, - XK_b, XK_B, - XK_n, XK_N, - XK_m, XK_M, - XK_comma, XK_less, - XK_period, XK_greater, - XK_slash, XK_question, - XK_Shift_R, NoSymbol, - XK_KP_Multiply, NoSymbol, - XK_Alt_L, XK_Meta_L, - XK_space, NoSymbol, - /*XK_Caps_Lock*/ NoSymbol, NoSymbol, - XK_F1, NoSymbol, - XK_F2, NoSymbol, - XK_F3, NoSymbol, - XK_F4, NoSymbol, - XK_F5, NoSymbol, - XK_F6, NoSymbol, - XK_F7, NoSymbol, - XK_F8, NoSymbol, - XK_F9, NoSymbol, - XK_F10, NoSymbol, - XK_Num_Lock, XK_Pointer_EnableKeys, - XK_Scroll_Lock, NoSymbol, - XK_KP_Home, XK_KP_7, - XK_KP_Up, XK_KP_8, - XK_KP_Prior, XK_KP_9, - XK_KP_Subtract, NoSymbol, - XK_KP_Left, XK_KP_4, - XK_KP_Begin, XK_KP_5, - XK_KP_Right, XK_KP_6, - XK_KP_Add, NoSymbol, - XK_KP_End, XK_KP_1, - XK_KP_Down, XK_KP_2, - XK_KP_Next, XK_KP_3, - XK_KP_Insert, XK_KP_0, - XK_KP_Delete, XK_KP_Decimal, - NoSymbol, NoSymbol, - NoSymbol, NoSymbol, - NoSymbol, NoSymbol, - XK_F11, NoSymbol, - XK_F12, NoSymbol, - XK_Home, NoSymbol, - XK_Up, NoSymbol, - XK_Prior, NoSymbol, - XK_Left, NoSymbol, - NoSymbol, NoSymbol, - XK_Right, NoSymbol, - XK_End, NoSymbol, - XK_Down, NoSymbol, - XK_Next, NoSymbol, - XK_Insert, NoSymbol, - XK_Delete, NoSymbol, - XK_KP_Enter, NoSymbol, - XK_Control_R, NoSymbol, - XK_Pause, XK_Break, - XK_Print, XK_Execute, - XK_KP_Divide, NoSymbol, - XK_Alt_R, XK_Meta_R, -}; - -static Bool GetMappings(KeySymsPtr pKeySyms, CARD8 *pModMap) -{ - int i; - - for (i = 0; i < MAP_LENGTH; i++) - pModMap[i] = NoSymbol; - - for (i = 0; i < VFB_MAP_LEN; i++) { - if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Caps_Lock) - pModMap[i + VFB_MIN_KEY] = LockMask; - else if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Shift_L || - keyboardMap[i * KEYSYMS_PER_KEY] == XK_Shift_R) - pModMap[i + VFB_MIN_KEY] = ShiftMask; - else if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Control_L || - keyboardMap[i * KEYSYMS_PER_KEY] == XK_Control_R) { - pModMap[i + VFB_MIN_KEY] = ControlMask; - } - else if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Alt_L || - keyboardMap[i * KEYSYMS_PER_KEY] == XK_Alt_R) - pModMap[i + VFB_MIN_KEY] = Mod1Mask; - } - - pKeySyms->minKeyCode = VFB_MIN_KEY; - pKeySyms->maxKeyCode = VFB_MAX_KEY; - pKeySyms->mapWidth = KEYSYMS_PER_KEY; - pKeySyms->map = keyboardMap; - - return TRUE; -} - -static void vfbBell(int percent, DeviceIntPtr device, pointer ctrl, int class_) -{ - if (percent > 0) - vncBell(); -} - -static int vfbKeybdProc(DeviceIntPtr pDevice, int onoff) -{ - KeySymsRec keySyms; - CARD8 modMap[MAP_LENGTH]; - DevicePtr pDev = (DevicePtr)pDevice; - - switch (onoff) - { - case DEVICE_INIT: - GetMappings(&keySyms, modMap); - InitKeyboardDeviceStruct(pDev, &keySyms, modMap, - (BellProcPtr)vfbBell, (KbdCtrlProcPtr)NoopDDA); - break; - case DEVICE_ON: - pDev->on = TRUE; - break; - case DEVICE_OFF: - pDev->on = FALSE; - break; - case DEVICE_CLOSE: - break; - } - return Success; -} - -static int vfbMouseProc(DeviceIntPtr pDevice, int onoff) -{ - BYTE map[6]; - DevicePtr pDev = (DevicePtr)pDevice; - - switch (onoff) - { - case DEVICE_INIT: - map[1] = 1; - map[2] = 2; - map[3] = 3; - map[4] = 4; - map[5] = 5; - InitPointerDeviceStruct(pDev, map, 5, miPointerGetMotionEvents, - (PtrCtrlProcPtr)NoopDDA, miPointerGetMotionBufferSize()); - break; - - case DEVICE_ON: - pDev->on = TRUE; - break; - - case DEVICE_OFF: - pDev->on = FALSE; - break; - - case DEVICE_CLOSE: - break; - } - return Success; -} - -// InitInput is called after InitExtensions, so we're guaranteed that -// vncExtensionInit() has already been called. - -void InitInput(int argc, char *argv[]) -{ - DeviceIntPtr p, k; - p = AddInputDevice(vfbMouseProc, TRUE); - k = AddInputDevice(vfbKeybdProc, TRUE); - RegisterPointerDevice(p); - RegisterKeyboardDevice(k); - miRegisterPointerDevice(screenInfo.screens[0], p); - (void)mieqInit ((DevicePtr)k, (DevicePtr)p); -} diff --git a/unix/xc/programs/Xserver/vnc/module/Imakefile b/unix/xc/programs/Xserver/vnc/module/Imakefile deleted file mode 100644 index d2d34ed0..00000000 --- a/unix/xc/programs/Xserver/vnc/module/Imakefile +++ /dev/null @@ -1,61 +0,0 @@ - - VNCUNIXDIR = VncUnixDir - VNCCOMMONDIR = VncCommonDir - VNCLIBS = VncExtLibs - VNCINCLUDE = -I$(VNCCOMMONDIR) -I$(VNCUNIXDIR)/vncconfig - -#define CplusplusSource - -#define IHaveModules -#include - - SRCS = vncExtInit.cc vncHooks.cc xf86vncModule.cc XserverDesktop.cc - OBJS = vncExtInit.o vncHooks.o xf86vncModule.o XserverDesktop.o -INCLUDES = -I.. -I../../include -I$(EXTINCSRC) -I$(XINCLUDESRC) \ - -I$(FONTINCSRC) -I$(XF86COMSRC) \ - -I../../render $(VNCINCLUDE) - DEFINES = $(STD_DEFINES) -DGC_HAS_COMPOSITE_CLIP -DXFree86LOADER - -LinkSourceFile(vncExtInit.cc,..) -LinkSourceFile(vncHooks.cc,..) -LinkSourceFile(xf86vncModule.cc,..) -LinkSourceFile(XserverDesktop.cc,..) - -ModuleObjectRule() -/* - LibraryModuleTarget(vnc,$(OBJS) $(VNCLIBS)) - InstallLibraryModule(vnc,$(MODULEDIR),extensions) -*/ - -/* *** The imake rules don't define a ModuleCplusplusObjectRule so - for now we just assume that NormalCplusplusObjectRule will - do the job. - NB: If we don't do this then make will assume CC is the C++ compiler! -*/ -NormalCplusplusObjectRule() - -/* - * CplusplusDynamicModuleTarget - build a module to be dynamically loaded - */ -#ifndef CplusplusDynamicModuleTarget -#define CplusplusDynamicModuleTarget(module,modlist) @@\ -AllTarget(module) @@\ - @@\ -module: modlist @@\ - RemoveFile($@) @@\ - $(CXX) -o $@ $(SHLIBLDFLAGS) modlist @@\ - @@\ -clean:: @@\ - RemoveFile(module) -#endif /* CplusplusDynamicModuleTarget */ - - - -CplusplusDynamicModuleTarget(vnc.so,$(OBJS) $(VNCLIBS)) -InstallDynamicModule(vnc.so,$(MODULEDIR),extensions) - -DependTarget() - -/* - InstallDriverSDKLibraryModule(vnc,$(DRIVERSDKMODULEDIR),extensions) -*/ diff --git a/unix/xc/programs/Xserver/vnc/vncExtInit.cc b/unix/xc/programs/Xserver/vnc/vncExtInit.cc deleted file mode 100644 index 9cf9d21b..00000000 --- a/unix/xc/programs/Xserver/vnc/vncExtInit.cc +++ /dev/null @@ -1,866 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#include - -extern "C" { -#define class c_class -#define NEED_EVENTS -#include "X.h" -#include "Xproto.h" -#include "misc.h" -#include "os.h" -#include "dixstruct.h" -#include "extnsionst.h" -#include "scrnintstr.h" -#include "selection.h" -#define _VNCEXT_SERVER_ -#define _VNCEXT_PROTO_ -#include "vncExt.h" -#undef class -#undef xalloc -} - -#include -#include -#include -#include -#include -#include -#include -#include -#undef max -#undef min -#include - -#include "XserverDesktop.h" -#include "vncHooks.h" -#include "vncExtInit.h" - -extern "C" { - - extern void vncExtensionInit(); - static void vncResetProc(ExtensionEntry* extEntry); - static void vncBlockHandler(pointer data, OSTimePtr t, pointer readmask); - static void vncWakeupHandler(pointer data, int nfds, pointer readmask); - static void vncClientStateChange(CallbackListPtr*, pointer, pointer); - static void SendSelectionChangeEvent(Atom selection); - static int ProcVncExtDispatch(ClientPtr client); - static int SProcVncExtDispatch(ClientPtr client); - - extern char *display; - - extern Selection *CurrentSelections; - extern int NumCurrentSelections; -} - -using namespace rfb; - -static rfb::LogWriter vlog("vncext"); - -static unsigned long vncExtGeneration = 0; -static bool initialised = false; -static XserverDesktop* desktop[MAXSCREENS] = { 0, }; -void* vncFbptr[MAXSCREENS] = { 0, }; - -static char* clientCutText = 0; -static int clientCutTextLen = 0; - -static XserverDesktop* queryConnectDesktop = 0; -static void* queryConnectId = 0; -static int queryConnectTimeout = 0; -static OsTimerPtr queryConnectTimer = 0; - -static struct VncInputSelect* vncInputSelectHead = 0; -struct VncInputSelect { - VncInputSelect(ClientPtr c, Window w, int m) : client(c), window(w), mask(m) - { - next = vncInputSelectHead; - vncInputSelectHead = this; - } - ClientPtr client; - Window window; - int mask; - VncInputSelect* next; -}; - -static int nPrevSelections = 0; -static TimeStamp* prevSelectionTimes = 0; - -static int vncErrorBase = 0; -static int vncEventBase = 0; -static char* vncPasswdFile = 0; -int vncInetdSock = -1; - -rfb::AliasParameter rfbauth("rfbauth", "Alias for PasswordFile", - &SSecurityFactoryStandard::vncAuthPasswdFile); -rfb::StringParameter httpDir("httpd", - "Directory containing files to serve via HTTP", - ""); -rfb::IntParameter httpPort("httpPort", "TCP port to listen for HTTP",0); -rfb::AliasParameter rfbwait("rfbwait", "Alias for ClientWaitTimeMillis", - &rfb::Server::clientWaitTimeMillis); -rfb::IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",0); -rfb::StringParameter desktopName("desktop", "Name of VNC desktop","x11"); -rfb::BoolParameter localhostOnly("localhost", - "Only allow connections from localhost", - false); - -void vncExtensionInit() -{ - if (vncExtGeneration == serverGeneration) { - vlog.error("vncExtensionInit: called twice in same generation?"); - return; - } - vncExtGeneration = serverGeneration; - - ExtensionEntry* extEntry - = AddExtension(VNCEXTNAME, VncExtNumberEvents, VncExtNumberErrors, - ProcVncExtDispatch, SProcVncExtDispatch, vncResetProc, - StandardMinorOpcode); - if (!extEntry) { - ErrorF("vncExtInit: AddExtension failed\n"); - return; - } - - vncErrorBase = extEntry->errorBase; - vncEventBase = extEntry->eventBase; - - vlog.info("VNC extension running!"); - - if (!AddCallback(&ClientStateCallback, vncClientStateChange, 0)) { - FatalError("AddCallback failed\n"); - } - - try { - if (!initialised) { - rfb::initStdIOLoggers(); - initialised = true; - } - - for (int scr = 0; scr < screenInfo.numScreens; scr++) { - - if (!desktop[scr]) { - network::TcpListener* listener = 0; - network::TcpListener* httpListener = 0; - if (scr == 0 && vncInetdSock != -1) { - if (network::TcpSocket::isSocket(vncInetdSock) && - !network::TcpSocket::isConnected(vncInetdSock)) - { - listener = new network::TcpListener(0, 0, vncInetdSock, true); - vlog.info("inetd wait"); - } - } else { - int port = rfbport; - if (port == 0) port = 5900 + atoi(display); - port += 1000 * scr; - listener = new network::TcpListener(port, localhostOnly); - vlog.info("Listening for VNC connections on port %d",port); - CharArray httpDirStr(httpDir.getData()); - if (httpDirStr.buf[0]) { - port = httpPort; - if (port == 0) port = 5800 + atoi(display); - port += 1000 * scr; - httpListener = new network::TcpListener(port, localhostOnly); - vlog.info("Listening for HTTP connections on port %d",port); - } - } - - CharArray desktopNameStr(desktopName.getData()); - desktop[scr] = new XserverDesktop(screenInfo.screens[scr], listener, - httpListener, - desktopNameStr.buf, - vncFbptr[scr]); - vlog.info("created VNC server for screen %d", scr); - - if (scr == 0 && vncInetdSock != -1 && !listener) { - network::Socket* sock = new network::TcpSocket(vncInetdSock); - desktop[scr]->addClient(sock, false); - vlog.info("added inetd sock"); - } - - } else { - desktop[scr]->serverReset(screenInfo.screens[scr]); - } - - vncHooksInit(screenInfo.screens[scr], desktop[scr]); - } - - RegisterBlockAndWakeupHandlers(vncBlockHandler, vncWakeupHandler, 0); - - } catch (rdr::Exception& e) { - vlog.error("vncExtInit: %s",e.str()); - } -} - -static void vncResetProc(ExtensionEntry* extEntry) -{ -} - -// -// vncBlockHandler - called just before the X server goes into select(). Call -// on to the block handler for each desktop. Then check whether any of the -// selections have changed, and if so, notify any interested X clients. -// - -static void vncBlockHandler(pointer data, OSTimePtr timeout, pointer readmask) -{ - fd_set* fds = (fd_set*)readmask; - - for (int scr = 0; scr < screenInfo.numScreens; scr++) { - if (desktop[scr]) { - desktop[scr]->blockHandler(fds); - } - } - - if (nPrevSelections != NumCurrentSelections) { - prevSelectionTimes - = (TimeStamp*)xnfrealloc(prevSelectionTimes, - NumCurrentSelections * sizeof(TimeStamp)); - for (int i = nPrevSelections; i < NumCurrentSelections; i++) { - prevSelectionTimes[i].months = 0; - prevSelectionTimes[i].milliseconds = 0; - } - nPrevSelections = NumCurrentSelections; - } - for (int i = 0; i < NumCurrentSelections; i++) { - if (CurrentSelections[i].lastTimeChanged.months - != prevSelectionTimes[i].months || - CurrentSelections[i].lastTimeChanged.milliseconds - != prevSelectionTimes[i].milliseconds) - { - SendSelectionChangeEvent(CurrentSelections[i].selection); - prevSelectionTimes[i] = CurrentSelections[i].lastTimeChanged; - } - } -} - -static void vncWakeupHandler(pointer data, int nfds, pointer readmask) -{ - fd_set* fds = (fd_set*)readmask; - - for (int scr = 0; scr < screenInfo.numScreens; scr++) { - if (desktop[scr]) { - desktop[scr]->wakeupHandler(fds, nfds); - } - } -} - -static void vncClientStateChange(CallbackListPtr*, pointer, pointer p) -{ - ClientPtr client = ((NewClientInfoRec*)p)->client; - if (client->clientState == ClientStateGone) { - VncInputSelect** nextPtr = &vncInputSelectHead; - for (VncInputSelect* cur = vncInputSelectHead; cur; cur = *nextPtr) { - if (cur->client == client) { - *nextPtr = cur->next; - delete cur; - continue; - } - nextPtr = &cur->next; - } - } -} - -void vncBell() -{ - for (int scr = 0; scr < screenInfo.numScreens; scr++) { - if (desktop[scr]) { - desktop[scr]->bell(); - } - } -} - -void vncClientGone(int fd) -{ - if (fd == vncInetdSock) { - fprintf(stderr,"inetdSock client gone\n"); - GiveUp(0); - } -} - -void vncClientCutText(const char* str, int len) -{ - delete [] clientCutText; - clientCutText = new char[len]; - memcpy(clientCutText, str, len); - clientCutTextLen = len; - xVncExtClientCutTextNotifyEvent ev; - ev.type = vncEventBase + VncExtClientCutTextNotify; - for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) { - if (cur->mask & VncExtClientCutTextMask) { - ev.sequenceNumber = cur->client->sequence; - ev.window = cur->window; - ev.time = GetTimeInMillis(); - if (cur->client->swapped) { - int n; - swaps(&ev.sequenceNumber, n); - swapl(&ev.window, n); - swapl(&ev.time, n); - } - WriteToClient(cur->client, sizeof(xVncExtClientCutTextNotifyEvent), - (char *)&ev); - } - } -} - - -static CARD32 queryConnectTimerCallback(OsTimerPtr timer, - CARD32 now, pointer arg) -{ - if (queryConnectTimeout) - queryConnectDesktop->approveConnection(queryConnectId, false, "The attempt to prompt the user to accept the connection failed"); - // Re-notify clients, causing them to discover that we're done - vncQueryConnect(queryConnectDesktop, queryConnectId); - return 0; -} - -void vncQueryConnect(XserverDesktop* desktop, void* opaqueId) -{ - // Only one query can be processed at any one time - if (queryConnectTimeout && ((desktop != queryConnectDesktop) || - (opaqueId != queryConnectId))) { - desktop->approveConnection(opaqueId, false, - "Another connection is currently being queried."); - return; - } - - // Get the query timeout. If it's zero, there is no query. - queryConnectTimeout = desktop->getQueryTimeout(opaqueId); - queryConnectId = queryConnectTimeout ? opaqueId : 0; - queryConnectDesktop = queryConnectTimeout ? desktop : 0; - - // Notify clients - bool notified = false; - xVncExtQueryConnectNotifyEvent ev; - ev.type = vncEventBase + VncExtQueryConnectNotify; - for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) { - if (cur->mask & VncExtQueryConnectMask) { - ev.sequenceNumber = cur->client->sequence; - ev.window = cur->window; - if (cur->client->swapped) { - int n; - swaps(&ev.sequenceNumber, n); - swapl(&ev.window, n); - } - WriteToClient(cur->client, sizeof(xVncExtQueryConnectNotifyEvent), - (char *)&ev); - notified = true; - } - } - - // If we're being asked to query a connection (rather than to cancel - // a query), and haven't been able to notify clients then reject it. - if (queryConnectTimeout && !notified) { - queryConnectTimeout = 0; - queryConnectId = 0; - queryConnectDesktop = 0; - desktop->approveConnection(opaqueId, false, - "Unable to query the local user to accept the connection."); - return; - } - - // Set a timer so that if no-one ever responds, we will eventually - // reject the connection - // NB: We don't set a timer if sock is null, since that indicates - // that pending queries should be cancelled. - if (queryConnectDesktop) - queryConnectTimer = TimerSet(queryConnectTimer, 0, - queryConnectTimeout*2000, - queryConnectTimerCallback, 0); - else - TimerCancel(queryConnectTimer); -} - -static void SendSelectionChangeEvent(Atom selection) -{ - xVncExtSelectionChangeNotifyEvent ev; - ev.type = vncEventBase + VncExtSelectionChangeNotify; - for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) { - if (cur->mask & VncExtSelectionChangeMask) { - ev.sequenceNumber = cur->client->sequence; - ev.window = cur->window; - ev.selection = selection; - if (cur->client->swapped) { - int n; - swaps(&ev.sequenceNumber, n); - swapl(&ev.window, n); - swapl(&ev.selection, n); - } - WriteToClient(cur->client, sizeof(xVncExtSelectionChangeNotifyEvent), - (char *)&ev); - } - } -} - -static int ProcVncExtSetParam(ClientPtr client) -{ - REQUEST(xVncExtSetParamReq); - REQUEST_FIXED_SIZE(xVncExtSetParamReq, stuff->paramLen); - CharArray param(stuff->paramLen+1); - strncpy(param.buf, (char*)&stuff[1], stuff->paramLen); - param.buf[stuff->paramLen] = 0; - - xVncExtSetParamReply rep; - int n; - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.success = rfb::Configuration::setParam(param.buf); - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - } - WriteToClient(client, sizeof(xVncExtSetParamReply), (char *)&rep); - return (client->noClientException); -} - -static int SProcVncExtSetParam(ClientPtr client) -{ - register char n; - REQUEST(xVncExtSetParamReq); - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xVncExtSetParamReq); - return ProcVncExtSetParam(client); -} - -static int ProcVncExtGetParam(ClientPtr client) -{ - REQUEST(xVncExtGetParamReq); - REQUEST_FIXED_SIZE(xVncExtGetParamReq, stuff->paramLen); - CharArray param(stuff->paramLen+1); - strncpy(param.buf, (char*)&stuff[1], stuff->paramLen); - param.buf[stuff->paramLen] = 0; - - xVncExtGetParamReply rep; - int n; - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.success = 0; - int len = 0; - char* value = 0; - rfb::VoidParameter* p = rfb::Configuration::getParam(param.buf); - // Hack to avoid exposing password! - if (strcasecmp(param.buf, "Password") == 0) - p = 0; - if (p) { - value = p->getValueStr(); - rep.success = 1; - len = value ? strlen(value) : 0; - } - rep.length = (len + 3) >> 2; - rep.valueLen = len; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.valueLen, n); - } - WriteToClient(client, sizeof(xVncExtGetParamReply), (char *)&rep); - if (value) - WriteToClient(client, len, value); - delete [] value; - return (client->noClientException); -} - -static int SProcVncExtGetParam(ClientPtr client) -{ - register char n; - REQUEST(xVncExtGetParamReq); - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xVncExtGetParamReq); - return ProcVncExtGetParam(client); -} - -static int ProcVncExtGetParamDesc(ClientPtr client) -{ - REQUEST(xVncExtGetParamDescReq); - REQUEST_FIXED_SIZE(xVncExtGetParamDescReq, stuff->paramLen); - CharArray param(stuff->paramLen+1); - strncpy(param.buf, (char*)&stuff[1], stuff->paramLen); - param.buf[stuff->paramLen] = 0; - - xVncExtGetParamDescReply rep; - int n; - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.success = 0; - int len = 0; - const char* desc = 0; - rfb::VoidParameter* p = rfb::Configuration::getParam(param.buf); - if (p) { - desc = p->getDescription(); - rep.success = 1; - len = desc ? strlen(desc) : 0; - } - rep.length = (len + 3) >> 2; - rep.descLen = len; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.descLen, n); - } - WriteToClient(client, sizeof(xVncExtGetParamDescReply), (char *)&rep); - if (desc) - WriteToClient(client, len, (char*)desc); - return (client->noClientException); -} - -static int SProcVncExtGetParamDesc(ClientPtr client) -{ - register char n; - REQUEST(xVncExtGetParamDescReq); - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xVncExtGetParamDescReq); - return ProcVncExtGetParamDesc(client); -} - -static int ProcVncExtListParams(ClientPtr client) -{ - REQUEST(xVncExtListParamsReq); - REQUEST_SIZE_MATCH(xVncExtListParamsReq); - - xVncExtListParamsReply rep; - int n; - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - - int nParams = 0; - int len = 0; - for (ParameterIterator i(Configuration::global()); i.param; i.next()) { - int l = strlen(i.param->getName()); - if (l <= 255) { - nParams++; - len += l + 1; - } - } - rep.length = (len + 3) >> 2; - rep.nParams = nParams; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.nParams, n); - } - WriteToClient(client, sizeof(xVncExtListParamsReply), (char *)&rep); - rdr::U8* data = new rdr::U8[len]; - rdr::U8* ptr = data; - for (ParameterIterator i(Configuration::global()); i.param; i.next()) { - int l = strlen(i.param->getName()); - if (l <= 255) { - *ptr++ = l; - memcpy(ptr, i.param->getName(), l); - ptr += l; - } - } - WriteToClient(client, len, (char*)data); - delete [] data; - return (client->noClientException); -} - -static int SProcVncExtListParams(ClientPtr client) -{ - register char n; - REQUEST(xVncExtListParamsReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xVncExtListParamsReq); - return ProcVncExtListParams(client); -} - -static int ProcVncExtSetServerCutText(ClientPtr client) -{ - REQUEST(xVncExtSetServerCutTextReq); - REQUEST_FIXED_SIZE(xVncExtSetServerCutTextReq, stuff->textLen); - char* str = new char[stuff->textLen+1]; - strncpy(str, (char*)&stuff[1], stuff->textLen); - str[stuff->textLen] = 0; - for (int scr = 0; scr < screenInfo.numScreens; scr++) { - if (desktop[scr]) { - desktop[scr]->serverCutText(str, stuff->textLen); - } - } - delete [] str; - return (client->noClientException); -} - -static int SProcVncExtSetServerCutText(ClientPtr client) -{ - register char n; - REQUEST(xVncExtSetServerCutTextReq); - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xVncExtSetServerCutTextReq); - swapl(&stuff->textLen, n); - return ProcVncExtSetServerCutText(client); -} - -static int ProcVncExtGetClientCutText(ClientPtr client) -{ - REQUEST(xVncExtGetClientCutTextReq); - REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq); - - xVncExtGetClientCutTextReply rep; - int n; - rep.type = X_Reply; - rep.length = (clientCutTextLen + 3) >> 2; - rep.sequenceNumber = client->sequence; - rep.textLen = clientCutTextLen; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.textLen, n); - } - WriteToClient(client, sizeof(xVncExtGetClientCutTextReply), (char *)&rep); - if (clientCutText) - WriteToClient(client, clientCutTextLen, clientCutText); - return (client->noClientException); -} - -static int SProcVncExtGetClientCutText(ClientPtr client) -{ - register char n; - REQUEST(xVncExtGetClientCutTextReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq); - return ProcVncExtGetClientCutText(client); -} - -static int ProcVncExtSelectInput(ClientPtr client) -{ - REQUEST(xVncExtSelectInputReq); - REQUEST_SIZE_MATCH(xVncExtSelectInputReq); - VncInputSelect** nextPtr = &vncInputSelectHead; - VncInputSelect* cur; - for (cur = vncInputSelectHead; cur; cur = *nextPtr) { - if (cur->client == client && cur->window == stuff->window) { - cur->mask = stuff->mask; - if (!cur->mask) { - *nextPtr = cur->next; - delete cur; - } - break; - } - nextPtr = &cur->next; - } - if (!cur) { - cur = new VncInputSelect(client, stuff->window, stuff->mask); - } - return (client->noClientException); -} - -static int SProcVncExtSelectInput(ClientPtr client) -{ - register char n; - REQUEST(xVncExtSelectInputReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xVncExtSelectInputReq); - swapl(&stuff->window, n); - swapl(&stuff->mask, n); - return ProcVncExtSelectInput(client); -} - -static int ProcVncExtConnect(ClientPtr client) -{ - REQUEST(xVncExtConnectReq); - REQUEST_FIXED_SIZE(xVncExtConnectReq, stuff->strLen); - CharArray str(stuff->strLen+1); - strncpy(str.buf, (char*)&stuff[1], stuff->strLen); - str.buf[stuff->strLen] = 0; - - xVncExtConnectReply rep; - rep.success = 0; - if (desktop[0]) { - if (stuff->strLen == 0) { - try { - desktop[0]->disconnectClients(); - rep.success = 1; - } catch (rdr::Exception& e) { - vlog.error("Disconnecting all clients: %s",e.str()); - } - } else { - int port = 5500; - for (int i = 0; i < stuff->strLen; i++) { - if (str.buf[i] == ':') { - port = atoi(&str.buf[i+1]); - str.buf[i] = 0; - break; - } - } - - try { - network::Socket* sock = new network::TcpSocket(str.buf, port); - desktop[0]->addClient(sock, true); - rep.success = 1; - } catch (rdr::Exception& e) { - vlog.error("Reverse connection: %s",e.str()); - } - } - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - if (client->swapped) { - int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - } - WriteToClient(client, sizeof(xVncExtConnectReply), (char *)&rep); - return (client->noClientException); -} - -static int SProcVncExtConnect(ClientPtr client) -{ - register char n; - REQUEST(xVncExtConnectReq); - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xVncExtConnectReq); - return ProcVncExtConnect(client); -} - - -static int ProcVncExtGetQueryConnect(ClientPtr client) -{ - REQUEST(xVncExtGetQueryConnectReq); - REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq); - - const char *qcAddress=0, *qcUsername=0; - int qcTimeout; - if (queryConnectDesktop) - qcTimeout = queryConnectDesktop->getQueryTimeout(queryConnectId, - &qcAddress, &qcUsername); - else - qcTimeout = 0; - - xVncExtGetQueryConnectReply rep; - int n; - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.timeout = qcTimeout; - rep.addrLen = qcTimeout ? strlen(qcAddress) : 0; - rep.userLen = qcTimeout ? strlen(qcUsername) : 0; - rep.opaqueId = (CARD32)queryConnectId; - rep.length = (rep.userLen + rep.addrLen + 3) >> 2; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.userLen, n); - swapl(&rep.addrLen, n); - swapl(&rep.timeout, n); - swapl(&rep.opaqueId, n); - } - WriteToClient(client, sizeof(xVncExtGetQueryConnectReply), (char *)&rep); - if (qcTimeout) - WriteToClient(client, strlen(qcAddress), (char*)qcAddress); - if (qcTimeout) - WriteToClient(client, strlen(qcUsername), (char*)qcUsername); - return (client->noClientException); -} - -static int SProcVncExtGetQueryConnect(ClientPtr client) -{ - register char n; - REQUEST(xVncExtGetQueryConnectReq); - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq); - return ProcVncExtGetQueryConnect(client); -} - - -static int ProcVncExtApproveConnect(ClientPtr client) -{ - REQUEST(xVncExtApproveConnectReq); - REQUEST_SIZE_MATCH(xVncExtApproveConnectReq); - if (queryConnectId == (void*)stuff->opaqueId) { - for (int scr = 0; scr < screenInfo.numScreens; scr++) { - if (desktop[scr]) { - desktop[scr]->approveConnection(queryConnectId, stuff->approve, - "Connection rejected by local user"); - } - } - // Inform other clients of the event and tidy up - vncQueryConnect(queryConnectDesktop, queryConnectId); - } - return (client->noClientException); -} - -static int SProcVncExtApproveConnect(ClientPtr client) -{ - register char n; - REQUEST(xVncExtApproveConnectReq); - swaps(&stuff->length, n); - swapl(&stuff->opaqueId, n); - REQUEST_SIZE_MATCH(xVncExtApproveConnectReq); - return ProcVncExtApproveConnect(client); -} - - -static int ProcVncExtDispatch(ClientPtr client) -{ - REQUEST(xReq); - switch (stuff->data) { - case X_VncExtSetParam: - return ProcVncExtSetParam(client); - case X_VncExtGetParam: - return ProcVncExtGetParam(client); - case X_VncExtGetParamDesc: - return ProcVncExtGetParamDesc(client); - case X_VncExtListParams: - return ProcVncExtListParams(client); - case X_VncExtSetServerCutText: - return ProcVncExtSetServerCutText(client); - case X_VncExtGetClientCutText: - return ProcVncExtGetClientCutText(client); - case X_VncExtSelectInput: - return ProcVncExtSelectInput(client); - case X_VncExtConnect: - return ProcVncExtConnect(client); - case X_VncExtGetQueryConnect: - return ProcVncExtGetQueryConnect(client); - case X_VncExtApproveConnect: - return ProcVncExtApproveConnect(client); - default: - return BadRequest; - } -} - -static int SProcVncExtDispatch(ClientPtr client) -{ - REQUEST(xReq); - switch (stuff->data) { - case X_VncExtSetParam: - return SProcVncExtSetParam(client); - case X_VncExtGetParam: - return SProcVncExtGetParam(client); - case X_VncExtGetParamDesc: - return SProcVncExtGetParamDesc(client); - case X_VncExtListParams: - return SProcVncExtListParams(client); - case X_VncExtSetServerCutText: - return SProcVncExtSetServerCutText(client); - case X_VncExtGetClientCutText: - return SProcVncExtGetClientCutText(client); - case X_VncExtSelectInput: - return SProcVncExtSelectInput(client); - case X_VncExtConnect: - return SProcVncExtConnect(client); - case X_VncExtGetQueryConnect: - return SProcVncExtGetQueryConnect(client); - case X_VncExtApproveConnect: - return SProcVncExtApproveConnect(client); - default: - return BadRequest; - } -} - diff --git a/unix/xc/programs/Xserver/vnc/vncExtInit.h b/unix/xc/programs/Xserver/vnc/vncExtInit.h deleted file mode 100644 index 45453e1f..00000000 --- a/unix/xc/programs/Xserver/vnc/vncExtInit.h +++ /dev/null @@ -1,32 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -#ifndef __VNCEXTINIT_H__ -#define __VNCEXTINIT_H__ - -#include -#include "XserverDesktop.h" - -extern void vncClientCutText(const char* str, int len); -extern void vncQueryConnect(XserverDesktop* desktop, void* opaqueId); -extern void vncClientGone(int fd); -extern void vncBell(); -extern void* vncFbptr[]; -extern int vncInetdSock; -extern rfb::StringParameter httpDir; - -#endif diff --git a/unix/xc/programs/Xserver/vnc/vncHooks.cc b/unix/xc/programs/Xserver/vnc/vncHooks.cc deleted file mode 100644 index ce8e7f02..00000000 --- a/unix/xc/programs/Xserver/vnc/vncHooks.cc +++ /dev/null @@ -1,1533 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#include -#include "XserverDesktop.h" -#include "vncHooks.h" - -extern "C" { -#define class c_class -#define private c_private -#include "scrnintstr.h" -#include "windowstr.h" -#include "gcstruct.h" -#include "regionstr.h" -#include "dixfontstr.h" -#include "colormapst.h" -#ifdef RENDER -#include "picturestr.h" -#endif - -#ifdef GC_HAS_COMPOSITE_CLIP -#define COMPOSITE_CLIP(gc) ((gc)->pCompositeClip) -#else -#include "mfb.h" -#define COMPOSITE_CLIP(gc) \ - (((mfbPrivGCPtr)((gc)->devPrivates[mfbGCPrivateIndex].ptr))->pCompositeClip) -#endif - -#undef class -#undef private -} - -#include "RegionHelper.h" - -#define DBGPRINT(x) //(fprintf x) - -// MAX_RECTS_PER_OP is the maximum number of rectangles we generate from -// operations like Polylines and PolySegment. If the operation is more complex -// than this, we simply use the bounding box. Ideally it would be a -// command-line option, but that would involve an extra malloc each time, so we -// fix it here. -#define MAX_RECTS_PER_OP 5 - -static unsigned long vncHooksGeneration = 0; - -// vncHooksScreenRec and vncHooksGCRec contain pointers to the original -// functions which we "wrap" in order to hook the screen changes. The screen -// functions are each wrapped individually, while the GC "funcs" and "ops" are -// wrapped as a unit. - -typedef struct { - XserverDesktop* desktop; - - CloseScreenProcPtr CloseScreen; - CreateGCProcPtr CreateGC; - PaintWindowBackgroundProcPtr PaintWindowBackground; - PaintWindowBorderProcPtr PaintWindowBorder; - CopyWindowProcPtr CopyWindow; - ClearToBackgroundProcPtr ClearToBackground; - RestoreAreasProcPtr RestoreAreas; - InstallColormapProcPtr InstallColormap; - StoreColorsProcPtr StoreColors; - DisplayCursorProcPtr DisplayCursor; - ScreenBlockHandlerProcPtr BlockHandler; -#ifdef RENDER - CompositeProcPtr Composite; -#endif -} vncHooksScreenRec, *vncHooksScreenPtr; - -typedef struct { - GCFuncs *wrappedFuncs; - GCOps *wrappedOps; -} vncHooksGCRec, *vncHooksGCPtr; - -static int vncHooksScreenIndex; -static int vncHooksGCIndex; - - -// screen functions - -static Bool vncHooksCloseScreen(int i, ScreenPtr pScreen); -static Bool vncHooksCreateGC(GCPtr pGC); -static void vncHooksPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion, - int what); -static void vncHooksPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion, - int what); -static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, - RegionPtr pOldRegion); -static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w, - int h, Bool generateExposures); -static RegionPtr vncHooksRestoreAreas(WindowPtr pWin, RegionPtr prgnExposed); -static void vncHooksInstallColormap(ColormapPtr pColormap); -static void vncHooksStoreColors(ColormapPtr pColormap, int ndef, - xColorItem* pdef); -static Bool vncHooksDisplayCursor(ScreenPtr pScreen, CursorPtr cursor); -static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout, - pointer pReadmask); -#ifdef RENDER -static void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, - PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, - INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height); -#endif - -// GC "funcs" - -static void vncHooksValidateGC(GCPtr pGC, unsigned long changes, - DrawablePtr pDrawable); -static void vncHooksChangeGC(GCPtr pGC, unsigned long mask); -static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst); -static void vncHooksDestroyGC(GCPtr pGC); -static void vncHooksChangeClip(GCPtr pGC, int type, pointer pValue,int nrects); -static void vncHooksDestroyClip(GCPtr pGC); -static void vncHooksCopyClip(GCPtr dst, GCPtr src); - -static GCFuncs vncHooksGCFuncs = { - vncHooksValidateGC, vncHooksChangeGC, vncHooksCopyGC, vncHooksDestroyGC, - vncHooksChangeClip, vncHooksDestroyClip, vncHooksCopyClip, -}; - -// GC "ops" - -static void vncHooksFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit, - DDXPointPtr pptInit, int *pwidthInit, - int fSorted); -static void vncHooksSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc, - DDXPointPtr ppt, int *pwidth, int nspans, - int fSorted); -static void vncHooksPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, - int x, int y, int w, int h, int leftPad, - int format, char *pBits); -static RegionPtr vncHooksCopyArea(DrawablePtr pSrc, DrawablePtr pDst, - GCPtr pGC, int srcx, int srcy, int w, int h, - int dstx, int dsty); -static RegionPtr vncHooksCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, - GCPtr pGC, int srcx, int srcy, int w, int h, - int dstx, int dsty, unsigned long plane); -static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, - int npt, xPoint *pts); -static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, - int npt, DDXPointPtr ppts); -static void vncHooksPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg, - xSegment *segs); -static void vncHooksPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects, - xRectangle *rects); -static void vncHooksPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, - xArc *arcs); -static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape, - int mode, int count, DDXPointPtr pts); -static void vncHooksPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects, - xRectangle *rects); -static void vncHooksPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, - xArc *arcs); -static int vncHooksPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y, - int count, char *chars); -static int vncHooksPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y, - int count, unsigned short *chars); -static void vncHooksImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y, - int count, char *chars); -static void vncHooksImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y, - int count, unsigned short *chars); -static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, - int y, unsigned int nglyph, - CharInfoPtr *ppci, pointer pglyphBase); -static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, - int y, unsigned int nglyph, - CharInfoPtr *ppci, pointer pglyphBase); -static void vncHooksPushPixels(GCPtr pGC, PixmapPtr pBitMap, - DrawablePtr pDrawable, int w, int h, int x, - int y); - -static GCOps vncHooksGCOps = { - vncHooksFillSpans, vncHooksSetSpans, vncHooksPutImage, vncHooksCopyArea, - vncHooksCopyPlane, vncHooksPolyPoint, vncHooksPolylines, vncHooksPolySegment, - vncHooksPolyRectangle, vncHooksPolyArc, vncHooksFillPolygon, - vncHooksPolyFillRect, vncHooksPolyFillArc, vncHooksPolyText8, - vncHooksPolyText16, vncHooksImageText8, vncHooksImageText16, - vncHooksImageGlyphBlt, vncHooksPolyGlyphBlt, vncHooksPushPixels -}; - - - -///////////////////////////////////////////////////////////////////////////// -// vncHooksInit() is called at initialisation time and every time the server -// resets. It is called once for each screen, but the indexes are only -// allocated once for each server generation. - -Bool vncHooksInit(ScreenPtr pScreen, XserverDesktop* desktop) -{ - vncHooksScreenPtr vncHooksScreen; - - if (vncHooksGeneration != serverGeneration) { - vncHooksGeneration = serverGeneration; - - vncHooksScreenIndex = AllocateScreenPrivateIndex(); - if (vncHooksScreenIndex < 0) { - ErrorF("vncHooksInit: AllocateScreenPrivateIndex failed\n"); - return FALSE; - } - - vncHooksGCIndex = AllocateGCPrivateIndex(); - if (vncHooksGCIndex < 0) { - ErrorF("vncHooksInit: AllocateGCPrivateIndex failed\n"); - return FALSE; - } - } - - if (!AllocateGCPrivate(pScreen, vncHooksGCIndex, sizeof(vncHooksGCRec))) { - ErrorF("vncHooksInit: AllocateGCPrivate failed\n"); - return FALSE; - } - - vncHooksScreen = (vncHooksScreenPtr)xnfalloc(sizeof(vncHooksScreenRec)); - pScreen->devPrivates[vncHooksScreenIndex].ptr = (pointer)vncHooksScreen; - - vncHooksScreen->desktop = desktop; - - vncHooksScreen->CloseScreen = pScreen->CloseScreen; - vncHooksScreen->CreateGC = pScreen->CreateGC; - vncHooksScreen->PaintWindowBackground = pScreen->PaintWindowBackground; - vncHooksScreen->PaintWindowBorder = pScreen->PaintWindowBorder; - vncHooksScreen->CopyWindow = pScreen->CopyWindow; - vncHooksScreen->ClearToBackground = pScreen->ClearToBackground; - vncHooksScreen->RestoreAreas = pScreen->RestoreAreas; - vncHooksScreen->InstallColormap = pScreen->InstallColormap; - vncHooksScreen->StoreColors = pScreen->StoreColors; - vncHooksScreen->DisplayCursor = pScreen->DisplayCursor; - vncHooksScreen->BlockHandler = pScreen->BlockHandler; -#ifdef RENDER - PictureScreenPtr ps; - ps = GetPictureScreenIfSet(pScreen); - if (ps) { - vncHooksScreen->Composite = ps->Composite; - } -#endif - - pScreen->CloseScreen = vncHooksCloseScreen; - pScreen->CreateGC = vncHooksCreateGC; - pScreen->PaintWindowBackground = vncHooksPaintWindowBackground; - pScreen->PaintWindowBorder = vncHooksPaintWindowBorder; - pScreen->CopyWindow = vncHooksCopyWindow; - pScreen->ClearToBackground = vncHooksClearToBackground; - pScreen->RestoreAreas = vncHooksRestoreAreas; - pScreen->InstallColormap = vncHooksInstallColormap; - pScreen->StoreColors = vncHooksStoreColors; - pScreen->DisplayCursor = vncHooksDisplayCursor; - pScreen->BlockHandler = vncHooksBlockHandler; -#ifdef RENDER - if (ps) { - ps->Composite = vncHooksComposite; - } -#endif - - return TRUE; -} - - - -///////////////////////////////////////////////////////////////////////////// -// -// screen functions -// - -// SCREEN_UNWRAP and SCREEN_REWRAP unwrap and rewrap the given screen function. -// It would be nice to do this with a C++ class, but each function is of a -// distinct type, so it would have to use templates, and it's not worth that -// much pain. - -#define SCREEN_UNWRAP(scrn,field) \ - ScreenPtr pScreen = scrn; \ - vncHooksScreenPtr vncHooksScreen \ - = ((vncHooksScreenPtr)pScreen->devPrivates[vncHooksScreenIndex].ptr); \ - pScreen->field = vncHooksScreen->field; \ - DBGPRINT((stderr,"vncHooks" #field " called\n")); - -#define SCREEN_REWRAP(field) pScreen->field = vncHooks##field; - - -// CloseScreen - unwrap the screen functions and call the original CloseScreen -// function - -static Bool vncHooksCloseScreen(int i, ScreenPtr pScreen_) -{ - SCREEN_UNWRAP(pScreen_, CloseScreen); - - pScreen->CreateGC = vncHooksScreen->CreateGC; - pScreen->PaintWindowBackground = vncHooksScreen->PaintWindowBackground; - pScreen->PaintWindowBorder = vncHooksScreen->PaintWindowBorder; - pScreen->CopyWindow = vncHooksScreen->CopyWindow; - pScreen->ClearToBackground = vncHooksScreen->ClearToBackground; - pScreen->RestoreAreas = vncHooksScreen->RestoreAreas; - pScreen->InstallColormap = vncHooksScreen->InstallColormap; - pScreen->StoreColors = vncHooksScreen->StoreColors; - pScreen->DisplayCursor = vncHooksScreen->DisplayCursor; - pScreen->BlockHandler = vncHooksScreen->BlockHandler; - - xfree((pointer)vncHooksScreen); - - DBGPRINT((stderr,"vncHooksCloseScreen: unwrapped screen functions\n")); - - return (*pScreen->CloseScreen)(i, pScreen); -} - -// CreateGC - wrap the "GC funcs" - -static Bool vncHooksCreateGC(GCPtr pGC) -{ - SCREEN_UNWRAP(pGC->pScreen, CreateGC); - - vncHooksGCPtr vncHooksGC - = (vncHooksGCPtr)pGC->devPrivates[vncHooksGCIndex].ptr; - - Bool ret = (*pScreen->CreateGC) (pGC); - - vncHooksGC->wrappedOps = 0; - vncHooksGC->wrappedFuncs = pGC->funcs; - pGC->funcs = &vncHooksGCFuncs; - - SCREEN_REWRAP(CreateGC); - - return ret; -} - -// PaintWindowBackground - changed region is the given region - -static void vncHooksPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion, - int what) -{ - SCREEN_UNWRAP(pWin->drawable.pScreen, PaintWindowBackground); - - RegionHelper changed(pScreen, pRegion); - - (*pScreen->PaintWindowBackground) (pWin, pRegion, what); - - vncHooksScreen->desktop->add_changed(changed.reg); - - SCREEN_REWRAP(PaintWindowBackground); -} - -// PaintWindowBorder - changed region is the given region - -static void vncHooksPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion, - int what) -{ - SCREEN_UNWRAP(pWin->drawable.pScreen, PaintWindowBorder); - - RegionHelper changed(pScreen, pRegion); - - (*pScreen->PaintWindowBorder) (pWin, pRegion, what); - - vncHooksScreen->desktop->add_changed(changed.reg); - - SCREEN_REWRAP(PaintWindowBorder); -} - -// CopyWindow - destination of the copy is the old region, clipped by -// borderClip, translated by the delta. This call only does the copy - it -// doesn't affect any other bits. - -static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, - RegionPtr pOldRegion) -{ - SCREEN_UNWRAP(pWin->drawable.pScreen, CopyWindow); - - RegionHelper copied(pScreen, pOldRegion); - int dx = pWin->drawable.x - ptOldOrg.x; - int dy = pWin->drawable.y - ptOldOrg.y; - REGION_TRANSLATE(pScreen, copied.reg, dx, dy); - REGION_INTERSECT(pWin->drawable.pScreen, copied.reg, copied.reg, - &pWin->borderClip); - - (*pScreen->CopyWindow) (pWin, ptOldOrg, pOldRegion); - - vncHooksScreen->desktop->add_copied(copied.reg, dx, dy); - - SCREEN_REWRAP(CopyWindow); -} - -// ClearToBackground - changed region is the given rectangle, clipped by -// clipList, but only if generateExposures is false. - -static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w, - int h, Bool generateExposures) -{ - SCREEN_UNWRAP(pWin->drawable.pScreen, ClearToBackground); - - BoxRec box; - box.x1 = x + pWin->drawable.x; - box.y1 = y + pWin->drawable.y; - box.x2 = w ? (box.x1 + w) : (pWin->drawable.x + pWin->drawable.width); - box.y2 = h ? (box.y1 + h) : (pWin->drawable.y + pWin->drawable.height); - - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, &pWin->clipList); - - (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures); - - if (!generateExposures) { - vncHooksScreen->desktop->add_changed(changed.reg); - } - - SCREEN_REWRAP(ClearToBackground); -} - -// RestoreAreas - changed region is the given region - -static RegionPtr vncHooksRestoreAreas(WindowPtr pWin, RegionPtr pRegion) -{ - SCREEN_UNWRAP(pWin->drawable.pScreen, RestoreAreas); - - RegionHelper changed(pScreen, pRegion); - - RegionPtr result = (*pScreen->RestoreAreas) (pWin, pRegion); - - vncHooksScreen->desktop->add_changed(changed.reg); - - SCREEN_REWRAP(RestoreAreas); - - return result; -} - -// InstallColormap - get the new colormap - -static void vncHooksInstallColormap(ColormapPtr pColormap) -{ - SCREEN_UNWRAP(pColormap->pScreen, InstallColormap); - - (*pScreen->InstallColormap) (pColormap); - - vncHooksScreen->desktop->setColormap(pColormap); - - SCREEN_REWRAP(InstallColormap); -} - -// StoreColors - get the colormap changes - -static void vncHooksStoreColors(ColormapPtr pColormap, int ndef, - xColorItem* pdef) -{ - SCREEN_UNWRAP(pColormap->pScreen, StoreColors); - - (*pScreen->StoreColors) (pColormap, ndef, pdef); - - vncHooksScreen->desktop->setColourMapEntries(pColormap, ndef, pdef); - - SCREEN_REWRAP(StoreColors); -} - -// DisplayCursor - get the cursor shape - -static Bool vncHooksDisplayCursor(ScreenPtr pScreen_, CursorPtr cursor) -{ - SCREEN_UNWRAP(pScreen_, DisplayCursor); - - Bool ret = (*pScreen->DisplayCursor) (pScreen, cursor); - - vncHooksScreen->desktop->setCursor(cursor); - - SCREEN_REWRAP(DisplayCursor); - - return ret; -} - -// BlockHandler - ignore any changes during the block handler - it's likely -// these are just drawing the cursor. - -static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout, - pointer pReadmask) -{ - SCREEN_UNWRAP(screenInfo.screens[i], BlockHandler); - - vncHooksScreen->desktop->ignoreHooks(true); - - (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); - - vncHooksScreen->desktop->ignoreHooks(false); - - SCREEN_REWRAP(BlockHandler); -} - -// Composite - needed for RENDER - -#ifdef RENDER -void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, - PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, - INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - vncHooksScreenPtr vncHooksScreen = ((vncHooksScreenPtr)pScreen->devPrivates[vncHooksScreenIndex].ptr); - BoxRec box; - PictureScreenPtr ps = GetPictureScreen(pScreen); - rfb::Rect rect1, rect2; - - rect1.setXYWH(pDst->pDrawable->x + xDst, - pDst->pDrawable->y + yDst, - width, - height); - - rect2 = rect1.intersect(vncHooksScreen->desktop->getRect()); - if (!rect2.is_empty()) { - box.x1 = rect2.tl.x; - box.y1 = rect2.tl.y; - box.x2 = rect2.br.x; - box.y2 = rect2.br.y; - RegionHelper changed(pScreen, &box, 0); - vncHooksScreen->desktop->add_changed(changed.reg); - } - - ps->Composite = vncHooksScreen->Composite; - (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc, - xMask, yMask, xDst, yDst, width, height); - ps->Composite = vncHooksComposite; -} - -#endif /* RENDER */ - - -///////////////////////////////////////////////////////////////////////////// -// -// GC "funcs" -// - -// GCFuncUnwrapper is a helper class which unwraps the GC funcs and ops in its -// constructor and rewraps them in its destructor. - -class GCFuncUnwrapper { -public: - GCFuncUnwrapper(GCPtr pGC_) : pGC(pGC_) { - vncHooksGC = (vncHooksGCPtr)pGC->devPrivates[vncHooksGCIndex].ptr; - pGC->funcs = vncHooksGC->wrappedFuncs; - if (vncHooksGC->wrappedOps) - pGC->ops = vncHooksGC->wrappedOps; - } - ~GCFuncUnwrapper() { - vncHooksGC->wrappedFuncs = pGC->funcs; - pGC->funcs = &vncHooksGCFuncs; - if (vncHooksGC->wrappedOps) { - vncHooksGC->wrappedOps = pGC->ops; - pGC->ops = &vncHooksGCOps; - } - } - GCPtr pGC; - vncHooksGCPtr vncHooksGC; -}; - - -// ValidateGC - wrap the "ops" if a viewable window - -static void vncHooksValidateGC(GCPtr pGC, unsigned long changes, - DrawablePtr pDrawable) -{ - GCFuncUnwrapper u(pGC); - - DBGPRINT((stderr,"vncHooksValidateGC called\n")); - - (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable); - - u.vncHooksGC->wrappedOps = 0; - if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr)pDrawable)->viewable) { - WindowPtr pWin = (WindowPtr)pDrawable; - RegionPtr pRegion = &pWin->clipList; - - if (pGC->subWindowMode == IncludeInferiors) - pRegion = &pWin->borderClip; - if (REGION_NOTEMPTY(pDrawable->pScreen, pRegion)) { - u.vncHooksGC->wrappedOps = pGC->ops; - DBGPRINT((stderr,"vncHooksValidateGC: wrapped GC ops\n")); - } - } -} - -// Other GC funcs - just unwrap and call on - -static void vncHooksChangeGC(GCPtr pGC, unsigned long mask) { - GCFuncUnwrapper u(pGC); - (*pGC->funcs->ChangeGC) (pGC, mask); -} -static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst) { - GCFuncUnwrapper u(dst); - (*dst->funcs->CopyGC) (src, mask, dst); -} -static void vncHooksDestroyGC(GCPtr pGC) { - GCFuncUnwrapper u(pGC); - (*pGC->funcs->DestroyGC) (pGC); -} -static void vncHooksChangeClip(GCPtr pGC, int type, pointer pValue, int nrects) -{ - GCFuncUnwrapper u(pGC); - (*pGC->funcs->ChangeClip) (pGC, type, pValue, nrects); -} -static void vncHooksDestroyClip(GCPtr pGC) { - GCFuncUnwrapper u(pGC); - (*pGC->funcs->DestroyClip) (pGC); -} -static void vncHooksCopyClip(GCPtr dst, GCPtr src) { - GCFuncUnwrapper u(dst); - (*dst->funcs->CopyClip) (dst, src); -} - - -///////////////////////////////////////////////////////////////////////////// -// -// GC "ops" -// - -// GCOpUnwrapper is a helper class which unwraps the GC funcs and ops in its -// constructor and rewraps them in its destructor. - -class GCOpUnwrapper { -public: - GCOpUnwrapper(DrawablePtr pDrawable, GCPtr pGC_) - : pGC(pGC_), pScreen(pDrawable->pScreen) - { - vncHooksGC = (vncHooksGCPtr)pGC->devPrivates[vncHooksGCIndex].ptr; - oldFuncs = pGC->funcs; - pGC->funcs = vncHooksGC->wrappedFuncs; - pGC->ops = vncHooksGC->wrappedOps; - } - ~GCOpUnwrapper() { - vncHooksGC->wrappedOps = pGC->ops; - pGC->funcs = oldFuncs; - pGC->ops = &vncHooksGCOps; - } - GCPtr pGC; - vncHooksGCPtr vncHooksGC; - GCFuncs* oldFuncs; - ScreenPtr pScreen; -}; - -#define GC_OP_UNWRAPPER(pDrawable, pGC, name) \ - GCOpUnwrapper u(pDrawable, pGC); \ - ScreenPtr pScreen = (pDrawable)->pScreen; \ - vncHooksScreenPtr vncHooksScreen \ - = ((vncHooksScreenPtr)pScreen->devPrivates[vncHooksScreenIndex].ptr); \ - DBGPRINT((stderr,"vncHooks" #name " called\n")); - - -// FillSpans - changed region is the whole of borderClip. This is pessimistic, -// but I believe this function is rarely used so it doesn't matter. - -static void vncHooksFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit, - DDXPointPtr pptInit, int *pwidthInit, - int fSorted) -{ - GC_OP_UNWRAPPER(pDrawable, pGC, FillSpans); - - RegionHelper changed(pScreen, &((WindowPtr)pDrawable)->borderClip); - - (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted); - - vncHooksScreen->desktop->add_changed(changed.reg); -} - -// SetSpans - changed region is the whole of borderClip. This is pessimistic, -// but I believe this function is rarely used so it doesn't matter. - -static void vncHooksSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc, - DDXPointPtr ppt, int *pwidth, int nspans, - int fSorted) -{ - GC_OP_UNWRAPPER(pDrawable, pGC, SetSpans); - - RegionHelper changed(pScreen, &((WindowPtr)pDrawable)->borderClip); - - (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); - - vncHooksScreen->desktop->add_changed(changed.reg); -} - -// PutImage - changed region is the given rectangle, clipped by pCompositeClip - -static void vncHooksPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, - int x, int y, int w, int h, int leftPad, - int format, char *pBits) -{ - GC_OP_UNWRAPPER(pDrawable, pGC, PutImage); - - BoxRec box; - box.x1 = x + pDrawable->x; - box.y1 = y + pDrawable->y; - box.x2 = box.x1 + w; - box.y2 = box.y1 + h; - - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); - - (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, leftPad, format, - pBits); - - vncHooksScreen->desktop->add_changed(changed.reg); -} - -// CopyArea - destination of the copy is the dest rectangle, clipped by -// pCompositeClip. Any parts of the destination which cannot be copied from -// the source (could be all of it) go into the changed region. - -static RegionPtr vncHooksCopyArea(DrawablePtr pSrc, DrawablePtr pDst, - GCPtr pGC, int srcx, int srcy, int w, int h, - int dstx, int dsty) -{ - GC_OP_UNWRAPPER(pDst, pGC, CopyArea); - - BoxRec box; - box.x1 = dstx + pDst->x; - box.y1 = dsty + pDst->y; - box.x2 = box.x1 + w; - box.y2 = box.y1 + h; - - RegionHelper dst(pScreen, &box, 0); - REGION_INTERSECT(pScreen, dst.reg, dst.reg, COMPOSITE_CLIP(pGC)); - - RegionHelper src(pScreen); - - if ((pSrc->type == DRAWABLE_WINDOW) && (pSrc->pScreen == pScreen)) { - box.x1 = srcx + pSrc->x; - box.y1 = srcy + pSrc->y; - box.x2 = box.x1 + w; - box.y2 = box.y1 + h; - - src.init(&box, 0); - REGION_INTERSECT(pScreen, src.reg, src.reg, &((WindowPtr)pSrc)->clipList); - REGION_TRANSLATE(pScreen, src.reg, - dstx + pDst->x - srcx - pSrc->x, - dsty + pDst->y - srcy - pSrc->y); - } else { - src.init(NullBox, 0); - } - - RegionHelper changed(pScreen, NullBox, 0); - REGION_SUBTRACT(pScreen, changed.reg, dst.reg, src.reg); - REGION_INTERSECT(pScreen, dst.reg, dst.reg, src.reg); - - RegionPtr rgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h, - dstx, dsty); - - if (REGION_NOTEMPTY(pScreen, dst.reg)) - vncHooksScreen->desktop->add_copied(dst.reg, - dstx + pDst->x - srcx - pSrc->x, - dsty + pDst->y - srcy - pSrc->y); - - if (REGION_NOTEMPTY(pScreen, changed.reg)) - vncHooksScreen->desktop->add_changed(changed.reg); - - return rgn; -} - - -// CopyPlane - changed region is the destination rectangle, clipped by -// pCompositeClip - -static RegionPtr vncHooksCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, - GCPtr pGC, int srcx, int srcy, int w, int h, - int dstx, int dsty, unsigned long plane) -{ - GC_OP_UNWRAPPER(pDst, pGC, CopyPlane); - - BoxRec box; - box.x1 = dstx + pDst->x; - box.y1 = dsty + pDst->y; - box.x2 = box.x1 + w; - box.y2 = box.y1 + h; - - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); - - RegionPtr rgn = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h, - dstx, dsty, plane); - vncHooksScreen->desktop->add_changed(changed.reg); - - return rgn; -} - -// PolyPoint - changed region is the bounding rect, clipped by pCompositeClip - -static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, - int npt, xPoint *pts) -{ - GC_OP_UNWRAPPER(pDrawable, pGC, PolyPoint); - - if (npt == 0) { - (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts); - return; - } - - int minX = pts[0].x; - int maxX = pts[0].x; - int minY = pts[0].y; - int maxY = pts[0].y; - - if (mode == CoordModePrevious) { - int x = pts[0].x; - int y = pts[0].y; - - for (int i = 1; i < npt; i++) { - x += pts[i].x; - y += pts[i].y; - if (x < minX) minX = x; - if (x > maxX) maxX = x; - if (y < minY) minY = y; - if (y > maxY) maxY = y; - } - } else { - for (int i = 1; i < npt; i++) { - if (pts[i].x < minX) minX = pts[i].x; - if (pts[i].x > maxX) maxX = pts[i].x; - if (pts[i].y < minY) minY = pts[i].y; - if (pts[i].y > maxY) maxY = pts[i].y; - } - } - - BoxRec box; - box.x1 = minX + pDrawable->x; - box.y1 = minY + pDrawable->y; - box.x2 = maxX + 1 + pDrawable->x; - box.y2 = maxY + 1 + pDrawable->y; - - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); - - (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts); - - vncHooksScreen->desktop->add_changed(changed.reg); -} - -// Polylines - changed region is the union of the bounding rects of each line, -// clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP lines, -// just use the bounding rect of all the lines. - -static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, - int npt, DDXPointPtr ppts) -{ - GC_OP_UNWRAPPER(pDrawable, pGC, Polylines); - - if (npt == 0) { - (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts); - return; - } - - int nRegRects = npt - 1; - xRectangle regRects[MAX_RECTS_PER_OP]; - - int lw = pGC->lineWidth; - if (lw == 0) lw = 1; - - if (npt == 1) - { - // a single point - nRegRects = 1; - regRects[0].x = pDrawable->x + ppts[0].x - lw; - regRects[0].y = pDrawable->y + ppts[0].y - lw; - regRects[0].width = 2*lw; - regRects[0].height = 2*lw; - } - else - { - /* - * mitered joins can project quite a way from - * the line end; the 11 degree miter limit limits - * this extension to lw / (2 * tan(11/2)), rounded up - * and converted to int yields 6 * lw - */ - - int extra = lw / 2; - if (pGC->joinStyle == JoinMiter) { - extra = 6 * lw; - } - - int prevX, prevY, curX, curY; - int rectX1, rectY1, rectX2, rectY2; - int minX, minY, maxX, maxY; - - prevX = ppts[0].x + pDrawable->x; - prevY = ppts[0].y + pDrawable->y; - minX = maxX = prevX; - minY = maxY = prevY; - - for (int i = 0; i < nRegRects; i++) { - if (mode == CoordModeOrigin) { - curX = pDrawable->x + ppts[i+1].x; - curY = pDrawable->y + ppts[i+1].y; - } else { - curX = prevX + ppts[i+1].x; - curY = prevY + ppts[i+1].y; - } - - if (prevX > curX) { - rectX1 = curX - extra; - rectX2 = prevX + extra + 1; - } else { - rectX1 = prevX - extra; - rectX2 = curX + extra + 1; - } - - if (prevY > curY) { - rectY1 = curY - extra; - rectY2 = prevY + extra + 1; - } else { - rectY1 = prevY - extra; - rectY2 = curY + extra + 1; - } - - if (nRegRects <= MAX_RECTS_PER_OP) { - regRects[i].x = rectX1; - regRects[i].y = rectY1; - regRects[i].width = rectX2 - rectX1; - regRects[i].height = rectY2 - rectY1; - } else { - if (rectX1 < minX) minX = rectX1; - if (rectY1 < minY) minY = rectY1; - if (rectX2 > maxX) maxX = rectX2; - if (rectY2 > maxY) maxY = rectY2; - } - - prevX = curX; - prevY = curY; - } - - if (nRegRects > MAX_RECTS_PER_OP) { - regRects[0].x = minX; - regRects[0].y = minY; - regRects[0].width = maxX - minX; - regRects[0].height = maxY - minY; - nRegRects = 1; - } - } - - RegionHelper changed(pScreen, nRegRects, regRects); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); - - (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts); - - vncHooksScreen->desktop->add_changed(changed.reg); -} - -// PolySegment - changed region is the union of the bounding rects of each -// segment, clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP -// segments, just use the bounding rect of all the segments. - -static void vncHooksPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg, - xSegment *segs) -{ - GC_OP_UNWRAPPER(pDrawable, pGC, PolySegment); - - if (nseg == 0) { - (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs); - return; - } - - xRectangle regRects[MAX_RECTS_PER_OP]; - int nRegRects = nseg; - - int lw = pGC->lineWidth; - int extra = lw / 2; - - int rectX1, rectY1, rectX2, rectY2; - int minX, minY, maxX, maxY; - - minX = maxX = segs[0].x1; - minY = maxY = segs[0].y1; - - for (int i = 0; i < nseg; i++) { - if (segs[i].x1 > segs[i].x2) { - rectX1 = pDrawable->x + segs[i].x2 - extra; - rectX2 = pDrawable->x + segs[i].x1 + extra + 1; - } else { - rectX1 = pDrawable->x + segs[i].x1 - extra; - rectX2 = pDrawable->x + segs[i].x2 + extra + 1; - } - - if (segs[i].y1 > segs[i].y2) { - rectY1 = pDrawable->y + segs[i].y2 - extra; - rectY2 = pDrawable->y + segs[i].y1 + extra + 1; - } else { - rectY1 = pDrawable->y + segs[i].y1 - extra; - rectY2 = pDrawable->y + segs[i].y2 + extra + 1; - } - - if (nseg <= MAX_RECTS_PER_OP) { - regRects[i].x = rectX1; - regRects[i].y = rectY1; - regRects[i].width = rectX2 - rectX1; - regRects[i].height = rectY2 - rectY1; - } else { - if (rectX1 < minX) minX = rectX1; - if (rectY1 < minY) minY = rectY1; - if (rectX2 > maxX) maxX = rectX2; - if (rectY2 > maxY) maxY = rectY2; - } - } - - if (nseg > MAX_RECTS_PER_OP) { - regRects[0].x = minX; - regRects[0].y = minY; - regRects[0].width = maxX - minX; - regRects[0].height = maxY - minY; - nRegRects = 1; - } - - RegionHelper changed(pScreen, nRegRects, regRects); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); - - (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs); - - vncHooksScreen->desktop->add_changed(changed.reg); -} - -// PolyRectangle - changed region is the union of the bounding rects around -// each side of the outline rectangles, clipped by pCompositeClip. If there -// are more than MAX_RECTS_PER_OP rectangles, just use the bounding rect of all -// the rectangles. - -static void vncHooksPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects, - xRectangle *rects) -{ - GC_OP_UNWRAPPER(pDrawable, pGC, PolyRectangle); - - if (nrects == 0) { - (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects); - return; - } - - xRectangle regRects[MAX_RECTS_PER_OP*4]; - int nRegRects = nrects * 4; - - int lw = pGC->lineWidth; - int extra = lw / 2; - - int rectX1, rectY1, rectX2, rectY2; - int minX, minY, maxX, maxY; - - minX = maxX = rects[0].x; - minY = maxY = rects[0].y; - - for (int i = 0; i < nrects; i++) { - if (nrects <= MAX_RECTS_PER_OP) { - regRects[i*4].x = rects[i].x - extra + pDrawable->x; - regRects[i*4].y = rects[i].y - extra + pDrawable->y; - regRects[i*4].width = rects[i].width + 1 + 2 * extra; - regRects[i*4].height = 1 + 2 * extra; - - regRects[i*4+1].x = rects[i].x - extra + pDrawable->x; - regRects[i*4+1].y = rects[i].y - extra + pDrawable->y; - regRects[i*4+1].width = 1 + 2 * extra; - regRects[i*4+1].height = rects[i].height + 1 + 2 * extra; - - regRects[i*4+2].x = rects[i].x + rects[i].width - extra + pDrawable->x; - regRects[i*4+2].y = rects[i].y - extra + pDrawable->y; - regRects[i*4+2].width = 1 + 2 * extra; - regRects[i*4+2].height = rects[i].height + 1 + 2 * extra; - - regRects[i*4+3].x = rects[i].x - extra + pDrawable->x; - regRects[i*4+3].y = rects[i].y + rects[i].height - extra + pDrawable->y; - regRects[i*4+3].width = rects[i].width + 1 + 2 * extra; - regRects[i*4+3].height = 1 + 2 * extra; - } else { - rectX1 = pDrawable->x + rects[i].x - extra; - rectY1 = pDrawable->y + rects[i].y - extra; - rectX2 = pDrawable->x + rects[i].x + rects[i].width + extra+1; - rectY2 = pDrawable->y + rects[i].y + rects[i].height + extra+1; - if (rectX1 < minX) minX = rectX1; - if (rectY1 < minY) minY = rectY1; - if (rectX2 > maxX) maxX = rectX2; - if (rectY2 > maxY) maxY = rectY2; - } - } - - if (nrects > MAX_RECTS_PER_OP) { - regRects[0].x = minX; - regRects[0].y = minY; - regRects[0].width = maxX - minX; - regRects[0].height = maxY - minY; - nRegRects = 1; - } - - RegionHelper changed(pScreen, nRegRects, regRects); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); - - (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects); - - vncHooksScreen->desktop->add_changed(changed.reg); -} - -// PolyArc - changed region is the union of bounding rects around each arc, -// clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP -// arcs, just use the bounding rect of all the arcs. - -static void vncHooksPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, - xArc *arcs) -{ - GC_OP_UNWRAPPER(pDrawable, pGC, PolyArc); - - if (narcs == 0) { - (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs); - return; - } - - xRectangle regRects[MAX_RECTS_PER_OP]; - int nRegRects = narcs; - - int lw = pGC->lineWidth; - if (lw == 0) lw = 1; - int extra = lw / 2; - - int rectX1, rectY1, rectX2, rectY2; - int minX, minY, maxX, maxY; - - minX = maxX = arcs[0].x; - minY = maxY = arcs[0].y; - - for (int i = 0; i < narcs; i++) { - if (narcs <= MAX_RECTS_PER_OP) { - regRects[i].x = arcs[i].x - extra + pDrawable->x; - regRects[i].y = arcs[i].y - extra + pDrawable->y; - regRects[i].width = arcs[i].width + lw; - regRects[i].height = arcs[i].height + lw; - } else { - rectX1 = pDrawable->x + arcs[i].x - extra; - rectY1 = pDrawable->y + arcs[i].y - extra; - rectX2 = pDrawable->x + arcs[i].x + arcs[i].width + lw; - rectY2 = pDrawable->y + arcs[i].y + arcs[i].height + lw; - if (rectX1 < minX) minX = rectX1; - if (rectY1 < minY) minY = rectY1; - if (rectX2 > maxX) maxX = rectX2; - if (rectY2 > maxY) maxY = rectY2; - } - } - - if (narcs > MAX_RECTS_PER_OP) { - regRects[0].x = minX; - regRects[0].y = minY; - regRects[0].width = maxX - minX; - regRects[0].height = maxY - minY; - nRegRects = 1; - } - - RegionHelper changed(pScreen, nRegRects, regRects); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); - - (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs); - - vncHooksScreen->desktop->add_changed(changed.reg); -} - - -// FillPolygon - changed region is the bounding rect around the polygon, -// clipped by pCompositeClip - -static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape, - int mode, int count, DDXPointPtr pts) -{ - GC_OP_UNWRAPPER(pDrawable, pGC, FillPolygon); - - if (count == 0) { - (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts); - return; - } - - int minX = pts[0].x; - int maxX = pts[0].x; - int minY = pts[0].y; - int maxY = pts[0].y; - - if (mode == CoordModePrevious) { - int x = pts[0].x; - int y = pts[0].y; - - for (int i = 1; i < count; i++) { - x += pts[i].x; - y += pts[i].y; - if (x < minX) minX = x; - if (x > maxX) maxX = x; - if (y < minY) minY = y; - if (y > maxY) maxY = y; - } - } else { - for (int i = 1; i < count; i++) { - if (pts[i].x < minX) minX = pts[i].x; - if (pts[i].x > maxX) maxX = pts[i].x; - if (pts[i].y < minY) minY = pts[i].y; - if (pts[i].y > maxY) maxY = pts[i].y; - } - } - - BoxRec box; - box.x1 = minX + pDrawable->x; - box.y1 = minY + pDrawable->y; - box.x2 = maxX + 1 + pDrawable->x; - box.y2 = maxY + 1 + pDrawable->y; - - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); - - (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts); - - vncHooksScreen->desktop->add_changed(changed.reg); -} - -// PolyFillRect - changed region is the union of the rectangles, clipped by -// pCompositeClip. If there are more than MAX_RECTS_PER_OP rectangles, just -// use the bounding rect of all the rectangles. - -static void vncHooksPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects, - xRectangle *rects) -{ - GC_OP_UNWRAPPER(pDrawable, pGC, PolyFillRect); - - if (nrects == 0) { - (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects); - return; - } - - xRectangle regRects[MAX_RECTS_PER_OP]; - int nRegRects = nrects; - int rectX1, rectY1, rectX2, rectY2; - int minX, minY, maxX, maxY; - minX = maxX = rects[0].x; - minY = maxY = rects[0].y; - - for (int i = 0; i < nrects; i++) { - if (nrects <= MAX_RECTS_PER_OP) { - regRects[i].x = rects[i].x + pDrawable->x; - regRects[i].y = rects[i].y + pDrawable->y; - regRects[i].width = rects[i].width; - regRects[i].height = rects[i].height; - } else { - rectX1 = pDrawable->x + rects[i].x; - rectY1 = pDrawable->y + rects[i].y; - rectX2 = pDrawable->x + rects[i].x + rects[i].width; - rectY2 = pDrawable->y + rects[i].y + rects[i].height; - if (rectX1 < minX) minX = rectX1; - if (rectY1 < minY) minY = rectY1; - if (rectX2 > maxX) maxX = rectX2; - if (rectY2 > maxY) maxY = rectY2; - } - } - - if (nrects > MAX_RECTS_PER_OP) { - regRects[0].x = minX; - regRects[0].y = minY; - regRects[0].width = maxX - minX; - regRects[0].height = maxY - minY; - nRegRects = 1; - } - - RegionHelper changed(pScreen, nRegRects, regRects); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); - - (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects); - - vncHooksScreen->desktop->add_changed(changed.reg); -} - -// PolyFillArc - changed region is the union of bounding rects around each arc, -// clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP arcs, -// just use the bounding rect of all the arcs. - -static void vncHooksPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, - xArc *arcs) -{ - GC_OP_UNWRAPPER(pDrawable, pGC, PolyFillArc); - - if (narcs == 0) { - (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs); - return; - } - - xRectangle regRects[MAX_RECTS_PER_OP]; - int nRegRects = narcs; - - int lw = pGC->lineWidth; - if (lw == 0) lw = 1; - int extra = lw / 2; - - int rectX1, rectY1, rectX2, rectY2; - int minX, minY, maxX, maxY; - - minX = maxX = arcs[0].x; - minY = maxY = arcs[0].y; - - for (int i = 0; i < narcs; i++) { - if (narcs <= MAX_RECTS_PER_OP) { - regRects[i].x = arcs[i].x - extra + pDrawable->x; - regRects[i].y = arcs[i].y - extra + pDrawable->y; - regRects[i].width = arcs[i].width + lw; - regRects[i].height = arcs[i].height + lw; - } else { - rectX1 = pDrawable->x + arcs[i].x - extra; - rectY1 = pDrawable->y + arcs[i].y - extra; - rectX2 = pDrawable->x + arcs[i].x + arcs[i].width + lw; - rectY2 = pDrawable->y + arcs[i].y + arcs[i].height + lw; - if (rectX1 < minX) minX = rectX1; - if (rectY1 < minY) minY = rectY1; - if (rectX2 > maxX) maxX = rectX2; - if (rectY2 > maxY) maxY = rectY2; - } - } - - if (narcs > MAX_RECTS_PER_OP) { - regRects[0].x = minX; - regRects[0].y = minY; - regRects[0].width = maxX - minX; - regRects[0].height = maxY - minY; - nRegRects = 1; - } - - RegionHelper changed(pScreen, nRegRects, regRects); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); - - (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs); - - vncHooksScreen->desktop->add_changed(changed.reg); -} - -// GetTextBoundingRect - calculate a bounding rectangle around n chars of a -// font. Not particularly accurate, but good enough. - -static void GetTextBoundingRect(DrawablePtr pDrawable, FontPtr font, int x, - int y, int nchars, BoxPtr box) -{ - int ascent = __rfbmax(FONTASCENT(font), FONTMAXBOUNDS(font, ascent)); - int descent = __rfbmax(FONTDESCENT(font), FONTMAXBOUNDS(font, descent)); - int charWidth = __rfbmax(FONTMAXBOUNDS(font,rightSideBearing), - FONTMAXBOUNDS(font,characterWidth)); - - box->x1 = pDrawable->x + x; - box->y1 = pDrawable->y + y - ascent; - box->x2 = box->x1 + charWidth * nchars; - box->y2 = box->y1 + ascent + descent; - - if (FONTMINBOUNDS(font,leftSideBearing) < 0) - box->x1 += FONTMINBOUNDS(font,leftSideBearing); -} - -// PolyText8 - changed region is bounding rect around count chars, clipped by -// pCompositeClip - -static int vncHooksPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y, - int count, char *chars) -{ - GC_OP_UNWRAPPER(pDrawable, pGC, PolyText8); - - if (count == 0) - return (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars); - - BoxRec box; - GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box); - - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); - - int ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars); - - vncHooksScreen->desktop->add_changed(changed.reg); - - return ret; -} - -// PolyText16 - changed region is bounding rect around count chars, clipped by -// pCompositeClip - -static int vncHooksPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y, - int count, unsigned short *chars) -{ - GC_OP_UNWRAPPER(pDrawable, pGC, PolyText16); - - if (count == 0) - return (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars); - - BoxRec box; - GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box); - - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); - - int ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars); - - vncHooksScreen->desktop->add_changed(changed.reg); - - return ret; -} - -// ImageText8 - changed region is bounding rect around count chars, clipped by -// pCompositeClip - -static void vncHooksImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y, - int count, char *chars) -{ - GC_OP_UNWRAPPER(pDrawable, pGC, ImageText8); - - if (count == 0) { - (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars); - return; - } - - BoxRec box; - GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box); - - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); - - (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars); - - vncHooksScreen->desktop->add_changed(changed.reg); -} - -// ImageText16 - changed region is bounding rect around count chars, clipped by -// pCompositeClip - -static void vncHooksImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y, - int count, unsigned short *chars) -{ - GC_OP_UNWRAPPER(pDrawable, pGC, ImageText16); - - if (count == 0) { - (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars); - return; - } - - BoxRec box; - GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box); - - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); - - (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars); - - vncHooksScreen->desktop->add_changed(changed.reg); -} - -// ImageGlyphBlt - changed region is bounding rect around nglyph chars, clipped -// by pCompositeClip - -static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, - int y, unsigned int nglyph, - CharInfoPtr *ppci, pointer pglyphBase) -{ - GC_OP_UNWRAPPER(pDrawable, pGC, ImageGlyphBlt); - - if (nglyph == 0) { - (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase); - return; - } - - BoxRec box; - GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box); - - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); - - (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); - - vncHooksScreen->desktop->add_changed(changed.reg); -} - -// PolyGlyphBlt - changed region is bounding rect around nglyph chars, clipped -// by pCompositeClip - -static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, - int y, unsigned int nglyph, - CharInfoPtr *ppci, pointer pglyphBase) -{ - GC_OP_UNWRAPPER(pDrawable, pGC, PolyGlyphBlt); - - if (nglyph == 0) { - (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase); - return; - } - - BoxRec box; - GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box); - - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); - - (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); - - vncHooksScreen->desktop->add_changed(changed.reg); -} - -// PushPixels - changed region is the given rectangle, clipped by -// pCompositeClip - -static void vncHooksPushPixels(GCPtr pGC, PixmapPtr pBitMap, - DrawablePtr pDrawable, int w, int h, int x, - int y) -{ - GC_OP_UNWRAPPER(pDrawable, pGC, PushPixels); - - BoxRec box; - box.x1 = x + pDrawable->x; - box.y1 = y + pDrawable->y; - box.x2 = box.x1 + w; - box.y2 = box.y1 + h; - - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); - - (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y); - - vncHooksScreen->desktop->add_changed(changed.reg); -} diff --git a/unix/xc/programs/Xserver/vnc/vncHooks.h b/unix/xc/programs/Xserver/vnc/vncHooks.h deleted file mode 100644 index c556ef3a..00000000 --- a/unix/xc/programs/Xserver/vnc/vncHooks.h +++ /dev/null @@ -1,26 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -#ifndef __VNCHOOKS_H__ -#define __VNCHOOKS_H__ - -extern "C" { -#include - extern Bool vncHooksInit(ScreenPtr pScreen, XserverDesktop* desktop); -} - -#endif diff --git a/unix/xc/programs/Xserver/vnc/xf86vncModule.cc b/unix/xc/programs/Xserver/vnc/xf86vncModule.cc deleted file mode 100644 index ef8ea506..00000000 --- a/unix/xc/programs/Xserver/vnc/xf86vncModule.cc +++ /dev/null @@ -1,97 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -/* This is the xf86 module code for the vnc extension. - */ - -#include -#include -#include - -extern "C" { -#define class c_class -#define private c_private -#define bool c_bool -#define new c_new -#include "xf86.h" -#include "xf86Module.h" -#undef class -#undef private -#undef bool -#undef new - -using namespace rfb; - -extern void vncExtensionInit(); -static void vncExtensionInitWithParams(INITARGS); - -#ifdef XFree86LOADER - -static MODULESETUPPROTO(vncSetup); - -ExtensionModule vncExt = -{ - vncExtensionInitWithParams, - "VNC", - NULL, - NULL, - NULL -}; - -static XF86ModuleVersionInfo vncVersRec = -{ - "vnc", - "Constantin Kaplinsky", - MODINFOSTRING1, - MODINFOSTRING2, - XF86_VERSION_CURRENT, - 1, 0, 0, - ABI_CLASS_EXTENSION, /* needs the server extension ABI */ - ABI_EXTENSION_VERSION, - MOD_CLASS_EXTENSION, - {0,0,0,0} -}; - -XF86ModuleData vncModuleData = { &vncVersRec, vncSetup, NULL }; - -static pointer -vncSetup(pointer module, pointer opts, int *errmaj, int *errmin) { - LoadExtension(&vncExt, FALSE); - /* Need a non-NULL return value to indicate success */ - return (pointer)1; -} - -static void vncExtensionInitWithParams(INITARGS) -{ - rfb::initStdIOLoggers(); - rfb::LogWriter::setLogParams("*:stderr:30"); - - for (int scr = 0; scr < screenInfo.numScreens; scr++) { - ScrnInfoPtr pScrn = xf86Screens[scr]; - - for (ParameterIterator i(Configuration::global()); i.param; i.next()) { - char* val = xf86FindOptionValue(pScrn->options, i.param->getName()); - if (val) - i.param->setParam(val); - } - } - - vncExtensionInit(); -} - -#endif /* XFree86LOADER */ -} diff --git a/unix/xserver.patch b/unix/xserver.patch new file mode 100644 index 00000000..fb90c567 --- /dev/null +++ b/unix/xserver.patch @@ -0,0 +1,68 @@ +diff -up os/WaitFor.c.orig xorg/os/WaitFor.c +--- os/WaitFor.c.orig 2008-01-28 10:20:35.000000000 +0100 ++++ os/WaitFor.c 2008-01-28 10:21:08.000000000 +0100 +@@ -332,13 +332,11 @@ WaitForSomething(int *pClientsReady) + + if (XFD_ANYSET (&devicesReadable) || XFD_ANYSET (&clientsReadable)) + break; +-#ifdef WIN32 + /* Windows keyboard and mouse events are added to the input queue + in Block- and WakupHandlers. There is no device to check if + data is ready. So check here if new input is available */ + if (*checkForInput[0] != *checkForInput[1]) + return 0; +-#endif + } + } + +diff -up mi/miinitext.c.orig xorg/mi/miinitext.c +--- mi/miinitext.c.orig 2008-01-28 10:18:46.000000000 +0100 ++++ mi/miinitext.c 2008-01-28 10:18:58.000000000 +0100 +@@ -289,6 +289,7 @@ extern void BigReqExtensionInit(INITARGS + #ifdef MITMISC + extern void MITMiscExtensionInit(INITARGS); + #endif ++extern void vncExtensionInit(INITARGS); + #ifdef XIDLE + extern void XIdleExtensionInit(INITARGS); + #endif +@@ -560,6 +561,7 @@ InitExtensions(argc, argv) + #ifdef MITMISC + if (!noMITMiscExtension) MITMiscExtensionInit(); + #endif ++ vncExtensionInit(); + #ifdef XIDLE + if (!noXIdleExtension) XIdleExtensionInit(); + #endif +diff -up hw/Makefile.am.orig xorg/hw/Makefile.am +--- hw/Makefile.am.orig 2008-01-28 10:18:46.000000000 +0100 ++++ hw/Makefile.am 2008-01-28 10:18:58.000000000 +0100 +@@ -43,7 +43,8 @@ SUBDIRS = \ + $(DMX_SUBDIRS) \ + $(KDRIVE_SUBDIRS) \ + $(XQUARTZ_SUBDIRS) \ +- $(XPRINT_SUBDIRS) ++ $(XPRINT_SUBDIRS) \ ++ vnc + + DIST_SUBDIRS = dmx xfree86 vfb xnest xwin xquartz kdrive xgl xprint + +diff -up configure.ac.orig xorg/configure.ac +--- configure.ac.orig 2008-01-28 10:18:45.000000000 +0100 ++++ configure.ac 2008-01-28 10:18:58.000000000 +0100 +@@ -29,7 +29,6 @@ AC_PREREQ(2.57) + AC_INIT([xorg-server], 1.4.99.2, [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg], xorg-server) + AC_CONFIG_SRCDIR([Makefile.am]) + AM_INIT_AUTOMAKE([dist-bzip2 foreign]) +-AM_MAINTAINER_MODE + + dnl this gets generated by autoheader, and thus contains all the defines. we + dnl don't ever actually use it, internally. +@@ -2173,6 +2172,7 @@ hw/dmx/input/Makefile + hw/dmx/glxProxy/Makefile + hw/dmx/Makefile + hw/vfb/Makefile ++hw/vnc/Makefile + hw/xgl/Makefile + hw/xgl/egl/Makefile + hw/xgl/egl/module/Makefile diff --git a/unix/xserver/hw/vnc/RegionHelper.h b/unix/xserver/hw/vnc/RegionHelper.h new file mode 100644 index 00000000..61dc89ff --- /dev/null +++ b/unix/xserver/hw/vnc/RegionHelper.h @@ -0,0 +1,84 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +#ifndef __REGIONHELPER_H__ +#define __REGIONHELPER_H__ + +// RegionHelper is a class which helps in using X server regions by +// automatically freeing them in the destructor. It also fixes a problem with +// REGION_INIT when given an empty rectangle. + +// REGION_NULL was introduced in the Xorg tree as the way to initialise an +// empty region. If it's not already defined do it the old way. Note that the +// old way causes a segfault in the new tree... +#ifndef REGION_NULL +#define REGION_NULL(pScreen,pReg) REGION_INIT(pScreen,pReg,NullBox,0) +#endif + +class RegionHelper { +public: + + // constructor from a single rect + RegionHelper(ScreenPtr pScreen_, BoxPtr rect, int size) + : pScreen(pScreen_), reg(0) + { + init(rect, size); + } + + // constructor from an existing X server region + RegionHelper(ScreenPtr pScreen_, RegionPtr pRegion) + : pScreen(pScreen_), reg(®Rec) + { + REGION_NULL(pScreen, reg); + REGION_COPY(pScreen, reg, pRegion); + } + + // constructor from an array of rectangles + RegionHelper(ScreenPtr pScreen_, int nrects, xRectanglePtr rects, + int ctype=CT_NONE) + : pScreen(pScreen_) + { + reg = RECTS_TO_REGION(pScreen, nrects, rects, ctype); + } + + // constructor for calling init() later + RegionHelper(ScreenPtr pScreen_) : pScreen(pScreen_), reg(0) { + } + + void init(BoxPtr rect, int size) { + reg = ®Rec; + if (!rect || (rect && (rect->x2 == rect->x1 || rect->y2 == rect->y1))) { + REGION_NULL(pScreen, reg); + } else { + REGION_INIT(pScreen, reg, rect, size); + } + } + + // destructor frees as appropriate + ~RegionHelper() { + if (reg == ®Rec) { + REGION_UNINIT(pScreen, reg); + } else if (reg) { + REGION_DESTROY(pScreen, reg); + } + } + ScreenPtr pScreen; + RegionRec regRec; + RegionPtr reg; +}; + +#endif diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc new file mode 100644 index 00000000..9e5ea0f7 --- /dev/null +++ b/unix/xserver/hw/vnc/XserverDesktop.cc @@ -0,0 +1,1147 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +// +// XserverDesktop.cxx +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "XserverDesktop.h" +#include "vncExtInit.h" + +extern "C" { +#define public c_public +#define class c_class + + // windowTable is in globals.h in XFree 4, but not in XFree 3 unfortunately +extern WindowPtr *WindowTable; +extern char *display; + +#include "inputstr.h" +#include "servermd.h" +#include "colormapst.h" +#include "resource.h" +#include "cursorstr.h" +#include "windowstr.h" +#define XK_CYRILLIC +#include "keysym.h" +#undef public +#undef class +} + +using namespace rfb; +using namespace network; + +static LogWriter vlog("XserverDesktop"); + +rfb::IntParameter deferUpdateTime("DeferUpdate", + "Time in milliseconds to defer updates",40); + +rfb::BoolParameter alwaysSetDeferUpdateTimer("AlwaysSetDeferUpdateTimer", + "Always reset the defer update timer on every change",false); + +IntParameter queryConnectTimeout("QueryConnectTimeout", + "Number of seconds to show the Accept Connection dialog before " + "rejecting the connection", + 10); + +static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col); + +static rdr::U8 reverseBits[] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, + 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, + 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, + 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, + 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, + 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, + 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, + 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, + 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, + 0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, + 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, + 0x3f, 0xbf, 0x7f, 0xff +}; + + +class FileHTTPServer : public rfb::HTTPServer { +public: + FileHTTPServer(XserverDesktop* d) : desktop(d) {} + virtual ~FileHTTPServer() {} + + virtual rdr::InStream* getFile(const char* name, const char** contentType, + int* contentLength, time_t* lastModified) + { + if (name[0] != '/' || strstr(name, "..") != 0) { + vlog.info("http request was for invalid file name"); + return 0; + } + + if (strcmp(name, "/") == 0) name = "/index.vnc"; + + CharArray httpDirStr(httpDir.getData()); + CharArray fname(strlen(httpDirStr.buf)+strlen(name)+1); + sprintf(fname.buf, "%s%s", httpDirStr.buf, name); + int fd = open(fname.buf, O_RDONLY); + if (fd < 0) return 0; + rdr::InStream* is = new rdr::FdInStream(fd, -1, 0, true); + *contentType = guessContentType(name, *contentType); + if (strlen(name) > 4 && strcasecmp(&name[strlen(name)-4], ".vnc") == 0) { + is = new rdr::SubstitutingInStream(is, desktop, 20); + *contentType = "text/html"; + } else { + struct stat st; + if (fstat(fd, &st) == 0) { + *contentLength = st.st_size; + *lastModified = st.st_mtime; + } + } + return is; + } + + XserverDesktop* desktop; +}; + + +XserverDesktop::XserverDesktop(ScreenPtr pScreen_, + network::TcpListener* listener_, + network::TcpListener* httpListener_, + const char* name, void* fbptr) + : pScreen(pScreen_), deferredUpdateTimer(0), dummyTimer(0), + server(0), httpServer(0), + listener(listener_), httpListener(httpListener_), + cmap(0), deferredUpdateTimerSet(false), + grabbing(false), ignoreHooks_(false), directFbptr(fbptr != 0), + oldButtonMask(0), + queryConnectId(0) +{ + int i; + format.depth = pScreen->rootDepth; + for (i = 0; i < screenInfo.numPixmapFormats; i++) { + if (screenInfo.formats[i].depth == format.depth) { + format.bpp = screenInfo.formats[i].bitsPerPixel; + break; + } + } + if (i == screenInfo.numPixmapFormats) { + fprintf(stderr,"no pixmap format for root depth???\n"); + abort(); + } + format.bigEndian = (screenInfo.imageByteOrder == MSBFirst); + + VisualPtr vis; + for (i = 0; i < pScreen->numVisuals; i++) { + if (pScreen->visuals[i].vid == pScreen->rootVisual) { + vis = &pScreen->visuals[i]; + break; + } + } + if (i == pScreen->numVisuals) { + fprintf(stderr,"no visual rec for root visual???\n"); + abort(); + } + format.trueColour = (vis->c_class == TrueColor); + if (!format.trueColour && format.bpp != 8) + throw rfb::Exception("X server uses unsupported visual"); + format.redShift = ffs(vis->redMask) - 1; + format.greenShift = ffs(vis->greenMask) - 1; + format.blueShift = ffs(vis->blueMask) - 1; + format.redMax = vis->redMask >> format.redShift; + format.greenMax = vis->greenMask >> format.greenShift; + format.blueMax = vis->blueMask >> format.blueShift; + + width_ = pScreen->width; + height_ = pScreen->height; + if (fbptr) + data = (rdr::U8*)fbptr; + else + data = new rdr::U8[pScreen->width * pScreen->height * (format.bpp/8)]; + colourmap = this; + + serverReset(pScreen); + + server = new VNCServerST(name, this); + server->setPixelBuffer(this); + server->setQueryConnectionHandler(this); + + if (httpListener) + httpServer = new FileHTTPServer(this); +} + +XserverDesktop::~XserverDesktop() +{ + if (!directFbptr) + delete [] data; + TimerFree(deferredUpdateTimer); + TimerFree(dummyTimer); + delete httpServer; + delete server; +} + +void XserverDesktop::serverReset(ScreenPtr pScreen_) +{ + pScreen = pScreen_; + XID* ids = new XID[pScreen->maxInstalledCmaps]; + int nmaps = (*pScreen->ListInstalledColormaps)(pScreen, ids); + cmap = (ColormapPtr)LookupIDByType(ids[0], RT_COLORMAP); + delete [] ids; +} + +char* XserverDesktop::substitute(const char* varName) +{ + if (strcmp(varName, "$$") == 0) { + return rfb::strDup("$"); + } + if (strcmp(varName, "$PORT") == 0) { + char* str = new char[10]; + sprintf(str, "%d", listener ? listener->getMyPort() : 0); + return str; + } + if (strcmp(varName, "$WIDTH") == 0) { + char* str = new char[10]; + sprintf(str, "%d", width()); + return str; + } + if (strcmp(varName, "$HEIGHT") == 0) { + char* str = new char[10]; + sprintf(str, "%d", height()); + return str; + } + if (strcmp(varName, "$APPLETWIDTH") == 0) { + char* str = new char[10]; + sprintf(str, "%d", width()); + return str; + } + if (strcmp(varName, "$APPLETHEIGHT") == 0) { + char* str = new char[10]; + sprintf(str, "%d", height() + 32); + return str; + } + if (strcmp(varName, "$DESKTOP") == 0) { + return rfb::strDup(server->getName()); + } + if (strcmp(varName, "$DISPLAY") == 0) { + struct utsname uts; + uname(&uts); + char* str = new char[256]; + strncat(str, uts.nodename, 240); + strcat(str, ":"); + strncat(str, display, 10); + return str; + } + if (strcmp(varName, "$USER") == 0) { + struct passwd* user = getpwuid(getuid()); + return rfb::strDup(user ? user->pw_name : "?"); + } + return 0; +} + +rfb::VNCServerST::queryResult +XserverDesktop::queryConnection(network::Socket* sock, + const char* userName, + char** reason) { + if (queryConnectId) { + *reason = strDup("Another connection is currently being queried."); + return rfb::VNCServerST::REJECT; + } + queryConnectAddress.replaceBuf(sock->getPeerAddress()); + if (!userName) + userName = "(anonymous)"; + queryConnectUsername.replaceBuf(strDup(userName)); + queryConnectId = sock; + vncQueryConnect(this, sock); + return rfb::VNCServerST::PENDING; +} + + +void XserverDesktop::setColormap(ColormapPtr cmap_) +{ + if (cmap != cmap_) { + cmap = cmap_; + setColourMapEntries(0, 0); + } +} + +void XserverDesktop::setColourMapEntries(ColormapPtr pColormap, int ndef, + xColorItem* pdef) +{ + if (cmap != pColormap || ndef <= 0) return; + + int first = pdef[0].pixel; + int n = 1; + + for (int i = 1; i < ndef; i++) { + if (first + n == pdef[i].pixel) { + n++; + } else { + setColourMapEntries(first, n); + first = pdef[i].pixel; + n = 1; + } + } + setColourMapEntries(first, n); +} + +void XserverDesktop::setColourMapEntries(int firstColour, int nColours) +{ + try { + server->setColourMapEntries(firstColour, nColours); + } catch (rdr::Exception& e) { + vlog.error("XserverDesktop::setColourMapEntries: %s",e.str()); + } +} + +void XserverDesktop::bell() +{ + server->bell(); +} + +void XserverDesktop::serverCutText(const char* str, int len) +{ + try { + server->serverCutText(str, len); + } catch (rdr::Exception& e) { + vlog.error("XserverDesktop::serverCutText: %s",e.str()); + } +} + +void XserverDesktop::setCursor(CursorPtr cursor) +{ + try { + int w = cursor->bits->width; + int h = cursor->bits->height; + rdr::U8* cursorData = new rdr::U8[w * h * (getPF().bpp / 8)]; + + xColorItem fg, bg; + fg.red = cursor->foreRed; + fg.green = cursor->foreGreen; + fg.blue = cursor->foreBlue; + FakeAllocColor(cmap, &fg); + bg.red = cursor->backRed; + bg.green = cursor->backGreen; + bg.blue = cursor->backBlue; + FakeAllocColor(cmap, &bg); + FakeFreeColor(cmap, fg.pixel); + FakeFreeColor(cmap, bg.pixel); + + int xMaskBytesPerRow = BitmapBytePad(w); + + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + int byte = y * xMaskBytesPerRow + x / 8; +#if (BITMAP_BIT_ORDER == MSBFirst) + int bit = 7 - x % 8; +#else + int bit = x % 8; +#endif + switch (getPF().bpp) { + case 8: + ((rdr::U8*)cursorData)[y * w + x] + = (cursor->bits->source[byte] & (1 << bit)) ? fg.pixel : bg.pixel; + break; + case 16: + ((rdr::U16*)cursorData)[y * w + x] + = (cursor->bits->source[byte] & (1 << bit)) ? fg.pixel : bg.pixel; + break; + case 32: + ((rdr::U32*)cursorData)[y * w + x] + = (cursor->bits->source[byte] & (1 << bit)) ? fg.pixel : bg.pixel; + break; + } + } + } + + int rfbMaskBytesPerRow = (w + 7) / 8; + + rdr::U8* cursorMask = new rdr::U8[rfbMaskBytesPerRow * h]; + + for (int j = 0; j < h; j++) { + for (int i = 0; i < rfbMaskBytesPerRow; i++) +#if (BITMAP_BIT_ORDER == MSBFirst) + cursorMask[j * rfbMaskBytesPerRow + i] + = cursor->bits->mask[j * xMaskBytesPerRow + i]; +#else + cursorMask[j * rfbMaskBytesPerRow + i] + = reverseBits[cursor->bits->mask[j * xMaskBytesPerRow + i]]; +#endif + } + + server->setCursor(cursor->bits->width, cursor->bits->height, + Point(cursor->bits->xhot, cursor->bits->yhot), + cursorData, cursorMask); + server->tryUpdate(); + delete [] cursorData; + delete [] cursorMask; + } catch (rdr::Exception& e) { + vlog.error("XserverDesktop::setCursor: %s",e.str()); + } +} + +static void printRegion(RegionPtr reg) +{ + int nrects = REGION_NUM_RECTS(reg); + + fprintf(stderr,"Region num rects %2d extents %3d,%3d %3dx%3d\n",nrects, + (REGION_EXTENTS(pScreen,reg))->x1, + (REGION_EXTENTS(pScreen,reg))->y1, + (REGION_EXTENTS(pScreen,reg))->x2-(REGION_EXTENTS(pScreen,reg))->x1, + (REGION_EXTENTS(pScreen,reg))->y2-(REGION_EXTENTS(pScreen,reg))->y1); + + for (int i = 0; i < nrects; i++) { + fprintf(stderr," rect %3d,%3d %3dx%3d\n", + REGION_RECTS(reg)[i].x1, + REGION_RECTS(reg)[i].y1, + REGION_RECTS(reg)[i].x2-REGION_RECTS(reg)[i].x1, + REGION_RECTS(reg)[i].y2-REGION_RECTS(reg)[i].y1); + } +} + +CARD32 XserverDesktop::deferredUpdateTimerCallback(OsTimerPtr timer, + CARD32 now, pointer arg) +{ + XserverDesktop* desktop = (XserverDesktop*)arg; + desktop->deferredUpdateTimerSet = false; + try { + desktop->server->tryUpdate(); + } catch (rdr::Exception& e) { + vlog.error("XserverDesktop::deferredUpdateTimerCallback: %s",e.str()); + } + return 0; +} + +void XserverDesktop::deferUpdate() +{ + if (deferUpdateTime != 0) { + if (!deferredUpdateTimerSet || alwaysSetDeferUpdateTimer) { + deferredUpdateTimerSet = true; + deferredUpdateTimer = TimerSet(deferredUpdateTimer, 0, + deferUpdateTime, + deferredUpdateTimerCallback, this); + } + } else { + server->tryUpdate(); + } +} + +void XserverDesktop::add_changed(RegionPtr reg) +{ + if (ignoreHooks_) return; + if (grabbing) return; + try { + rfb::Region rfbReg; + rfbReg.setExtentsAndOrderedRects((ShortRect*)REGION_EXTENTS(pScreen, reg), + REGION_NUM_RECTS(reg), + (ShortRect*)REGION_RECTS(reg)); + server->add_changed(rfbReg); + deferUpdate(); + } catch (rdr::Exception& e) { + vlog.error("XserverDesktop::add_changed: %s",e.str()); + } +} + +void XserverDesktop::add_copied(RegionPtr dst, int dx, int dy) +{ + if (ignoreHooks_) return; + if (grabbing) return; + try { + rfb::Region rfbReg; + rfbReg.setExtentsAndOrderedRects((ShortRect*)REGION_EXTENTS(pScreen, dst), + REGION_NUM_RECTS(dst), + (ShortRect*)REGION_RECTS(dst)); + server->add_copied(rfbReg, rfb::Point(dx, dy)); + deferUpdate(); + } catch (rdr::Exception& e) { + vlog.error("XserverDesktop::add_copied: %s",e.str()); + } +} + +void XserverDesktop::positionCursor() +{ + if (!cursorPos.equals(oldCursorPos)) { + oldCursorPos = cursorPos; + (*pScreen->SetCursorPosition) (pScreen, cursorPos.x, cursorPos.y, FALSE); + server->setCursorPos(cursorPos); + server->tryUpdate(); + } +} + +void XserverDesktop::blockHandler(fd_set* fds) +{ + try { + ScreenPtr screenWithCursor = GetCurrentRootWindow()->drawable.pScreen; + if (screenWithCursor == pScreen) { + int x, y; + GetSpritePosition(&x, &y); + if (x != cursorPos.x || y != cursorPos.y) { + cursorPos = oldCursorPos = Point(x, y); + server->setCursorPos(cursorPos); + server->tryUpdate(); + } + } + + if (listener) + FD_SET(listener->getFd(), fds); + if (httpListener) + FD_SET(httpListener->getFd(), fds); + + std::list sockets; + server->getSockets(&sockets); + std::list::iterator i; + for (i = sockets.begin(); i != sockets.end(); i++) { + int fd = (*i)->getFd(); + if ((*i)->isShutdown()) { + vlog.debug("client gone, sock %d",fd); + server->removeSocket(*i); + vncClientGone(fd); + delete (*i); + } else { + FD_SET(fd, fds); + } + } + if (httpServer) { + httpServer->getSockets(&sockets); + for (i = sockets.begin(); i != sockets.end(); i++) { + int fd = (*i)->getFd(); + if ((*i)->isShutdown()) { + vlog.debug("http client gone, sock %d",fd); + httpServer->removeSocket(*i); + delete (*i); + } else { + FD_SET(fd, fds); + } + } + } + } catch (rdr::Exception& e) { + vlog.error("XserverDesktop::blockHandler: %s",e.str()); + } +} + +static CARD32 dummyTimerCallback(OsTimerPtr timer, CARD32 now, pointer arg) { + return 0; +} + +void XserverDesktop::wakeupHandler(fd_set* fds, int nfds) +{ + try { + if (nfds >= 1) { + + if (listener) { + if (FD_ISSET(listener->getFd(), fds)) { + FD_CLR(listener->getFd(), fds); + Socket* sock = listener->accept(); + server->addSocket(sock); + vlog.debug("new client, sock %d",sock->getFd()); + } + } + + if (httpListener) { + if (FD_ISSET(httpListener->getFd(), fds)) { + FD_CLR(httpListener->getFd(), fds); + Socket* sock = httpListener->accept(); + httpServer->addSocket(sock); + vlog.debug("new http client, sock %d",sock->getFd()); + } + } + + std::list sockets; + server->getSockets(&sockets); + std::list::iterator i; + for (i = sockets.begin(); i != sockets.end(); i++) { + int fd = (*i)->getFd(); + if (FD_ISSET(fd, fds)) { + FD_CLR(fd, fds); + server->processSocketEvent(*i); + } + } + + if (httpServer) { + httpServer->getSockets(&sockets); + for (i = sockets.begin(); i != sockets.end(); i++) { + int fd = (*i)->getFd(); + if (FD_ISSET(fd, fds)) { + FD_CLR(fd, fds); + httpServer->processSocketEvent(*i); + } + } + } + + positionCursor(); + } + + int timeout = server->checkTimeouts(); + if (timeout > 0) { + // set a dummy timer just so we are guaranteed be called again next time. + dummyTimer = TimerSet(dummyTimer, 0, timeout, + dummyTimerCallback, 0); + } + + } catch (rdr::Exception& e) { + vlog.error("XserverDesktop::wakeupHandler: %s",e.str()); + } +} + +void XserverDesktop::addClient(Socket* sock, bool reverse) +{ + vlog.debug("new client, sock %d reverse %d",sock->getFd(),reverse); + server->addSocket(sock, reverse); +} + +void XserverDesktop::disconnectClients() +{ + vlog.debug("disconnecting all clients"); + return server->closeClients("Disconnection from server end"); +} + + +int XserverDesktop::getQueryTimeout(void* opaqueId, + const char** address, + const char** username) +{ + if (opaqueId && queryConnectId == opaqueId) { + vlog.info("address=%s, username=%s, timeout=%d", + queryConnectAddress.buf, queryConnectUsername.buf, + (int)queryConnectTimeout); + if (address) *address = queryConnectAddress.buf; + if (username) *username = queryConnectUsername.buf; + return queryConnectTimeout; + } + return 0; +} + +void XserverDesktop::approveConnection(void* opaqueId, bool accept, + const char* rejectMsg) +{ + if (queryConnectId == opaqueId) { + server->approveConnection((network::Socket*)opaqueId, accept, rejectMsg); + queryConnectId = 0; + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDesktop callbacks + + +void XserverDesktop::pointerEvent(const Point& pos, int buttonMask) +{ + xEvent ev; + DevicePtr dev = LookupPointerDevice(); + + // SetCursorPosition seems to be very expensive (at least on XFree86 3.3.6 + // for S3), so we delay calling it until positionCursor() is called at the + // end of processing a load of RFB. + //(*pScreen->SetCursorPosition) (pScreen, pos.x, pos.y, FALSE); + + NewCurrentScreen(pScreen, pos.x, pos.y); + + ev.u.u.type = MotionNotify; + ev.u.u.detail = 0; + ev.u.keyButtonPointer.rootX = pos.x; + ev.u.keyButtonPointer.rootY = pos.y; + ev.u.keyButtonPointer.time = GetTimeInMillis(); + + if (!pos.equals(cursorPos)) + (*dev->processInputProc)(&ev, (DeviceIntPtr)dev, 1); + + for (int i = 0; i < 5; i++) { + if ((buttonMask ^ oldButtonMask) & (1<processInputProc)(&ev, (DeviceIntPtr)dev, 1); + } + } + + cursorPos = pos; + oldButtonMask = buttonMask; +} + +void XserverDesktop::clientCutText(const char* str, int len) +{ + vncClientCutText(str, len); +} + +void XserverDesktop::grabRegion(const rfb::Region& region) +{ + if (directFbptr) return; + if (!pScreen->GetImage) { + vlog.error("VNC error: pScreen->GetImage == 0"); + return; + } + + grabbing = true; + + int bytesPerPixel = format.bpp/8; + int bytesPerRow = pScreen->width * bytesPerPixel; + + std::vector rects; + std::vector::iterator i; + region.get_rects(&rects); + for (i = rects.begin(); i != rects.end(); i++) { + for (int y = i->tl.y; y < i->br.y; y++) { + (*pScreen->GetImage) ((DrawablePtr)WindowTable[pScreen->myNum], + i->tl.x, y, i->width(), 1, + ZPixmap, (unsigned long)~0L, + ((char*)data + + y * bytesPerRow + i->tl.x * bytesPerPixel)); + } + } + grabbing = false; +} + +void XserverDesktop::lookup(int index, int* r, int* g, int* b) +{ + if ((cmap->c_class | DynamicClass) == DirectColor) { + VisualPtr v = cmap->pVisual; + *r = cmap->red [(index & v->redMask ) >> v->offsetRed ].co.local.red; + *g = cmap->green[(index & v->greenMask) >> v->offsetGreen].co.local.green; + *b = cmap->blue [(index & v->blueMask ) >> v->offsetBlue ].co.local.blue; + } else { + EntryPtr pent; + pent = (EntryPtr)&cmap->red[index]; + if (pent->fShared) { + *r = pent->co.shco.red->color; + *g = pent->co.shco.green->color; + *b = pent->co.shco.blue->color; + } else { + *r = pent->co.local.red; + *g = pent->co.local.green; + *b = pent->co.local.blue; + } + } +} + +// +// Keyboard handling +// + +#define IS_PRESSED(keyc, keycode) \ + ((keyc)->down[(keycode) >> 3] & (1 << ((keycode) & 7))) + +// ModifierState is a class which helps simplify generating a "fake" press +// or release of shift, ctrl, alt, etc. An instance of the class is created +// for every modifier which may need to be pressed or released. Then either +// press() or release() may be called to make sure that the corresponding keys +// are in the right state. The destructor of the class automatically reverts +// to the previous state. Each modifier may have multiple keys associated with +// it, so in the case of a fake release, this may involve releasing more than +// one key. + +class ModifierState { +public: + ModifierState(DeviceIntPtr dev_, int modIndex_) + : dev(dev_), modIndex(modIndex_), nKeys(0), keys(0), pressed(false) + { + } + ~ModifierState() { + for (int i = 0; i < nKeys; i++) + generateXKeyEvent(keys[i], !pressed); + delete [] keys; + } + void press() { + KeyClassPtr keyc = dev->key; + if (!(keyc->state & (1<modifierKeyMap[modIndex * keyc->maxKeysPerModifier], + true); + pressed = true; + } + } + void release() { + KeyClassPtr keyc = dev->key; + if (keyc->state & (1<maxKeysPerModifier; k++) { + int keycode + = keyc->modifierKeyMap[modIndex * keyc->maxKeysPerModifier + k]; + if (keycode && IS_PRESSED(keyc, keycode)) + tempKeyEvent(keycode, false); + } + } + } +private: + void tempKeyEvent(int keycode, bool down) { + if (keycode) { + if (!keys) keys = new int[dev->key->maxKeysPerModifier]; + keys[nKeys++] = keycode; + generateXKeyEvent(keycode, down); + } + } + void generateXKeyEvent(int keycode, bool down) { + xEvent ev; + ev.u.u.type = down ? KeyPress : KeyRelease; + ev.u.u.detail = keycode; + ev.u.keyButtonPointer.time = GetTimeInMillis(); + (*dev->c_public.processInputProc)(&ev, dev, 1); + vlog.debug("fake keycode %d %s", keycode, down ? "down" : "up"); + } + DeviceIntPtr dev; + int modIndex; + int nKeys; + int* keys; + bool pressed; +}; + + +// altKeysym is a table of alternative keysyms which have the same meaning. + +struct altKeysym_t { + KeySym a, b; +}; + +altKeysym_t altKeysym[] = { + { XK_Shift_L, XK_Shift_R }, + { XK_Control_L, XK_Control_R }, + { XK_Meta_L, XK_Meta_R }, + { XK_Alt_L, XK_Alt_R }, + { XK_Super_L, XK_Super_R }, + { XK_Hyper_L, XK_Hyper_R }, + { XK_KP_Space, XK_space }, + { XK_KP_Tab, XK_Tab }, + { XK_KP_Enter, XK_Return }, + { XK_KP_F1, XK_F1 }, + { XK_KP_F2, XK_F2 }, + { XK_KP_F3, XK_F3 }, + { XK_KP_F4, XK_F4 }, + { XK_KP_Home, XK_Home }, + { XK_KP_Left, XK_Left }, + { XK_KP_Up, XK_Up }, + { XK_KP_Right, XK_Right }, + { XK_KP_Down, XK_Down }, + { XK_KP_Page_Up, XK_Page_Up }, + { XK_KP_Page_Down, XK_Page_Down }, + { XK_KP_End, XK_End }, + { XK_KP_Begin, XK_Begin }, + { XK_KP_Insert, XK_Insert }, + { XK_KP_Delete, XK_Delete }, + { XK_KP_Equal, XK_equal }, + { XK_KP_Multiply, XK_asterisk }, + { XK_KP_Add, XK_plus }, + { XK_KP_Separator, XK_comma }, + { XK_KP_Subtract, XK_minus }, + { XK_KP_Decimal, XK_period }, + { XK_KP_Divide, XK_slash }, + { XK_KP_0, XK_0 }, + { XK_KP_1, XK_1 }, + { XK_KP_2, XK_2 }, + { XK_KP_3, XK_3 }, + { XK_KP_4, XK_4 }, + { XK_KP_5, XK_5 }, + { XK_KP_6, XK_6 }, + { XK_KP_7, XK_7 }, + { XK_KP_8, XK_8 }, + { XK_KP_9, XK_9 }, +}; + +// keyEvent() - work out the best keycode corresponding to the keysym sent by +// the viewer. This is non-trivial because we can't assume much about the +// local keyboard layout. We must also find out which column of the keyboard +// mapping the keysym is in, and alter the shift state appropriately. Column 0 +// means both shift and "mode_switch" (AltGr) must be released, column 1 means +// shift must be pressed and mode_switch released, column 2 means shift must be +// released and mode_switch pressed, and column 3 means both shift and +// mode_switch must be pressed. + +void XserverDesktop::keyEvent(rdr::U32 keysym, bool down) +{ + if (keysym == XK_Caps_Lock) { + vlog.debug("Ignoring caps lock"); + return; + } + DeviceIntPtr dev = (DeviceIntPtr)LookupKeyboardDevice(); + KeyClassPtr keyc = dev->key; + KeySymsPtr keymap = &keyc->curKeySyms; + + // find which modifier Mode_switch is on. + int modeSwitchMapIndex = 0; + for (int i = 3; i < 8; i++) { + for (int k = 0; k < keyc->maxKeysPerModifier; k++) { + int keycode = keyc->modifierKeyMap[i * keyc->maxKeysPerModifier + k]; + for (int j = 0; j < keymap->mapWidth; j++) { + if (keycode != 0 && + keymap->map[(keycode - keymap->minKeyCode) + * keymap->mapWidth + j] == XK_Mode_switch) + { + modeSwitchMapIndex = i; + break; + } + } + } + } + + int col = 0; + if (keyc->state & (1<state & (1<state & (1<maxKeyCode; kc >= keymap->minKeyCode; kc--) { + if (!keymap->map[(kc - keymap->minKeyCode) * keymap->mapWidth]) { + keymap->map[(kc - keymap->minKeyCode) * keymap->mapWidth] = keysym; + col = 0; + SendMappingNotify(MappingKeyboard, kc, 1, serverClient); + vlog.info("Added unknown keysym 0x%x to keycode %d",keysym,kc); + break; + } + } + if (kc < keymap->minKeyCode) { + vlog.info("Keyboard mapping full - ignoring unknown keysym 0x%x",keysym); + return; + } + } + + // See if it's a modifier key. If so, then don't do any auto-repeat, because + // the X server will translate each press into a release followed by a press. + for (int i = 0; i < 8; i++) { + for (int k = 0; k < keyc->maxKeysPerModifier; k++) { + if (kc == keyc->modifierKeyMap[i * keyc->maxKeysPerModifier + k] && + IS_PRESSED(keyc,kc) && down) + return; + } + } + + ModifierState shift(dev, ShiftMapIndex); + ModifierState modeSwitch(dev, modeSwitchMapIndex); + if (down) { + if (col & 1) + shift.press(); + else + shift.release(); + if (modeSwitchMapIndex) { + if (col & 2) + modeSwitch.press(); + else + modeSwitch.release(); + } + } + vlog.debug("keycode %d %s", kc, down ? "down" : "up"); + xEvent ev; + ev.u.u.type = down ? KeyPress : KeyRelease; + ev.u.u.detail = kc; + ev.u.keyButtonPointer.time = GetTimeInMillis(); + (*dev->c_public.processInputProc)(&ev, dev, 1); +} + + +void XConvertCase(KeySym sym, KeySym *lower, KeySym *upper) +{ + *lower = sym; + *upper = sym; + switch(sym >> 8) { + case 0: /* Latin 1 */ + if ((sym >= XK_A) && (sym <= XK_Z)) + *lower += (XK_a - XK_A); + else if ((sym >= XK_a) && (sym <= XK_z)) + *upper -= (XK_a - XK_A); + else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) + *lower += (XK_agrave - XK_Agrave); + else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis)) + *upper -= (XK_agrave - XK_Agrave); + else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn)) + *lower += (XK_oslash - XK_Ooblique); + else if ((sym >= XK_oslash) && (sym <= XK_thorn)) + *upper -= (XK_oslash - XK_Ooblique); + break; + case 1: /* Latin 2 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym == XK_Aogonek) + *lower = XK_aogonek; + else if (sym >= XK_Lstroke && sym <= XK_Sacute) + *lower += (XK_lstroke - XK_Lstroke); + else if (sym >= XK_Scaron && sym <= XK_Zacute) + *lower += (XK_scaron - XK_Scaron); + else if (sym >= XK_Zcaron && sym <= XK_Zabovedot) + *lower += (XK_zcaron - XK_Zcaron); + else if (sym == XK_aogonek) + *upper = XK_Aogonek; + else if (sym >= XK_lstroke && sym <= XK_sacute) + *upper -= (XK_lstroke - XK_Lstroke); + else if (sym >= XK_scaron && sym <= XK_zacute) + *upper -= (XK_scaron - XK_Scaron); + else if (sym >= XK_zcaron && sym <= XK_zabovedot) + *upper -= (XK_zcaron - XK_Zcaron); + else if (sym >= XK_Racute && sym <= XK_Tcedilla) + *lower += (XK_racute - XK_Racute); + else if (sym >= XK_racute && sym <= XK_tcedilla) + *upper -= (XK_racute - XK_Racute); + break; + case 2: /* Latin 3 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Hstroke && sym <= XK_Hcircumflex) + *lower += (XK_hstroke - XK_Hstroke); + else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex) + *lower += (XK_gbreve - XK_Gbreve); + else if (sym >= XK_hstroke && sym <= XK_hcircumflex) + *upper -= (XK_hstroke - XK_Hstroke); + else if (sym >= XK_gbreve && sym <= XK_jcircumflex) + *upper -= (XK_gbreve - XK_Gbreve); + else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex) + *lower += (XK_cabovedot - XK_Cabovedot); + else if (sym >= XK_cabovedot && sym <= XK_scircumflex) + *upper -= (XK_cabovedot - XK_Cabovedot); + break; + case 3: /* Latin 4 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Rcedilla && sym <= XK_Tslash) + *lower += (XK_rcedilla - XK_Rcedilla); + else if (sym >= XK_rcedilla && sym <= XK_tslash) + *upper -= (XK_rcedilla - XK_Rcedilla); + else if (sym == XK_ENG) + *lower = XK_eng; + else if (sym == XK_eng) + *upper = XK_ENG; + else if (sym >= XK_Amacron && sym <= XK_Umacron) + *lower += (XK_amacron - XK_Amacron); + else if (sym >= XK_amacron && sym <= XK_umacron) + *upper -= (XK_amacron - XK_Amacron); + break; + case 6: /* Cyrillic */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE) + *lower -= (XK_Serbian_DJE - XK_Serbian_dje); + else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze) + *upper += (XK_Serbian_DJE - XK_Serbian_dje); + else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN) + *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu); + else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign) + *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu); + break; + case 7: /* Greek */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent) + *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); + else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent && + sym != XK_Greek_iotaaccentdieresis && + sym != XK_Greek_upsilonaccentdieresis) + *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); + else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA) + *lower += (XK_Greek_alpha - XK_Greek_ALPHA); + else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega && + sym != XK_Greek_finalsmallsigma) + *upper -= (XK_Greek_alpha - XK_Greek_ALPHA); + break; + } +} + +static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col) +{ + register int per = keymap->mapWidth; + register KeySym *syms; + KeySym lsym, usym; + + if ((col < 0) || ((col >= per) && (col > 3)) || + (keycode < keymap->minKeyCode) || (keycode > keymap->maxKeyCode)) + return NoSymbol; + + syms = &keymap->map[(keycode - keymap->minKeyCode) * per]; + if (col < 4) { + if (col > 1) { + while ((per > 2) && (syms[per - 1] == NoSymbol)) + per--; + if (per < 3) + col -= 2; + } + if ((per <= (col|1)) || (syms[col|1] == NoSymbol)) { + XConvertCase(syms[col&~1], &lsym, &usym); + if (!(col & 1)) + return lsym; + // I'm commenting out this logic because it's incorrect even though it + // was copied from the Xlib sources. The X protocol book quite clearly + // states that where a group consists of element 1 being a non-alphabetic + // keysym and element 2 being NoSymbol that you treat the second element + // as being the same as the first. This also tallies with the behaviour + // produced by the installed Xlib on my linux box (I believe this is + // because it uses some XKB code rather than the original Xlib code - + // compare XKBBind.c with KeyBind.c in lib/X11). + // else if (usym == lsym) + // return NoSymbol; + else + return usym; + } + } + return syms[col]; +} + +// KeysymToKeycode() - find the keycode and column corresponding to the given +// keysym. The value of col passed in should be the column determined from the +// current shift state. If the keysym can be found in that column we prefer +// that to finding it in a different column (which would require fake events to +// alter the shift state). + +static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col) +{ + register int i, j; + + j = *col; + for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) { + if (KeyCodetoKeySym(keymap, i, j) == ks) + return i; + } + + for (j = 0; j < keymap->mapWidth; j++) { + for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) { + if (KeyCodetoKeySym(keymap, i, j) == ks) { + *col = j; + return i; + } + } + } + return 0; +} diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h new file mode 100644 index 00000000..880acc21 --- /dev/null +++ b/unix/xserver/hw/vnc/XserverDesktop.h @@ -0,0 +1,130 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +// +// XserverDesktop.h +// + +#ifndef __XSERVERDESKTOP_H__ +#define __XSERVERDESKTOP_H__ + +#include +#include +#include +#include +#include +#include + +extern "C" { +#define class c_class; +#include +#include +#undef class +} + +namespace rfb { + class VNCServerST; +} + +namespace network { class TcpListener; class Socket; } + +class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer, + public rfb::ColourMap, public rdr::Substitutor, + public rfb::VNCServerST::QueryConnectionHandler { +public: + + XserverDesktop(ScreenPtr pScreen, network::TcpListener* listener, + network::TcpListener* httpListener_, + const char* name, void* fbptr); + virtual ~XserverDesktop(); + + // methods called from X server code + void serverReset(ScreenPtr pScreen); + void setColormap(ColormapPtr cmap); + void setColourMapEntries(ColormapPtr pColormap, int ndef, xColorItem* pdef); + void bell(); + void serverCutText(const char* str, int len); + void setCursor(CursorPtr cursor); + void add_changed(RegionPtr reg); + void add_copied(RegionPtr dst, int dx, int dy); + void positionCursor(); + void ignoreHooks(bool b) { ignoreHooks_ = b; } + void blockHandler(fd_set* fds); + void wakeupHandler(fd_set* fds, int nfds); + void addClient(network::Socket* sock, bool reverse); + void disconnectClients(); + + // QueryConnect methods called from X server code + // getQueryTimeout() + // Returns the timeout associated with a particular + // connection, identified by an opaque Id passed to the + // X code earlier. Also optionally gets the address and + // name associated with that connection. + // Returns zero if the Id is not recognised. + int getQueryTimeout(void* opaqueId, + const char** address=0, + const char** username=0); + + // approveConnection() + // Used by X server code to supply the result of a query. + void approveConnection(void* opaqueId, bool accept, + const char* rejectMsg=0); + + // rfb::SDesktop callbacks + virtual void pointerEvent(const rfb::Point& pos, int buttonMask); + virtual void keyEvent(rdr::U32 key, bool down); + virtual void clientCutText(const char* str, int len); + virtual rfb::Point getFbSize() { return rfb::Point(width(), height()); } + + // rfb::PixelBuffer callbacks + virtual void grabRegion(const rfb::Region& r); + + // rfb::ColourMap callbacks + virtual void lookup(int index, int* r, int* g, int* b); + + // rdr::Substitutor callback + virtual char* substitute(const char* varName); + + // rfb::VNCServerST::QueryConnectionHandler callback + virtual rfb::VNCServerST::queryResult queryConnection(network::Socket* sock, + const char* userName, + char** reason); + +private: + void setColourMapEntries(int firstColour, int nColours); + static CARD32 deferredUpdateTimerCallback(OsTimerPtr timer, CARD32 now, + pointer arg); + void deferUpdate(); + ScreenPtr pScreen; + OsTimerPtr deferredUpdateTimer, dummyTimer; + rfb::VNCServerST* server; + rfb::HTTPServer* httpServer; + network::TcpListener* listener; + network::TcpListener* httpListener; + ColormapPtr cmap; + bool deferredUpdateTimerSet; + bool grabbing; + bool ignoreHooks_; + bool directFbptr; + int oldButtonMask; + rfb::Point cursorPos, oldCursorPos; + + void* queryConnectId; + rfb::CharArray queryConnectAddress; + rfb::CharArray queryConnectUsername; +}; +#endif diff --git a/unix/xserver/hw/vnc/Xvnc.man b/unix/xserver/hw/vnc/Xvnc.man new file mode 100644 index 00000000..94a2786c --- /dev/null +++ b/unix/xserver/hw/vnc/Xvnc.man @@ -0,0 +1,284 @@ +.TH Xvnc 1 "17 Apr 2006" "TightVNC" "Virtual Network Computing" +.SH NAME +Xvnc \- the X VNC server +.SH SYNOPSIS +.B Xvnc +.RI [ options ] +.RI : display# +.SH DESCRIPTION +.B Xvnc +is the X VNC (Virtual Network Computing) server. It is based on a standard X +server, but it has a "virtual" screen rather than a physical one. X +applications display themselves on it as if it were a normal X display, but +they can only be accessed via a VNC viewer - see \fBvncviewer\fP(1). + +So Xvnc is really two servers in one. To the applications it is an X server, +and to the remote VNC users it is a VNC server. By convention we have arranged +that the VNC server display number will be the same as the X server display +number, which means you can use eg. snoopy:2 to refer to display 2 on machine +"snoopy" in both the X world and the VNC world. + +The best way of starting \fBXvnc\fP is via the \fBvncserver\fP script. This +sets up the environment appropriately and runs some X applications to get you +going. See the manual page for \fBvncserver\fP(1) for more information. + +.SH OPTIONS +.B Xvnc +takes lots of options - running \fBXvnc -help\fP gives a list. Many of these +are standard X server options, which are described in the \fBXserver\fP(1) +manual page. In addition to options which can only be set via the +command-line, there are also "parameters" which can be set both via the +command-line and through the \fBvncconfig\fP(1) program. + +.TP +.B \-geometry \fIwidth\fPx\fIheight\fP +Specify the size of the desktop to be created. Default is 1024x768. + +.TP +.B \-depth \fIdepth\fP +Specify the pixel depth in bits of the desktop to be created. Default is 16, +other possible values are 8, 15, and 24 - anything else is likely to cause +strange behaviour by applications. + +.TP +.B \-pixelformat \fIformat\fP +Specify pixel format for server to use (BGRnnn or RGBnnn). The default for +depth 8 is BGR233 (meaning the most significant two bits represent blue, the +next three green, and the least significant three represent red), the default +for depth 16 is RGB565 and for depth 24 is RGB888. + +.TP +.B \-cc 3 +As an alternative to the default TrueColor visual, this allows you to run an +Xvnc server with a PseudoColor visual (i.e. one which uses a color map or +palette), which can be useful for running some old X applications which only +work on such a display. Values other than 3 (PseudoColor) and 4 (TrueColor) +for the \-cc option may result in strange behaviour, and PseudoColor desktops +must be 8 bits deep (i.e. \fB-depth 8\fP). + +.TP +.B \-inetd +This significantly changes Xvnc's behaviour so that it can be launched from +inetd. See the section below on usage with inetd. + +.TP +.B \-help +List all the options and parameters + +.SH PARAMETERS +VNC parameters can be set both via the command-line and through the +\fBvncconfig\fP(1) program, and with a VNC-enabled XFree86 server via Options +entries in the XF86Config file. + +Parameters can be turned on with -\fIparam\fP or off with +-\fIparam\fP=0. Parameters which take a value can be specified as +-\fIparam\fP \fIvalue\fP. Other valid forms are \fIparam\fP\fB=\fP\fIvalue\fP +-\fIparam\fP=\fIvalue\fP --\fIparam\fP=\fIvalue\fP. Parameter names are +case-insensitive. + +.TP +.B \-desktop \fIdesktop-name\fP +Each desktop has a name which may be displayed by the viewer. It defaults to +"x11". + +.TP +.B \-rfbport \fIport\fP +Specifies the TCP port on which Xvnc listens for connections from viewers (the +protocol used in VNC is called RFB - "remote framebuffer"). The default is +5900 plus the display number. + +.TP +.B \-rfbwait \fItime\fP, \-ClientWaitTimeMillis \fItime\fP + +Time in milliseconds to wait for a viewer which is blocking Xvnc. This is +necessary because Xvnc is single-threaded and sometimes blocks until the viewer +has finished sending or receiving a message - note that this does not mean an +update will be aborted after this time. Default is 20000 (20 seconds). + +.TP +.B \-httpd \fIdirectory\fP +Run a mini-HTTP server which serves files from the given directory. Normally +the directory will contain the classes for the Java viewer. In addition, files +with a .vnc extension will have certain substitutions made so that a single +installation of the Java VNC viewer can be served by separate instances of +Xvnc. + +.TP +.B \-httpPort \fIport\fP +Specifies the port on which the mini-HTTP server runs. Default is 5800 plus +the display number. + +.TP +.B \-rfbauth \fIpasswd-file\fP, \-PasswordFile \fIpasswd-file\fP +Specifies the file containing the password used to authenticate viewers. The +file is accessed each time a connection comes in, so it can be changed on the +fly via \fBvncpasswd\fP(1). + +.TP +.B \-deferUpdate \fItime\fP +Xvnc uses a "deferred update" mechanism which enhances performance in many +cases. After any change to the framebuffer, Xvnc waits for this number of +milliseconds (default 40) before sending an update to any waiting clients. This +means that more changes tend to get coalesced together in a single +update. Setting it to 0 results in the same behaviour as earlier versions of +Xvnc, where the first change to the framebuffer causes an immediate update to +any waiting clients. + +.TP +.B \-SendCutText +Send clipboard changes to clients (default is on). Note that you must also run +\fBvncconfig\fP(1) to get the clipboard to work. + +.TP +.B \-AcceptCutText +Accept clipboard updates from clients (default is on). Note that you must also +run \fBvncconfig\fP(1) to get the clipboard to work. + +.TP +.B \-AcceptPointerEvents +Accept pointer press and release events from clients (default is on). + +.TP +.B \-AcceptKeyEvents +Accept key press and release events from clients (default is on). + +.TP +.B \-DisconnectClients +Disconnect existing clients if an incoming connection is non-shared (default is +on). If \fBDisconnectClients\fP is false, then a new non-shared connection will +be refused while there is a client active. When combined with +\fBNeverShared\fP this means only one client is allowed at a time. + +.TP +.B \-NeverShared +Never treat incoming connections as shared, regardless of the client-specified +setting (default is off). + +.TP +.B \-AlwaysShared +Always treat incoming connections as shared, regardless of the client-specified +setting (default is off). + +.TP +.B \-Protocol3.3 +Always use protocol version 3.3 for backwards compatibility with badly-behaved +clients (default is off). + +.TP +.B \-CompareFB +Perform pixel comparison on framebuffer to reduce unnecessary updates (default +is on). + +.TP +.B \-SecurityTypes \fIsec-types\fP +Specify which security schemes to use separated by commas. At present only +"None" and "VncAuth" are supported. The default is "VncAuth" - note that if +you want a server which does not require a password, you must set this +parameter to "None". + +.TP +.B \-IdleTimeout \fIseconds\fP +The number of seconds after which an idle VNC connection will be dropped +(default is 0, which means that idle connections will never be dropped). + +.TP +.B \-QueryConnect +Prompts the user of the desktop to explicitly accept or reject incoming +connections. This is most useful when using the vnc.so module or +\fBx0vncserver\fP(1) program to access an existing X desktop via VNC. + +The \fBvncconfig\fP(1) program must be running on the desktop in order for +QueryConnect to be supported by the \fBvnc.so\fP(1) module or +\fBXvnc\fP(1) program. The \fBx0vncserver\fP(1) program does not require +\fBvncconfig\fP(1) to be running. + +.TP +.B \-localhost +Only allow connections from the same machine. Useful if you use SSH and want to +stop non-SSH connections from any other hosts. See the guide to using VNC with +SSH on the web site. + +.TP +.B \-log \fIlogname\fP:\fIdest\fP:\fIlevel\fP +Configures the debug log settings. \fIdest\fP can currently be \fBstderr\fP or +\fBstdout\fP, and \fIlevel\fP is between 0 and 100, 100 meaning most verbose +output. \fIlogname\fP is usually \fB*\fP meaning all, but you can target a +specific source file if you know the name of its "LogWriter". Default is +\fB*:stderr:30\fP. + +.TP +.B \-RemapKeys \fImapping +Sets up a keyboard mapping. +.I mapping +is a comma-separated string of character mappings, each of the form +.IR char -> char , +or +.IR char <> char , +where +.I char +is a hexadecimal keysym. For example, to exchange the " and @ symbols you would specify the following: +.IP "" 10 +RemapKeys=0x22<>0x40 + +.SH USAGE WITH INETD +By configuring the \fBinetd\fP(1) service appropriately, Xvnc can be launched +on demand when a connection comes in, rather than having to be started +manually. When given the \fB-inetd\fP option, instead of listening for TCP +connections on a given port it uses its standard input and standard output. +There are two modes controlled by the wait/nowait entry in the inetd.conf file. + +In the nowait mode, Xvnc uses its standard input and output directly as the +connection to a viewer. It never has a listening socket, so cannot accept +further connections from viewers (it can however connect out to listening +viewers by use of the vncconfig program). Further viewer connections to the +same TCP port result in inetd spawning off a new Xvnc to deal with each +connection. When the connection to the viewer dies, the Xvnc and any +associated X clients die. This behaviour is most useful when combined with the +XDMCP options -query and -once. An typical example in inetd.conf might be (all +on one line): + +5950 stream tcp nowait nobody /usr/local/bin/Xvnc Xvnc -inetd -query +localhost -once securitytypes=none + +In this example a viewer connection to :50 will result in a new Xvnc for that +connection which should display the standard XDM login screen on that machine. +Because the user needs to login via XDM, it is usually OK to accept connections +without a VNC password in this case. + +In the wait mode, when the first connection comes in, inetd gives the listening +socket to Xvnc. This means that for a given TCP port, there is only ever one +Xvnc at a time. Further viewer connections to the same port are accepted by +the same Xvnc in the normal way. Even when the original connection is broken, +the Xvnc will continue to run. If this is used with the XDMCP options -query +and -once, the Xvnc and associated X clients will die when the user logs out of +the X session in the normal way. It is important to use a VNC password in this +case. A typical entry in inetd.conf might be: + +5951 stream tcp wait james /usr/local/bin/Xvnc Xvnc -inetd -query localhost -once passwordFile=/home/james/.vnc/passwd + +In fact typically, you would have one entry for each user who uses VNC +regularly, each of whom has their own dedicated TCP port which they use. In +this example, when user "james" connects to :51, he enters his VNC password, +then gets the XDM login screen where he logs in in the normal way. However, +unlike the previous example, if he disconnects, the session remains persistent, +and when he reconnects he will get the same session back again. When he logs +out of the X session, the Xvnc will die, but of course a new one will be +created automatically the next time he connects. + +.SH SEE ALSO +.BR vncconfig (1), +.BR vncpasswd (1), +.BR vncserver (1), +.BR vncviewer (1), +.BR Xserver (1), +.BR inetd (1) +.br +http://www.tightvnc.com + +.SH AUTHOR +Tristan Richardson, RealVNC Ltd. + +VNC was originally developed by the RealVNC team while at Olivetti +Research Ltd / AT&T Laboratories Cambridge. TightVNC additions were +implemented by Constantin Kaplinsky. Many other people participated in +development, testing and support. diff --git a/unix/xserver/hw/vnc/buildtime.c b/unix/xserver/hw/vnc/buildtime.c new file mode 100644 index 00000000..3f4c3690 --- /dev/null +++ b/unix/xserver/hw/vnc/buildtime.c @@ -0,0 +1,18 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +char buildtime[] = __DATE__ " " __TIME__; diff --git a/unix/xserver/hw/vnc/vncExtInit.cc b/unix/xserver/hw/vnc/vncExtInit.cc new file mode 100644 index 00000000..9cf9d21b --- /dev/null +++ b/unix/xserver/hw/vnc/vncExtInit.cc @@ -0,0 +1,866 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include + +extern "C" { +#define class c_class +#define NEED_EVENTS +#include "X.h" +#include "Xproto.h" +#include "misc.h" +#include "os.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "scrnintstr.h" +#include "selection.h" +#define _VNCEXT_SERVER_ +#define _VNCEXT_PROTO_ +#include "vncExt.h" +#undef class +#undef xalloc +} + +#include +#include +#include +#include +#include +#include +#include +#include +#undef max +#undef min +#include + +#include "XserverDesktop.h" +#include "vncHooks.h" +#include "vncExtInit.h" + +extern "C" { + + extern void vncExtensionInit(); + static void vncResetProc(ExtensionEntry* extEntry); + static void vncBlockHandler(pointer data, OSTimePtr t, pointer readmask); + static void vncWakeupHandler(pointer data, int nfds, pointer readmask); + static void vncClientStateChange(CallbackListPtr*, pointer, pointer); + static void SendSelectionChangeEvent(Atom selection); + static int ProcVncExtDispatch(ClientPtr client); + static int SProcVncExtDispatch(ClientPtr client); + + extern char *display; + + extern Selection *CurrentSelections; + extern int NumCurrentSelections; +} + +using namespace rfb; + +static rfb::LogWriter vlog("vncext"); + +static unsigned long vncExtGeneration = 0; +static bool initialised = false; +static XserverDesktop* desktop[MAXSCREENS] = { 0, }; +void* vncFbptr[MAXSCREENS] = { 0, }; + +static char* clientCutText = 0; +static int clientCutTextLen = 0; + +static XserverDesktop* queryConnectDesktop = 0; +static void* queryConnectId = 0; +static int queryConnectTimeout = 0; +static OsTimerPtr queryConnectTimer = 0; + +static struct VncInputSelect* vncInputSelectHead = 0; +struct VncInputSelect { + VncInputSelect(ClientPtr c, Window w, int m) : client(c), window(w), mask(m) + { + next = vncInputSelectHead; + vncInputSelectHead = this; + } + ClientPtr client; + Window window; + int mask; + VncInputSelect* next; +}; + +static int nPrevSelections = 0; +static TimeStamp* prevSelectionTimes = 0; + +static int vncErrorBase = 0; +static int vncEventBase = 0; +static char* vncPasswdFile = 0; +int vncInetdSock = -1; + +rfb::AliasParameter rfbauth("rfbauth", "Alias for PasswordFile", + &SSecurityFactoryStandard::vncAuthPasswdFile); +rfb::StringParameter httpDir("httpd", + "Directory containing files to serve via HTTP", + ""); +rfb::IntParameter httpPort("httpPort", "TCP port to listen for HTTP",0); +rfb::AliasParameter rfbwait("rfbwait", "Alias for ClientWaitTimeMillis", + &rfb::Server::clientWaitTimeMillis); +rfb::IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",0); +rfb::StringParameter desktopName("desktop", "Name of VNC desktop","x11"); +rfb::BoolParameter localhostOnly("localhost", + "Only allow connections from localhost", + false); + +void vncExtensionInit() +{ + if (vncExtGeneration == serverGeneration) { + vlog.error("vncExtensionInit: called twice in same generation?"); + return; + } + vncExtGeneration = serverGeneration; + + ExtensionEntry* extEntry + = AddExtension(VNCEXTNAME, VncExtNumberEvents, VncExtNumberErrors, + ProcVncExtDispatch, SProcVncExtDispatch, vncResetProc, + StandardMinorOpcode); + if (!extEntry) { + ErrorF("vncExtInit: AddExtension failed\n"); + return; + } + + vncErrorBase = extEntry->errorBase; + vncEventBase = extEntry->eventBase; + + vlog.info("VNC extension running!"); + + if (!AddCallback(&ClientStateCallback, vncClientStateChange, 0)) { + FatalError("AddCallback failed\n"); + } + + try { + if (!initialised) { + rfb::initStdIOLoggers(); + initialised = true; + } + + for (int scr = 0; scr < screenInfo.numScreens; scr++) { + + if (!desktop[scr]) { + network::TcpListener* listener = 0; + network::TcpListener* httpListener = 0; + if (scr == 0 && vncInetdSock != -1) { + if (network::TcpSocket::isSocket(vncInetdSock) && + !network::TcpSocket::isConnected(vncInetdSock)) + { + listener = new network::TcpListener(0, 0, vncInetdSock, true); + vlog.info("inetd wait"); + } + } else { + int port = rfbport; + if (port == 0) port = 5900 + atoi(display); + port += 1000 * scr; + listener = new network::TcpListener(port, localhostOnly); + vlog.info("Listening for VNC connections on port %d",port); + CharArray httpDirStr(httpDir.getData()); + if (httpDirStr.buf[0]) { + port = httpPort; + if (port == 0) port = 5800 + atoi(display); + port += 1000 * scr; + httpListener = new network::TcpListener(port, localhostOnly); + vlog.info("Listening for HTTP connections on port %d",port); + } + } + + CharArray desktopNameStr(desktopName.getData()); + desktop[scr] = new XserverDesktop(screenInfo.screens[scr], listener, + httpListener, + desktopNameStr.buf, + vncFbptr[scr]); + vlog.info("created VNC server for screen %d", scr); + + if (scr == 0 && vncInetdSock != -1 && !listener) { + network::Socket* sock = new network::TcpSocket(vncInetdSock); + desktop[scr]->addClient(sock, false); + vlog.info("added inetd sock"); + } + + } else { + desktop[scr]->serverReset(screenInfo.screens[scr]); + } + + vncHooksInit(screenInfo.screens[scr], desktop[scr]); + } + + RegisterBlockAndWakeupHandlers(vncBlockHandler, vncWakeupHandler, 0); + + } catch (rdr::Exception& e) { + vlog.error("vncExtInit: %s",e.str()); + } +} + +static void vncResetProc(ExtensionEntry* extEntry) +{ +} + +// +// vncBlockHandler - called just before the X server goes into select(). Call +// on to the block handler for each desktop. Then check whether any of the +// selections have changed, and if so, notify any interested X clients. +// + +static void vncBlockHandler(pointer data, OSTimePtr timeout, pointer readmask) +{ + fd_set* fds = (fd_set*)readmask; + + for (int scr = 0; scr < screenInfo.numScreens; scr++) { + if (desktop[scr]) { + desktop[scr]->blockHandler(fds); + } + } + + if (nPrevSelections != NumCurrentSelections) { + prevSelectionTimes + = (TimeStamp*)xnfrealloc(prevSelectionTimes, + NumCurrentSelections * sizeof(TimeStamp)); + for (int i = nPrevSelections; i < NumCurrentSelections; i++) { + prevSelectionTimes[i].months = 0; + prevSelectionTimes[i].milliseconds = 0; + } + nPrevSelections = NumCurrentSelections; + } + for (int i = 0; i < NumCurrentSelections; i++) { + if (CurrentSelections[i].lastTimeChanged.months + != prevSelectionTimes[i].months || + CurrentSelections[i].lastTimeChanged.milliseconds + != prevSelectionTimes[i].milliseconds) + { + SendSelectionChangeEvent(CurrentSelections[i].selection); + prevSelectionTimes[i] = CurrentSelections[i].lastTimeChanged; + } + } +} + +static void vncWakeupHandler(pointer data, int nfds, pointer readmask) +{ + fd_set* fds = (fd_set*)readmask; + + for (int scr = 0; scr < screenInfo.numScreens; scr++) { + if (desktop[scr]) { + desktop[scr]->wakeupHandler(fds, nfds); + } + } +} + +static void vncClientStateChange(CallbackListPtr*, pointer, pointer p) +{ + ClientPtr client = ((NewClientInfoRec*)p)->client; + if (client->clientState == ClientStateGone) { + VncInputSelect** nextPtr = &vncInputSelectHead; + for (VncInputSelect* cur = vncInputSelectHead; cur; cur = *nextPtr) { + if (cur->client == client) { + *nextPtr = cur->next; + delete cur; + continue; + } + nextPtr = &cur->next; + } + } +} + +void vncBell() +{ + for (int scr = 0; scr < screenInfo.numScreens; scr++) { + if (desktop[scr]) { + desktop[scr]->bell(); + } + } +} + +void vncClientGone(int fd) +{ + if (fd == vncInetdSock) { + fprintf(stderr,"inetdSock client gone\n"); + GiveUp(0); + } +} + +void vncClientCutText(const char* str, int len) +{ + delete [] clientCutText; + clientCutText = new char[len]; + memcpy(clientCutText, str, len); + clientCutTextLen = len; + xVncExtClientCutTextNotifyEvent ev; + ev.type = vncEventBase + VncExtClientCutTextNotify; + for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) { + if (cur->mask & VncExtClientCutTextMask) { + ev.sequenceNumber = cur->client->sequence; + ev.window = cur->window; + ev.time = GetTimeInMillis(); + if (cur->client->swapped) { + int n; + swaps(&ev.sequenceNumber, n); + swapl(&ev.window, n); + swapl(&ev.time, n); + } + WriteToClient(cur->client, sizeof(xVncExtClientCutTextNotifyEvent), + (char *)&ev); + } + } +} + + +static CARD32 queryConnectTimerCallback(OsTimerPtr timer, + CARD32 now, pointer arg) +{ + if (queryConnectTimeout) + queryConnectDesktop->approveConnection(queryConnectId, false, "The attempt to prompt the user to accept the connection failed"); + // Re-notify clients, causing them to discover that we're done + vncQueryConnect(queryConnectDesktop, queryConnectId); + return 0; +} + +void vncQueryConnect(XserverDesktop* desktop, void* opaqueId) +{ + // Only one query can be processed at any one time + if (queryConnectTimeout && ((desktop != queryConnectDesktop) || + (opaqueId != queryConnectId))) { + desktop->approveConnection(opaqueId, false, + "Another connection is currently being queried."); + return; + } + + // Get the query timeout. If it's zero, there is no query. + queryConnectTimeout = desktop->getQueryTimeout(opaqueId); + queryConnectId = queryConnectTimeout ? opaqueId : 0; + queryConnectDesktop = queryConnectTimeout ? desktop : 0; + + // Notify clients + bool notified = false; + xVncExtQueryConnectNotifyEvent ev; + ev.type = vncEventBase + VncExtQueryConnectNotify; + for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) { + if (cur->mask & VncExtQueryConnectMask) { + ev.sequenceNumber = cur->client->sequence; + ev.window = cur->window; + if (cur->client->swapped) { + int n; + swaps(&ev.sequenceNumber, n); + swapl(&ev.window, n); + } + WriteToClient(cur->client, sizeof(xVncExtQueryConnectNotifyEvent), + (char *)&ev); + notified = true; + } + } + + // If we're being asked to query a connection (rather than to cancel + // a query), and haven't been able to notify clients then reject it. + if (queryConnectTimeout && !notified) { + queryConnectTimeout = 0; + queryConnectId = 0; + queryConnectDesktop = 0; + desktop->approveConnection(opaqueId, false, + "Unable to query the local user to accept the connection."); + return; + } + + // Set a timer so that if no-one ever responds, we will eventually + // reject the connection + // NB: We don't set a timer if sock is null, since that indicates + // that pending queries should be cancelled. + if (queryConnectDesktop) + queryConnectTimer = TimerSet(queryConnectTimer, 0, + queryConnectTimeout*2000, + queryConnectTimerCallback, 0); + else + TimerCancel(queryConnectTimer); +} + +static void SendSelectionChangeEvent(Atom selection) +{ + xVncExtSelectionChangeNotifyEvent ev; + ev.type = vncEventBase + VncExtSelectionChangeNotify; + for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) { + if (cur->mask & VncExtSelectionChangeMask) { + ev.sequenceNumber = cur->client->sequence; + ev.window = cur->window; + ev.selection = selection; + if (cur->client->swapped) { + int n; + swaps(&ev.sequenceNumber, n); + swapl(&ev.window, n); + swapl(&ev.selection, n); + } + WriteToClient(cur->client, sizeof(xVncExtSelectionChangeNotifyEvent), + (char *)&ev); + } + } +} + +static int ProcVncExtSetParam(ClientPtr client) +{ + REQUEST(xVncExtSetParamReq); + REQUEST_FIXED_SIZE(xVncExtSetParamReq, stuff->paramLen); + CharArray param(stuff->paramLen+1); + strncpy(param.buf, (char*)&stuff[1], stuff->paramLen); + param.buf[stuff->paramLen] = 0; + + xVncExtSetParamReply rep; + int n; + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.success = rfb::Configuration::setParam(param.buf); + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + } + WriteToClient(client, sizeof(xVncExtSetParamReply), (char *)&rep); + return (client->noClientException); +} + +static int SProcVncExtSetParam(ClientPtr client) +{ + register char n; + REQUEST(xVncExtSetParamReq); + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xVncExtSetParamReq); + return ProcVncExtSetParam(client); +} + +static int ProcVncExtGetParam(ClientPtr client) +{ + REQUEST(xVncExtGetParamReq); + REQUEST_FIXED_SIZE(xVncExtGetParamReq, stuff->paramLen); + CharArray param(stuff->paramLen+1); + strncpy(param.buf, (char*)&stuff[1], stuff->paramLen); + param.buf[stuff->paramLen] = 0; + + xVncExtGetParamReply rep; + int n; + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.success = 0; + int len = 0; + char* value = 0; + rfb::VoidParameter* p = rfb::Configuration::getParam(param.buf); + // Hack to avoid exposing password! + if (strcasecmp(param.buf, "Password") == 0) + p = 0; + if (p) { + value = p->getValueStr(); + rep.success = 1; + len = value ? strlen(value) : 0; + } + rep.length = (len + 3) >> 2; + rep.valueLen = len; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.valueLen, n); + } + WriteToClient(client, sizeof(xVncExtGetParamReply), (char *)&rep); + if (value) + WriteToClient(client, len, value); + delete [] value; + return (client->noClientException); +} + +static int SProcVncExtGetParam(ClientPtr client) +{ + register char n; + REQUEST(xVncExtGetParamReq); + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xVncExtGetParamReq); + return ProcVncExtGetParam(client); +} + +static int ProcVncExtGetParamDesc(ClientPtr client) +{ + REQUEST(xVncExtGetParamDescReq); + REQUEST_FIXED_SIZE(xVncExtGetParamDescReq, stuff->paramLen); + CharArray param(stuff->paramLen+1); + strncpy(param.buf, (char*)&stuff[1], stuff->paramLen); + param.buf[stuff->paramLen] = 0; + + xVncExtGetParamDescReply rep; + int n; + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.success = 0; + int len = 0; + const char* desc = 0; + rfb::VoidParameter* p = rfb::Configuration::getParam(param.buf); + if (p) { + desc = p->getDescription(); + rep.success = 1; + len = desc ? strlen(desc) : 0; + } + rep.length = (len + 3) >> 2; + rep.descLen = len; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.descLen, n); + } + WriteToClient(client, sizeof(xVncExtGetParamDescReply), (char *)&rep); + if (desc) + WriteToClient(client, len, (char*)desc); + return (client->noClientException); +} + +static int SProcVncExtGetParamDesc(ClientPtr client) +{ + register char n; + REQUEST(xVncExtGetParamDescReq); + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xVncExtGetParamDescReq); + return ProcVncExtGetParamDesc(client); +} + +static int ProcVncExtListParams(ClientPtr client) +{ + REQUEST(xVncExtListParamsReq); + REQUEST_SIZE_MATCH(xVncExtListParamsReq); + + xVncExtListParamsReply rep; + int n; + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + + int nParams = 0; + int len = 0; + for (ParameterIterator i(Configuration::global()); i.param; i.next()) { + int l = strlen(i.param->getName()); + if (l <= 255) { + nParams++; + len += l + 1; + } + } + rep.length = (len + 3) >> 2; + rep.nParams = nParams; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.nParams, n); + } + WriteToClient(client, sizeof(xVncExtListParamsReply), (char *)&rep); + rdr::U8* data = new rdr::U8[len]; + rdr::U8* ptr = data; + for (ParameterIterator i(Configuration::global()); i.param; i.next()) { + int l = strlen(i.param->getName()); + if (l <= 255) { + *ptr++ = l; + memcpy(ptr, i.param->getName(), l); + ptr += l; + } + } + WriteToClient(client, len, (char*)data); + delete [] data; + return (client->noClientException); +} + +static int SProcVncExtListParams(ClientPtr client) +{ + register char n; + REQUEST(xVncExtListParamsReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xVncExtListParamsReq); + return ProcVncExtListParams(client); +} + +static int ProcVncExtSetServerCutText(ClientPtr client) +{ + REQUEST(xVncExtSetServerCutTextReq); + REQUEST_FIXED_SIZE(xVncExtSetServerCutTextReq, stuff->textLen); + char* str = new char[stuff->textLen+1]; + strncpy(str, (char*)&stuff[1], stuff->textLen); + str[stuff->textLen] = 0; + for (int scr = 0; scr < screenInfo.numScreens; scr++) { + if (desktop[scr]) { + desktop[scr]->serverCutText(str, stuff->textLen); + } + } + delete [] str; + return (client->noClientException); +} + +static int SProcVncExtSetServerCutText(ClientPtr client) +{ + register char n; + REQUEST(xVncExtSetServerCutTextReq); + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xVncExtSetServerCutTextReq); + swapl(&stuff->textLen, n); + return ProcVncExtSetServerCutText(client); +} + +static int ProcVncExtGetClientCutText(ClientPtr client) +{ + REQUEST(xVncExtGetClientCutTextReq); + REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq); + + xVncExtGetClientCutTextReply rep; + int n; + rep.type = X_Reply; + rep.length = (clientCutTextLen + 3) >> 2; + rep.sequenceNumber = client->sequence; + rep.textLen = clientCutTextLen; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.textLen, n); + } + WriteToClient(client, sizeof(xVncExtGetClientCutTextReply), (char *)&rep); + if (clientCutText) + WriteToClient(client, clientCutTextLen, clientCutText); + return (client->noClientException); +} + +static int SProcVncExtGetClientCutText(ClientPtr client) +{ + register char n; + REQUEST(xVncExtGetClientCutTextReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq); + return ProcVncExtGetClientCutText(client); +} + +static int ProcVncExtSelectInput(ClientPtr client) +{ + REQUEST(xVncExtSelectInputReq); + REQUEST_SIZE_MATCH(xVncExtSelectInputReq); + VncInputSelect** nextPtr = &vncInputSelectHead; + VncInputSelect* cur; + for (cur = vncInputSelectHead; cur; cur = *nextPtr) { + if (cur->client == client && cur->window == stuff->window) { + cur->mask = stuff->mask; + if (!cur->mask) { + *nextPtr = cur->next; + delete cur; + } + break; + } + nextPtr = &cur->next; + } + if (!cur) { + cur = new VncInputSelect(client, stuff->window, stuff->mask); + } + return (client->noClientException); +} + +static int SProcVncExtSelectInput(ClientPtr client) +{ + register char n; + REQUEST(xVncExtSelectInputReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xVncExtSelectInputReq); + swapl(&stuff->window, n); + swapl(&stuff->mask, n); + return ProcVncExtSelectInput(client); +} + +static int ProcVncExtConnect(ClientPtr client) +{ + REQUEST(xVncExtConnectReq); + REQUEST_FIXED_SIZE(xVncExtConnectReq, stuff->strLen); + CharArray str(stuff->strLen+1); + strncpy(str.buf, (char*)&stuff[1], stuff->strLen); + str.buf[stuff->strLen] = 0; + + xVncExtConnectReply rep; + rep.success = 0; + if (desktop[0]) { + if (stuff->strLen == 0) { + try { + desktop[0]->disconnectClients(); + rep.success = 1; + } catch (rdr::Exception& e) { + vlog.error("Disconnecting all clients: %s",e.str()); + } + } else { + int port = 5500; + for (int i = 0; i < stuff->strLen; i++) { + if (str.buf[i] == ':') { + port = atoi(&str.buf[i+1]); + str.buf[i] = 0; + break; + } + } + + try { + network::Socket* sock = new network::TcpSocket(str.buf, port); + desktop[0]->addClient(sock, true); + rep.success = 1; + } catch (rdr::Exception& e) { + vlog.error("Reverse connection: %s",e.str()); + } + } + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + if (client->swapped) { + int n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + } + WriteToClient(client, sizeof(xVncExtConnectReply), (char *)&rep); + return (client->noClientException); +} + +static int SProcVncExtConnect(ClientPtr client) +{ + register char n; + REQUEST(xVncExtConnectReq); + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xVncExtConnectReq); + return ProcVncExtConnect(client); +} + + +static int ProcVncExtGetQueryConnect(ClientPtr client) +{ + REQUEST(xVncExtGetQueryConnectReq); + REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq); + + const char *qcAddress=0, *qcUsername=0; + int qcTimeout; + if (queryConnectDesktop) + qcTimeout = queryConnectDesktop->getQueryTimeout(queryConnectId, + &qcAddress, &qcUsername); + else + qcTimeout = 0; + + xVncExtGetQueryConnectReply rep; + int n; + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.timeout = qcTimeout; + rep.addrLen = qcTimeout ? strlen(qcAddress) : 0; + rep.userLen = qcTimeout ? strlen(qcUsername) : 0; + rep.opaqueId = (CARD32)queryConnectId; + rep.length = (rep.userLen + rep.addrLen + 3) >> 2; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.userLen, n); + swapl(&rep.addrLen, n); + swapl(&rep.timeout, n); + swapl(&rep.opaqueId, n); + } + WriteToClient(client, sizeof(xVncExtGetQueryConnectReply), (char *)&rep); + if (qcTimeout) + WriteToClient(client, strlen(qcAddress), (char*)qcAddress); + if (qcTimeout) + WriteToClient(client, strlen(qcUsername), (char*)qcUsername); + return (client->noClientException); +} + +static int SProcVncExtGetQueryConnect(ClientPtr client) +{ + register char n; + REQUEST(xVncExtGetQueryConnectReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq); + return ProcVncExtGetQueryConnect(client); +} + + +static int ProcVncExtApproveConnect(ClientPtr client) +{ + REQUEST(xVncExtApproveConnectReq); + REQUEST_SIZE_MATCH(xVncExtApproveConnectReq); + if (queryConnectId == (void*)stuff->opaqueId) { + for (int scr = 0; scr < screenInfo.numScreens; scr++) { + if (desktop[scr]) { + desktop[scr]->approveConnection(queryConnectId, stuff->approve, + "Connection rejected by local user"); + } + } + // Inform other clients of the event and tidy up + vncQueryConnect(queryConnectDesktop, queryConnectId); + } + return (client->noClientException); +} + +static int SProcVncExtApproveConnect(ClientPtr client) +{ + register char n; + REQUEST(xVncExtApproveConnectReq); + swaps(&stuff->length, n); + swapl(&stuff->opaqueId, n); + REQUEST_SIZE_MATCH(xVncExtApproveConnectReq); + return ProcVncExtApproveConnect(client); +} + + +static int ProcVncExtDispatch(ClientPtr client) +{ + REQUEST(xReq); + switch (stuff->data) { + case X_VncExtSetParam: + return ProcVncExtSetParam(client); + case X_VncExtGetParam: + return ProcVncExtGetParam(client); + case X_VncExtGetParamDesc: + return ProcVncExtGetParamDesc(client); + case X_VncExtListParams: + return ProcVncExtListParams(client); + case X_VncExtSetServerCutText: + return ProcVncExtSetServerCutText(client); + case X_VncExtGetClientCutText: + return ProcVncExtGetClientCutText(client); + case X_VncExtSelectInput: + return ProcVncExtSelectInput(client); + case X_VncExtConnect: + return ProcVncExtConnect(client); + case X_VncExtGetQueryConnect: + return ProcVncExtGetQueryConnect(client); + case X_VncExtApproveConnect: + return ProcVncExtApproveConnect(client); + default: + return BadRequest; + } +} + +static int SProcVncExtDispatch(ClientPtr client) +{ + REQUEST(xReq); + switch (stuff->data) { + case X_VncExtSetParam: + return SProcVncExtSetParam(client); + case X_VncExtGetParam: + return SProcVncExtGetParam(client); + case X_VncExtGetParamDesc: + return SProcVncExtGetParamDesc(client); + case X_VncExtListParams: + return SProcVncExtListParams(client); + case X_VncExtSetServerCutText: + return SProcVncExtSetServerCutText(client); + case X_VncExtGetClientCutText: + return SProcVncExtGetClientCutText(client); + case X_VncExtSelectInput: + return SProcVncExtSelectInput(client); + case X_VncExtConnect: + return SProcVncExtConnect(client); + case X_VncExtGetQueryConnect: + return SProcVncExtGetQueryConnect(client); + case X_VncExtApproveConnect: + return SProcVncExtApproveConnect(client); + default: + return BadRequest; + } +} + diff --git a/unix/xserver/hw/vnc/vncExtInit.h b/unix/xserver/hw/vnc/vncExtInit.h new file mode 100644 index 00000000..45453e1f --- /dev/null +++ b/unix/xserver/hw/vnc/vncExtInit.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +#ifndef __VNCEXTINIT_H__ +#define __VNCEXTINIT_H__ + +#include +#include "XserverDesktop.h" + +extern void vncClientCutText(const char* str, int len); +extern void vncQueryConnect(XserverDesktop* desktop, void* opaqueId); +extern void vncClientGone(int fd); +extern void vncBell(); +extern void* vncFbptr[]; +extern int vncInetdSock; +extern rfb::StringParameter httpDir; + +#endif diff --git a/unix/xserver/hw/vnc/vncHooks.cc b/unix/xserver/hw/vnc/vncHooks.cc new file mode 100644 index 00000000..ce8e7f02 --- /dev/null +++ b/unix/xserver/hw/vnc/vncHooks.cc @@ -0,0 +1,1533 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include +#include "XserverDesktop.h" +#include "vncHooks.h" + +extern "C" { +#define class c_class +#define private c_private +#include "scrnintstr.h" +#include "windowstr.h" +#include "gcstruct.h" +#include "regionstr.h" +#include "dixfontstr.h" +#include "colormapst.h" +#ifdef RENDER +#include "picturestr.h" +#endif + +#ifdef GC_HAS_COMPOSITE_CLIP +#define COMPOSITE_CLIP(gc) ((gc)->pCompositeClip) +#else +#include "mfb.h" +#define COMPOSITE_CLIP(gc) \ + (((mfbPrivGCPtr)((gc)->devPrivates[mfbGCPrivateIndex].ptr))->pCompositeClip) +#endif + +#undef class +#undef private +} + +#include "RegionHelper.h" + +#define DBGPRINT(x) //(fprintf x) + +// MAX_RECTS_PER_OP is the maximum number of rectangles we generate from +// operations like Polylines and PolySegment. If the operation is more complex +// than this, we simply use the bounding box. Ideally it would be a +// command-line option, but that would involve an extra malloc each time, so we +// fix it here. +#define MAX_RECTS_PER_OP 5 + +static unsigned long vncHooksGeneration = 0; + +// vncHooksScreenRec and vncHooksGCRec contain pointers to the original +// functions which we "wrap" in order to hook the screen changes. The screen +// functions are each wrapped individually, while the GC "funcs" and "ops" are +// wrapped as a unit. + +typedef struct { + XserverDesktop* desktop; + + CloseScreenProcPtr CloseScreen; + CreateGCProcPtr CreateGC; + PaintWindowBackgroundProcPtr PaintWindowBackground; + PaintWindowBorderProcPtr PaintWindowBorder; + CopyWindowProcPtr CopyWindow; + ClearToBackgroundProcPtr ClearToBackground; + RestoreAreasProcPtr RestoreAreas; + InstallColormapProcPtr InstallColormap; + StoreColorsProcPtr StoreColors; + DisplayCursorProcPtr DisplayCursor; + ScreenBlockHandlerProcPtr BlockHandler; +#ifdef RENDER + CompositeProcPtr Composite; +#endif +} vncHooksScreenRec, *vncHooksScreenPtr; + +typedef struct { + GCFuncs *wrappedFuncs; + GCOps *wrappedOps; +} vncHooksGCRec, *vncHooksGCPtr; + +static int vncHooksScreenIndex; +static int vncHooksGCIndex; + + +// screen functions + +static Bool vncHooksCloseScreen(int i, ScreenPtr pScreen); +static Bool vncHooksCreateGC(GCPtr pGC); +static void vncHooksPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion, + int what); +static void vncHooksPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion, + int what); +static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, + RegionPtr pOldRegion); +static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w, + int h, Bool generateExposures); +static RegionPtr vncHooksRestoreAreas(WindowPtr pWin, RegionPtr prgnExposed); +static void vncHooksInstallColormap(ColormapPtr pColormap); +static void vncHooksStoreColors(ColormapPtr pColormap, int ndef, + xColorItem* pdef); +static Bool vncHooksDisplayCursor(ScreenPtr pScreen, CursorPtr cursor); +static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout, + pointer pReadmask); +#ifdef RENDER +static void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, + PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, + INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height); +#endif + +// GC "funcs" + +static void vncHooksValidateGC(GCPtr pGC, unsigned long changes, + DrawablePtr pDrawable); +static void vncHooksChangeGC(GCPtr pGC, unsigned long mask); +static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst); +static void vncHooksDestroyGC(GCPtr pGC); +static void vncHooksChangeClip(GCPtr pGC, int type, pointer pValue,int nrects); +static void vncHooksDestroyClip(GCPtr pGC); +static void vncHooksCopyClip(GCPtr dst, GCPtr src); + +static GCFuncs vncHooksGCFuncs = { + vncHooksValidateGC, vncHooksChangeGC, vncHooksCopyGC, vncHooksDestroyGC, + vncHooksChangeClip, vncHooksDestroyClip, vncHooksCopyClip, +}; + +// GC "ops" + +static void vncHooksFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit, + DDXPointPtr pptInit, int *pwidthInit, + int fSorted); +static void vncHooksSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc, + DDXPointPtr ppt, int *pwidth, int nspans, + int fSorted); +static void vncHooksPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, + int x, int y, int w, int h, int leftPad, + int format, char *pBits); +static RegionPtr vncHooksCopyArea(DrawablePtr pSrc, DrawablePtr pDst, + GCPtr pGC, int srcx, int srcy, int w, int h, + int dstx, int dsty); +static RegionPtr vncHooksCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, + GCPtr pGC, int srcx, int srcy, int w, int h, + int dstx, int dsty, unsigned long plane); +static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, + int npt, xPoint *pts); +static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, + int npt, DDXPointPtr ppts); +static void vncHooksPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg, + xSegment *segs); +static void vncHooksPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects, + xRectangle *rects); +static void vncHooksPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, + xArc *arcs); +static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape, + int mode, int count, DDXPointPtr pts); +static void vncHooksPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects, + xRectangle *rects); +static void vncHooksPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, + xArc *arcs); +static int vncHooksPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y, + int count, char *chars); +static int vncHooksPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y, + int count, unsigned short *chars); +static void vncHooksImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y, + int count, char *chars); +static void vncHooksImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y, + int count, unsigned short *chars); +static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, + int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase); +static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, + int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase); +static void vncHooksPushPixels(GCPtr pGC, PixmapPtr pBitMap, + DrawablePtr pDrawable, int w, int h, int x, + int y); + +static GCOps vncHooksGCOps = { + vncHooksFillSpans, vncHooksSetSpans, vncHooksPutImage, vncHooksCopyArea, + vncHooksCopyPlane, vncHooksPolyPoint, vncHooksPolylines, vncHooksPolySegment, + vncHooksPolyRectangle, vncHooksPolyArc, vncHooksFillPolygon, + vncHooksPolyFillRect, vncHooksPolyFillArc, vncHooksPolyText8, + vncHooksPolyText16, vncHooksImageText8, vncHooksImageText16, + vncHooksImageGlyphBlt, vncHooksPolyGlyphBlt, vncHooksPushPixels +}; + + + +///////////////////////////////////////////////////////////////////////////// +// vncHooksInit() is called at initialisation time and every time the server +// resets. It is called once for each screen, but the indexes are only +// allocated once for each server generation. + +Bool vncHooksInit(ScreenPtr pScreen, XserverDesktop* desktop) +{ + vncHooksScreenPtr vncHooksScreen; + + if (vncHooksGeneration != serverGeneration) { + vncHooksGeneration = serverGeneration; + + vncHooksScreenIndex = AllocateScreenPrivateIndex(); + if (vncHooksScreenIndex < 0) { + ErrorF("vncHooksInit: AllocateScreenPrivateIndex failed\n"); + return FALSE; + } + + vncHooksGCIndex = AllocateGCPrivateIndex(); + if (vncHooksGCIndex < 0) { + ErrorF("vncHooksInit: AllocateGCPrivateIndex failed\n"); + return FALSE; + } + } + + if (!AllocateGCPrivate(pScreen, vncHooksGCIndex, sizeof(vncHooksGCRec))) { + ErrorF("vncHooksInit: AllocateGCPrivate failed\n"); + return FALSE; + } + + vncHooksScreen = (vncHooksScreenPtr)xnfalloc(sizeof(vncHooksScreenRec)); + pScreen->devPrivates[vncHooksScreenIndex].ptr = (pointer)vncHooksScreen; + + vncHooksScreen->desktop = desktop; + + vncHooksScreen->CloseScreen = pScreen->CloseScreen; + vncHooksScreen->CreateGC = pScreen->CreateGC; + vncHooksScreen->PaintWindowBackground = pScreen->PaintWindowBackground; + vncHooksScreen->PaintWindowBorder = pScreen->PaintWindowBorder; + vncHooksScreen->CopyWindow = pScreen->CopyWindow; + vncHooksScreen->ClearToBackground = pScreen->ClearToBackground; + vncHooksScreen->RestoreAreas = pScreen->RestoreAreas; + vncHooksScreen->InstallColormap = pScreen->InstallColormap; + vncHooksScreen->StoreColors = pScreen->StoreColors; + vncHooksScreen->DisplayCursor = pScreen->DisplayCursor; + vncHooksScreen->BlockHandler = pScreen->BlockHandler; +#ifdef RENDER + PictureScreenPtr ps; + ps = GetPictureScreenIfSet(pScreen); + if (ps) { + vncHooksScreen->Composite = ps->Composite; + } +#endif + + pScreen->CloseScreen = vncHooksCloseScreen; + pScreen->CreateGC = vncHooksCreateGC; + pScreen->PaintWindowBackground = vncHooksPaintWindowBackground; + pScreen->PaintWindowBorder = vncHooksPaintWindowBorder; + pScreen->CopyWindow = vncHooksCopyWindow; + pScreen->ClearToBackground = vncHooksClearToBackground; + pScreen->RestoreAreas = vncHooksRestoreAreas; + pScreen->InstallColormap = vncHooksInstallColormap; + pScreen->StoreColors = vncHooksStoreColors; + pScreen->DisplayCursor = vncHooksDisplayCursor; + pScreen->BlockHandler = vncHooksBlockHandler; +#ifdef RENDER + if (ps) { + ps->Composite = vncHooksComposite; + } +#endif + + return TRUE; +} + + + +///////////////////////////////////////////////////////////////////////////// +// +// screen functions +// + +// SCREEN_UNWRAP and SCREEN_REWRAP unwrap and rewrap the given screen function. +// It would be nice to do this with a C++ class, but each function is of a +// distinct type, so it would have to use templates, and it's not worth that +// much pain. + +#define SCREEN_UNWRAP(scrn,field) \ + ScreenPtr pScreen = scrn; \ + vncHooksScreenPtr vncHooksScreen \ + = ((vncHooksScreenPtr)pScreen->devPrivates[vncHooksScreenIndex].ptr); \ + pScreen->field = vncHooksScreen->field; \ + DBGPRINT((stderr,"vncHooks" #field " called\n")); + +#define SCREEN_REWRAP(field) pScreen->field = vncHooks##field; + + +// CloseScreen - unwrap the screen functions and call the original CloseScreen +// function + +static Bool vncHooksCloseScreen(int i, ScreenPtr pScreen_) +{ + SCREEN_UNWRAP(pScreen_, CloseScreen); + + pScreen->CreateGC = vncHooksScreen->CreateGC; + pScreen->PaintWindowBackground = vncHooksScreen->PaintWindowBackground; + pScreen->PaintWindowBorder = vncHooksScreen->PaintWindowBorder; + pScreen->CopyWindow = vncHooksScreen->CopyWindow; + pScreen->ClearToBackground = vncHooksScreen->ClearToBackground; + pScreen->RestoreAreas = vncHooksScreen->RestoreAreas; + pScreen->InstallColormap = vncHooksScreen->InstallColormap; + pScreen->StoreColors = vncHooksScreen->StoreColors; + pScreen->DisplayCursor = vncHooksScreen->DisplayCursor; + pScreen->BlockHandler = vncHooksScreen->BlockHandler; + + xfree((pointer)vncHooksScreen); + + DBGPRINT((stderr,"vncHooksCloseScreen: unwrapped screen functions\n")); + + return (*pScreen->CloseScreen)(i, pScreen); +} + +// CreateGC - wrap the "GC funcs" + +static Bool vncHooksCreateGC(GCPtr pGC) +{ + SCREEN_UNWRAP(pGC->pScreen, CreateGC); + + vncHooksGCPtr vncHooksGC + = (vncHooksGCPtr)pGC->devPrivates[vncHooksGCIndex].ptr; + + Bool ret = (*pScreen->CreateGC) (pGC); + + vncHooksGC->wrappedOps = 0; + vncHooksGC->wrappedFuncs = pGC->funcs; + pGC->funcs = &vncHooksGCFuncs; + + SCREEN_REWRAP(CreateGC); + + return ret; +} + +// PaintWindowBackground - changed region is the given region + +static void vncHooksPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion, + int what) +{ + SCREEN_UNWRAP(pWin->drawable.pScreen, PaintWindowBackground); + + RegionHelper changed(pScreen, pRegion); + + (*pScreen->PaintWindowBackground) (pWin, pRegion, what); + + vncHooksScreen->desktop->add_changed(changed.reg); + + SCREEN_REWRAP(PaintWindowBackground); +} + +// PaintWindowBorder - changed region is the given region + +static void vncHooksPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion, + int what) +{ + SCREEN_UNWRAP(pWin->drawable.pScreen, PaintWindowBorder); + + RegionHelper changed(pScreen, pRegion); + + (*pScreen->PaintWindowBorder) (pWin, pRegion, what); + + vncHooksScreen->desktop->add_changed(changed.reg); + + SCREEN_REWRAP(PaintWindowBorder); +} + +// CopyWindow - destination of the copy is the old region, clipped by +// borderClip, translated by the delta. This call only does the copy - it +// doesn't affect any other bits. + +static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, + RegionPtr pOldRegion) +{ + SCREEN_UNWRAP(pWin->drawable.pScreen, CopyWindow); + + RegionHelper copied(pScreen, pOldRegion); + int dx = pWin->drawable.x - ptOldOrg.x; + int dy = pWin->drawable.y - ptOldOrg.y; + REGION_TRANSLATE(pScreen, copied.reg, dx, dy); + REGION_INTERSECT(pWin->drawable.pScreen, copied.reg, copied.reg, + &pWin->borderClip); + + (*pScreen->CopyWindow) (pWin, ptOldOrg, pOldRegion); + + vncHooksScreen->desktop->add_copied(copied.reg, dx, dy); + + SCREEN_REWRAP(CopyWindow); +} + +// ClearToBackground - changed region is the given rectangle, clipped by +// clipList, but only if generateExposures is false. + +static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w, + int h, Bool generateExposures) +{ + SCREEN_UNWRAP(pWin->drawable.pScreen, ClearToBackground); + + BoxRec box; + box.x1 = x + pWin->drawable.x; + box.y1 = y + pWin->drawable.y; + box.x2 = w ? (box.x1 + w) : (pWin->drawable.x + pWin->drawable.width); + box.y2 = h ? (box.y1 + h) : (pWin->drawable.y + pWin->drawable.height); + + RegionHelper changed(pScreen, &box, 0); + + REGION_INTERSECT(pScreen, changed.reg, changed.reg, &pWin->clipList); + + (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures); + + if (!generateExposures) { + vncHooksScreen->desktop->add_changed(changed.reg); + } + + SCREEN_REWRAP(ClearToBackground); +} + +// RestoreAreas - changed region is the given region + +static RegionPtr vncHooksRestoreAreas(WindowPtr pWin, RegionPtr pRegion) +{ + SCREEN_UNWRAP(pWin->drawable.pScreen, RestoreAreas); + + RegionHelper changed(pScreen, pRegion); + + RegionPtr result = (*pScreen->RestoreAreas) (pWin, pRegion); + + vncHooksScreen->desktop->add_changed(changed.reg); + + SCREEN_REWRAP(RestoreAreas); + + return result; +} + +// InstallColormap - get the new colormap + +static void vncHooksInstallColormap(ColormapPtr pColormap) +{ + SCREEN_UNWRAP(pColormap->pScreen, InstallColormap); + + (*pScreen->InstallColormap) (pColormap); + + vncHooksScreen->desktop->setColormap(pColormap); + + SCREEN_REWRAP(InstallColormap); +} + +// StoreColors - get the colormap changes + +static void vncHooksStoreColors(ColormapPtr pColormap, int ndef, + xColorItem* pdef) +{ + SCREEN_UNWRAP(pColormap->pScreen, StoreColors); + + (*pScreen->StoreColors) (pColormap, ndef, pdef); + + vncHooksScreen->desktop->setColourMapEntries(pColormap, ndef, pdef); + + SCREEN_REWRAP(StoreColors); +} + +// DisplayCursor - get the cursor shape + +static Bool vncHooksDisplayCursor(ScreenPtr pScreen_, CursorPtr cursor) +{ + SCREEN_UNWRAP(pScreen_, DisplayCursor); + + Bool ret = (*pScreen->DisplayCursor) (pScreen, cursor); + + vncHooksScreen->desktop->setCursor(cursor); + + SCREEN_REWRAP(DisplayCursor); + + return ret; +} + +// BlockHandler - ignore any changes during the block handler - it's likely +// these are just drawing the cursor. + +static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout, + pointer pReadmask) +{ + SCREEN_UNWRAP(screenInfo.screens[i], BlockHandler); + + vncHooksScreen->desktop->ignoreHooks(true); + + (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); + + vncHooksScreen->desktop->ignoreHooks(false); + + SCREEN_REWRAP(BlockHandler); +} + +// Composite - needed for RENDER + +#ifdef RENDER +void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, + PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, + INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + vncHooksScreenPtr vncHooksScreen = ((vncHooksScreenPtr)pScreen->devPrivates[vncHooksScreenIndex].ptr); + BoxRec box; + PictureScreenPtr ps = GetPictureScreen(pScreen); + rfb::Rect rect1, rect2; + + rect1.setXYWH(pDst->pDrawable->x + xDst, + pDst->pDrawable->y + yDst, + width, + height); + + rect2 = rect1.intersect(vncHooksScreen->desktop->getRect()); + if (!rect2.is_empty()) { + box.x1 = rect2.tl.x; + box.y1 = rect2.tl.y; + box.x2 = rect2.br.x; + box.y2 = rect2.br.y; + RegionHelper changed(pScreen, &box, 0); + vncHooksScreen->desktop->add_changed(changed.reg); + } + + ps->Composite = vncHooksScreen->Composite; + (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc, + xMask, yMask, xDst, yDst, width, height); + ps->Composite = vncHooksComposite; +} + +#endif /* RENDER */ + + +///////////////////////////////////////////////////////////////////////////// +// +// GC "funcs" +// + +// GCFuncUnwrapper is a helper class which unwraps the GC funcs and ops in its +// constructor and rewraps them in its destructor. + +class GCFuncUnwrapper { +public: + GCFuncUnwrapper(GCPtr pGC_) : pGC(pGC_) { + vncHooksGC = (vncHooksGCPtr)pGC->devPrivates[vncHooksGCIndex].ptr; + pGC->funcs = vncHooksGC->wrappedFuncs; + if (vncHooksGC->wrappedOps) + pGC->ops = vncHooksGC->wrappedOps; + } + ~GCFuncUnwrapper() { + vncHooksGC->wrappedFuncs = pGC->funcs; + pGC->funcs = &vncHooksGCFuncs; + if (vncHooksGC->wrappedOps) { + vncHooksGC->wrappedOps = pGC->ops; + pGC->ops = &vncHooksGCOps; + } + } + GCPtr pGC; + vncHooksGCPtr vncHooksGC; +}; + + +// ValidateGC - wrap the "ops" if a viewable window + +static void vncHooksValidateGC(GCPtr pGC, unsigned long changes, + DrawablePtr pDrawable) +{ + GCFuncUnwrapper u(pGC); + + DBGPRINT((stderr,"vncHooksValidateGC called\n")); + + (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable); + + u.vncHooksGC->wrappedOps = 0; + if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr)pDrawable)->viewable) { + WindowPtr pWin = (WindowPtr)pDrawable; + RegionPtr pRegion = &pWin->clipList; + + if (pGC->subWindowMode == IncludeInferiors) + pRegion = &pWin->borderClip; + if (REGION_NOTEMPTY(pDrawable->pScreen, pRegion)) { + u.vncHooksGC->wrappedOps = pGC->ops; + DBGPRINT((stderr,"vncHooksValidateGC: wrapped GC ops\n")); + } + } +} + +// Other GC funcs - just unwrap and call on + +static void vncHooksChangeGC(GCPtr pGC, unsigned long mask) { + GCFuncUnwrapper u(pGC); + (*pGC->funcs->ChangeGC) (pGC, mask); +} +static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst) { + GCFuncUnwrapper u(dst); + (*dst->funcs->CopyGC) (src, mask, dst); +} +static void vncHooksDestroyGC(GCPtr pGC) { + GCFuncUnwrapper u(pGC); + (*pGC->funcs->DestroyGC) (pGC); +} +static void vncHooksChangeClip(GCPtr pGC, int type, pointer pValue, int nrects) +{ + GCFuncUnwrapper u(pGC); + (*pGC->funcs->ChangeClip) (pGC, type, pValue, nrects); +} +static void vncHooksDestroyClip(GCPtr pGC) { + GCFuncUnwrapper u(pGC); + (*pGC->funcs->DestroyClip) (pGC); +} +static void vncHooksCopyClip(GCPtr dst, GCPtr src) { + GCFuncUnwrapper u(dst); + (*dst->funcs->CopyClip) (dst, src); +} + + +///////////////////////////////////////////////////////////////////////////// +// +// GC "ops" +// + +// GCOpUnwrapper is a helper class which unwraps the GC funcs and ops in its +// constructor and rewraps them in its destructor. + +class GCOpUnwrapper { +public: + GCOpUnwrapper(DrawablePtr pDrawable, GCPtr pGC_) + : pGC(pGC_), pScreen(pDrawable->pScreen) + { + vncHooksGC = (vncHooksGCPtr)pGC->devPrivates[vncHooksGCIndex].ptr; + oldFuncs = pGC->funcs; + pGC->funcs = vncHooksGC->wrappedFuncs; + pGC->ops = vncHooksGC->wrappedOps; + } + ~GCOpUnwrapper() { + vncHooksGC->wrappedOps = pGC->ops; + pGC->funcs = oldFuncs; + pGC->ops = &vncHooksGCOps; + } + GCPtr pGC; + vncHooksGCPtr vncHooksGC; + GCFuncs* oldFuncs; + ScreenPtr pScreen; +}; + +#define GC_OP_UNWRAPPER(pDrawable, pGC, name) \ + GCOpUnwrapper u(pDrawable, pGC); \ + ScreenPtr pScreen = (pDrawable)->pScreen; \ + vncHooksScreenPtr vncHooksScreen \ + = ((vncHooksScreenPtr)pScreen->devPrivates[vncHooksScreenIndex].ptr); \ + DBGPRINT((stderr,"vncHooks" #name " called\n")); + + +// FillSpans - changed region is the whole of borderClip. This is pessimistic, +// but I believe this function is rarely used so it doesn't matter. + +static void vncHooksFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit, + DDXPointPtr pptInit, int *pwidthInit, + int fSorted) +{ + GC_OP_UNWRAPPER(pDrawable, pGC, FillSpans); + + RegionHelper changed(pScreen, &((WindowPtr)pDrawable)->borderClip); + + (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted); + + vncHooksScreen->desktop->add_changed(changed.reg); +} + +// SetSpans - changed region is the whole of borderClip. This is pessimistic, +// but I believe this function is rarely used so it doesn't matter. + +static void vncHooksSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc, + DDXPointPtr ppt, int *pwidth, int nspans, + int fSorted) +{ + GC_OP_UNWRAPPER(pDrawable, pGC, SetSpans); + + RegionHelper changed(pScreen, &((WindowPtr)pDrawable)->borderClip); + + (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); + + vncHooksScreen->desktop->add_changed(changed.reg); +} + +// PutImage - changed region is the given rectangle, clipped by pCompositeClip + +static void vncHooksPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, + int x, int y, int w, int h, int leftPad, + int format, char *pBits) +{ + GC_OP_UNWRAPPER(pDrawable, pGC, PutImage); + + BoxRec box; + box.x1 = x + pDrawable->x; + box.y1 = y + pDrawable->y; + box.x2 = box.x1 + w; + box.y2 = box.y1 + h; + + RegionHelper changed(pScreen, &box, 0); + + REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); + + (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, leftPad, format, + pBits); + + vncHooksScreen->desktop->add_changed(changed.reg); +} + +// CopyArea - destination of the copy is the dest rectangle, clipped by +// pCompositeClip. Any parts of the destination which cannot be copied from +// the source (could be all of it) go into the changed region. + +static RegionPtr vncHooksCopyArea(DrawablePtr pSrc, DrawablePtr pDst, + GCPtr pGC, int srcx, int srcy, int w, int h, + int dstx, int dsty) +{ + GC_OP_UNWRAPPER(pDst, pGC, CopyArea); + + BoxRec box; + box.x1 = dstx + pDst->x; + box.y1 = dsty + pDst->y; + box.x2 = box.x1 + w; + box.y2 = box.y1 + h; + + RegionHelper dst(pScreen, &box, 0); + REGION_INTERSECT(pScreen, dst.reg, dst.reg, COMPOSITE_CLIP(pGC)); + + RegionHelper src(pScreen); + + if ((pSrc->type == DRAWABLE_WINDOW) && (pSrc->pScreen == pScreen)) { + box.x1 = srcx + pSrc->x; + box.y1 = srcy + pSrc->y; + box.x2 = box.x1 + w; + box.y2 = box.y1 + h; + + src.init(&box, 0); + REGION_INTERSECT(pScreen, src.reg, src.reg, &((WindowPtr)pSrc)->clipList); + REGION_TRANSLATE(pScreen, src.reg, + dstx + pDst->x - srcx - pSrc->x, + dsty + pDst->y - srcy - pSrc->y); + } else { + src.init(NullBox, 0); + } + + RegionHelper changed(pScreen, NullBox, 0); + REGION_SUBTRACT(pScreen, changed.reg, dst.reg, src.reg); + REGION_INTERSECT(pScreen, dst.reg, dst.reg, src.reg); + + RegionPtr rgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h, + dstx, dsty); + + if (REGION_NOTEMPTY(pScreen, dst.reg)) + vncHooksScreen->desktop->add_copied(dst.reg, + dstx + pDst->x - srcx - pSrc->x, + dsty + pDst->y - srcy - pSrc->y); + + if (REGION_NOTEMPTY(pScreen, changed.reg)) + vncHooksScreen->desktop->add_changed(changed.reg); + + return rgn; +} + + +// CopyPlane - changed region is the destination rectangle, clipped by +// pCompositeClip + +static RegionPtr vncHooksCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, + GCPtr pGC, int srcx, int srcy, int w, int h, + int dstx, int dsty, unsigned long plane) +{ + GC_OP_UNWRAPPER(pDst, pGC, CopyPlane); + + BoxRec box; + box.x1 = dstx + pDst->x; + box.y1 = dsty + pDst->y; + box.x2 = box.x1 + w; + box.y2 = box.y1 + h; + + RegionHelper changed(pScreen, &box, 0); + + REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); + + RegionPtr rgn = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h, + dstx, dsty, plane); + vncHooksScreen->desktop->add_changed(changed.reg); + + return rgn; +} + +// PolyPoint - changed region is the bounding rect, clipped by pCompositeClip + +static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, + int npt, xPoint *pts) +{ + GC_OP_UNWRAPPER(pDrawable, pGC, PolyPoint); + + if (npt == 0) { + (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts); + return; + } + + int minX = pts[0].x; + int maxX = pts[0].x; + int minY = pts[0].y; + int maxY = pts[0].y; + + if (mode == CoordModePrevious) { + int x = pts[0].x; + int y = pts[0].y; + + for (int i = 1; i < npt; i++) { + x += pts[i].x; + y += pts[i].y; + if (x < minX) minX = x; + if (x > maxX) maxX = x; + if (y < minY) minY = y; + if (y > maxY) maxY = y; + } + } else { + for (int i = 1; i < npt; i++) { + if (pts[i].x < minX) minX = pts[i].x; + if (pts[i].x > maxX) maxX = pts[i].x; + if (pts[i].y < minY) minY = pts[i].y; + if (pts[i].y > maxY) maxY = pts[i].y; + } + } + + BoxRec box; + box.x1 = minX + pDrawable->x; + box.y1 = minY + pDrawable->y; + box.x2 = maxX + 1 + pDrawable->x; + box.y2 = maxY + 1 + pDrawable->y; + + RegionHelper changed(pScreen, &box, 0); + + REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); + + (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts); + + vncHooksScreen->desktop->add_changed(changed.reg); +} + +// Polylines - changed region is the union of the bounding rects of each line, +// clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP lines, +// just use the bounding rect of all the lines. + +static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, + int npt, DDXPointPtr ppts) +{ + GC_OP_UNWRAPPER(pDrawable, pGC, Polylines); + + if (npt == 0) { + (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts); + return; + } + + int nRegRects = npt - 1; + xRectangle regRects[MAX_RECTS_PER_OP]; + + int lw = pGC->lineWidth; + if (lw == 0) lw = 1; + + if (npt == 1) + { + // a single point + nRegRects = 1; + regRects[0].x = pDrawable->x + ppts[0].x - lw; + regRects[0].y = pDrawable->y + ppts[0].y - lw; + regRects[0].width = 2*lw; + regRects[0].height = 2*lw; + } + else + { + /* + * mitered joins can project quite a way from + * the line end; the 11 degree miter limit limits + * this extension to lw / (2 * tan(11/2)), rounded up + * and converted to int yields 6 * lw + */ + + int extra = lw / 2; + if (pGC->joinStyle == JoinMiter) { + extra = 6 * lw; + } + + int prevX, prevY, curX, curY; + int rectX1, rectY1, rectX2, rectY2; + int minX, minY, maxX, maxY; + + prevX = ppts[0].x + pDrawable->x; + prevY = ppts[0].y + pDrawable->y; + minX = maxX = prevX; + minY = maxY = prevY; + + for (int i = 0; i < nRegRects; i++) { + if (mode == CoordModeOrigin) { + curX = pDrawable->x + ppts[i+1].x; + curY = pDrawable->y + ppts[i+1].y; + } else { + curX = prevX + ppts[i+1].x; + curY = prevY + ppts[i+1].y; + } + + if (prevX > curX) { + rectX1 = curX - extra; + rectX2 = prevX + extra + 1; + } else { + rectX1 = prevX - extra; + rectX2 = curX + extra + 1; + } + + if (prevY > curY) { + rectY1 = curY - extra; + rectY2 = prevY + extra + 1; + } else { + rectY1 = prevY - extra; + rectY2 = curY + extra + 1; + } + + if (nRegRects <= MAX_RECTS_PER_OP) { + regRects[i].x = rectX1; + regRects[i].y = rectY1; + regRects[i].width = rectX2 - rectX1; + regRects[i].height = rectY2 - rectY1; + } else { + if (rectX1 < minX) minX = rectX1; + if (rectY1 < minY) minY = rectY1; + if (rectX2 > maxX) maxX = rectX2; + if (rectY2 > maxY) maxY = rectY2; + } + + prevX = curX; + prevY = curY; + } + + if (nRegRects > MAX_RECTS_PER_OP) { + regRects[0].x = minX; + regRects[0].y = minY; + regRects[0].width = maxX - minX; + regRects[0].height = maxY - minY; + nRegRects = 1; + } + } + + RegionHelper changed(pScreen, nRegRects, regRects); + + REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); + + (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts); + + vncHooksScreen->desktop->add_changed(changed.reg); +} + +// PolySegment - changed region is the union of the bounding rects of each +// segment, clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP +// segments, just use the bounding rect of all the segments. + +static void vncHooksPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg, + xSegment *segs) +{ + GC_OP_UNWRAPPER(pDrawable, pGC, PolySegment); + + if (nseg == 0) { + (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs); + return; + } + + xRectangle regRects[MAX_RECTS_PER_OP]; + int nRegRects = nseg; + + int lw = pGC->lineWidth; + int extra = lw / 2; + + int rectX1, rectY1, rectX2, rectY2; + int minX, minY, maxX, maxY; + + minX = maxX = segs[0].x1; + minY = maxY = segs[0].y1; + + for (int i = 0; i < nseg; i++) { + if (segs[i].x1 > segs[i].x2) { + rectX1 = pDrawable->x + segs[i].x2 - extra; + rectX2 = pDrawable->x + segs[i].x1 + extra + 1; + } else { + rectX1 = pDrawable->x + segs[i].x1 - extra; + rectX2 = pDrawable->x + segs[i].x2 + extra + 1; + } + + if (segs[i].y1 > segs[i].y2) { + rectY1 = pDrawable->y + segs[i].y2 - extra; + rectY2 = pDrawable->y + segs[i].y1 + extra + 1; + } else { + rectY1 = pDrawable->y + segs[i].y1 - extra; + rectY2 = pDrawable->y + segs[i].y2 + extra + 1; + } + + if (nseg <= MAX_RECTS_PER_OP) { + regRects[i].x = rectX1; + regRects[i].y = rectY1; + regRects[i].width = rectX2 - rectX1; + regRects[i].height = rectY2 - rectY1; + } else { + if (rectX1 < minX) minX = rectX1; + if (rectY1 < minY) minY = rectY1; + if (rectX2 > maxX) maxX = rectX2; + if (rectY2 > maxY) maxY = rectY2; + } + } + + if (nseg > MAX_RECTS_PER_OP) { + regRects[0].x = minX; + regRects[0].y = minY; + regRects[0].width = maxX - minX; + regRects[0].height = maxY - minY; + nRegRects = 1; + } + + RegionHelper changed(pScreen, nRegRects, regRects); + + REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); + + (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs); + + vncHooksScreen->desktop->add_changed(changed.reg); +} + +// PolyRectangle - changed region is the union of the bounding rects around +// each side of the outline rectangles, clipped by pCompositeClip. If there +// are more than MAX_RECTS_PER_OP rectangles, just use the bounding rect of all +// the rectangles. + +static void vncHooksPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects, + xRectangle *rects) +{ + GC_OP_UNWRAPPER(pDrawable, pGC, PolyRectangle); + + if (nrects == 0) { + (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects); + return; + } + + xRectangle regRects[MAX_RECTS_PER_OP*4]; + int nRegRects = nrects * 4; + + int lw = pGC->lineWidth; + int extra = lw / 2; + + int rectX1, rectY1, rectX2, rectY2; + int minX, minY, maxX, maxY; + + minX = maxX = rects[0].x; + minY = maxY = rects[0].y; + + for (int i = 0; i < nrects; i++) { + if (nrects <= MAX_RECTS_PER_OP) { + regRects[i*4].x = rects[i].x - extra + pDrawable->x; + regRects[i*4].y = rects[i].y - extra + pDrawable->y; + regRects[i*4].width = rects[i].width + 1 + 2 * extra; + regRects[i*4].height = 1 + 2 * extra; + + regRects[i*4+1].x = rects[i].x - extra + pDrawable->x; + regRects[i*4+1].y = rects[i].y - extra + pDrawable->y; + regRects[i*4+1].width = 1 + 2 * extra; + regRects[i*4+1].height = rects[i].height + 1 + 2 * extra; + + regRects[i*4+2].x = rects[i].x + rects[i].width - extra + pDrawable->x; + regRects[i*4+2].y = rects[i].y - extra + pDrawable->y; + regRects[i*4+2].width = 1 + 2 * extra; + regRects[i*4+2].height = rects[i].height + 1 + 2 * extra; + + regRects[i*4+3].x = rects[i].x - extra + pDrawable->x; + regRects[i*4+3].y = rects[i].y + rects[i].height - extra + pDrawable->y; + regRects[i*4+3].width = rects[i].width + 1 + 2 * extra; + regRects[i*4+3].height = 1 + 2 * extra; + } else { + rectX1 = pDrawable->x + rects[i].x - extra; + rectY1 = pDrawable->y + rects[i].y - extra; + rectX2 = pDrawable->x + rects[i].x + rects[i].width + extra+1; + rectY2 = pDrawable->y + rects[i].y + rects[i].height + extra+1; + if (rectX1 < minX) minX = rectX1; + if (rectY1 < minY) minY = rectY1; + if (rectX2 > maxX) maxX = rectX2; + if (rectY2 > maxY) maxY = rectY2; + } + } + + if (nrects > MAX_RECTS_PER_OP) { + regRects[0].x = minX; + regRects[0].y = minY; + regRects[0].width = maxX - minX; + regRects[0].height = maxY - minY; + nRegRects = 1; + } + + RegionHelper changed(pScreen, nRegRects, regRects); + + REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); + + (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects); + + vncHooksScreen->desktop->add_changed(changed.reg); +} + +// PolyArc - changed region is the union of bounding rects around each arc, +// clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP +// arcs, just use the bounding rect of all the arcs. + +static void vncHooksPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, + xArc *arcs) +{ + GC_OP_UNWRAPPER(pDrawable, pGC, PolyArc); + + if (narcs == 0) { + (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs); + return; + } + + xRectangle regRects[MAX_RECTS_PER_OP]; + int nRegRects = narcs; + + int lw = pGC->lineWidth; + if (lw == 0) lw = 1; + int extra = lw / 2; + + int rectX1, rectY1, rectX2, rectY2; + int minX, minY, maxX, maxY; + + minX = maxX = arcs[0].x; + minY = maxY = arcs[0].y; + + for (int i = 0; i < narcs; i++) { + if (narcs <= MAX_RECTS_PER_OP) { + regRects[i].x = arcs[i].x - extra + pDrawable->x; + regRects[i].y = arcs[i].y - extra + pDrawable->y; + regRects[i].width = arcs[i].width + lw; + regRects[i].height = arcs[i].height + lw; + } else { + rectX1 = pDrawable->x + arcs[i].x - extra; + rectY1 = pDrawable->y + arcs[i].y - extra; + rectX2 = pDrawable->x + arcs[i].x + arcs[i].width + lw; + rectY2 = pDrawable->y + arcs[i].y + arcs[i].height + lw; + if (rectX1 < minX) minX = rectX1; + if (rectY1 < minY) minY = rectY1; + if (rectX2 > maxX) maxX = rectX2; + if (rectY2 > maxY) maxY = rectY2; + } + } + + if (narcs > MAX_RECTS_PER_OP) { + regRects[0].x = minX; + regRects[0].y = minY; + regRects[0].width = maxX - minX; + regRects[0].height = maxY - minY; + nRegRects = 1; + } + + RegionHelper changed(pScreen, nRegRects, regRects); + + REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); + + (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs); + + vncHooksScreen->desktop->add_changed(changed.reg); +} + + +// FillPolygon - changed region is the bounding rect around the polygon, +// clipped by pCompositeClip + +static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape, + int mode, int count, DDXPointPtr pts) +{ + GC_OP_UNWRAPPER(pDrawable, pGC, FillPolygon); + + if (count == 0) { + (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts); + return; + } + + int minX = pts[0].x; + int maxX = pts[0].x; + int minY = pts[0].y; + int maxY = pts[0].y; + + if (mode == CoordModePrevious) { + int x = pts[0].x; + int y = pts[0].y; + + for (int i = 1; i < count; i++) { + x += pts[i].x; + y += pts[i].y; + if (x < minX) minX = x; + if (x > maxX) maxX = x; + if (y < minY) minY = y; + if (y > maxY) maxY = y; + } + } else { + for (int i = 1; i < count; i++) { + if (pts[i].x < minX) minX = pts[i].x; + if (pts[i].x > maxX) maxX = pts[i].x; + if (pts[i].y < minY) minY = pts[i].y; + if (pts[i].y > maxY) maxY = pts[i].y; + } + } + + BoxRec box; + box.x1 = minX + pDrawable->x; + box.y1 = minY + pDrawable->y; + box.x2 = maxX + 1 + pDrawable->x; + box.y2 = maxY + 1 + pDrawable->y; + + RegionHelper changed(pScreen, &box, 0); + + REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); + + (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts); + + vncHooksScreen->desktop->add_changed(changed.reg); +} + +// PolyFillRect - changed region is the union of the rectangles, clipped by +// pCompositeClip. If there are more than MAX_RECTS_PER_OP rectangles, just +// use the bounding rect of all the rectangles. + +static void vncHooksPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects, + xRectangle *rects) +{ + GC_OP_UNWRAPPER(pDrawable, pGC, PolyFillRect); + + if (nrects == 0) { + (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects); + return; + } + + xRectangle regRects[MAX_RECTS_PER_OP]; + int nRegRects = nrects; + int rectX1, rectY1, rectX2, rectY2; + int minX, minY, maxX, maxY; + minX = maxX = rects[0].x; + minY = maxY = rects[0].y; + + for (int i = 0; i < nrects; i++) { + if (nrects <= MAX_RECTS_PER_OP) { + regRects[i].x = rects[i].x + pDrawable->x; + regRects[i].y = rects[i].y + pDrawable->y; + regRects[i].width = rects[i].width; + regRects[i].height = rects[i].height; + } else { + rectX1 = pDrawable->x + rects[i].x; + rectY1 = pDrawable->y + rects[i].y; + rectX2 = pDrawable->x + rects[i].x + rects[i].width; + rectY2 = pDrawable->y + rects[i].y + rects[i].height; + if (rectX1 < minX) minX = rectX1; + if (rectY1 < minY) minY = rectY1; + if (rectX2 > maxX) maxX = rectX2; + if (rectY2 > maxY) maxY = rectY2; + } + } + + if (nrects > MAX_RECTS_PER_OP) { + regRects[0].x = minX; + regRects[0].y = minY; + regRects[0].width = maxX - minX; + regRects[0].height = maxY - minY; + nRegRects = 1; + } + + RegionHelper changed(pScreen, nRegRects, regRects); + + REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); + + (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects); + + vncHooksScreen->desktop->add_changed(changed.reg); +} + +// PolyFillArc - changed region is the union of bounding rects around each arc, +// clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP arcs, +// just use the bounding rect of all the arcs. + +static void vncHooksPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, + xArc *arcs) +{ + GC_OP_UNWRAPPER(pDrawable, pGC, PolyFillArc); + + if (narcs == 0) { + (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs); + return; + } + + xRectangle regRects[MAX_RECTS_PER_OP]; + int nRegRects = narcs; + + int lw = pGC->lineWidth; + if (lw == 0) lw = 1; + int extra = lw / 2; + + int rectX1, rectY1, rectX2, rectY2; + int minX, minY, maxX, maxY; + + minX = maxX = arcs[0].x; + minY = maxY = arcs[0].y; + + for (int i = 0; i < narcs; i++) { + if (narcs <= MAX_RECTS_PER_OP) { + regRects[i].x = arcs[i].x - extra + pDrawable->x; + regRects[i].y = arcs[i].y - extra + pDrawable->y; + regRects[i].width = arcs[i].width + lw; + regRects[i].height = arcs[i].height + lw; + } else { + rectX1 = pDrawable->x + arcs[i].x - extra; + rectY1 = pDrawable->y + arcs[i].y - extra; + rectX2 = pDrawable->x + arcs[i].x + arcs[i].width + lw; + rectY2 = pDrawable->y + arcs[i].y + arcs[i].height + lw; + if (rectX1 < minX) minX = rectX1; + if (rectY1 < minY) minY = rectY1; + if (rectX2 > maxX) maxX = rectX2; + if (rectY2 > maxY) maxY = rectY2; + } + } + + if (narcs > MAX_RECTS_PER_OP) { + regRects[0].x = minX; + regRects[0].y = minY; + regRects[0].width = maxX - minX; + regRects[0].height = maxY - minY; + nRegRects = 1; + } + + RegionHelper changed(pScreen, nRegRects, regRects); + + REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); + + (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs); + + vncHooksScreen->desktop->add_changed(changed.reg); +} + +// GetTextBoundingRect - calculate a bounding rectangle around n chars of a +// font. Not particularly accurate, but good enough. + +static void GetTextBoundingRect(DrawablePtr pDrawable, FontPtr font, int x, + int y, int nchars, BoxPtr box) +{ + int ascent = __rfbmax(FONTASCENT(font), FONTMAXBOUNDS(font, ascent)); + int descent = __rfbmax(FONTDESCENT(font), FONTMAXBOUNDS(font, descent)); + int charWidth = __rfbmax(FONTMAXBOUNDS(font,rightSideBearing), + FONTMAXBOUNDS(font,characterWidth)); + + box->x1 = pDrawable->x + x; + box->y1 = pDrawable->y + y - ascent; + box->x2 = box->x1 + charWidth * nchars; + box->y2 = box->y1 + ascent + descent; + + if (FONTMINBOUNDS(font,leftSideBearing) < 0) + box->x1 += FONTMINBOUNDS(font,leftSideBearing); +} + +// PolyText8 - changed region is bounding rect around count chars, clipped by +// pCompositeClip + +static int vncHooksPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y, + int count, char *chars) +{ + GC_OP_UNWRAPPER(pDrawable, pGC, PolyText8); + + if (count == 0) + return (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars); + + BoxRec box; + GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box); + + RegionHelper changed(pScreen, &box, 0); + + REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); + + int ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars); + + vncHooksScreen->desktop->add_changed(changed.reg); + + return ret; +} + +// PolyText16 - changed region is bounding rect around count chars, clipped by +// pCompositeClip + +static int vncHooksPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y, + int count, unsigned short *chars) +{ + GC_OP_UNWRAPPER(pDrawable, pGC, PolyText16); + + if (count == 0) + return (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars); + + BoxRec box; + GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box); + + RegionHelper changed(pScreen, &box, 0); + + REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); + + int ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars); + + vncHooksScreen->desktop->add_changed(changed.reg); + + return ret; +} + +// ImageText8 - changed region is bounding rect around count chars, clipped by +// pCompositeClip + +static void vncHooksImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y, + int count, char *chars) +{ + GC_OP_UNWRAPPER(pDrawable, pGC, ImageText8); + + if (count == 0) { + (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars); + return; + } + + BoxRec box; + GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box); + + RegionHelper changed(pScreen, &box, 0); + + REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); + + (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars); + + vncHooksScreen->desktop->add_changed(changed.reg); +} + +// ImageText16 - changed region is bounding rect around count chars, clipped by +// pCompositeClip + +static void vncHooksImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y, + int count, unsigned short *chars) +{ + GC_OP_UNWRAPPER(pDrawable, pGC, ImageText16); + + if (count == 0) { + (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars); + return; + } + + BoxRec box; + GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box); + + RegionHelper changed(pScreen, &box, 0); + + REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); + + (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars); + + vncHooksScreen->desktop->add_changed(changed.reg); +} + +// ImageGlyphBlt - changed region is bounding rect around nglyph chars, clipped +// by pCompositeClip + +static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, + int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase) +{ + GC_OP_UNWRAPPER(pDrawable, pGC, ImageGlyphBlt); + + if (nglyph == 0) { + (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase); + return; + } + + BoxRec box; + GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box); + + RegionHelper changed(pScreen, &box, 0); + + REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); + + (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); + + vncHooksScreen->desktop->add_changed(changed.reg); +} + +// PolyGlyphBlt - changed region is bounding rect around nglyph chars, clipped +// by pCompositeClip + +static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, + int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase) +{ + GC_OP_UNWRAPPER(pDrawable, pGC, PolyGlyphBlt); + + if (nglyph == 0) { + (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase); + return; + } + + BoxRec box; + GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box); + + RegionHelper changed(pScreen, &box, 0); + + REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); + + (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); + + vncHooksScreen->desktop->add_changed(changed.reg); +} + +// PushPixels - changed region is the given rectangle, clipped by +// pCompositeClip + +static void vncHooksPushPixels(GCPtr pGC, PixmapPtr pBitMap, + DrawablePtr pDrawable, int w, int h, int x, + int y) +{ + GC_OP_UNWRAPPER(pDrawable, pGC, PushPixels); + + BoxRec box; + box.x1 = x + pDrawable->x; + box.y1 = y + pDrawable->y; + box.x2 = box.x1 + w; + box.y2 = box.y1 + h; + + RegionHelper changed(pScreen, &box, 0); + + REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC)); + + (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y); + + vncHooksScreen->desktop->add_changed(changed.reg); +} diff --git a/unix/xserver/hw/vnc/vncHooks.h b/unix/xserver/hw/vnc/vncHooks.h new file mode 100644 index 00000000..c556ef3a --- /dev/null +++ b/unix/xserver/hw/vnc/vncHooks.h @@ -0,0 +1,26 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +#ifndef __VNCHOOKS_H__ +#define __VNCHOOKS_H__ + +extern "C" { +#include + extern Bool vncHooksInit(ScreenPtr pScreen, XserverDesktop* desktop); +} + +#endif diff --git a/unix/xserver/hw/vnc/xf86vncModule.cc b/unix/xserver/hw/vnc/xf86vncModule.cc new file mode 100644 index 00000000..ef8ea506 --- /dev/null +++ b/unix/xserver/hw/vnc/xf86vncModule.cc @@ -0,0 +1,97 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +/* This is the xf86 module code for the vnc extension. + */ + +#include +#include +#include + +extern "C" { +#define class c_class +#define private c_private +#define bool c_bool +#define new c_new +#include "xf86.h" +#include "xf86Module.h" +#undef class +#undef private +#undef bool +#undef new + +using namespace rfb; + +extern void vncExtensionInit(); +static void vncExtensionInitWithParams(INITARGS); + +#ifdef XFree86LOADER + +static MODULESETUPPROTO(vncSetup); + +ExtensionModule vncExt = +{ + vncExtensionInitWithParams, + "VNC", + NULL, + NULL, + NULL +}; + +static XF86ModuleVersionInfo vncVersRec = +{ + "vnc", + "Constantin Kaplinsky", + MODINFOSTRING1, + MODINFOSTRING2, + XF86_VERSION_CURRENT, + 1, 0, 0, + ABI_CLASS_EXTENSION, /* needs the server extension ABI */ + ABI_EXTENSION_VERSION, + MOD_CLASS_EXTENSION, + {0,0,0,0} +}; + +XF86ModuleData vncModuleData = { &vncVersRec, vncSetup, NULL }; + +static pointer +vncSetup(pointer module, pointer opts, int *errmaj, int *errmin) { + LoadExtension(&vncExt, FALSE); + /* Need a non-NULL return value to indicate success */ + return (pointer)1; +} + +static void vncExtensionInitWithParams(INITARGS) +{ + rfb::initStdIOLoggers(); + rfb::LogWriter::setLogParams("*:stderr:30"); + + for (int scr = 0; scr < screenInfo.numScreens; scr++) { + ScrnInfoPtr pScrn = xf86Screens[scr]; + + for (ParameterIterator i(Configuration::global()); i.param; i.next()) { + char* val = xf86FindOptionValue(pScrn->options, i.param->getName()); + if (val) + i.param->setParam(val); + } + } + + vncExtensionInit(); +} + +#endif /* XFree86LOADER */ +} diff --git a/unix/xserver/hw/vnc/xvnc.cc b/unix/xserver/hw/vnc/xvnc.cc new file mode 100644 index 00000000..5daf663d --- /dev/null +++ b/unix/xserver/hw/vnc/xvnc.cc @@ -0,0 +1,1472 @@ +/* Copyright (c) 1993 X Consortium + Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice 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 X CONSORTIUM 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 X Consortium 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 X Consortium. + +*/ + +#include +#include +#include +#include +#include "vncExtInit.h" + +extern "C" { +#define class c_class +#define public c_public +#define xor c_xor +#define and c_and +#ifdef WIN32 +#include +#endif +#include +#include "X11/X.h" +#define NEED_EVENTS +#include "X11/Xproto.h" +#include "X11/Xos.h" +#include "scrnintstr.h" +#include "servermd.h" +#include "fb.h" +#include "mi.h" +#include "mibstore.h" +#include "colormapst.h" +#include "gcstruct.h" +#include "input.h" +#include "mipointer.h" +#define new New +#include "micmap.h" +#undef new +#include +#ifdef HAS_MMAP +#include +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif +#endif /* HAS_MMAP */ +#include +#include +#ifndef WIN32 +#include +#endif +#include +#ifdef HAS_SHM +#include +#include +#endif /* HAS_SHM */ +#include "dix.h" +#include "miline.h" +#include "inputstr.h" +#include "keysym.h" + extern int defaultColorVisualClass; + extern char buildtime[]; +#undef class +#undef public +#undef xor +#undef and +} + +#define XVNCVERSION "TightVNC 1.5 series" +#define XVNCCOPYRIGHT ("Copyright (C) 2002-2005 RealVNC Ltd.\n" \ + "Copyright (C) 2000-2006 Constantin Kaplinsky\n" \ + "Copyright (C) 2004-2006 Peter Astrand, Cendio AB\n" \ + "See http://www.tightvnc.com for information on TightVNC.\n") + + +extern char *display; +extern int monitorResolution; + +#define VFB_DEFAULT_WIDTH 1024 +#define VFB_DEFAULT_HEIGHT 768 +#define VFB_DEFAULT_DEPTH 16 +#define VFB_DEFAULT_WHITEPIXEL 0xffff +#define VFB_DEFAULT_BLACKPIXEL 0 +#define VFB_DEFAULT_LINEBIAS 0 +#define XWD_WINDOW_NAME_LEN 60 + +typedef struct +{ + int scrnum; + int width; + int paddedBytesWidth; + int paddedWidth; + int height; + int depth; + int bitsPerPixel; + int sizeInBytes; + int ncolors; + char *pfbMemory; + XWDColor *pXWDCmap; + XWDFileHeader *pXWDHeader; + Pixel blackPixel; + Pixel whitePixel; + unsigned int lineBias; + CloseScreenProcPtr closeScreen; + +#ifdef HAS_MMAP + int mmap_fd; + char mmap_file[MAXPATHLEN]; +#endif + +#ifdef HAS_SHM + int shmid; +#endif + + Bool pixelFormatDefined; + Bool rgbNotBgr; + int redBits, greenBits, blueBits; + +} vfbScreenInfo, *vfbScreenInfoPtr; + +static int vfbNumScreens; +static vfbScreenInfo vfbScreens[MAXSCREENS]; +static Bool vfbPixmapDepths[33]; +#ifdef HAS_MMAP +static char *pfbdir = NULL; +#endif +typedef enum { NORMAL_MEMORY_FB, SHARED_MEMORY_FB, MMAPPED_FILE_FB } fbMemType; +static fbMemType fbmemtype = NORMAL_MEMORY_FB; +static char needswap = 0; +static int lastScreen = -1; +static Bool Render = TRUE; + +static bool displaySpecified = false; +static bool wellKnownSocketsCreated = false; +static char displayNumStr[16]; + +#define swapcopy16(_dst, _src) \ + if (needswap) { CARD16 _s = _src; cpswaps(_s, _dst); } \ + else _dst = _src; + +#define swapcopy32(_dst, _src) \ + if (needswap) { CARD32 _s = _src; cpswapl(_s, _dst); } \ + else _dst = _src; + + +static void +vfbInitializePixmapDepths(void) +{ + int i; + vfbPixmapDepths[1] = TRUE; /* always need bitmaps */ + for (i = 2; i <= 32; i++) + vfbPixmapDepths[i] = FALSE; +} + +static void +vfbInitializeDefaultScreens(void) +{ + int i; + + for (i = 0; i < MAXSCREENS; i++) + { + vfbScreens[i].scrnum = i; + vfbScreens[i].width = VFB_DEFAULT_WIDTH; + vfbScreens[i].height = VFB_DEFAULT_HEIGHT; + vfbScreens[i].depth = VFB_DEFAULT_DEPTH; + vfbScreens[i].blackPixel = VFB_DEFAULT_BLACKPIXEL; + vfbScreens[i].whitePixel = VFB_DEFAULT_WHITEPIXEL; + vfbScreens[i].lineBias = VFB_DEFAULT_LINEBIAS; + vfbScreens[i].pixelFormatDefined = FALSE; + vfbScreens[i].pfbMemory = NULL; + } + vfbNumScreens = 1; +} + +static int +vfbBitsPerPixel(int depth) +{ + if (depth == 1) return 1; + else if (depth <= 8) return 8; + else if (depth <= 16) return 16; + else return 32; +} + + +extern "C" { + + void ddxGiveUp() + { + int i; + + /* clean up the framebuffers */ + + switch (fbmemtype) + { +#ifdef HAS_MMAP + case MMAPPED_FILE_FB: + for (i = 0; i < vfbNumScreens; i++) + { + if (-1 == unlink(vfbScreens[i].mmap_file)) + { + perror("unlink"); + ErrorF("unlink %s failed, errno %d", + vfbScreens[i].mmap_file, errno); + } + } + break; +#else /* HAS_MMAP */ + case MMAPPED_FILE_FB: + break; +#endif /* HAS_MMAP */ + +#ifdef HAS_SHM + case SHARED_MEMORY_FB: + for (i = 0; i < vfbNumScreens; i++) + { + if (-1 == shmdt((char *)vfbScreens[i].pXWDHeader)) + { + perror("shmdt"); + ErrorF("shmdt failed, errno %d", errno); + } + } + break; +#else /* HAS_SHM */ + case SHARED_MEMORY_FB: + break; +#endif /* HAS_SHM */ + + case NORMAL_MEMORY_FB: + for (i = 0; i < vfbNumScreens; i++) + { + Xfree(vfbScreens[i].pXWDHeader); + } + break; + } +} + +void +AbortDDX() +{ + ddxGiveUp(); +} + +#ifdef __DARWIN__ +void +DarwinHandleGUI(int argc, char *argv[]) +{ +} + +void GlxExtensionInit(); +void GlxWrapInitVisuals(void *procPtr); + +void +DarwinGlxExtensionInit() +{ + GlxExtensionInit(); +} + +void +DarwinGlxWrapInitVisuals( + void *procPtr) +{ + GlxWrapInitVisuals(procPtr); +} +#endif + +void +OsVendorInit() +{ +} + +void +OsVendorFatalError() +{ +} + +void ddxBeforeReset(void) +{ + return; +} + +void +ddxUseMsg() +{ + ErrorF("\nXvnc %s - built %s\n%s", XVNCVERSION, buildtime, XVNCCOPYRIGHT); + ErrorF("Underlying X server release %d, %s\n\n", VENDOR_RELEASE, + VENDOR_STRING); + ErrorF("-screen scrn WxHxD set screen's width, height, depth\n"); + ErrorF("-pixdepths list-of-int support given pixmap depths\n"); +#ifdef RENDER + ErrorF("+/-render turn on/off RENDER extension support" + "(default on)\n"); +#endif + ErrorF("-linebias n adjust thin line pixelization\n"); + ErrorF("-blackpixel n pixel value for black\n"); + ErrorF("-whitepixel n pixel value for white\n"); + +#ifdef HAS_MMAP + ErrorF("-fbdir directory put framebuffers in mmap'ed files in directory\n"); +#endif + +#ifdef HAS_SHM + ErrorF("-shmem put framebuffers in shared memory\n"); +#endif + + ErrorF("-geometry WxH set screen 0's width, height\n"); + ErrorF("-depth D set screen 0's depth\n"); + ErrorF("-pixelformat fmt set pixel format (rgbNNN or bgrNNN)\n"); + ErrorF("-inetd has been launched from inetd\n"); + ErrorF("\nVNC parameters:\n"); + + fprintf(stderr,"\n" + "Parameters can be turned on with - or off with -=0\n" + "Parameters which take a value can be specified as " + "- \n" + "Other valid forms are = -= " + "--=\n" + "Parameter names are case-insensitive. The parameters are:\n\n"); + rfb::Configuration::listParams(79, 14); + } +} + +/* ddxInitGlobals - called by |InitGlobals| from os/util.c */ +void ddxInitGlobals(void) +{ +} + +static +bool displayNumFree(int num) +{ + try { + network::TcpListener l(6000+num); + } catch (rdr::Exception& e) { + return false; + } + char file[256]; + sprintf(file, "/tmp/.X%d-lock", num); + if (access(file, F_OK) == 0) return false; + sprintf(file, "/tmp/.X11-unix/X%d", num); + if (access(file, F_OK) == 0) return false; + sprintf(file, "/usr/spool/sockets/X11/%d", num); + if (access(file, F_OK) == 0) return false; + return true; +} + +int +ddxProcessArgument(int argc, char *argv[], int i) +{ + static Bool firstTime = TRUE; + + if (firstTime) + { + vfbInitializeDefaultScreens(); + vfbInitializePixmapDepths(); + firstTime = FALSE; + rfb::initStdIOLoggers(); + rfb::LogWriter::setLogParams("*:stderr:30"); + } + + if (argv[i][0] == ':') + displaySpecified = true; + + if (strcmp (argv[i], "-screen") == 0) /* -screen n WxHxD */ + { + int screenNum; + if (i + 2 >= argc) UseMsg(); + screenNum = atoi(argv[i+1]); + if (screenNum < 0 || screenNum >= MAXSCREENS) + { + ErrorF("Invalid screen number %d\n", screenNum); + UseMsg(); + } + if (3 != sscanf(argv[i+2], "%dx%dx%d", + &vfbScreens[screenNum].width, + &vfbScreens[screenNum].height, + &vfbScreens[screenNum].depth)) + { + ErrorF("Invalid screen configuration %s\n", argv[i+2]); + UseMsg(); + } + + if (screenNum >= vfbNumScreens) + vfbNumScreens = screenNum + 1; + lastScreen = screenNum; + return 3; + } + + if (strcmp (argv[i], "-pixdepths") == 0) /* -pixdepths list-of-depth */ + { + int depth, ret = 1; + + if (++i >= argc) UseMsg(); + while ((i < argc) && (depth = atoi(argv[i++])) != 0) + { + if (depth < 0 || depth > 32) + { + ErrorF("Invalid pixmap depth %d\n", depth); + UseMsg(); + } + vfbPixmapDepths[depth] = TRUE; + ret++; + } + return ret; + } + + if (strcmp (argv[i], "+render") == 0) /* +render */ + { + Render = TRUE; + return 1; + } + + if (strcmp (argv[i], "-render") == 0) /* -render */ + { + Render = FALSE; + return 1; + } + + if (strcmp (argv[i], "-blackpixel") == 0) /* -blackpixel n */ + { + Pixel pix; + if (++i >= argc) UseMsg(); + pix = atoi(argv[i]); + if (-1 == lastScreen) + { + int i; + for (i = 0; i < MAXSCREENS; i++) + { + vfbScreens[i].blackPixel = pix; + } + } + else + { + vfbScreens[lastScreen].blackPixel = pix; + } + return 2; + } + + if (strcmp (argv[i], "-whitepixel") == 0) /* -whitepixel n */ + { + Pixel pix; + if (++i >= argc) UseMsg(); + pix = atoi(argv[i]); + if (-1 == lastScreen) + { + int i; + for (i = 0; i < MAXSCREENS; i++) + { + vfbScreens[i].whitePixel = pix; + } + } + else + { + vfbScreens[lastScreen].whitePixel = pix; + } + return 2; + } + + if (strcmp (argv[i], "-linebias") == 0) /* -linebias n */ + { + unsigned int linebias; + if (++i >= argc) UseMsg(); + linebias = atoi(argv[i]); + if (-1 == lastScreen) + { + int i; + for (i = 0; i < MAXSCREENS; i++) + { + vfbScreens[i].lineBias = linebias; + } + } + else + { + vfbScreens[lastScreen].lineBias = linebias; + } + return 2; + } + +#ifdef HAS_MMAP + if (strcmp (argv[i], "-fbdir") == 0) /* -fbdir directory */ + { + if (++i >= argc) UseMsg(); + pfbdir = argv[i]; + fbmemtype = MMAPPED_FILE_FB; + return 2; + } +#endif /* HAS_MMAP */ + +#ifdef HAS_SHM + if (strcmp (argv[i], "-shmem") == 0) /* -shmem */ + { + fbmemtype = SHARED_MEMORY_FB; + return 1; + } +#endif + + if (strcmp(argv[i], "-geometry") == 0) + { + if (++i >= argc) UseMsg(); + if (sscanf(argv[i],"%dx%d",&vfbScreens[0].width, + &vfbScreens[0].height) != 2) { + ErrorF("Invalid geometry %s\n", argv[i]); + UseMsg(); + } + return 2; + } + + if (strcmp(argv[i], "-depth") == 0) + { + if (++i >= argc) UseMsg(); + vfbScreens[0].depth = atoi(argv[i]); + return 2; + } + + if (strcmp(argv[i], "-pixelformat") == 0) + { + char rgbbgr[4]; + int bits1, bits2, bits3; + if (++i >= argc) UseMsg(); + if (sscanf(argv[i], "%3s%1d%1d%1d", rgbbgr,&bits1,&bits2,&bits3) < 4) { + ErrorF("Invalid pixel format %s\n", argv[i]); + UseMsg(); + } + +#define SET_PIXEL_FORMAT(vfbScreen) \ + (vfbScreen).pixelFormatDefined = TRUE; \ + (vfbScreen).depth = bits1 + bits2 + bits3; \ + (vfbScreen).greenBits = bits2; \ + if (strcasecmp(rgbbgr, "bgr") == 0) { \ + (vfbScreen).rgbNotBgr = FALSE; \ + (vfbScreen).redBits = bits3; \ + (vfbScreen).blueBits = bits1; \ + } else if (strcasecmp(rgbbgr, "rgb") == 0) { \ + (vfbScreen).rgbNotBgr = TRUE; \ + (vfbScreen).redBits = bits1; \ + (vfbScreen).blueBits = bits3; \ + } else { \ + ErrorF("Invalid pixel format %s\n", argv[i]); \ + UseMsg(); \ + } + + if (-1 == lastScreen) + { + int i; + for (i = 0; i < MAXSCREENS; i++) + { + SET_PIXEL_FORMAT(vfbScreens[i]); + } + } + else + { + SET_PIXEL_FORMAT(vfbScreens[lastScreen]); + } + + return 2; + } + + if (strcmp(argv[i], "-inetd") == 0) + { + dup2(0,3); + vncInetdSock = 3; + close(2); + + if (!displaySpecified) { + int port = network::TcpSocket::getSockPort(vncInetdSock); + int displayNum = port - 5900; + if (displayNum < 0 || displayNum > 99 || !displayNumFree(displayNum)) { + for (displayNum = 1; displayNum < 100; displayNum++) + if (displayNumFree(displayNum)) break; + + if (displayNum == 100) + FatalError("Xvnc error: no free display number for -inetd"); + } + + display = displayNumStr; + sprintf(displayNumStr, "%d", displayNum); + } + + return 1; + } + + if (rfb::Configuration::setParam(argv[i])) + return 1; + + if (argv[i][0] == '-' && i+1 < argc) { + if (rfb::Configuration::setParam(&argv[i][1], argv[i+1])) + return 2; + } + + return 0; +} + +#ifdef DDXTIME /* from ServerOSDefines */ +CARD32 +GetTimeInMillis() +{ + struct timeval tp; + + X_GETTIMEOFDAY(&tp); + return(tp.tv_sec * 1000) + (tp.tv_usec / 1000); +} +#endif + +static ColormapPtr InstalledMaps[MAXSCREENS]; + +static int +vfbListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps) +{ + /* By the time we are processing requests, we can guarantee that there + * is always a colormap installed */ + *pmaps = InstalledMaps[pScreen->myNum]->mid; + return (1); +} + + +static void +vfbInstallColormap(ColormapPtr pmap) +{ + int index = pmap->pScreen->myNum; + ColormapPtr oldpmap = InstalledMaps[index]; + + if (pmap != oldpmap) + { + int entries; + XWDFileHeader *pXWDHeader; + XWDColor *pXWDCmap; + VisualPtr pVisual; + Pixel * ppix; + xrgb * prgb; + xColorItem *defs; + int i; + + if(oldpmap != (ColormapPtr)None) + WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid); + /* Install pmap */ + InstalledMaps[index] = pmap; + WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid); + + entries = pmap->pVisual->ColormapEntries; + pXWDHeader = vfbScreens[pmap->pScreen->myNum].pXWDHeader; + pXWDCmap = vfbScreens[pmap->pScreen->myNum].pXWDCmap; + pVisual = pmap->pVisual; + + swapcopy32(pXWDHeader->visual_class, pVisual->c_class); + swapcopy32(pXWDHeader->red_mask, pVisual->redMask); + swapcopy32(pXWDHeader->green_mask, pVisual->greenMask); + swapcopy32(pXWDHeader->blue_mask, pVisual->blueMask); + swapcopy32(pXWDHeader->bits_per_rgb, pVisual->bitsPerRGBValue); + swapcopy32(pXWDHeader->colormap_entries, pVisual->ColormapEntries); + + ppix = (Pixel *)ALLOCATE_LOCAL(entries * sizeof(Pixel)); + prgb = (xrgb *)ALLOCATE_LOCAL(entries * sizeof(xrgb)); + defs = (xColorItem *)ALLOCATE_LOCAL(entries * sizeof(xColorItem)); + + for (i = 0; i < entries; i++) ppix[i] = i; + /* XXX truecolor */ + QueryColors(pmap, entries, ppix, prgb); + + for (i = 0; i < entries; i++) { /* convert xrgbs to xColorItems */ + defs[i].pixel = ppix[i] & 0xff; /* change pixel to index */ + defs[i].red = prgb[i].red; + defs[i].green = prgb[i].green; + defs[i].blue = prgb[i].blue; + defs[i].flags = DoRed|DoGreen|DoBlue; + } + (*pmap->pScreen->StoreColors)(pmap, entries, defs); + + DEALLOCATE_LOCAL(ppix); + DEALLOCATE_LOCAL(prgb); + DEALLOCATE_LOCAL(defs); + } +} + +static void +vfbUninstallColormap(ColormapPtr pmap) +{ + ColormapPtr curpmap = InstalledMaps[pmap->pScreen->myNum]; + + if(pmap == curpmap) + { + if (pmap->mid != pmap->pScreen->defColormap) + { + curpmap = (ColormapPtr) LookupIDByType(pmap->pScreen->defColormap, + RT_COLORMAP); + (*pmap->pScreen->InstallColormap)(curpmap); + } + } +} + +static void +vfbStoreColors(ColormapPtr pmap, int ndef, xColorItem *pdefs) +{ + XWDColor *pXWDCmap; + int i; + + if (pmap != InstalledMaps[pmap->pScreen->myNum]) + { + return; + } + + pXWDCmap = vfbScreens[pmap->pScreen->myNum].pXWDCmap; + + if ((pmap->pVisual->c_class | DynamicClass) == DirectColor) + { + return; + } + + for (i = 0; i < ndef; i++) + { + if (pdefs[i].flags & DoRed) + { + swapcopy16(pXWDCmap[pdefs[i].pixel].red, pdefs[i].red); + } + if (pdefs[i].flags & DoGreen) + { + swapcopy16(pXWDCmap[pdefs[i].pixel].green, pdefs[i].green); + } + if (pdefs[i].flags & DoBlue) + { + swapcopy16(pXWDCmap[pdefs[i].pixel].blue, pdefs[i].blue); + } + } +} + +static Bool +vfbSaveScreen(ScreenPtr pScreen, int on) +{ + return TRUE; +} + +#ifdef HAS_MMAP + +/* this flushes any changes to the screens out to the mmapped file */ +static void +vfbBlockHandler(pointer blockData, OSTimePtr pTimeout, pointer pReadmask) +{ + int i; + + for (i = 0; i < vfbNumScreens; i++) + { +#ifdef MS_ASYNC + if (-1 == msync((caddr_t)vfbScreens[i].pXWDHeader, + (size_t)vfbScreens[i].sizeInBytes, MS_ASYNC)) +#else + /* silly NetBSD and who else? */ + if (-1 == msync((caddr_t)vfbScreens[i].pXWDHeader, + (size_t)vfbScreens[i].sizeInBytes)) +#endif + { + perror("msync"); + ErrorF("msync failed, errno %d", errno); + } + } +} + + +static void +vfbWakeupHandler(pointer blockData, int result, pointer pReadmask) +{ +} + + +static void +vfbAllocateMmappedFramebuffer(vfbScreenInfoPtr pvfb) +{ +#define DUMMY_BUFFER_SIZE 65536 + char dummyBuffer[DUMMY_BUFFER_SIZE]; + int currentFileSize, writeThisTime; + + sprintf(pvfb->mmap_file, "%s/Xvfb_screen%d", pfbdir, pvfb->scrnum); + if (-1 == (pvfb->mmap_fd = open(pvfb->mmap_file, O_CREAT|O_RDWR, 0666))) + { + perror("open"); + ErrorF("open %s failed, errno %d", pvfb->mmap_file, errno); + return; + } + + /* Extend the file to be the proper size */ + + bzero(dummyBuffer, DUMMY_BUFFER_SIZE); + for (currentFileSize = 0; + currentFileSize < pvfb->sizeInBytes; + currentFileSize += writeThisTime) + { + writeThisTime = min(DUMMY_BUFFER_SIZE, + pvfb->sizeInBytes - currentFileSize); + if (-1 == write(pvfb->mmap_fd, dummyBuffer, writeThisTime)) + { + perror("write"); + ErrorF("write %s failed, errno %d", pvfb->mmap_file, errno); + return; + } + } + + /* try to mmap the file */ + + pvfb->pXWDHeader = (XWDFileHeader *)mmap((caddr_t)NULL, pvfb->sizeInBytes, + PROT_READ|PROT_WRITE, + MAP_FILE|MAP_SHARED, + pvfb->mmap_fd, 0); + if (-1 == (long)pvfb->pXWDHeader) + { + perror("mmap"); + ErrorF("mmap %s failed, errno %d", pvfb->mmap_file, errno); + pvfb->pXWDHeader = NULL; + return; + } + + if (!RegisterBlockAndWakeupHandlers(vfbBlockHandler, vfbWakeupHandler, + NULL)) + { + pvfb->pXWDHeader = NULL; + } +} +#endif /* HAS_MMAP */ + + +#ifdef HAS_SHM +static void +vfbAllocateSharedMemoryFramebuffer(vfbScreenInfoPtr pvfb) +{ + /* create the shared memory segment */ + + pvfb->shmid = shmget(IPC_PRIVATE, pvfb->sizeInBytes, IPC_CREAT|0777); + if (pvfb->shmid < 0) + { + perror("shmget"); + ErrorF("shmget %d bytes failed, errno %d", pvfb->sizeInBytes, errno); + return; + } + + /* try to attach it */ + + pvfb->pXWDHeader = (XWDFileHeader *)shmat(pvfb->shmid, 0, 0); + if (-1 == (long)pvfb->pXWDHeader) + { + perror("shmat"); + ErrorF("shmat failed, errno %d", errno); + pvfb->pXWDHeader = NULL; + return; + } + + ErrorF("screen %d shmid %d\n", pvfb->scrnum, pvfb->shmid); +} +#endif /* HAS_SHM */ + + +static char * +vfbAllocateFramebufferMemory(vfbScreenInfoPtr pvfb) +{ + if (pvfb->pfbMemory) return pvfb->pfbMemory; /* already done */ + + pvfb->sizeInBytes = pvfb->paddedBytesWidth * pvfb->height; + + /* Calculate how many entries in colormap. This is rather bogus, because + * the visuals haven't even been set up yet, but we need to know because we + * have to allocate space in the file for the colormap. The number 10 + * below comes from the MAX_PSEUDO_DEPTH define in cfbcmap.c. + */ + + if (pvfb->depth <= 10) + { /* single index colormaps */ + pvfb->ncolors = 1 << pvfb->depth; + } + else + { /* decomposed colormaps */ + int nplanes_per_color_component = pvfb->depth / 3; + if (pvfb->depth % 3) nplanes_per_color_component++; + pvfb->ncolors = 1 << nplanes_per_color_component; + } + + /* add extra bytes for XWDFileHeader, window name, and colormap */ + + pvfb->sizeInBytes += SIZEOF(XWDheader) + XWD_WINDOW_NAME_LEN + + pvfb->ncolors * SIZEOF(XWDColor); + + pvfb->pXWDHeader = NULL; + switch (fbmemtype) + { +#ifdef HAS_MMAP + case MMAPPED_FILE_FB: vfbAllocateMmappedFramebuffer(pvfb); break; +#else + case MMAPPED_FILE_FB: break; +#endif + +#ifdef HAS_SHM + case SHARED_MEMORY_FB: vfbAllocateSharedMemoryFramebuffer(pvfb); break; +#else + case SHARED_MEMORY_FB: break; +#endif + + case NORMAL_MEMORY_FB: + pvfb->pXWDHeader = (XWDFileHeader *)Xalloc(pvfb->sizeInBytes); + break; + } + + if (pvfb->pXWDHeader) + { + pvfb->pXWDCmap = (XWDColor *)((char *)pvfb->pXWDHeader + + SIZEOF(XWDheader) + XWD_WINDOW_NAME_LEN); + pvfb->pfbMemory = (char *)(pvfb->pXWDCmap + pvfb->ncolors); + + return pvfb->pfbMemory; + } + else + return NULL; +} + +static void +vfbWriteXWDFileHeader(ScreenPtr pScreen) +{ + vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum]; + XWDFileHeader *pXWDHeader = pvfb->pXWDHeader; + char hostname[XWD_WINDOW_NAME_LEN]; + unsigned long swaptest = 1; + int i; + + needswap = *(char *) &swaptest; + + pXWDHeader->header_size = (char *)pvfb->pXWDCmap - (char *)pvfb->pXWDHeader; + pXWDHeader->file_version = XWD_FILE_VERSION; + + pXWDHeader->pixmap_format = ZPixmap; + pXWDHeader->pixmap_depth = pvfb->depth; + pXWDHeader->pixmap_height = pXWDHeader->window_height = pvfb->height; + pXWDHeader->xoffset = 0; + pXWDHeader->byte_order = IMAGE_BYTE_ORDER; + pXWDHeader->bitmap_bit_order = BITMAP_BIT_ORDER; +#ifndef INTERNAL_VS_EXTERNAL_PADDING + pXWDHeader->pixmap_width = pXWDHeader->window_width = pvfb->width; + pXWDHeader->bitmap_unit = BITMAP_SCANLINE_UNIT; + pXWDHeader->bitmap_pad = BITMAP_SCANLINE_PAD; +#else + pXWDHeader->pixmap_width = pXWDHeader->window_width = pvfb->paddedWidth; + pXWDHeader->bitmap_unit = BITMAP_SCANLINE_UNIT_PROTO; + pXWDHeader->bitmap_pad = BITMAP_SCANLINE_PAD_PROTO; +#endif + pXWDHeader->bits_per_pixel = pvfb->bitsPerPixel; + pXWDHeader->bytes_per_line = pvfb->paddedBytesWidth; + pXWDHeader->ncolors = pvfb->ncolors; + + /* visual related fields are written when colormap is installed */ + + pXWDHeader->window_x = pXWDHeader->window_y = 0; + pXWDHeader->window_bdrwidth = 0; + + /* write xwd "window" name: Xvfb hostname:server.screen */ + + if (-1 == gethostname(hostname, sizeof(hostname))) + hostname[0] = 0; + else + hostname[XWD_WINDOW_NAME_LEN-1] = 0; + sprintf((char *)(pXWDHeader+1), "Xvfb %s:%s.%d", hostname, display, + pScreen->myNum); + + /* write colormap pixel slot values */ + + for (i = 0; i < pvfb->ncolors; i++) + { + pvfb->pXWDCmap[i].pixel = i; + } + + /* byte swap to most significant byte first */ + + if (needswap) + { + SwapLongs((CARD32 *)pXWDHeader, SIZEOF(XWDheader)/4); + for (i = 0; i < pvfb->ncolors; i++) + { + register char n; + swapl(&pvfb->pXWDCmap[i].pixel, n); + } + } +} + + +static Bool +vfbCursorOffScreen (ScreenPtr *ppScreen, int *x, int *y) +{ + return FALSE; +} + +static void +vfbCrossScreen (ScreenPtr pScreen, Bool entering) +{ +} + +static Bool vfbRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) { + return TRUE; +} + +static Bool vfbUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) { + return TRUE; +} + +static void vfbSetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y) +{ +} + +static void vfbMoveCursor(ScreenPtr pScreen, int x, int y) +{ +} + +static miPointerSpriteFuncRec vfbPointerSpriteFuncs = { + vfbRealizeCursor, + vfbUnrealizeCursor, + vfbSetCursor, + vfbMoveCursor +}; + +static miPointerScreenFuncRec vfbPointerCursorFuncs = { + vfbCursorOffScreen, + vfbCrossScreen, + miPointerWarpCursor +}; + +static Bool +vfbCloseScreen(int index, ScreenPtr pScreen) +{ + vfbScreenInfoPtr pvfb = &vfbScreens[index]; + int i; + + pScreen->CloseScreen = pvfb->closeScreen; + + /* + * XXX probably lots of stuff to clean. For now, + * clear InstalledMaps[] so that server reset works correctly. + */ + for (i = 0; i < MAXSCREENS; i++) + InstalledMaps[i] = NULL; + + return pScreen->CloseScreen(index, pScreen); +} + +static Bool +vfbScreenInit(int index, ScreenPtr pScreen, int argc, char **argv) +{ + vfbScreenInfoPtr pvfb = &vfbScreens[index]; + int dpi = 100; + int ret; + char *pbits; + + if (monitorResolution) dpi = monitorResolution; + + pvfb->paddedBytesWidth = PixmapBytePad(pvfb->width, pvfb->depth); + pvfb->bitsPerPixel = vfbBitsPerPixel(pvfb->depth); + pvfb->paddedWidth = pvfb->paddedBytesWidth * 8 / pvfb->bitsPerPixel; + pbits = vfbAllocateFramebufferMemory(pvfb); + if (!pbits) return FALSE; + vncFbptr[index] = pbits; + + defaultColorVisualClass + = (pvfb->bitsPerPixel > 8) ? TrueColor : PseudoColor; + + ret = fbScreenInit(pScreen, pbits, pvfb->width, pvfb->height, + dpi, dpi, pvfb->paddedWidth, pvfb->bitsPerPixel); + +#ifdef RENDER + if (ret && Render) + fbPictureInit (pScreen, 0, 0); +#endif + + if (!ret) return FALSE; + + /* miInitializeBackingStore(pScreen); */ + + /* + * Circumvent the backing store that was just initialised. This amounts + * to a truely bizarre way of initialising SaveDoomedAreas and friends. + */ + + pScreen->InstallColormap = vfbInstallColormap; + pScreen->UninstallColormap = vfbUninstallColormap; + pScreen->ListInstalledColormaps = vfbListInstalledColormaps; + + pScreen->SaveScreen = vfbSaveScreen; + pScreen->StoreColors = vfbStoreColors; + + miPointerInitialize(pScreen, &vfbPointerSpriteFuncs, &vfbPointerCursorFuncs, + FALSE); + + vfbWriteXWDFileHeader(pScreen); + + pScreen->blackPixel = pvfb->blackPixel; + pScreen->whitePixel = pvfb->whitePixel; + + if (!pvfb->pixelFormatDefined && pvfb->depth == 16) { + pvfb->pixelFormatDefined = TRUE; + pvfb->rgbNotBgr = TRUE; + pvfb->blueBits = pvfb->redBits = 5; + pvfb->greenBits = 6; + } + + if (pvfb->pixelFormatDefined) { + VisualPtr vis = pScreen->visuals; + for (int i = 0; i < pScreen->numVisuals; i++) { + if (pvfb->rgbNotBgr) { + vis->offsetBlue = 0; + vis->blueMask = (1 << pvfb->blueBits) - 1; + vis->offsetGreen = pvfb->blueBits; + vis->greenMask = ((1 << pvfb->greenBits) - 1) << vis->offsetGreen; + vis->offsetRed = vis->offsetGreen + pvfb->greenBits; + vis->redMask = ((1 << pvfb->redBits) - 1) << vis->offsetRed; + } else { + vis->offsetRed = 0; + vis->redMask = (1 << pvfb->redBits) - 1; + vis->offsetGreen = pvfb->redBits; + vis->greenMask = ((1 << pvfb->greenBits) - 1) << vis->offsetGreen; + vis->offsetBlue = vis->offsetGreen + pvfb->greenBits; + vis->blueMask = ((1 << pvfb->blueBits) - 1) << vis->offsetBlue; + } + vis++; + } + } + + ret = fbCreateDefColormap(pScreen); + + miSetZeroLineBias(pScreen, pvfb->lineBias); + + pvfb->closeScreen = pScreen->CloseScreen; + pScreen->CloseScreen = vfbCloseScreen; + +#ifndef NO_INIT_BACKING_STORE + miInitializeBackingStore(pScreen); + pScreen->backingStoreSupport = Always; +#endif + + return ret; + +} /* end vfbScreenInit */ + + +static void vfbClientStateChange(CallbackListPtr*, pointer, pointer) { + dispatchException &= ~DE_RESET; +} + +void +InitOutput(ScreenInfo *screenInfo, int argc, char **argv) +{ + ErrorF("\nXvnc %s - built %s\n%s", XVNCVERSION, buildtime, XVNCCOPYRIGHT); + ErrorF("Underlying X server release %d, %s\n\n", VENDOR_RELEASE, + VENDOR_STRING); + int i; + int NumFormats = 0; + + /* initialize pixmap formats */ + + /* must have a pixmap depth to match every screen depth */ + for (i = 0; i < vfbNumScreens; i++) + { + vfbPixmapDepths[vfbScreens[i].depth] = TRUE; + } + + /* RENDER needs a good set of pixmaps. */ + if (Render) { + vfbPixmapDepths[1] = TRUE; + vfbPixmapDepths[4] = TRUE; + vfbPixmapDepths[8] = TRUE; +/* vfbPixmapDepths[15] = TRUE; */ + vfbPixmapDepths[16] = TRUE; + vfbPixmapDepths[24] = TRUE; + vfbPixmapDepths[32] = TRUE; + } + + for (i = 1; i <= 32; i++) + { + if (vfbPixmapDepths[i]) + { + if (NumFormats >= MAXFORMATS) + FatalError ("MAXFORMATS is too small for this server\n"); + screenInfo->formats[NumFormats].depth = i; + screenInfo->formats[NumFormats].bitsPerPixel = vfbBitsPerPixel(i); + screenInfo->formats[NumFormats].scanlinePad = BITMAP_SCANLINE_PAD; + NumFormats++; + } + } + + screenInfo->imageByteOrder = IMAGE_BYTE_ORDER; + screenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; + screenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD; + screenInfo->bitmapBitOrder = BITMAP_BIT_ORDER; + screenInfo->numPixmapFormats = NumFormats; + + /* initialize screens */ + + for (i = 0; i < vfbNumScreens; i++) + { + if (-1 == AddScreen(vfbScreenInit, argc, argv)) + { + FatalError("Couldn't add screen %d", i); + } + } + + if (!AddCallback(&ClientStateCallback, vfbClientStateChange, 0)) { + FatalError("AddCallback failed\n"); + } +} /* end InitOutput */ + +#ifdef DPMSExtension +extern "C" { +#if NeedFunctionPrototypes + void DPMSSet(CARD16 level) +#else + void DPMSSet(level) + CARD16 level; +#endif + { + return; + } + + Bool DPMSSupported() + { + return FALSE; + } +} +#endif + +/* this is just to get the server to link on AIX */ +#ifdef AIXV3 +int SelectWaitTime = 10000; /* usec */ +#endif + +Bool LegalModifier(unsigned int key, DevicePtr pDev) +{ + return TRUE; +} + +void ProcessInputEvents() +{ + mieqProcessInputEvents(); + miPointerUpdate(); +} + +/* Fairly standard US PC Keyboard */ + +#define VFB_MIN_KEY 8 +#define VFB_MAX_KEY 255 +#define VFB_MAP_LEN (VFB_MAX_KEY - VFB_MIN_KEY + 1) +#define KEYSYMS_PER_KEY 2 +KeySym keyboardMap[VFB_MAP_LEN * KEYSYMS_PER_KEY] = { + NoSymbol, NoSymbol, + XK_Escape, NoSymbol, + XK_1, XK_exclam, + XK_2, XK_at, + XK_3, XK_numbersign, + XK_4, XK_dollar, + XK_5, XK_percent, + XK_6, XK_asciicircum, + XK_7, XK_ampersand, + XK_8, XK_asterisk, + XK_9, XK_parenleft, + XK_0, XK_parenright, + XK_minus, XK_underscore, + XK_equal, XK_plus, + XK_BackSpace, NoSymbol, + XK_Tab, NoSymbol, + XK_q, XK_Q, + XK_w, XK_W, + XK_e, XK_E, + XK_r, XK_R, + XK_t, XK_T, + XK_y, XK_Y, + XK_u, XK_U, + XK_i, XK_I, + XK_o, XK_O, + XK_p, XK_P, + XK_bracketleft, XK_braceleft, + XK_bracketright, XK_braceright, + XK_Return, NoSymbol, + XK_Control_L, NoSymbol, + XK_a, XK_A, + XK_s, XK_S, + XK_d, XK_D, + XK_f, XK_F, + XK_g, XK_G, + XK_h, XK_H, + XK_j, XK_J, + XK_k, XK_K, + XK_l, XK_L, + XK_semicolon, XK_colon, + XK_apostrophe, XK_quotedbl, + XK_grave, XK_asciitilde, + XK_Shift_L, NoSymbol, + XK_backslash, XK_bar, + XK_z, XK_Z, + XK_x, XK_X, + XK_c, XK_C, + XK_v, XK_V, + XK_b, XK_B, + XK_n, XK_N, + XK_m, XK_M, + XK_comma, XK_less, + XK_period, XK_greater, + XK_slash, XK_question, + XK_Shift_R, NoSymbol, + XK_KP_Multiply, NoSymbol, + XK_Alt_L, XK_Meta_L, + XK_space, NoSymbol, + /*XK_Caps_Lock*/ NoSymbol, NoSymbol, + XK_F1, NoSymbol, + XK_F2, NoSymbol, + XK_F3, NoSymbol, + XK_F4, NoSymbol, + XK_F5, NoSymbol, + XK_F6, NoSymbol, + XK_F7, NoSymbol, + XK_F8, NoSymbol, + XK_F9, NoSymbol, + XK_F10, NoSymbol, + XK_Num_Lock, XK_Pointer_EnableKeys, + XK_Scroll_Lock, NoSymbol, + XK_KP_Home, XK_KP_7, + XK_KP_Up, XK_KP_8, + XK_KP_Prior, XK_KP_9, + XK_KP_Subtract, NoSymbol, + XK_KP_Left, XK_KP_4, + XK_KP_Begin, XK_KP_5, + XK_KP_Right, XK_KP_6, + XK_KP_Add, NoSymbol, + XK_KP_End, XK_KP_1, + XK_KP_Down, XK_KP_2, + XK_KP_Next, XK_KP_3, + XK_KP_Insert, XK_KP_0, + XK_KP_Delete, XK_KP_Decimal, + NoSymbol, NoSymbol, + NoSymbol, NoSymbol, + NoSymbol, NoSymbol, + XK_F11, NoSymbol, + XK_F12, NoSymbol, + XK_Home, NoSymbol, + XK_Up, NoSymbol, + XK_Prior, NoSymbol, + XK_Left, NoSymbol, + NoSymbol, NoSymbol, + XK_Right, NoSymbol, + XK_End, NoSymbol, + XK_Down, NoSymbol, + XK_Next, NoSymbol, + XK_Insert, NoSymbol, + XK_Delete, NoSymbol, + XK_KP_Enter, NoSymbol, + XK_Control_R, NoSymbol, + XK_Pause, XK_Break, + XK_Print, XK_Execute, + XK_KP_Divide, NoSymbol, + XK_Alt_R, XK_Meta_R, +}; + +static Bool GetMappings(KeySymsPtr pKeySyms, CARD8 *pModMap) +{ + int i; + + for (i = 0; i < MAP_LENGTH; i++) + pModMap[i] = NoSymbol; + + for (i = 0; i < VFB_MAP_LEN; i++) { + if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Caps_Lock) + pModMap[i + VFB_MIN_KEY] = LockMask; + else if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Shift_L || + keyboardMap[i * KEYSYMS_PER_KEY] == XK_Shift_R) + pModMap[i + VFB_MIN_KEY] = ShiftMask; + else if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Control_L || + keyboardMap[i * KEYSYMS_PER_KEY] == XK_Control_R) { + pModMap[i + VFB_MIN_KEY] = ControlMask; + } + else if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Alt_L || + keyboardMap[i * KEYSYMS_PER_KEY] == XK_Alt_R) + pModMap[i + VFB_MIN_KEY] = Mod1Mask; + } + + pKeySyms->minKeyCode = VFB_MIN_KEY; + pKeySyms->maxKeyCode = VFB_MAX_KEY; + pKeySyms->mapWidth = KEYSYMS_PER_KEY; + pKeySyms->map = keyboardMap; + + return TRUE; +} + +static void vfbBell(int percent, DeviceIntPtr device, pointer ctrl, int class_) +{ + if (percent > 0) + vncBell(); +} + +static int vfbKeybdProc(DeviceIntPtr pDevice, int onoff) +{ + KeySymsRec keySyms; + CARD8 modMap[MAP_LENGTH]; + DevicePtr pDev = (DevicePtr)pDevice; + + switch (onoff) + { + case DEVICE_INIT: + GetMappings(&keySyms, modMap); + InitKeyboardDeviceStruct(pDev, &keySyms, modMap, + (BellProcPtr)vfbBell, (KbdCtrlProcPtr)NoopDDA); + break; + case DEVICE_ON: + pDev->on = TRUE; + break; + case DEVICE_OFF: + pDev->on = FALSE; + break; + case DEVICE_CLOSE: + break; + } + return Success; +} + +static int vfbMouseProc(DeviceIntPtr pDevice, int onoff) +{ + BYTE map[6]; + DevicePtr pDev = (DevicePtr)pDevice; + + switch (onoff) + { + case DEVICE_INIT: + map[1] = 1; + map[2] = 2; + map[3] = 3; + map[4] = 4; + map[5] = 5; + InitPointerDeviceStruct(pDev, map, 5, miPointerGetMotionEvents, + (PtrCtrlProcPtr)NoopDDA, miPointerGetMotionBufferSize()); + break; + + case DEVICE_ON: + pDev->on = TRUE; + break; + + case DEVICE_OFF: + pDev->on = FALSE; + break; + + case DEVICE_CLOSE: + break; + } + return Success; +} + +// InitInput is called after InitExtensions, so we're guaranteed that +// vncExtensionInit() has already been called. + +void InitInput(int argc, char *argv[]) +{ + DeviceIntPtr p, k; + p = AddInputDevice(vfbMouseProc, TRUE); + k = AddInputDevice(vfbKeybdProc, TRUE); + RegisterPointerDevice(p); + RegisterKeyboardDevice(k); + miRegisterPointerDevice(screenInfo.screens[0], p); + (void)mieqInit ((DevicePtr)k, (DevicePtr)p); +}