aboutsummaryrefslogtreecommitdiffstats
path: root/unix/xc/programs
diff options
context:
space:
mode:
Diffstat (limited to 'unix/xc/programs')
-rw-r--r--unix/xc/programs/Xserver/Xvnc.man284
-rw-r--r--unix/xc/programs/Xserver/vnc/Imakefile44
-rw-r--r--unix/xc/programs/Xserver/vnc/RegionHelper.h84
-rw-r--r--unix/xc/programs/Xserver/vnc/XserverDesktop.cc1147
-rw-r--r--unix/xc/programs/Xserver/vnc/XserverDesktop.h130
-rw-r--r--unix/xc/programs/Xserver/vnc/Xvnc/Imakefile95
-rw-r--r--unix/xc/programs/Xserver/vnc/Xvnc/buildtime.c18
-rw-r--r--unix/xc/programs/Xserver/vnc/Xvnc/xvnc.cc1475
-rw-r--r--unix/xc/programs/Xserver/vnc/module/Imakefile60
-rw-r--r--unix/xc/programs/Xserver/vnc/vncExtInit.cc866
-rw-r--r--unix/xc/programs/Xserver/vnc/vncExtInit.h32
-rw-r--r--unix/xc/programs/Xserver/vnc/vncHooks.cc1533
-rw-r--r--unix/xc/programs/Xserver/vnc/vncHooks.h26
-rw-r--r--unix/xc/programs/Xserver/vnc/xf86vncModule.cc97
14 files changed, 5891 insertions, 0 deletions
diff --git a/unix/xc/programs/Xserver/Xvnc.man b/unix/xc/programs/Xserver/Xvnc.man
new file mode 100644
index 00000000..128bc937
--- /dev/null
+++ b/unix/xc/programs/Xserver/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 was
+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
new file mode 100644
index 00000000..1c8132d9
--- /dev/null
+++ b/unix/xc/programs/Xserver/vnc/Imakefile
@@ -0,0 +1,44 @@
+XCOMM CDEBUGFLAGS = -g
+XCOMM CXXDEBUGFLAGS = -g
+
+ VNCTOP = $(TOP)/..
+ VNCINCLUDE = -I$(VNCTOP) -I$(VNCTOP)/vncconfig_unix
+
+#define CplusplusSource
+
+#if DoLoadableServer
+#define IHaveSubdirs
+#endif
+
+#include <Server.tmpl>
+
+#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
new file mode 100644
index 00000000..61dc89ff
--- /dev/null
+++ b/unix/xc/programs/Xserver/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(&regRec)
+ {
+ 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 = &regRec;
+ 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 == &regRec) {
+ 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
new file mode 100644
index 00000000..9e5ea0f7
--- /dev/null
+++ b/unix/xc/programs/Xserver/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 <stdio.h>
+#include <strings.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/utsname.h>
+#include <network/TcpSocket.h>
+#include <rfb/Exception.h>
+#include <rfb/VNCServerST.h>
+#include <rfb/HTTPServer.h>
+#include <rfb/LogWriter.h>
+#include <rfb/Configuration.h>
+#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<Socket*> sockets;
+ server->getSockets(&sockets);
+ std::list<Socket*>::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<Socket*> sockets;
+ server->getSockets(&sockets);
+ std::list<Socket*>::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<<i)) {
+ // Do not use the pointer mapping. Treat VNC buttons as logical
+ // buttons.
+ ev.u.u.detail = i + 1;
+ ev.u.u.type = (buttonMask & (1<<i)) ? ButtonPress : ButtonRelease;
+ (*dev->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<rfb::Rect> rects;
+ std::vector<rfb::Rect>::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<<modIndex))) {
+ tempKeyEvent(keyc->modifierKeyMap[modIndex * keyc->maxKeysPerModifier],
+ true);
+ pressed = true;
+ }
+ }
+ void release() {
+ KeyClassPtr keyc = dev->key;
+ if (keyc->state & (1<<modIndex)) {
+ for (int k = 0; k < keyc->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<<ShiftMapIndex)) col |= 1;
+ if (modeSwitchMapIndex && (keyc->state & (1<<modeSwitchMapIndex))) col |= 2;
+
+ int kc = KeysymToKeycode(keymap, keysym, &col);
+
+ // Sort out the "shifted Tab" mess. If we are sent a shifted Tab, generate a
+ // local shifted Tab regardless of what the "shifted Tab" keysym is on the
+ // local keyboard (it might be Tab, ISO_Left_Tab or HP's private BackTab
+ // keysym, and quite possibly some others too). We never get ISO_Left_Tab
+ // here because it's already been translated in VNCSConnectionST.
+ if (keysym == XK_Tab && (keyc->state & (1<<ShiftMapIndex)))
+ col |= 1;
+
+ if (kc == 0) {
+ // Not a direct match in the local keyboard mapping. Check for alternative
+ // keysyms with the same meaning.
+ for (int i = 0; i < sizeof(altKeysym) / sizeof(altKeysym_t); i++) {
+ if (keysym == altKeysym[i].a)
+ kc = KeysymToKeycode(keymap, altKeysym[i].b, &col);
+ else if (keysym == altKeysym[i].b)
+ kc = KeysymToKeycode(keymap, altKeysym[i].a, &col);
+ if (kc) break;
+ }
+ }
+
+ if (kc == 0) {
+ // Last resort - dynamically add a new key to the keyboard mapping.
+ for (kc = keymap->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
new file mode 100644
index 00000000..880acc21
--- /dev/null
+++ b/unix/xc/programs/Xserver/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 <rfb/SDesktop.h>
+#include <rfb/HTTPServer.h>
+#include <rfb/PixelBuffer.h>
+#include <rfb/Configuration.h>
+#include <rfb/VNCServerST.h>
+#include <rdr/SubstitutingInStream.h>
+
+extern "C" {
+#define class c_class;
+#include <scrnintstr.h>
+#include <os.h>
+#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
new file mode 100644
index 00000000..93885ae3
--- /dev/null
+++ b/unix/xc/programs/Xserver/vnc/Xvnc/Imakefile
@@ -0,0 +1,95 @@
+
+ VNCTOP = $(TOP)/..
+ VNCLIBS = VncExtLibs
+ VNCINCLUDE = -I$(VNCTOP) -I$(VNCTOP)/vncconfig_unix
+
+#if defined(XFree86Version) && XFree86Version < 4000
+ VNCDEFINES = -DNO_INIT_BACKING_STORE
+#endif
+
+#define CplusplusSource
+
+#include <Server.tmpl>
+
+#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
+
+#ifdef XFree86Version
+/*
+ * Make sure XINPUT, XF86VidTune, etc arent defined for the miinitext.o
+ * used by Xvnc
+ */
+EXT_DEFINES = ExtensionDefines -UXF86VIDMODE -UXFreeXDGA -UXF86MISC
+#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
new file mode 100644
index 00000000..3f4c3690
--- /dev/null
+++ b/unix/xc/programs/Xserver/vnc/Xvnc/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/xc/programs/Xserver/vnc/Xvnc/xvnc.cc b/unix/xc/programs/Xserver/vnc/Xvnc/xvnc.cc
new file mode 100644
index 00000000..fcb73e65
--- /dev/null
+++ b/unix/xc/programs/Xserver/vnc/Xvnc/xvnc.cc
@@ -0,0 +1,1475 @@
+/* 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 <rfb/Configuration.h>
+#include <rfb/Logger_stdio.h>
+#include <rfb/LogWriter.h>
+#include <network/TcpSocket.h>
+#include "vncExtInit.h"
+
+extern "C" {
+#define class c_class
+#define public c_public
+#define xor c_xor
+#define and c_and
+#ifdef WIN32
+#include <X11/Xwinsock.h>
+#endif
+#include <stdio.h>
+#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 <sys/types.h>
+#ifdef HAS_MMAP
+#include <sys/mman.h>
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+#endif /* HAS_MMAP */
+#include <sys/stat.h>
+#include <errno.h>
+#ifndef WIN32
+#include <sys/param.h>
+#endif
+#include <X11/XWDFile.h>
+#ifdef HAS_SHM
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#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 "Free Edition 4.1.1"
+#define XVNCCOPYRIGHT ("Copyright (C) 2002-2005 RealVNC Ltd.\n" \
+ "See http://www.realvnc.com for information on VNC.\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" {
+
+ /* ddxInitGlobals - called by |InitGlobals| from os/util.c in XOrg */
+ void ddxInitGlobals(void)
+ {
+ }
+
+ 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 -<param> or off with -<param>=0\n"
+ "Parameters which take a value can be specified as "
+ "-<param> <value>\n"
+ "Other valid forms are <param>=<value> -<param>=<value> "
+ "--<param>=<value>\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
new file mode 100644
index 00000000..f279649c
--- /dev/null
+++ b/unix/xc/programs/Xserver/vnc/module/Imakefile
@@ -0,0 +1,60 @@
+
+ VNCTOP = $(TOP)/..
+ VNCLIBS = VncExtLibs
+ VNCINCLUDE = -I$(VNCTOP) -I$(VNCTOP)/vncconfig_unix
+
+#define CplusplusSource
+
+#define IHaveModules
+#include <Server.tmpl>
+
+ 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
new file mode 100644
index 00000000..9cf9d21b
--- /dev/null
+++ b/unix/xc/programs/Xserver/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 <stdio.h>
+
+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 <rfb/Configuration.h>
+#include <rfb/Logger_stdio.h>
+#include <rfb/LogWriter.h>
+#include <rfb/util.h>
+#include <rfb/ServerCore.h>
+#include <rfb/SSecurityFactoryStandard.h>
+#include <rdr/HexOutStream.h>
+#include <rfb/LogWriter.h>
+#undef max
+#undef min
+#include <network/TcpSocket.h>
+
+#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
new file mode 100644
index 00000000..45453e1f
--- /dev/null
+++ b/unix/xc/programs/Xserver/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 <rfb/Configuration.h>
+#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
new file mode 100644
index 00000000..ce8e7f02
--- /dev/null
+++ b/unix/xc/programs/Xserver/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 <stdio.h>
+#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
new file mode 100644
index 00000000..c556ef3a
--- /dev/null
+++ b/unix/xc/programs/Xserver/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 <screenint.h>
+ 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
new file mode 100644
index 00000000..ef8ea506
--- /dev/null
+++ b/unix/xc/programs/Xserver/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 <rfb/Configuration.h>
+#include <rfb/Logger_stdio.h>
+#include <rfb/LogWriter.h>
+
+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 */
+}