summaryrefslogtreecommitdiffstats
path: root/unix/vncconfig/vncconfig.cxx
diff options
context:
space:
mode:
authorConstantin Kaplinsky <const@tightvnc.com>2006-05-25 05:04:46 +0000
committerConstantin Kaplinsky <const@tightvnc.com>2006-05-25 05:04:46 +0000
commitb30ae7facbdf8273f34f5d67d3d2e9c81db75576 (patch)
tree5091b0a7b991672b19c17b86b263e5ff4f173a3e /unix/vncconfig/vncconfig.cxx
parenta2adc8d4cfdf7336ce9192414c5e775224742a97 (diff)
downloadtigervnc-b30ae7facbdf8273f34f5d67d3d2e9c81db75576.tar.gz
tigervnc-b30ae7facbdf8273f34f5d67d3d2e9c81db75576.zip
Migrating to new directory structure adopted from the RealVNC's source tree. More changes will follow.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@590 3789f03b-4d11-0410-bbf8-ca57d06f2519
Diffstat (limited to 'unix/vncconfig/vncconfig.cxx')
-rw-r--r--unix/vncconfig/vncconfig.cxx438
1 files changed, 438 insertions, 0 deletions
diff --git a/unix/vncconfig/vncconfig.cxx b/unix/vncconfig/vncconfig.cxx
new file mode 100644
index 00000000..c901d193
--- /dev/null
+++ b/unix/vncconfig/vncconfig.cxx
@@ -0,0 +1,438 @@
+/* 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.
+ */
+//
+// VNC server configuration utility
+//
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <signal.h>
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include "vncExt.h"
+#include <rdr/Exception.h>
+#include <rfb/Configuration.h>
+#include <rfb/Logger_stdio.h>
+#include <rfb/LogWriter.h>
+#include <rfb/Timer.h>
+#include "TXWindow.h"
+#include "TXCheckbox.h"
+#include "TXLabel.h"
+#include "QueryConnectDialog.h"
+
+using namespace rfb;
+
+LogWriter vlog("vncconfig");
+
+StringParameter displayname("display", "The X display", "");
+BoolParameter noWindow("nowin", "Don't display a window", 0);
+BoolParameter iconic("iconic", "Start with window iconified", 0);
+BoolParameter sendPrimary("SendPrimary", "Send the PRIMARY as well as the "
+ "CLIPBOARD selection", true);
+IntParameter pollTime("poll",
+ "How often to poll for clipboard changes in ms", 0);
+
+inline const char* selectionName(Atom sel) {
+ if (sel == xaCLIPBOARD) return "CLIPBOARD";
+ if (sel == XA_PRIMARY) return "PRIMARY";
+ return "unknown";
+}
+
+#define ACCEPT_CUT_TEXT "AcceptCutText"
+#define SEND_CUT_TEXT "SendCutText"
+
+char* programName = 0;
+Display* dpy;
+int vncExtEventBase, vncExtErrorBase;
+
+static bool getBoolParam(Display* dpy, const char* param) {
+ char* data;
+ int len;
+ if (XVncExtGetParam(dpy, param, &data, &len)) {
+ if (strcmp(data,"1") == 0) return true;
+ }
+ return false;
+}
+
+class VncConfigWindow : public TXWindow, public TXEventHandler,
+ public TXDeleteWindowCallback,
+ public TXCheckboxCallback,
+ public rfb::Timer::Callback,
+ public QueryResultCallback {
+public:
+ VncConfigWindow(Display* dpy)
+ : TXWindow(dpy, 300, 100), cutText(0), cutTextLen(0),
+ acceptClipboard(dpy, "Accept clipboard from viewers", this, false, this),
+ sendClipboard(dpy, "Send clipboard to viewers", this, false, this),
+ sendPrimaryCB(dpy, "Send primary selection to viewers", this,false,this),
+ pollTimer(this),
+ queryConnectDialog(0)
+ {
+ selection[0] = selection[1] = 0;
+ selectionLen[0] = selectionLen[1] = 0;
+ int y = yPad;
+ acceptClipboard.move(xPad, y);
+ acceptClipboard.checked(getBoolParam(dpy, ACCEPT_CUT_TEXT));
+ y += acceptClipboard.height();
+ sendClipboard.move(xPad, y);
+ sendClipboard.checked(getBoolParam(dpy, SEND_CUT_TEXT));
+ y += sendClipboard.height();
+ sendPrimaryCB.move(xPad, y);
+ sendPrimaryCB.checked(sendPrimary);
+ sendPrimaryCB.disabled(!sendClipboard.checked());
+ y += sendPrimaryCB.height();
+ setEventHandler(this);
+ toplevel("VNC config", this, 0, 0, 0, iconic);
+ XVncExtSelectInput(dpy, win(),
+ VncExtClientCutTextMask|
+ VncExtSelectionChangeMask|
+ VncExtQueryConnectMask);
+ XConvertSelection(dpy, XA_PRIMARY, XA_STRING,
+ XA_PRIMARY, win(), CurrentTime);
+ XConvertSelection(dpy, xaCLIPBOARD, XA_STRING,
+ xaCLIPBOARD, win(), CurrentTime);
+ if (pollTime != 0)
+ pollTimer.start(pollTime);
+ }
+
+ // handleEvent(). If we get a ClientCutTextNotify event from Xvnc, set the
+ // primary and clipboard selections to the clientCutText. If we get a
+ // SelectionChangeNotify event from Xvnc, set the serverCutText to the value
+ // of the new selection.
+
+ virtual void handleEvent(TXWindow* w, XEvent* ev) {
+ if (acceptClipboard.checked()) {
+ if (ev->type == vncExtEventBase + VncExtClientCutTextNotify) {
+ XVncExtClientCutTextEvent* cutEv = (XVncExtClientCutTextEvent*)ev;
+ if (cutText)
+ XFree(cutText);
+ cutText = 0;
+ if (XVncExtGetClientCutText(dpy, &cutText, &cutTextLen)) {
+ vlog.debug("Got client cut text: '%.*s%s'",
+ cutTextLen<9?cutTextLen:8, cutText,
+ cutTextLen<9?"":"...");
+ XStoreBytes(dpy, cutText, cutTextLen);
+ ownSelection(XA_PRIMARY, cutEv->time);
+ ownSelection(xaCLIPBOARD, cutEv->time);
+ delete [] selection[0];
+ delete [] selection[1];
+ selection[0] = selection[1] = 0;
+ selectionLen[0] = selectionLen[1] = 0;
+ }
+ }
+ }
+ if (sendClipboard.checked()) {
+ if (ev->type == vncExtEventBase + VncExtSelectionChangeNotify) {
+ vlog.debug("selection change event");
+ XVncExtSelectionChangeEvent* selEv = (XVncExtSelectionChangeEvent*)ev;
+ if (selEv->selection == xaCLIPBOARD ||
+ (selEv->selection == XA_PRIMARY && sendPrimaryCB.checked())) {
+ if (!selectionOwner(selEv->selection))
+ XConvertSelection(dpy, selEv->selection, XA_STRING,
+ selEv->selection, win(), CurrentTime);
+ }
+ }
+ }
+ if (ev->type == vncExtEventBase + VncExtQueryConnectNotify) {
+ vlog.debug("query connection event");
+ if (queryConnectDialog)
+ delete queryConnectDialog;
+ queryConnectDialog = 0;
+ char* qcAddress;
+ char* qcUser;
+ int qcTimeout;
+ if (XVncExtGetQueryConnect(dpy, &qcAddress, &qcUser,
+ &qcTimeout, &queryConnectId)) {
+ if (qcTimeout)
+ queryConnectDialog = new QueryConnectDialog(dpy, qcAddress,
+ qcUser, qcTimeout,
+ this);
+ if (queryConnectDialog)
+ queryConnectDialog->map();
+ XFree(qcAddress);
+ XFree(qcUser);
+ }
+ }
+ }
+
+
+ // selectionRequest() is called when we are the selection owner and another X
+ // client has requested the selection. We simply put the server's cut text
+ // into the requested property. TXWindow will handle the rest.
+ bool selectionRequest(Window requestor, Atom selection, Atom property)
+ {
+ if (cutText)
+ XChangeProperty(dpy, requestor, property, XA_STRING, 8,
+ PropModeReplace, (unsigned char*)cutText,
+ cutTextLen);
+ return cutText;
+ }
+
+ // selectionNotify() is called when we have requested the selection from the
+ // selection owner.
+ void selectionNotify(XSelectionEvent* ev, Atom type, int format,
+ int nitems, void* data)
+ {
+ if (ev->requestor != win() || ev->target != XA_STRING)
+ return;
+
+ if (data && format == 8) {
+ int i = (ev->selection == XA_PRIMARY ? 0 : 1);
+ if (selectionLen[i] == nitems && memcmp(selection[i], data, nitems) == 0)
+ return;
+ delete [] selection[i];
+ selection[i] = new char[nitems];
+ memcpy(selection[i], data, nitems);
+ selectionLen[i] = nitems;
+ if (cutTextLen == nitems && memcmp(cutText, data, nitems) == 0) {
+ vlog.debug("ignoring duplicate cut text");
+ return;
+ }
+ if (cutText)
+ XFree(cutText);
+ cutText = (char*)malloc(nitems); // assuming XFree() same as free()
+ memcpy(cutText, data, nitems);
+ cutTextLen = nitems;
+ vlog.debug("sending %s selection as server cut text: '%.*s%s'",
+ selectionName(ev->selection),cutTextLen<9?cutTextLen:8,
+ cutText, cutTextLen<9?"":"...");
+ XVncExtSetServerCutText(dpy, cutText, cutTextLen);
+ }
+ }
+
+ // TXDeleteWindowCallback method
+ virtual void deleteWindow(TXWindow* w) {
+ exit(1);
+ }
+
+ // TXCheckboxCallback method
+ virtual void checkboxSelect(TXCheckbox* checkbox) {
+ if (checkbox == &acceptClipboard) {
+ XVncExtSetParam(dpy, (acceptClipboard.checked()
+ ? ACCEPT_CUT_TEXT "=1" : ACCEPT_CUT_TEXT "=0"));
+ } else if (checkbox == &sendClipboard) {
+ XVncExtSetParam(dpy, (sendClipboard.checked()
+ ? SEND_CUT_TEXT "=1" : SEND_CUT_TEXT "=0"));
+ sendPrimaryCB.disabled(!sendClipboard.checked());
+ }
+ }
+
+ // rfb::Timer::Callback interface
+ virtual bool handleTimeout(rfb::Timer* timer) {
+ if (sendPrimaryCB.checked() && !selectionOwner(XA_PRIMARY))
+ XConvertSelection(dpy, XA_PRIMARY, XA_STRING,
+ XA_PRIMARY, win(), CurrentTime);
+ if (!selectionOwner(xaCLIPBOARD))
+ XConvertSelection(dpy, xaCLIPBOARD, XA_STRING,
+ xaCLIPBOARD, win(), CurrentTime);
+ return true;
+ }
+
+ // QueryResultCallback interface
+ virtual void queryApproved() {
+ XVncExtApproveConnect(dpy, queryConnectId, 1);
+ }
+ virtual void queryRejected() {
+ XVncExtApproveConnect(dpy, queryConnectId, 0);
+ }
+
+private:
+ char* cutText;
+ int cutTextLen;
+ char* selection[2];
+ int selectionLen[2];
+ TXCheckbox acceptClipboard, sendClipboard, sendPrimaryCB;
+ rfb::Timer pollTimer;
+
+ QueryConnectDialog* queryConnectDialog;
+ void* queryConnectId;
+};
+
+static void usage()
+{
+ fprintf(stderr,"usage: %s [parameters]\n",
+ programName);
+ fprintf(stderr," %s [parameters] -connect <host>[:<port>]\n",
+ programName);
+ fprintf(stderr," %s [parameters] -disconnect\n", programName);
+ fprintf(stderr," %s [parameters] [-set] <Xvnc-param>=<value> ...\n",
+ programName);
+ fprintf(stderr," %s [parameters] -list\n", programName);
+ fprintf(stderr," %s [parameters] -get <param>\n", programName);
+ fprintf(stderr," %s [parameters] -desc <param>\n",programName);
+ 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");
+ Configuration::listParams(79, 14);
+ exit(1);
+}
+
+void removeArgs(int* argc, char** argv, int first, int n)
+{
+ if (first + n > *argc) return;
+ for (int i = first + n; i < *argc; i++)
+ argv[i-n] = argv[i];
+ *argc -= n;
+}
+
+int main(int argc, char** argv)
+{
+ programName = argv[0];
+ rfb::initStdIOLoggers();
+ rfb::LogWriter::setLogParams("*:stderr:30");
+
+ // Process vncconfig's own parameters first, then we process the
+ // other arguments when we have the X display.
+ int i;
+ for (i = 1; i < argc; i++) {
+ if (Configuration::setParam(argv[i]))
+ continue;
+
+ if (argv[i][0] == '-' && i+1 < argc &&
+ Configuration::setParam(&argv[i][1], argv[i+1])) {
+ i++;
+ continue;
+ }
+ break;
+ }
+
+ CharArray displaynameStr(displayname.getData());
+ if (!(dpy = XOpenDisplay(displaynameStr.buf))) {
+ fprintf(stderr,"%s: unable to open display \"%s\"\n",
+ programName, XDisplayName(displaynameStr.buf));
+ exit(1);
+ }
+
+ if (!XVncExtQueryExtension(dpy, &vncExtEventBase, &vncExtErrorBase)) {
+ fprintf(stderr,"No VNC extension on display %s\n",
+ XDisplayName(displaynameStr.buf));
+ exit(1);
+ }
+
+ if (i < argc) {
+ for (; i < argc; i++) {
+ if (strcmp(argv[i], "-connect") == 0) {
+ i++;
+ if (i >= argc) usage();
+ if (!XVncExtConnect(dpy, argv[i])) {
+ fprintf(stderr,"connecting to %s failed\n",argv[i]);
+ }
+ } else if (strcmp(argv[i], "-disconnect") == 0) {
+ if (!XVncExtConnect(dpy, "")) {
+ fprintf(stderr,"disconnecting all clients failed\n");
+ }
+ } else if (strcmp(argv[i], "-get") == 0) {
+ i++;
+ if (i >= argc) usage();
+ char* data;
+ int len;
+ if (XVncExtGetParam(dpy, argv[i], &data, &len)) {
+ printf("%.*s\n",len,data);
+ } else {
+ fprintf(stderr,"getting param %s failed\n",argv[i]);
+ }
+ XFree(data);
+ } else if (strcmp(argv[i], "-desc") == 0) {
+ i++;
+ if (i >= argc) usage();
+ char* desc = XVncExtGetParamDesc(dpy, argv[i]);
+ if (desc) {
+ printf("%s\n",desc);
+ } else {
+ fprintf(stderr,"getting description for param %s failed\n",argv[i]);
+ }
+ XFree(desc);
+ } else if (strcmp(argv[i], "-list") == 0) {
+ int nParams;
+ char** list = XVncExtListParams(dpy, &nParams);
+ for (int i = 0; i < nParams; i++) {
+ printf("%s\n",list[i]);
+ }
+ XVncExtFreeParamList(list);
+ } else if (strcmp(argv[i], "-set") == 0) {
+ i++;
+ if (i >= argc) usage();
+ if (!XVncExtSetParam(dpy, argv[i])) {
+ fprintf(stderr,"setting param %s failed\n",argv[i]);
+ }
+ } else if (XVncExtSetParam(dpy, argv[i])) {
+ fprintf(stderr,"set parameter %s\n",argv[i]);
+ } else {
+ usage();
+ }
+ }
+
+ return 0;
+ }
+
+ try {
+ TXWindow::init(dpy,"Vncconfig");
+
+ VncConfigWindow w(dpy);
+ if (!noWindow) w.map();
+
+ while (true) {
+ struct timeval tv;
+ struct timeval* tvp = 0;
+
+ // Process any incoming X events
+ TXWindow::handleXEvents(dpy);
+
+ // Process expired timers and get the time until the next one
+ int timeoutMs = Timer::checkTimeouts();
+ if (timeoutMs) {
+ tv.tv_sec = timeoutMs / 1000;
+ tv.tv_usec = (timeoutMs % 1000) * 1000;
+ tvp = &tv;
+ }
+
+ // If there are X requests pending then poll, don't wait!
+ if (XPending(dpy)) {
+ tv.tv_usec = tv.tv_sec = 0;
+ tvp = &tv;
+ }
+
+ // Wait for X events, VNC traffic, or the next timer expiry
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ FD_SET(ConnectionNumber(dpy), &rfds);
+ int n = select(FD_SETSIZE, &rfds, 0, 0, tvp);
+ if (n < 0) throw rdr::SystemException("select",errno);
+ }
+
+ XCloseDisplay(dpy);
+
+ } catch (rdr::Exception &e) {
+ vlog.error(e.str());
+ }
+
+ return 0;
+}