("QueryConnect",
"Prompt the local user to accept or reject incoming connections.",
false);
-
+rfb::IntParameter rfb::Server::queryConnectTimeout
+("QueryConnectTimeout",
+ "Number of seconds to show the Accept Connection dialog before "
+ "rejecting the connection",
+ 10);
static BoolParameter sendCutText;
static BoolParameter acceptSetDesktopSize;
static BoolParameter queryConnect;
+ static IntParameter queryConnectTimeout;
};
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2009-2014 Pierre Ossman for Cendio AB
+ * Copyright 2009-2015 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
bool reverse)
- : SConnection(reverse), sock(s), inProcessMessages(false),
+ : SConnection(reverse), sock(s),
+ queryConnectTimer(this), inProcessMessages(false),
pendingSyncFence(false), syncFence(false), fenceFlags(0),
fenceDataLen(0), fenceData(NULL),
baseRTT(-1), minRTT(-1), seenCongestion(false), pingCounter(0),
CharArray reason;
VNCServerST::queryResult qr = server->queryConnection(sock, userName,
&reason.buf);
- if (qr == VNCServerST::PENDING)
+ if (qr == VNCServerST::PENDING) {
+ queryConnectTimer.start(rfb::Server::queryConnectTimeout * 1000);
return;
+ }
// - If server returns ACCEPT/REJECT then pass result to SConnection
approveConnection(qr == VNCServerST::ACCEPT, reason.buf);
writeFramebufferUpdate();
else if (t == &congestionTimer)
updateCongestion();
+ else if (t == &queryConnectTimer) {
+ if (state() == RFBSTATE_QUERYING)
+ approveConnection(false, "The attempt to prompt the user to accept the connection failed");
+ }
} catch (rdr::Exception& e) {
close(e.str());
}
network::Socket* sock;
CharArray peerEndpoint;
+ Timer queryConnectTimer;
+
bool inProcessMessages;
bool pendingSyncFence, syncFence;
--- /dev/null
+/* Copyright (C) 2009 TightVNC Team
+ * Copyright (C) 2009, 2014 Red Hat, Inc.
+ * Copyright 2013-2015 Pierre Ossman for Cendio AB
+ *
+ * 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "xorg-version.h"
+
+#include "Input.h"
+#include "vncExtInit.h"
+
+#include "inputstr.h"
+#if XORG >= 110
+#include "inpututils.h"
+#endif
+#include "mi.h"
+#if XORG >= 16
+#include "exevents.h"
+#endif
+#if XORG == 16
+extern void
+CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master);
+#endif
+#if XORG >= 17
+#include "xkbsrv.h"
+#include "xkbstr.h"
+#include "xserver-properties.h"
+extern _X_EXPORT DevPrivateKey CoreDevicePrivateKey;
+#endif
+#include <X11/keysym.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#define BUTTONS 7
+
+/* Event queue is shared between all devices. */
+#if XORG == 15
+static xEvent *eventq = NULL;
+#elif XORG < 111
+static EventList *eventq = NULL;
+#endif
+
+DeviceIntPtr vncKeyboardDev;
+DeviceIntPtr vncPointerDev;
+
+static int oldButtonMask;
+static int cursorPosX, cursorPosY;
+
+static KeySym pressedKeys[256];
+
+#if XORG < 17
+extern void vncGetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap);
+#endif
+
+static int vncPointerProc(DeviceIntPtr pDevice, int onoff);
+static void vncKeyboardBell(int percent, DeviceIntPtr device,
+ void * ctrl, int class);
+static int vncKeyboardProc(DeviceIntPtr pDevice, int onoff);
+
+#define LOG_NAME "Input"
+
+#define LOG_ERROR(...) vncLogError(LOG_NAME, __VA_ARGS__)
+#define LOG_STATUS(...) vncLogStatus(LOG_NAME, __VA_ARGS__)
+#define LOG_INFO(...) vncLogInfo(LOG_NAME, __VA_ARGS__)
+#define LOG_DEBUG(...) vncLogDebug(LOG_NAME, __VA_ARGS__)
+
+/*
+ * Init input device.
+ * This has to be called after core pointer/keyboard
+ * initialization which unfortunately is after extesions
+ * initialization (which means we cannot call it in
+ * vncExtensionInit(). Check InitExtensions(),
+ * InitCoreDevices() and InitInput() calls in dix/main.c.
+ * Instead we call it from XserverDesktop at an appropriate
+ * time.
+ */
+void vncInitInputDevice(void)
+{
+ int i, ret;
+
+ if ((vncPointerDev != NULL) || (vncKeyboardDev != NULL))
+ return;
+
+ for (i = 0;i < 256;i++)
+ pressedKeys[i] = NoSymbol;
+
+#if XORG < 17
+ vncPointerDev = AddInputDevice(
+#if XORG >= 16
+ serverClient,
+#endif
+ vncPointerProc, TRUE);
+ RegisterPointerDevice(vncPointerDev);
+
+ vncKeyboardDev = AddInputDevice(
+#if XORG >= 16
+ serverClient,
+#endif
+ vncKeyboardProc, TRUE);
+ RegisterKeyboardDevice(vncKeyboardDev);
+
+ if (ActivateDevice(vncPointerDev) != Success ||
+ ActivateDevice(vncKeyboardDev) != Success)
+ FatalError("Failed to activate TigerVNC devices\n");
+
+ if (!EnableDevice(vncPointerDev) ||
+ !EnableDevice(vncKeyboardDev))
+ FatalError("Failed to enable TigerVNC devices\n");
+#else /* < 17 */
+ ret = AllocDevicePair(serverClient, "TigerVNC",
+ &vncPointerDev, &vncKeyboardDev,
+ vncPointerProc, vncKeyboardProc,
+ FALSE);
+
+ if (ret != Success)
+ FatalError("Failed to initialize TigerVNC input devices\n");
+
+ if (ActivateDevice(vncPointerDev, TRUE) != Success ||
+ ActivateDevice(vncKeyboardDev, TRUE) != Success)
+ FatalError("Failed to activate TigerVNC devices\n");
+
+ if (!EnableDevice(vncPointerDev, TRUE) ||
+ !EnableDevice(vncKeyboardDev, TRUE))
+ FatalError("Failed to activate TigerVNC devices\n");
+#endif /* 17 */
+
+#if XORG < 111
+ /* eventq is never free()-ed because it exists during server life. */
+ if (eventq == NULL) {
+#if XORG == 15
+ eventq = (xEvent *)xcalloc(sizeof(xEvent),
+ GetMaximumEventsNum());
+ if (!eventq)
+ FatalError("Couldn't allocate eventq\n");
+#else
+ GetEventList(&eventq);
+#endif
+ }
+#endif
+
+ vncPrepareInputDevices();
+}
+
+void vncPointerButtonAction(int buttonMask)
+{
+ int i;
+#if XORG < 111
+ int n;
+#endif
+#if XORG >= 110
+ ValuatorMask mask;
+#endif
+
+ for (i = 0; i < BUTTONS; i++) {
+ if ((buttonMask ^ oldButtonMask) & (1 << i)) {
+ int action = (buttonMask & (1<<i)) ?
+ ButtonPress : ButtonRelease;
+#if XORG < 110
+ n = GetPointerEvents(eventq, vncPointerDev,
+ action, i + 1,
+ POINTER_RELATIVE, 0, 0, NULL);
+ enqueueEvents(vncPointerDev, n);
+#elif XORG < 111
+ valuator_mask_set_range(&mask, 0, 0, NULL);
+ n = GetPointerEvents(eventq, vncPointerDev,
+ action, i + 1,
+ POINTER_RELATIVE, &mask);
+ enqueueEvents(vncPointerDev, n);
+#else
+ valuator_mask_set_range(&mask, 0, 0, NULL);
+ QueuePointerEvents(vncPointerDev, action, i + 1,
+ POINTER_RELATIVE, &mask);
+#endif
+ }
+ }
+
+ oldButtonMask = buttonMask;
+}
+
+void vncPointerMove(int x, int y)
+{
+ int valuators[2];
+#if XORG < 111
+ int n;
+#endif
+#if XORG >= 110
+ ValuatorMask mask;
+#endif
+
+ if (cursorPosX == x && cursorPosY == y)
+ return;
+
+ valuators[0] = x;
+ valuators[1] = y;
+#if XORG < 110
+ n = GetPointerEvents(eventq, vncPointerDev, MotionNotify, 0,
+ POINTER_ABSOLUTE, 0, 2, valuators);
+ enqueueEvents(vncPointerDev, n);
+#elif XORG < 111
+ valuator_mask_set_range(&mask, 0, 2, valuators);
+ n = GetPointerEvents(eventq, vncPointerDev, MotionNotify, 0,
+ POINTER_ABSOLUTE, &mask);
+ enqueueEvents(vncPointerDev, n);
+#else
+ valuator_mask_set_range(&mask, 0, 2, valuators);
+ QueuePointerEvents(vncPointerDev, MotionNotify, 0,
+ POINTER_ABSOLUTE, &mask);
+#endif
+
+ cursorPosX = x;
+ cursorPosY = y;
+}
+
+void vncGetPointerPos(int *x, int *y)
+{
+ if (vncPointerDev != NULL)
+ GetSpritePosition(vncPointerDev, &cursorPosX, &cursorPosY);
+
+ *x = cursorPosX;
+ *y = cursorPosY;
+}
+
+#if XORG < 111
+static void enqueueEvents(DeviceIntPtr dev, int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++) {
+ /*
+ * Passing arguments in global variable eventq is probably not
+ * good programming practise but in this case it is safe and
+ * clear.
+ */
+ mieqEnqueue(dev,
+#if XORG == 15
+ eventq + i
+#elif XORG == 16
+ (eventq + i)->event
+#else
+ (InternalEvent *) (eventq + i)->event
+#endif
+ );
+ }
+}
+#endif /* XORG < 111 */
+
+static int vncPointerProc(DeviceIntPtr pDevice, int onoff)
+{
+ BYTE map[BUTTONS + 1];
+ DevicePtr pDev = (DevicePtr)pDevice;
+ int i;
+#if XORG >= 17
+ /*
+ * NOTE: map[] array is one element longer than btn_labels[] array. This
+ * is not a bug.
+ */
+ Atom btn_labels[BUTTONS];
+ Atom axes_labels[2];
+#endif
+
+ switch (onoff) {
+ case DEVICE_INIT:
+ for (i = 0; i < BUTTONS + 1; i++)
+ map[i] = i;
+
+#if XORG >= 17
+ btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
+ btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
+ btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
+ btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
+ btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
+ btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
+ btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
+
+ axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
+ axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
+#endif
+
+ InitPointerDeviceStruct(pDev, map, BUTTONS,
+#if XORG == 15
+ GetMotionHistory,
+#elif XORG >= 17
+ btn_labels,
+#endif
+ (PtrCtrlProcPtr)NoopDDA,
+ GetMotionHistorySize(), 2
+#if XORG >= 17
+ , axes_labels
+#endif
+ );
+ break;
+ case DEVICE_ON:
+ pDev->on = TRUE;
+ break;
+ case DEVICE_OFF:
+ pDev->on = FALSE;
+ break;
+ case DEVICE_CLOSE:
+ vncPointerDev = NULL;
+ break;
+ }
+
+ return Success;
+}
+
+static void vncKeyboardBell(int percent, DeviceIntPtr device,
+ void * ctrl, int class)
+{
+ if (percent > 0)
+ vncBell();
+}
+
+static int vncKeyboardProc(DeviceIntPtr pDevice, int onoff)
+{
+#if XORG < 17
+ KeySymsRec keySyms;
+ CARD8 modMap[MAP_LENGTH];
+#endif
+ DevicePtr pDev = (DevicePtr)pDevice;
+
+ switch (onoff) {
+ case DEVICE_INIT:
+#if XORG < 17
+ vncGetInitKeyboardMap(&keySyms, modMap);
+#endif
+ InitKeyboardDeviceStruct(
+#if XORG >= 17
+ pDevice, NULL,
+#else
+ pDev, &keySyms, modMap,
+#endif
+ vncKeyboardBell,
+ (KbdCtrlProcPtr)NoopDDA);
+ break;
+ case DEVICE_ON:
+ pDev->on = TRUE;
+ break;
+ case DEVICE_OFF:
+ pDev->on = FALSE;
+ break;
+ case DEVICE_CLOSE:
+ vncKeyboardDev = NULL;
+ break;
+ }
+
+ return Success;
+}
+
+static inline void pressKey(DeviceIntPtr dev, int kc, Bool down, const char *msg)
+{
+ int action;
+#if XORG < 111
+ unsigned int n;
+#endif
+
+ if (msg != NULL)
+ LOG_DEBUG("%s %d %s", msg, kc, down ? "down" : "up");
+
+ action = down ? KeyPress : KeyRelease;
+#if XORG < 111
+ n = GetKeyboardEvents(eventq, dev, action, kc);
+ enqueueEvents(dev, n);
+#else
+ QueueKeyboardEvents(dev, action, kc, NULL);
+#endif
+}
+
+/* altKeysym is a table of alternative keysyms which have the same meaning. */
+
+static struct altKeysym_t {
+ KeySym a, b;
+} 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 },
+ { XK_ISO_Level3_Shift, XK_Mode_switch },
+};
+
+/*
+ * vncKeyboardEvent() - work out the best keycode corresponding to the keysym
+ * sent by the viewer. This is basically impossible in the general case, but
+ * we make a best effort by assuming that all useful keysyms can be reached
+ * using just the Shift and Level 3 (AltGr) modifiers. For core keyboards this
+ * is basically always true, and should be true for most sane, western XKB
+ * layouts.
+ */
+void vncKeyboardEvent(KeySym keysym, int down)
+{
+ int i;
+ unsigned state, new_state;
+ KeyCode keycode;
+
+ unsigned level_three_mask;
+ KeyCode shift_press, level_three_press;
+ KeyCode shift_release[8], level_three_release[8];
+ size_t shift_release_count, level_three_release_count;
+
+ /*
+ * Release events must match the press event, so look up what
+ * keycode we sent for the press.
+ */
+ if (!down) {
+ for (i = 0;i < 256;i++) {
+ if (pressedKeys[i] == keysym) {
+ pressedKeys[i] = NoSymbol;
+ pressKey(vncKeyboardDev, i, FALSE, "keycode");
+ mieqProcessInputEvents();
+ return;
+ }
+ }
+
+ /*
+ * This can happen quite often as we ignore some
+ * key presses.
+ */
+ LOG_DEBUG("Unexpected release of keysym 0x%x", keysym);
+ return;
+ }
+
+ /*
+ * Since we are checking the current state to determine if we need
+ * to fake modifiers, we must make sure that everything put on the
+ * input queue is processed before we start. Otherwise, shift may be
+ * stuck down.
+ */
+ mieqProcessInputEvents();
+
+ state = vncGetKeyboardState();
+
+ keycode = vncKeysymToKeycode(keysym, state, &new_state);
+
+ /* Try some equivalent keysyms if we couldn't find a perfect match */
+ if (keycode == 0) {
+ for (i = 0;i < sizeof(altKeysym)/sizeof(altKeysym[0]);i++) {
+ KeySym altsym;
+
+ if (altKeysym[i].a == keysym)
+ altsym = altKeysym[i].b;
+ else if (altKeysym[i].b == keysym)
+ altsym = altKeysym[i].a;
+ else
+ continue;
+
+ keycode = vncKeysymToKeycode(altsym, state, &new_state);
+ if (keycode != 0)
+ break;
+ }
+ }
+
+ /* We don't have lock synchronisation... */
+ if (vncIsLockModifier(keycode, new_state)) {
+ LOG_DEBUG("Ignoring lock key (e.g. caps lock)");
+ return;
+ }
+
+ /* No matches. Will have to add a new entry... */
+ if (keycode == 0) {
+ keycode = vncAddKeysym(keysym, state);
+ if (keycode == 0) {
+ LOG_ERROR("Failure adding new keysym 0x%x", keysym);
+ return;
+ }
+
+ LOG_INFO("Added unknown keysym 0x%x to keycode %d",
+ keysym, keycode);
+
+ /*
+ * The state given to addKeysym() is just a hint and
+ * the actual result might still require some state
+ * changes.
+ */
+ keycode = vncKeysymToKeycode(keysym, state, &new_state);
+ if (keycode == 0) {
+ LOG_ERROR("Newly added keysym 0x%x cannot be generated", keysym);
+ return;
+ }
+ }
+
+ /*
+ * X11 generally lets shift toggle the keys on the numeric pad
+ * the same way NumLock does. This is however not the case on
+ * other systems like Windows. As a result, some applications
+ * get confused when we do a fake shift to get the same effect
+ * that having NumLock active would produce.
+ *
+ * Until we have proper NumLock synchronisation (so we can
+ * avoid faking shift), we try to avoid the fake shifts if we
+ * can use an alternative keysym.
+ */
+ if (((state & ShiftMask) != (new_state & ShiftMask)) &&
+ vncGetAvoidShiftNumLock() && vncIsAffectedByNumLock(keycode)) {
+ KeyCode keycode2;
+ unsigned new_state2;
+
+ LOG_DEBUG("Finding alternative to keysym 0x%x to avoid fake shift for numpad", keysym);
+
+ for (i = 0;i < sizeof(altKeysym)/sizeof(altKeysym[0]);i++) {
+ KeySym altsym;
+
+ if (altKeysym[i].a == keysym)
+ altsym = altKeysym[i].b;
+ else if (altKeysym[i].b == keysym)
+ altsym = altKeysym[i].a;
+ else
+ continue;
+
+ keycode2 = vncKeysymToKeycode(altsym, state, &new_state2);
+ if (keycode2 == 0)
+ continue;
+
+ if (((state & ShiftMask) != (new_state2 & ShiftMask)) &&
+ vncIsAffectedByNumLock(keycode2))
+ continue;
+
+ break;
+ }
+
+ if (i == sizeof(altKeysym)/sizeof(altKeysym[0]))
+ LOG_DEBUG("No alternative keysym found");
+ else {
+ keycode = keycode2;
+ new_state = new_state2;
+ }
+ }
+
+ /*
+ * "Shifted Tab" is a bit of a mess. Some systems have varying,
+ * special keysyms for this symbol. VNC mandates that clients
+ * should always send the plain XK_Tab keysym and the server
+ * should deduce the meaning based on current Shift state.
+ * To comply with this, we will find the keycode that sends
+ * XK_Tab, and make sure that Shift isn't cleared. This can
+ * possibly result in a different keysym than XK_Tab, but that
+ * is the desired behaviour.
+ *
+ * Note: We never get ISO_Left_Tab here because it's already
+ * been translated in VNCSConnectionST.
+ */
+ if (keysym == XK_Tab && (state & ShiftMask))
+ new_state |= ShiftMask;
+
+ /*
+ * We need a bigger state change than just shift,
+ * so we need to know what the mask is for level 3 shifts.
+ */
+ if ((new_state & ~ShiftMask) != (state & ~ShiftMask))
+ level_three_mask = vncGetLevelThreeMask();
+ else
+ level_three_mask = 0;
+
+ shift_press = level_three_press = 0;
+ shift_release_count = level_three_release_count = 0;
+
+ /* Need a fake press or release of shift? */
+ if (!(state & ShiftMask) && (new_state & ShiftMask)) {
+ shift_press = vncPressShift();
+ if (shift_press == 0) {
+ LOG_ERROR("Unable to find a modifier key for Shift");
+ return;
+ }
+
+ pressKey(vncKeyboardDev, shift_press, TRUE, "temp shift");
+ } else if ((state & ShiftMask) && !(new_state & ShiftMask)) {
+ shift_release_count = vncReleaseShift(shift_release,
+ sizeof(shift_release)/sizeof(*shift_release));
+ if (shift_release_count == 0) {
+ LOG_ERROR("Unable to find the modifier key(s) for releasing Shift");
+ return;
+ }
+
+ for (i = 0;i < shift_release_count;i++)
+ pressKey(vncKeyboardDev, shift_release[i], FALSE, "temp shift");
+ }
+
+ /* Need a fake press or release of level three shift? */
+ if (!(state & level_three_mask) && (new_state & level_three_mask)) {
+ level_three_press = vncPressLevelThree();
+ if (level_three_press == 0) {
+ LOG_ERROR("Unable to find a modifier key for ISO_Level3_Shift/Mode_Switch");
+ return;
+ }
+
+ pressKey(vncKeyboardDev, level_three_press, TRUE, "temp level 3 shift");
+ } else if ((state & level_three_mask) && !(new_state & level_three_mask)) {
+ level_three_release_count = vncReleaseLevelThree(level_three_release,
+ sizeof(level_three_release)/sizeof(*level_three_release));
+ if (level_three_release_count == 0) {
+ LOG_ERROR("Unable to find the modifier key(s) for releasing ISO_Level3_Shift/Mode_Switch");
+ return;
+ }
+
+ for (i = 0;i < level_three_release_count;i++)
+ pressKey(vncKeyboardDev, level_three_release[i], FALSE, "temp level 3 shift");
+ }
+
+ /* Now press the actual key */
+ pressKey(vncKeyboardDev, keycode, TRUE, "keycode");
+
+ /* And store the mapping so that we can do a proper release later */
+ for (i = 0;i < 256;i++) {
+ if (i == keycode)
+ continue;
+ if (pressedKeys[i] == keysym) {
+ LOG_ERROR("Keysym 0x%x generated by both keys %d and %d", keysym, i, keycode);
+ pressedKeys[i] = NoSymbol;
+ }
+ }
+
+ pressedKeys[keycode] = keysym;
+
+ /* Undo any fake level three shift */
+ if (level_three_press != 0)
+ pressKey(vncKeyboardDev, level_three_press, FALSE, "temp level 3 shift");
+ else if (level_three_release_count != 0) {
+ for (i = 0;i < level_three_release_count;i++)
+ pressKey(vncKeyboardDev, level_three_release[i], TRUE, "temp level 3 shift");
+ }
+
+ /* Undo any fake shift */
+ if (shift_press != 0)
+ pressKey(vncKeyboardDev, shift_press, FALSE, "temp shift");
+ else if (shift_release_count != 0) {
+ for (i = 0;i < shift_release_count;i++)
+ pressKey(vncKeyboardDev, shift_release[i], TRUE, "temp shift");
+ }
+
+ /*
+ * When faking a modifier we are putting a keycode (which can
+ * currently activate the desired modifier) on the input
+ * queue. A future modmap change can change the mapping so
+ * that this keycode means something else entirely. Guard
+ * against this by processing the queue now.
+ */
+ mieqProcessInputEvents();
+}
+++ /dev/null
-/* Copyright (C) 2009 TightVNC Team
- * Copyright (C) 2009, 2014 Red Hat, Inc.
- * Copyright 2013 Pierre Ossman for Cendio AB
- *
- * 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.
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <rfb/LogWriter.h>
-#include "Input.h"
-#include "xorg-version.h"
-#include "vncExtInit.h"
-
-extern "C" {
-#define public c_public
-#define class c_class
-#include "inputstr.h"
-#if XORG >= 110
-#include "inpututils.h"
-#endif
-#include "mi.h"
-#if XORG >= 16
-#include "exevents.h"
-#endif
-#if XORG == 16
-extern void
-CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master);
-#endif
-#if XORG >= 17
-#include "xkbsrv.h"
-#include "xkbstr.h"
-#include "xserver-properties.h"
-extern _X_EXPORT DevPrivateKey CoreDevicePrivateKey;
-#endif
-#include <X11/keysym.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#undef public
-#undef class
-}
-
-#if XORG >= 110
-#define Xfree free
-#endif
-
-using namespace rdr;
-using namespace rfb;
-
-static LogWriter vlog("Input");
-
-rfb::BoolParameter avoidShiftNumLock("AvoidShiftNumLock", "Avoid fake Shift presses for keys affected by NumLock.", true);
-
-#define BUTTONS 7
-
-class InputDevice *vncInputDevice;
-InputDevice InputDevice::singleton;
-
-/* Event queue is shared between all devices. */
-#if XORG == 15
-static xEvent *eventq = NULL;
-#elif XORG < 111
-static EventList *eventq = NULL;
-#endif
-
-#if XORG < 111
-static void initEventq(void)
-{
- /* eventq is never free()-ed because it exists during server life. */
- if (eventq == NULL) {
-#if XORG == 15
- eventq = (xEvent *)xcalloc(sizeof(xEvent),
- GetMaximumEventsNum());
- if (!eventq)
- FatalError("Couldn't allocate eventq\n");
-#else
- GetEventList(&eventq);
-#endif
- }
-}
-#endif /* XORG < 111 */
-
-#if XORG < 111
-static void enqueueEvents(DeviceIntPtr dev, int n)
-{
- int i;
-
- for (i = 0; i < n; i++) {
- /*
- * Passing arguments in global variable eventq is probably not
- * good programming practise but in this case it is safe and
- * clear.
- */
- mieqEnqueue(dev,
-#if XORG == 15
- eventq + i
-#elif XORG == 16
- (eventq + i)->event
-#else
- (InternalEvent *) (eventq + i)->event
-#endif
- );
- }
-}
-#endif /* XORG < 111 */
-
-InputDevice::InputDevice()
- : oldButtonMask(0)
-{
- int i;
-
- vncInputDevice = this;
-
- for (i = 0;i < 256;i++)
- pressedKeys[i] = NoSymbol;
-}
-
-void InputDevice::PointerButtonAction(int buttonMask)
-{
- int i;
-#if XORG < 111
- int n;
-#endif
-#if XORG >= 110
- ValuatorMask mask;
-#endif
-
- for (i = 0; i < BUTTONS; i++) {
- if ((buttonMask ^ oldButtonMask) & (1 << i)) {
- int action = (buttonMask & (1<<i)) ?
- ButtonPress : ButtonRelease;
-#if XORG < 110
- n = GetPointerEvents(eventq, pointerDev, action, i + 1,
- POINTER_RELATIVE, 0, 0, NULL);
- enqueueEvents(pointerDev, n);
-#elif XORG < 111
- valuator_mask_set_range(&mask, 0, 0, NULL);
- n = GetPointerEvents(eventq, pointerDev, action, i + 1,
- POINTER_RELATIVE, &mask);
- enqueueEvents(pointerDev, n);
-#else
- valuator_mask_set_range(&mask, 0, 0, NULL);
- QueuePointerEvents(pointerDev, action, i + 1,
- POINTER_RELATIVE, &mask);
-#endif
- }
- }
-
- oldButtonMask = buttonMask;
-}
-
-void InputDevice::PointerMove(const rfb::Point &pos)
-{
- int valuators[2];
-#if XORG < 111
- int n;
-#endif
-#if XORG >= 110
- ValuatorMask mask;
-#endif
-
- if (pos.equals(cursorPos))
- return;
-
- valuators[0] = pos.x;
- valuators[1] = pos.y;
-#if XORG < 110
- n = GetPointerEvents(eventq, pointerDev, MotionNotify, 0, POINTER_ABSOLUTE, 0,
- 2, valuators);
- enqueueEvents(pointerDev, n);
-#elif XORG < 111
- valuator_mask_set_range(&mask, 0, 2, valuators);
- n = GetPointerEvents(eventq, pointerDev, MotionNotify, 0, POINTER_ABSOLUTE,
- &mask);
- enqueueEvents(pointerDev, n);
-#else
- valuator_mask_set_range(&mask, 0, 2, valuators);
- QueuePointerEvents(pointerDev, MotionNotify, 0, POINTER_ABSOLUTE, &mask);
-#endif
-
- cursorPos = pos;
-}
-
-const rfb::Point &InputDevice::getPointerPos(void)
-{
- if (pointerDev != NULL) {
- int x, y;
-
- GetSpritePosition (pointerDev, &x, &y);
- cursorPos.x = x;
- cursorPos.y = y;
- }
-
- return cursorPos;
-}
-
-int InputDevice::pointerProc(DeviceIntPtr pDevice, int onoff)
-{
- BYTE map[BUTTONS + 1];
- DevicePtr pDev = (DevicePtr)pDevice;
- int i;
-#if XORG >= 17
- /*
- * NOTE: map[] array is one element longer than btn_labels[] array. This
- * is not a bug.
- */
- Atom btn_labels[BUTTONS];
- Atom axes_labels[2];
-#endif
-
- switch (onoff) {
- case DEVICE_INIT:
- for (i = 0; i < BUTTONS + 1; i++)
- map[i] = i;
-
-#if XORG >= 17
- btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
- btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
- btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
- btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
- btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
- btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
- btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
-
- axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
- axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
-#endif
-
- InitPointerDeviceStruct(pDev, map, BUTTONS,
-#if XORG == 15
- GetMotionHistory,
-#elif XORG >= 17
- btn_labels,
-#endif
- (PtrCtrlProcPtr)NoopDDA,
- GetMotionHistorySize(), 2
-#if XORG >= 17
- , axes_labels
-#endif
- );
- break;
- case DEVICE_ON:
- pDev->on = TRUE;
- break;
- case DEVICE_OFF:
- pDev->on = FALSE;
- break;
- case DEVICE_CLOSE:
- singleton.pointerDev = NULL;
- break;
- }
-
- return Success;
-}
-
-static void keyboardBell(int percent, DeviceIntPtr device, void * ctrl,
- int class_)
-{
- if (percent > 0)
- vncBell();
-}
-
-int InputDevice::keyboardProc(DeviceIntPtr pDevice, int onoff)
-{
-#if XORG < 17
- KeySymsRec keySyms;
- CARD8 modMap[MAP_LENGTH];
-#endif
- DevicePtr pDev = (DevicePtr)pDevice;
-
- switch (onoff) {
- case DEVICE_INIT:
-#if XORG < 17
- GetInitKeyboardMap(&keySyms, modMap);
-#endif
- InitKeyboardDeviceStruct(
-#if XORG >= 17
- pDevice, NULL,
-#else
- pDev, &keySyms, modMap,
-#endif
- keyboardBell, (KbdCtrlProcPtr)NoopDDA);
- break;
- case DEVICE_ON:
- pDev->on = TRUE;
- break;
- case DEVICE_OFF:
- pDev->on = FALSE;
- break;
- case DEVICE_CLOSE:
- singleton.keyboardDev = NULL;
- break;
- }
-
- return Success;
-}
-
-void InputDevice::InitInputDevice(void)
-{
- if ((pointerDev != NULL) || (keyboardDev != NULL))
- return;
-
-#if XORG < 17
- pointerDev = AddInputDevice(
-#if XORG >= 16
- serverClient,
-#endif
- pointerProc, TRUE);
- RegisterPointerDevice(pointerDev);
-
- keyboardDev = AddInputDevice(
-#if XORG >= 16
- serverClient,
-#endif
- keyboardProc, TRUE);
- RegisterKeyboardDevice(keyboardDev);
-
- if (ActivateDevice(pointerDev) != Success ||
- ActivateDevice(keyboardDev) != Success)
- FatalError("Failed to activate TigerVNC devices\n");
-
- if (!EnableDevice(pointerDev) ||
- !EnableDevice(keyboardDev))
- FatalError("Failed to enable TigerVNC devices\n");
-#else /* < 17 */
- int ret;
-
- ret = AllocDevicePair(serverClient, "TigerVNC", &pointerDev,
- &keyboardDev, pointerProc, keyboardProc,
- FALSE);
-
- if (ret != Success)
- FatalError("Failed to initialize TigerVNC input devices\n");
-
- if (ActivateDevice(pointerDev, TRUE) != Success ||
- ActivateDevice(keyboardDev, TRUE) != Success)
- FatalError("Failed to activate TigerVNC devices\n");
-
- if (!EnableDevice(pointerDev, TRUE) ||
- !EnableDevice(keyboardDev, TRUE))
- FatalError("Failed to activate TigerVNC devices\n");
-#endif /* 17 */
-
-#if XORG < 111
- initEventq();
-#endif
-
- PrepareInputDevices();
-}
-
-static inline void pressKey(DeviceIntPtr dev, int kc, bool down, const char *msg)
-{
- int action;
-#if XORG < 111
- unsigned int n;
-#endif
-
- if (msg != NULL)
- vlog.debug("%s %d %s", msg, kc, down ? "down" : "up");
-
- action = down ? KeyPress : KeyRelease;
-#if XORG < 111
- n = GetKeyboardEvents(eventq, dev, action, kc);
- enqueueEvents(dev, n);
-#else
- QueueKeyboardEvents(dev, action, kc, NULL);
-#endif
-}
-
-/* altKeysym is a table of alternative keysyms which have the same meaning. */
-
-static struct altKeysym_t {
- KeySym a, b;
-} 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 },
- { XK_ISO_Level3_Shift, XK_Mode_switch },
-};
-
-/*
- * keyEvent() - work out the best keycode corresponding to the keysym sent by
- * the viewer. This is basically impossible in the general case, but we make
- * a best effort by assuming that all useful keysyms can be reached using
- * just the Shift and Level 3 (AltGr) modifiers. For core keyboards this is
- * basically always true, and should be true for most sane, western XKB
- * layouts.
- */
-void InputDevice::keyEvent(rdr::U32 keysym, bool down)
-{
- int i;
- unsigned state, new_state;
- KeyCode keycode;
-
- unsigned level_three_mask;
- KeyCode shift_press, level_three_press;
- std::list<KeyCode> shift_release, level_three_release;
-
- /*
- * Release events must match the press event, so look up what
- * keycode we sent for the press.
- */
- if (!down) {
- for (i = 0;i < 256;i++) {
- if (pressedKeys[i] == keysym) {
- pressedKeys[i] = NoSymbol;
- pressKey(keyboardDev, i, false, "keycode");
- mieqProcessInputEvents();
- return;
- }
- }
-
- /*
- * This can happen quite often as we ignore some
- * key presses.
- */
- vlog.debug("Unexpected release of keysym 0x%x", keysym);
- return;
- }
-
- /*
- * Since we are checking the current state to determine if we need
- * to fake modifiers, we must make sure that everything put on the
- * input queue is processed before we start. Otherwise, shift may be
- * stuck down.
- */
- mieqProcessInputEvents();
-
- state = getKeyboardState();
-
- keycode = keysymToKeycode(keysym, state, &new_state);
-
- /* Try some equivalent keysyms if we couldn't find a perfect match */
- if (keycode == 0) {
- for (i = 0;i < sizeof(altKeysym)/sizeof(altKeysym[0]);i++) {
- KeySym altsym;
-
- if (altKeysym[i].a == keysym)
- altsym = altKeysym[i].b;
- else if (altKeysym[i].b == keysym)
- altsym = altKeysym[i].a;
- else
- continue;
-
- keycode = keysymToKeycode(altsym, state, &new_state);
- if (keycode != 0)
- break;
- }
- }
-
- /* We don't have lock synchronisation... */
- if (isLockModifier(keycode, new_state)) {
- vlog.debug("Ignoring lock key (e.g. caps lock)");
- return;
- }
-
- /* No matches. Will have to add a new entry... */
- if (keycode == 0) {
- keycode = addKeysym(keysym, state);
- if (keycode == 0) {
- vlog.error("Failure adding new keysym 0x%x", keysym);
- return;
- }
-
- vlog.info("Added unknown keysym 0x%x to keycode %d",
- keysym, keycode);
-
- /*
- * The state given to addKeysym() is just a hint and
- * the actual result might still require some state
- * changes.
- */
- keycode = keysymToKeycode(keysym, state, &new_state);
- if (keycode == 0) {
- vlog.error("Newly added keysym 0x%x cannot be generated", keysym);
- return;
- }
- }
-
- /*
- * X11 generally lets shift toggle the keys on the numeric pad
- * the same way NumLock does. This is however not the case on
- * other systems like Windows. As a result, some applications
- * get confused when we do a fake shift to get the same effect
- * that having NumLock active would produce.
- *
- * Until we have proper NumLock synchronisation (so we can
- * avoid faking shift), we try to avoid the fake shifts if we
- * can use an alternative keysym.
- */
- if (((state & ShiftMask) != (new_state & ShiftMask)) &&
- avoidShiftNumLock && isAffectedByNumLock(keycode)) {
- KeyCode keycode2;
- unsigned new_state2;
-
- vlog.debug("Finding alternative to keysym 0x%x to avoid fake shift for numpad", keysym);
-
- for (i = 0;i < sizeof(altKeysym)/sizeof(altKeysym[0]);i++) {
- KeySym altsym;
-
- if (altKeysym[i].a == keysym)
- altsym = altKeysym[i].b;
- else if (altKeysym[i].b == keysym)
- altsym = altKeysym[i].a;
- else
- continue;
-
- keycode2 = keysymToKeycode(altsym, state, &new_state2);
- if (keycode2 == 0)
- continue;
-
- if (((state & ShiftMask) != (new_state2 & ShiftMask)) &&
- isAffectedByNumLock(keycode2))
- continue;
-
- break;
- }
-
- if (i == sizeof(altKeysym)/sizeof(altKeysym[0]))
- vlog.debug("No alternative keysym found");
- else {
- keycode = keycode2;
- new_state = new_state2;
- }
- }
-
- /*
- * "Shifted Tab" is a bit of a mess. Some systems have varying,
- * special keysyms for this symbol. VNC mandates that clients
- * should always send the plain XK_Tab keysym and the server
- * should deduce the meaning based on current Shift state.
- * To comply with this, we will find the keycode that sends
- * XK_Tab, and make sure that Shift isn't cleared. This can
- * possibly result in a different keysym than XK_Tab, but that
- * is the desired behaviour.
- *
- * Note: We never get ISO_Left_Tab here because it's already
- * been translated in VNCSConnectionST.
- */
- if (keysym == XK_Tab && (state & ShiftMask))
- new_state |= ShiftMask;
-
- /*
- * We need a bigger state change than just shift,
- * so we need to know what the mask is for level 3 shifts.
- */
- if ((new_state & ~ShiftMask) != (state & ~ShiftMask))
- level_three_mask = getLevelThreeMask();
- else
- level_three_mask = 0;
-
- shift_press = level_three_press = 0;
-
- /* Need a fake press or release of shift? */
- if (!(state & ShiftMask) && (new_state & ShiftMask)) {
- shift_press = pressShift();
- if (shift_press == 0) {
- vlog.error("Unable to find a modifier key for Shift");
- return;
- }
-
- pressKey(keyboardDev, shift_press, true, "temp shift");
- } else if ((state & ShiftMask) && !(new_state & ShiftMask)) {
- std::list<KeyCode>::const_iterator iter;
-
- shift_release = releaseShift();
- if (shift_release.empty()) {
- vlog.error("Unable to find the modifier key(s) for releasing Shift");
- return;
- }
-
- for (iter = shift_release.begin();iter != shift_release.end();++iter)
- pressKey(keyboardDev, *iter, false, "temp shift");
- }
-
- /* Need a fake press or release of level three shift? */
- if (!(state & level_three_mask) && (new_state & level_three_mask)) {
- level_three_press = pressLevelThree();
- if (level_three_press == 0) {
- vlog.error("Unable to find a modifier key for ISO_Level3_Shift/Mode_Switch");
- return;
- }
-
- pressKey(keyboardDev, level_three_press, true, "temp level 3 shift");
- } else if ((state & level_three_mask) && !(new_state & level_three_mask)) {
- std::list<KeyCode>::const_iterator iter;
-
- level_three_release = releaseLevelThree();
- if (level_three_release.empty()) {
- vlog.error("Unable to find the modifier key(s) for releasing ISO_Level3_Shift/Mode_Switch");
- return;
- }
-
- for (iter = level_three_release.begin();iter != level_three_release.end();++iter)
- pressKey(keyboardDev, *iter, false, "temp level 3 shift");
- }
-
- /* Now press the actual key */
- pressKey(keyboardDev, keycode, true, "keycode");
-
- /* And store the mapping so that we can do a proper release later */
- for (i = 0;i < 256;i++) {
- if (i == keycode)
- continue;
- if (pressedKeys[i] == keysym) {
- vlog.error("Keysym 0x%x generated by both keys %d and %d", keysym, i, keycode);
- pressedKeys[i] = NoSymbol;
- }
- }
-
- pressedKeys[keycode] = keysym;
-
- /* Undo any fake level three shift */
- if (level_three_press != 0)
- pressKey(keyboardDev, level_three_press, false, "temp level 3 shift");
- else if (!level_three_release.empty()) {
- std::list<KeyCode>::const_iterator iter;
- for (iter = level_three_release.begin();iter != level_three_release.end();++iter)
- pressKey(keyboardDev, *iter, true, "temp level 3 shift");
- }
-
- /* Undo any fake shift */
- if (shift_press != 0)
- pressKey(keyboardDev, shift_press, false, "temp shift");
- else if (!shift_release.empty()) {
- std::list<KeyCode>::const_iterator iter;
- for (iter = shift_release.begin();iter != shift_release.end();++iter)
- pressKey(keyboardDev, *iter, true, "temp shift");
- }
-
- /*
- * When faking a modifier we are putting a keycode (which can
- * currently activate the desired modifier) on the input
- * queue. A future modmap change can change the mapping so
- * that this keycode means something else entirely. Guard
- * against this by processing the queue now.
- */
- mieqProcessInputEvents();
-}
/* Copyright (C) 2009 TightVNC Team
* Copyright (C) 2009, 2010 Red Hat, Inc.
* Copyright (C) 2009, 2010 TigerVNC Team
- * Copyright 2013 Pierre Ossman for Cendio AB
+ * Copyright 2013-2015 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#ifndef INPUT_H_
#define INPUT_H_
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <list>
-
-#include <rdr/types.h>
-#include <rfb/Rect.h>
+#include <stdlib.h>
+#include <X11/X.h>
+#ifdef __cplusplus
extern "C" {
-#include "input.h"
-/* The Xorg headers define macros that wreak havoc with STL */
-#undef max
-};
-
-#include "xorg-version.h"
-
-/*
- * Represents input device (keyboard + pointer)
- *
- * Is a singleton as input devices are global in the X server so
- * we do not have one per desktop (i.e. per screen).
- */
-extern class InputDevice *vncInputDevice;
-
-class InputDevice {
-public:
- /*
- * Press or release buttons. Relationship between buttonMask and
- * buttons is specified in RFB protocol.
- */
- void PointerButtonAction(int buttonMask);
-
- /* Move pointer to target location (point coords are absolute). */
- void PointerMove(const rfb::Point &point);
-
- /* Get current known location of the pointer */
- const rfb::Point &getPointerPos(void);
-
- /* Press or release one or more keys to get the given symbol */
- void KeyboardPress(rdr::U32 keysym) { keyEvent(keysym, true); }
- void KeyboardRelease(rdr::U32 keysym) { keyEvent(keysym, false); }
+#endif
- /*
- * Init input device.
- * This has to be called after core pointer/keyboard
- * initialization which unfortunately is after extesions
- * initialization (which means we cannot call it in
- * vncExtensionInit(). Check InitExtensions(),
- * InitCoreDevices() and InitInput() calls in dix/main.c.
- * Instead we call it from XserverDesktop at an appropriate
- * time.
- */
- void InitInputDevice(void);
+void vncInitInputDevice(void);
-private:
- InputDevice();
+void vncPointerButtonAction(int buttonMask);
+void vncPointerMove(int x, int y);
+void vncGetPointerPos(int *x, int *y);
- void keyEvent(rdr::U32 keysym, bool down);
+void vncKeyboardEvent(KeySym keysym, int down);
- /* Backend dependent functions below here */
- void PrepareInputDevices(void);
+/* Backend dependent functions below here */
- unsigned getKeyboardState(void);
- unsigned getLevelThreeMask(void);
+void vncPrepareInputDevices(void);
- KeyCode pressShift(void);
- std::list<KeyCode> releaseShift(void);
+unsigned vncGetKeyboardState(void);
+unsigned vncGetLevelThreeMask(void);
- KeyCode pressLevelThree(void);
- std::list<KeyCode> releaseLevelThree(void);
+KeyCode vncPressShift(void);
+size_t vncReleaseShift(KeyCode *keys, size_t maxKeys);
- KeyCode keysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state);
+KeyCode vncPressLevelThree(void);
+size_t vncReleaseLevelThree(KeyCode *keys, size_t maxKeys);
- bool isLockModifier(KeyCode keycode, unsigned state);
+KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state);
- bool isAffectedByNumLock(KeyCode keycode);
+int vncIsLockModifier(KeyCode keycode, unsigned state);
- KeyCode addKeysym(KeySym keysym, unsigned state);
+int vncIsAffectedByNumLock(KeyCode keycode);
-private:
- static int pointerProc(DeviceIntPtr pDevice, int onoff);
- static int keyboardProc(DeviceIntPtr pDevice, int onoff);
+KeyCode vncAddKeysym(KeySym keysym, unsigned state);
-#if XORG >= 17
- static void vncXkbProcessDeviceEvent(int screenNum,
- InternalEvent *event,
- DeviceIntPtr dev);
-#else
- static void GetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap);
+#ifdef __cplusplus
+}
#endif
-private:
- DeviceIntPtr keyboardDev;
- DeviceIntPtr pointerDev;
-
- int oldButtonMask;
- rfb::Point cursorPos;
-
- KeySym pressedKeys[256];
-
-private:
- static InputDevice singleton;
-};
-
#endif
--- /dev/null
+/* Copyright (C) 2009 TightVNC Team
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright 2013-2015 Pierre Ossman for Cendio AB
+ *
+ * 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "Input.h"
+#include "xorg-version.h"
+
+#include "inputstr.h"
+#ifndef XKB_IN_SERVER
+#define XKB_IN_SERVER
+#endif
+#ifdef XKB
+/*
+ * This include is needed to use XkbConvertCase instead of XConvertCase even if
+ * we don't use XKB extension.
+ */
+#include <xkbsrv.h>
+#endif
+/* These defines give us access to all keysyms we need */
+#define XK_PUBLISHING
+#define XK_TECHNICAL
+#include <X11/keysym.h>
+#include <X11/XF86keysym.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+extern DeviceIntPtr vncKeyboardDev;
+
+#if XORG < 17
+
+#define IS_PRESSED(dev, keycode) \
+ ((dev)->key->down[(keycode) >> 3] & (1 << ((keycode) & 7)))
+
+/* Fairly standard US PC Keyboard */
+
+#define MIN_KEY 8
+#define MAX_KEY 255
+#define MAP_LEN (MAX_KEY - MIN_KEY + 1)
+#define KEYSYMS_PER_KEY 2
+static KeySym keyboardMap[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,
+ 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,
+ NoSymbol, NoSymbol,
+ XK_Super_L, NoSymbol,
+ XK_Super_R, NoSymbol,
+ XK_Menu, NoSymbol,
+};
+
+void vncGetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap)
+{
+ int i;
+
+ for (i = 0; i < MAP_LENGTH; i++)
+ modmap[i] = NoSymbol;
+
+ for (i = 0; i < MAP_LEN; i++) {
+ switch (keyboardMap[i * KEYSYMS_PER_KEY]) {
+ case XK_Shift_L:
+ case XK_Shift_R:
+ modmap[i + MIN_KEY] = ShiftMask;
+ break;
+ case XK_Caps_Lock:
+ modmap[i + MIN_KEY] = LockMask;
+ break;
+ case XK_Control_L:
+ case XK_Control_R:
+ modmap[i + MIN_KEY] = ControlMask;
+ break;
+ case XK_Alt_L:
+ case XK_Alt_R:
+ modmap[i + MIN_KEY] = Mod1Mask;
+ break;
+ case XK_Num_Lock:
+ modmap[i + MIN_KEY] = Mod2Mask;
+ break;
+ /* No defaults for Mod3Mask yet */
+ case XK_Super_L:
+ case XK_Super_R:
+ case XK_Hyper_L:
+ case XK_Hyper_R:
+ modmap[i + MIN_KEY] = Mod4Mask;
+ break;
+ case XK_ISO_Level3_Shift:
+ case XK_Mode_switch:
+ modmap[i + MIN_KEY] = Mod5Mask;
+ break;
+ }
+ }
+
+ keysyms->minKeyCode = MIN_KEY;
+ keysyms->maxKeyCode = MAX_KEY;
+ keysyms->mapWidth = KEYSYMS_PER_KEY;
+ keysyms->map = keyboardMap;
+}
+
+void vncPrepareInputDevices(void)
+{
+ /* Don't need to do anything here */
+}
+
+unsigned vncGetKeyboardState(void)
+{
+ return vncKeyboardDev->key->state;
+}
+
+unsigned vncGetLevelThreeMask(void)
+{
+ int i, j, k;
+
+ int minKeyCode, mapWidth;
+ KeySym *map;
+
+ int maxKeysPerMod;
+ CARD8 *modmap;
+
+ minKeyCode = vncKeyboardDev->key->curKeySyms.minKeyCode;
+ mapWidth = vncKeyboardDev->key->curKeySyms.mapWidth;
+ map = vncKeyboardDev->key->curKeySyms.map;
+
+ maxKeysPerMod = vncKeyboardDev->key->maxKeysPerModifier;
+ modmap = vncKeyboardDev->key->modifierKeyMap;
+
+ for (i = 3; i < 8; i++) {
+ for (k = 0; k < maxKeysPerMod; k++) {
+ int index = i * maxKeysPerMod + k;
+ int keycode = modmap[index];
+
+ if (keycode == 0)
+ continue;
+
+ for (j = 0; j < mapWidth; j++) {
+ KeySym keysym;
+ keysym = map[(keycode - minKeyCode) * mapWidth + j];
+ if (keysym == XK_Mode_switch)
+ return 1 << i;
+ }
+ }
+ }
+
+ return 0;
+}
+
+KeyCode vncPressShift(void)
+{
+ int maxKeysPerMod;
+
+ maxKeysPerMod = vncKeyboardDev->key->maxKeysPerModifier;
+ return vncKeyboardDev->key->modifierKeyMap[ShiftMapIndex * maxKeysPerMod];
+}
+
+size_t vncReleaseShift(KeyCode *keys, size_t maxKeys)
+{
+ size_t count;
+ int maxKeysPerMod;
+
+ count = 0;
+ maxKeysPerMod = vncKeyboardDev->key->maxKeysPerModifier;
+ for (int k = 0; k < maxKeysPerMod; k++) {
+ int keycode;
+ int index;
+
+ index = ShiftMapIndex * maxKeysPerMod + k;
+
+ keycode = vncKeyboardDev->key->modifierKeyMap[index];
+ if (keycode == 0)
+ continue;
+
+ if (!IS_PRESSED(vncKeyboardDev, keycode))
+ continue;
+
+ if (count >= maxKeys)
+ return 0;
+
+ keys[count++] = keycode;
+ }
+
+ return count;
+}
+
+KeyCode vncPressLevelThree(void)
+{
+ unsigned mask, index;
+ int maxKeysPerMod;
+
+ mask = getLevelThreeMask();
+ if (mask == 0)
+ return 0;
+
+ index = ffs(mask) - 1;
+ maxKeysPerMod = vncKeyboardDev->key->maxKeysPerModifier;
+ return vncKeyboardDev->key->modifierKeyMap[index * maxKeysPerMod];
+}
+
+size_t vncReleaseLevelThree(KeyCode *keys, size_t maxKeys)
+{
+ size_t count;
+ unsigned mask, msindex;
+ int maxKeysPerMod;
+
+ mask = getLevelThreeMask();
+ if (mask == 0)
+ return 0;
+
+ msindex = ffs(mask) - 1;
+
+ count = 0;
+ maxKeysPerMod = vncKeyboardDev->key->maxKeysPerModifier;
+ for (int k = 0; k < maxKeysPerMod; k++) {
+ int keycode;
+ int index;
+
+ index = msindex * maxKeysPerMod + k;
+
+ keycode = vncKeyboardDev->key->modifierKeyMap[index];
+ if (keycode == 0)
+ continue;
+
+ if (!IS_PRESSED(vncKeyboardDev, keycode))
+ continue;
+
+ if (count >= maxKeys)
+ return 0;
+
+ keys[count++] = keycode;
+ }
+
+ return count;
+}
+
+static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col)
+{
+ int per = keymap->mapWidth;
+ 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)
+ return syms[col];
+
+ if (col > 1) {
+ while ((per > 2) && (syms[per - 1] == NoSymbol))
+ per--;
+ if (per < 3)
+ col -= 2;
+ }
+
+ if ((per <= (col|1)) || (syms[col|1] == NoSymbol)) {
+ XkbConvertCase(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).
+ */
+#if 0
+ else if (usym == lsym)
+ return NoSymbol;
+#endif
+ else
+ return usym;
+ }
+
+ return syms[col];
+}
+
+KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state)
+{
+ int i, j;
+ unsigned mask;
+
+ KeySymsPtr keymap;
+ int mapWidth;
+
+ mask = vncGetLevelThreeMask();
+
+ keymap = &vncKeyboardDev->key->curKeySyms;
+
+ /*
+ * 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.
+ */
+ j = 0;
+ if (state & ShiftMask)
+ j |= 0x1;
+ if (state & mask)
+ j |= 0x2;
+
+ *new_state = state;
+ for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) {
+ if (KeyCodetoKeySym(keymap, i, j) == keysym)
+ return i;
+ }
+
+ /* Only the first four columns have well-defined meaning */
+ mapWidth = keymap->mapWidth;
+ if (mapWidth > 4)
+ mapWidth = 4;
+
+ for (j = 0; j < mapWidth; j++) {
+ for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) {
+ if (KeyCodetoKeySym(keymap, i, j) == keysym) {
+ *new_state = state & ~(ShiftMask|mask);
+ if (j & 0x1)
+ *new_state |= ShiftMask;
+ if (j & 0x2)
+ *new_state |= mask;
+
+ return i;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int vncIsLockModifier(KeyCode keycode, unsigned state)
+{
+ int i, j, k;
+
+ int minKeyCode, mapWidth;
+ KeySym *map;
+
+ int maxKeysPerMod;
+ CARD8 *modmap;
+
+ int num_lock_index;
+
+ minKeyCode = vncKeyboardDev->key->curKeySyms.minKeyCode;
+ mapWidth = vncKeyboardDev->key->curKeySyms.mapWidth;
+ map = vncKeyboardDev->key->curKeySyms.map;
+
+ maxKeysPerMod = vncKeyboardDev->key->maxKeysPerModifier;
+ modmap = vncKeyboardDev->key->modifierKeyMap;
+
+ /* Caps Lock is fairly easy as it has a dedicated modmap entry */
+ for (k = 0; k < maxKeysPerMod; k++) {
+ int index;
+
+ index = LockMapIndex * maxKeysPerMod + k;
+ if (keycode == modmap[index])
+ return 1;
+ }
+
+ /* For Num Lock we need to find the correct modmap entry */
+ num_lock_index = i;
+ for (i = 3; i < 8; i++) {
+ for (k = 0; k < maxKeysPerMod; k++) {
+ int index = i * maxKeysPerMod + k;
+ int keycode = modmap[index];
+
+ if (keycode == 0)
+ continue;
+
+ for (j = 0; j < mapWidth; j++) {
+ KeySym keysym;
+ keysym = map[(keycode - minKeyCode) * mapWidth + j];
+ if (keysym == XK_Num_Lock) {
+ num_lock_index = i;
+ goto done;
+ }
+ }
+ }
+ }
+done:
+
+ if (num_lock_index == 0)
+ return 0;
+
+ /* Now we can look in the modmap */
+ for (k = 0; k < maxKeysPerMod; k++) {
+ int index;
+
+ index = num_lock_index * maxKeysPerMod + k;
+ if (keycode == modmap[index])
+ return 1;
+ }
+
+ return 0;
+}
+
+int vncIsAffectedByNumLock(KeyCode keycode)
+{
+ KeySymsPtr keymap;
+ int i, per;
+ KeySym *syms;
+
+ keymap = &vncKeyboardDev->key->curKeySyms;
+ per = keymap->mapWidth;
+ syms = &keymap->map[(keycode - keymap->minKeyCode) * per];
+
+ for (i = 0;i < per;i++) {
+ if (IsKeypadKey(syms[i]))
+ return 1;
+ if (IsPrivateKeypadKey(syms[i]))
+ return 1;
+ }
+
+ return 0;
+}
+
+KeyCode vncAddKeysym(KeySym keysym, unsigned state)
+{
+ KeyCode kc;
+
+ int minKeyCode, maxKeyCode, mapWidth;
+ KeySym *map;
+
+ minKeyCode = vncKeyboardDev->key->curKeySyms.minKeyCode;
+ maxKeyCode = vncKeyboardDev->key->curKeySyms.maxKeyCode;
+ mapWidth = vncKeyboardDev->key->curKeySyms.mapWidth;
+ map = vncKeyboardDev->key->curKeySyms.map;
+
+ /*
+ * Magic, which dynamically adds keysym<->keycode mapping
+ * depends on X.Org version. Quick explanation of that "magic":
+ *
+ * 1.5
+ * - has only one core keyboard so we have to keep core
+ * keyboard mapping synchronized with vncKeyboardDevice. Do
+ * it via SwitchCoreKeyboard()
+ *
+ * 1.6 (aka MPX - Multi pointer X)
+ * - multiple master devices (= core devices) exists, keep
+ * vncKeyboardDevice synchronized with proper master device
+ */
+ for (kc = maxKeyCode; kc >= minKeyCode; kc--) {
+ DeviceIntPtr master;
+
+ if (map[(kc - minKeyCode) * mapWidth] != 0)
+ continue;
+
+ map[(kc - minKeyCode) * mapWidth] = keysym;
+
+#if XORG == 15
+ master = inputInfo.keyboard;
+#else
+ master = vncKeyboardDev->u.master;
+#endif
+ void *slave = dixLookupPrivate(&master->devPrivates,
+ CoreDevicePrivateKey);
+ if (vncKeyboardDev == slave) {
+ dixSetPrivate(&master->devPrivates,
+ CoreDevicePrivateKey, NULL);
+#if XORG == 15
+ SwitchCoreKeyboard(vncKeyboardDev);
+#else
+ CopyKeyClass(vncKeyboardDev, master);
+#endif
+ }
+
+ return kc;
+ }
+
+ return 0;
+}
+
+#endif
+
+++ /dev/null
-/* Copyright (C) 2009 TightVNC Team
- * Copyright (C) 2009 Red Hat, Inc.
- * Copyright 2013 Pierre Ossman for Cendio AB
- *
- * 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.
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include "Input.h"
-#include "xorg-version.h"
-
-extern "C" {
-#define public c_public
-#define class c_class
-#include "inputstr.h"
-#ifndef XKB_IN_SERVER
-#define XKB_IN_SERVER
-#endif
-#ifdef XKB
-/*
- * This include is needed to use XkbConvertCase instead of XConvertCase even if
- * we don't use XKB extension.
- */
-#include <xkbsrv.h>
-#endif
-/* These defines give us access to all keysyms we need */
-#define XK_PUBLISHING
-#define XK_TECHNICAL
-#include <X11/keysym.h>
-#include <X11/XF86keysym.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#undef public
-#undef class
-}
-
-#if XORG < 17
-
-#define IS_PRESSED(dev, keycode) \
- ((dev)->key->down[(keycode) >> 3] & (1 << ((keycode) & 7)))
-
-/* Fairly standard US PC Keyboard */
-
-#define MIN_KEY 8
-#define MAX_KEY 255
-#define MAP_LEN (MAX_KEY - MIN_KEY + 1)
-#define KEYSYMS_PER_KEY 2
-KeySym keyboardMap[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,
- 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,
- NoSymbol, NoSymbol,
- XK_Super_L, NoSymbol,
- XK_Super_R, NoSymbol,
- XK_Menu, NoSymbol,
-};
-
-void InputDevice::GetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap)
-{
- int i;
-
- for (i = 0; i < MAP_LENGTH; i++)
- modmap[i] = NoSymbol;
-
- for (i = 0; i < MAP_LEN; i++) {
- switch (keyboardMap[i * KEYSYMS_PER_KEY]) {
- case XK_Shift_L:
- case XK_Shift_R:
- modmap[i + MIN_KEY] = ShiftMask;
- break;
- case XK_Caps_Lock:
- modmap[i + MIN_KEY] = LockMask;
- break;
- case XK_Control_L:
- case XK_Control_R:
- modmap[i + MIN_KEY] = ControlMask;
- break;
- case XK_Alt_L:
- case XK_Alt_R:
- modmap[i + MIN_KEY] = Mod1Mask;
- break;
- case XK_Num_Lock:
- modmap[i + MIN_KEY] = Mod2Mask;
- break;
- /* No defaults for Mod3Mask yet */
- case XK_Super_L:
- case XK_Super_R:
- case XK_Hyper_L:
- case XK_Hyper_R:
- modmap[i + MIN_KEY] = Mod4Mask;
- break;
- case XK_ISO_Level3_Shift:
- case XK_Mode_switch:
- modmap[i + MIN_KEY] = Mod5Mask;
- break;
- }
- }
-
- keysyms->minKeyCode = MIN_KEY;
- keysyms->maxKeyCode = MAX_KEY;
- keysyms->mapWidth = KEYSYMS_PER_KEY;
- keysyms->map = keyboardMap;
-}
-
-void InputDevice::PrepareInputDevices(void)
-{
- /* Don't need to do anything here */
-}
-
-unsigned InputDevice::getKeyboardState(void)
-{
- return keyboardDev->key->state;
-}
-
-unsigned InputDevice::getLevelThreeMask(void)
-{
- int i, j, k;
-
- int minKeyCode, mapWidth;
- KeySym *map;
-
- int maxKeysPerMod;
- CARD8 *modmap;
-
- minKeyCode = keyboardDev->key->curKeySyms.minKeyCode;
- mapWidth = keyboardDev->key->curKeySyms.mapWidth;
- map = keyboardDev->key->curKeySyms.map;
-
- maxKeysPerMod = keyboardDev->key->maxKeysPerModifier;
- modmap = keyboardDev->key->modifierKeyMap;
-
- for (i = 3; i < 8; i++) {
- for (k = 0; k < maxKeysPerMod; k++) {
- int index = i * maxKeysPerMod + k;
- int keycode = modmap[index];
-
- if (keycode == 0)
- continue;
-
- for (j = 0; j < mapWidth; j++) {
- KeySym keysym;
- keysym = map[(keycode - minKeyCode) * mapWidth + j];
- if (keysym == XK_Mode_switch)
- return 1 << i;
- }
- }
- }
-
- return 0;
-}
-
-KeyCode InputDevice::pressShift(void)
-{
- int maxKeysPerMod;
-
- maxKeysPerMod = keyboardDev->key->maxKeysPerModifier;
- return keyboardDev->key->modifierKeyMap[ShiftMapIndex * maxKeysPerMod];
-}
-
-std::list<KeyCode> InputDevice::releaseShift(void)
-{
- std::list<KeyCode> keys;
-
- int maxKeysPerMod;
-
- maxKeysPerMod = keyboardDev->key->maxKeysPerModifier;
- for (int k = 0; k < maxKeysPerMod; k++) {
- int keycode;
- int index;
-
- index = ShiftMapIndex * maxKeysPerMod + k;
-
- keycode = keyboardDev->key->modifierKeyMap[index];
- if (keycode == 0)
- continue;
-
- if (!IS_PRESSED(keyboardDev, keycode))
- continue;
-
- keys.push_back(keycode);
- }
-
- return keys;
-}
-
-KeyCode InputDevice::pressLevelThree(void)
-{
- unsigned mask, index;
- int maxKeysPerMod;
-
- mask = getLevelThreeMask();
- if (mask == 0)
- return 0;
-
- index = ffs(mask) - 1;
- maxKeysPerMod = keyboardDev->key->maxKeysPerModifier;
- return keyboardDev->key->modifierKeyMap[index * maxKeysPerMod];
-}
-
-std::list<KeyCode> InputDevice::releaseLevelThree(void)
-{
- std::list<KeyCode> keys;
-
- unsigned mask, msindex;
- int maxKeysPerMod;
-
- mask = getLevelThreeMask();
- if (mask == 0)
- return keys;
-
- msindex = ffs(mask) - 1;
-
- maxKeysPerMod = keyboardDev->key->maxKeysPerModifier;
- for (int k = 0; k < maxKeysPerMod; k++) {
- int keycode;
- int index;
-
- index = msindex * maxKeysPerMod + k;
-
- keycode = keyboardDev->key->modifierKeyMap[index];
- if (keycode == 0)
- continue;
-
- if (!IS_PRESSED(keyboardDev, keycode))
- continue;
-
- keys.push_back(keycode);
- }
-
- return keys;
-}
-
-static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col)
-{
- int per = keymap->mapWidth;
- 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)
- return syms[col];
-
- if (col > 1) {
- while ((per > 2) && (syms[per - 1] == NoSymbol))
- per--;
- if (per < 3)
- col -= 2;
- }
-
- if ((per <= (col|1)) || (syms[col|1] == NoSymbol)) {
- XkbConvertCase(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).
- */
-#if 0
- else if (usym == lsym)
- return NoSymbol;
-#endif
- else
- return usym;
- }
-
- return syms[col];
-}
-
-KeyCode InputDevice::keysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state)
-{
- int i, j;
- unsigned mask;
-
- KeySymsPtr keymap;
- int mapWidth;
-
- mask = getLevelThreeMask();
-
- keymap = &keyboardDev->key->curKeySyms;
-
- /*
- * 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.
- */
- j = 0;
- if (state & ShiftMask)
- j |= 0x1;
- if (state & mask)
- j |= 0x2;
-
- *new_state = state;
- for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) {
- if (KeyCodetoKeySym(keymap, i, j) == keysym)
- return i;
- }
-
- /* Only the first four columns have well-defined meaning */
- mapWidth = keymap->mapWidth;
- if (mapWidth > 4)
- mapWidth = 4;
-
- for (j = 0; j < mapWidth; j++) {
- for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) {
- if (KeyCodetoKeySym(keymap, i, j) == keysym) {
- *new_state = state & ~(ShiftMask|mask);
- if (j & 0x1)
- *new_state |= ShiftMask;
- if (j & 0x2)
- *new_state |= mask;
-
- return i;
- }
- }
- }
-
- return 0;
-}
-
-bool InputDevice::isLockModifier(KeyCode keycode, unsigned state)
-{
- int i, j, k;
-
- int minKeyCode, mapWidth;
- KeySym *map;
-
- int maxKeysPerMod;
- CARD8 *modmap;
-
- int num_lock_index;
-
- minKeyCode = keyboardDev->key->curKeySyms.minKeyCode;
- mapWidth = keyboardDev->key->curKeySyms.mapWidth;
- map = keyboardDev->key->curKeySyms.map;
-
- maxKeysPerMod = keyboardDev->key->maxKeysPerModifier;
- modmap = keyboardDev->key->modifierKeyMap;
-
- /* Caps Lock is fairly easy as it has a dedicated modmap entry */
- for (k = 0; k < maxKeysPerMod; k++) {
- int index;
-
- index = LockMapIndex * maxKeysPerMod + k;
- if (keycode == modmap[index])
- return true;
- }
-
- /* For Num Lock we need to find the correct modmap entry */
- num_lock_index = i;
- for (i = 3; i < 8; i++) {
- for (k = 0; k < maxKeysPerMod; k++) {
- int index = i * maxKeysPerMod + k;
- int keycode = modmap[index];
-
- if (keycode == 0)
- continue;
-
- for (j = 0; j < mapWidth; j++) {
- KeySym keysym;
- keysym = map[(keycode - minKeyCode) * mapWidth + j];
- if (keysym == XK_Num_Lock) {
- num_lock_index = i;
- goto done;
- }
- }
- }
- }
-done:
-
- if (num_lock_index == 0)
- return false;
-
- /* Now we can look in the modmap */
- for (k = 0; k < maxKeysPerMod; k++) {
- int index;
-
- index = num_lock_index * maxKeysPerMod + k;
- if (keycode == modmap[index])
- return true;
- }
-
- return false;
-}
-
-bool InputDevice::isAffectedByNumLock(KeyCode keycode)
-{
- KeySymsPtr keymap;
- int i, per;
- KeySym *syms;
-
- keymap = &keyboardDev->key->curKeySyms;
- per = keymap->mapWidth;
- syms = &keymap->map[(keycode - keymap->minKeyCode) * per];
-
- for (i = 0;i < per;i++) {
- if (IsKeypadKey(syms[i]))
- return true;
- if (IsPrivateKeypadKey(syms[i]))
- return true;
- }
-
- return false;
-}
-
-KeyCode InputDevice::addKeysym(KeySym keysym, unsigned state)
-{
- KeyCode kc;
-
- int minKeyCode, maxKeyCode, mapWidth;
- KeySym *map;
-
- minKeyCode = keyboardDev->key->curKeySyms.minKeyCode;
- maxKeyCode = keyboardDev->key->curKeySyms.maxKeyCode;
- mapWidth = keyboardDev->key->curKeySyms.mapWidth;
- map = keyboardDev->key->curKeySyms.map;
-
- /*
- * Magic, which dynamically adds keysym<->keycode mapping
- * depends on X.Org version. Quick explanation of that "magic":
- *
- * 1.5
- * - has only one core keyboard so we have to keep core
- * keyboard mapping synchronized with vncKeyboardDevice. Do
- * it via SwitchCoreKeyboard()
- *
- * 1.6 (aka MPX - Multi pointer X)
- * - multiple master devices (= core devices) exists, keep
- * vncKeyboardDevice synchronized with proper master device
- */
- for (kc = maxKeyCode; kc >= minKeyCode; kc--) {
- DeviceIntPtr master;
-
- if (map[(kc - minKeyCode) * mapWidth] != 0)
- continue;
-
- map[(kc - minKeyCode) * mapWidth] = keysym;
-
-#if XORG == 15
- master = inputInfo.keyboard;
-#else
- master = keyboardDev->u.master;
-#endif
- void *slave = dixLookupPrivate(&master->devPrivates,
- CoreDevicePrivateKey);
- if (keyboardDev == slave) {
- dixSetPrivate(&master->devPrivates,
- CoreDevicePrivateKey, NULL);
-#if XORG == 15
- SwitchCoreKeyboard(keyboardDev);
-#else
- CopyKeyClass(keyboardDev, master);
-#endif
- }
-
- return kc;
- }
-
- return 0;
-}
-
-#endif
-
--- /dev/null
+/* Copyright (C) 2009 TightVNC Team
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright 2013-2015 Pierre Ossman for Cendio AB
+ *
+ * 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "xorg-version.h"
+
+#if XORG >= 17
+
+#include <stdio.h>
+
+#include <X11/keysym.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include "xkbsrv.h"
+#include "xkbstr.h"
+#include "eventstr.h"
+#include "scrnintstr.h"
+#include "mi.h"
+
+#include "Input.h"
+
+#ifndef KEYBOARD_OR_FLOAT
+#define KEYBOARD_OR_FLOAT MASTER_KEYBOARD
+#endif
+
+extern DeviceIntPtr vncKeyboardDev;
+
+static void vncXkbProcessDeviceEvent(int screenNum,
+ InternalEvent *event,
+ DeviceIntPtr dev);
+
+/* Stolen from libX11 */
+static Bool
+XkbTranslateKeyCode(register XkbDescPtr xkb, KeyCode key,
+ register unsigned int mods, unsigned int *mods_rtrn,
+ KeySym *keysym_rtrn)
+{
+ XkbKeyTypeRec *type;
+ int col,nKeyGroups;
+ unsigned preserve,effectiveGroup;
+ KeySym *syms;
+
+ if (mods_rtrn!=NULL)
+ *mods_rtrn = 0;
+
+ nKeyGroups= XkbKeyNumGroups(xkb,key);
+ if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) {
+ if (keysym_rtrn!=NULL)
+ *keysym_rtrn = NoSymbol;
+ return False;
+ }
+
+ syms = XkbKeySymsPtr(xkb,key);
+
+ /* find the offset of the effective group */
+ col = 0;
+ effectiveGroup= XkbGroupForCoreState(mods);
+ if ( effectiveGroup>=nKeyGroups ) {
+ unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
+ switch (XkbOutOfRangeGroupAction(groupInfo)) {
+ default:
+ effectiveGroup %= nKeyGroups;
+ break;
+ case XkbClampIntoRange:
+ effectiveGroup = nKeyGroups-1;
+ break;
+ case XkbRedirectIntoRange:
+ effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
+ if (effectiveGroup>=nKeyGroups)
+ effectiveGroup= 0;
+ break;
+ }
+ }
+ col= effectiveGroup*XkbKeyGroupsWidth(xkb,key);
+ type = XkbKeyKeyType(xkb,key,effectiveGroup);
+
+ preserve= 0;
+ if (type->map) { /* find the column (shift level) within the group */
+ register int i;
+ register XkbKTMapEntryPtr entry;
+ for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
+ if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) {
+ col+= entry->level;
+ if (type->preserve)
+ preserve= type->preserve[i].mask;
+ break;
+ }
+ }
+ }
+
+ if (keysym_rtrn!=NULL)
+ *keysym_rtrn= syms[col];
+ if (mods_rtrn)
+ *mods_rtrn= type->mods.mask&(~preserve);
+
+ return (syms[col]!=NoSymbol);
+}
+
+static XkbAction *XkbKeyActionPtr(XkbDescPtr xkb, KeyCode key, unsigned int mods)
+{
+ XkbKeyTypeRec *type;
+ int col,nKeyGroups;
+ unsigned effectiveGroup;
+ XkbAction *acts;
+
+ if (!XkbKeyHasActions(xkb, key))
+ return NULL;
+
+ nKeyGroups= XkbKeyNumGroups(xkb,key);
+ if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0))
+ return NULL;
+
+ acts = XkbKeyActionsPtr(xkb,key);
+
+ /* find the offset of the effective group */
+ col = 0;
+ effectiveGroup= XkbGroupForCoreState(mods);
+ if ( effectiveGroup>=nKeyGroups ) {
+ unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
+ switch (XkbOutOfRangeGroupAction(groupInfo)) {
+ default:
+ effectiveGroup %= nKeyGroups;
+ break;
+ case XkbClampIntoRange:
+ effectiveGroup = nKeyGroups-1;
+ break;
+ case XkbRedirectIntoRange:
+ effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
+ if (effectiveGroup>=nKeyGroups)
+ effectiveGroup= 0;
+ break;
+ }
+ }
+ col= effectiveGroup*XkbKeyGroupsWidth(xkb,key);
+ type = XkbKeyKeyType(xkb,key,effectiveGroup);
+
+ if (type->map) { /* find the column (shift level) within the group */
+ register int i;
+ register XkbKTMapEntryPtr entry;
+ for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
+ if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) {
+ col+= entry->level;
+ break;
+ }
+ }
+ }
+
+ return &acts[col];
+}
+
+static unsigned XkbKeyEffectiveGroup(XkbDescPtr xkb, KeyCode key, unsigned int mods)
+{
+ int nKeyGroups;
+ unsigned effectiveGroup;
+
+ nKeyGroups= XkbKeyNumGroups(xkb,key);
+ if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0))
+ return 0;
+
+ effectiveGroup= XkbGroupForCoreState(mods);
+ if ( effectiveGroup>=nKeyGroups ) {
+ unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
+ switch (XkbOutOfRangeGroupAction(groupInfo)) {
+ default:
+ effectiveGroup %= nKeyGroups;
+ break;
+ case XkbClampIntoRange:
+ effectiveGroup = nKeyGroups-1;
+ break;
+ case XkbRedirectIntoRange:
+ effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
+ if (effectiveGroup>=nKeyGroups)
+ effectiveGroup= 0;
+ break;
+ }
+ }
+
+ return effectiveGroup;
+}
+
+void vncPrepareInputDevices(void)
+{
+ /*
+ * Not ideal since these callbacks do not stack, but it's the only
+ * decent way we can reliably catch events for both the slave and
+ * master device.
+ */
+ mieqSetHandler(ET_KeyPress, vncXkbProcessDeviceEvent);
+ mieqSetHandler(ET_KeyRelease, vncXkbProcessDeviceEvent);
+}
+
+unsigned vncGetKeyboardState(void)
+{
+ DeviceIntPtr master;
+
+ master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
+ return XkbStateFieldFromRec(&master->key->xkbInfo->state);
+}
+
+unsigned vncGetLevelThreeMask(void)
+{
+ unsigned state;
+ KeyCode keycode;
+ XkbDescPtr xkb;
+ XkbAction *act;
+
+ /* Group state is still important */
+ state = vncGetKeyboardState();
+ state &= ~0xff;
+
+ keycode = vncKeysymToKeycode(XK_ISO_Level3_Shift, state, NULL);
+ if (keycode == 0) {
+ keycode = vncKeysymToKeycode(XK_Mode_switch, state, NULL);
+ if (keycode == 0)
+ return 0;
+ }
+
+ xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
+
+ act = XkbKeyActionPtr(xkb, keycode, state);
+ if (act == NULL)
+ return 0;
+ if (act->type != XkbSA_SetMods)
+ return 0;
+
+ if (act->mods.flags & XkbSA_UseModMapMods)
+ return xkb->map->modmap[keycode];
+ else
+ return act->mods.mask;
+}
+
+KeyCode vncPressShift(void)
+{
+ unsigned state;
+
+ XkbDescPtr xkb;
+ unsigned int key;
+
+ state = vncGetKeyboardState();
+ if (state & ShiftMask)
+ return 0;
+
+ xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
+ for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
+ XkbAction *act;
+ unsigned char mask;
+
+ act = XkbKeyActionPtr(xkb, key, state);
+ if (act == NULL)
+ continue;
+
+ if (act->type != XkbSA_SetMods)
+ continue;
+
+ if (act->mods.flags & XkbSA_UseModMapMods)
+ mask = xkb->map->modmap[key];
+ else
+ mask = act->mods.mask;
+
+ if ((mask & ShiftMask) == ShiftMask)
+ return key;
+ }
+
+ return 0;
+}
+
+size_t vncReleaseShift(KeyCode *keys, size_t maxKeys)
+{
+ size_t count;
+
+ unsigned state;
+
+ DeviceIntPtr master;
+ XkbDescPtr xkb;
+ unsigned int key;
+
+ state = vncGetKeyboardState();
+ if (!(state & ShiftMask))
+ return 0;
+
+ count = 0;
+
+ master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
+ xkb = master->key->xkbInfo->desc;
+ for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
+ XkbAction *act;
+ unsigned char mask;
+
+ if (!key_is_down(master, key, KEY_PROCESSED))
+ continue;
+
+ act = XkbKeyActionPtr(xkb, key, state);
+ if (act == NULL)
+ continue;
+
+ if (act->type != XkbSA_SetMods)
+ continue;
+
+ if (act->mods.flags & XkbSA_UseModMapMods)
+ mask = xkb->map->modmap[key];
+ else
+ mask = act->mods.mask;
+
+ if (!(mask & ShiftMask))
+ continue;
+
+ if (count >= maxKeys)
+ return 0;
+
+ keys[count++] = key;
+ }
+
+ return count;
+}
+
+KeyCode vncPressLevelThree(void)
+{
+ unsigned state, mask;
+
+ KeyCode keycode;
+ XkbDescPtr xkb;
+ XkbAction *act;
+
+ mask = vncGetLevelThreeMask();
+ if (mask == 0)
+ return 0;
+
+ state = vncGetKeyboardState();
+ if (state & mask)
+ return 0;
+
+ keycode = vncKeysymToKeycode(XK_ISO_Level3_Shift, state, NULL);
+ if (keycode == 0) {
+ keycode = vncKeysymToKeycode(XK_Mode_switch, state, NULL);
+ if (keycode == 0)
+ return 0;
+ }
+
+ xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
+
+ act = XkbKeyActionPtr(xkb, keycode, state);
+ if (act == NULL)
+ return 0;
+ if (act->type != XkbSA_SetMods)
+ return 0;
+
+ return keycode;
+}
+
+size_t vncReleaseLevelThree(KeyCode *keys, size_t maxKeys)
+{
+ size_t count;
+
+ unsigned state, mask;
+
+ DeviceIntPtr master;
+ XkbDescPtr xkb;
+ unsigned int key;
+
+ mask = vncGetLevelThreeMask();
+ if (mask == 0)
+ return 0;
+
+ state = vncGetKeyboardState();
+ if (!(state & mask))
+ return 0;
+
+ count = 0;
+
+ master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
+ xkb = master->key->xkbInfo->desc;
+ for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
+ XkbAction *act;
+ unsigned char key_mask;
+
+ if (!key_is_down(master, key, KEY_PROCESSED))
+ continue;
+
+ act = XkbKeyActionPtr(xkb, key, state);
+ if (act == NULL)
+ continue;
+
+ if (act->type != XkbSA_SetMods)
+ continue;
+
+ if (act->mods.flags & XkbSA_UseModMapMods)
+ key_mask = xkb->map->modmap[key];
+ else
+ key_mask = act->mods.mask;
+
+ if (!(key_mask & mask))
+ continue;
+
+ if (count >= maxKeys)
+ return 0;
+
+ keys[count++] = key;
+ }
+
+ return count;
+}
+
+KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state)
+{
+ XkbDescPtr xkb;
+ unsigned int key;
+ KeySym ks;
+ unsigned level_three_mask;
+
+ if (new_state != NULL)
+ *new_state = state;
+
+ xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
+ for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
+ unsigned int state_out;
+ KeySym dummy;
+
+ XkbTranslateKeyCode(xkb, key, state, &state_out, &ks);
+ if (ks == NoSymbol)
+ continue;
+
+ /*
+ * Despite every known piece of documentation on
+ * XkbTranslateKeyCode() stating that mods_rtrn returns
+ * the unconsumed modifiers, in reality it always
+ * returns the _potentially consumed_ modifiers.
+ */
+ state_out = state & ~state_out;
+ if (state_out & LockMask)
+ XkbConvertCase(ks, &dummy, &ks);
+
+ if (ks == keysym)
+ return key;
+ }
+
+ if (new_state == NULL)
+ return 0;
+
+ *new_state = (state & ~ShiftMask) |
+ ((state & ShiftMask) ? 0 : ShiftMask);
+ key = vncKeysymToKeycode(keysym, *new_state, NULL);
+ if (key != 0)
+ return key;
+
+ level_three_mask = vncGetLevelThreeMask();
+ if (level_three_mask == 0)
+ return 0;
+
+ *new_state = (state & ~level_three_mask) |
+ ((state & level_three_mask) ? 0 : level_three_mask);
+ key = vncKeysymToKeycode(keysym, *new_state, NULL);
+ if (key != 0)
+ return key;
+
+ *new_state = (state & ~(ShiftMask | level_three_mask)) |
+ ((state & ShiftMask) ? 0 : ShiftMask) |
+ ((state & level_three_mask) ? 0 : level_three_mask);
+ key = vncKeysymToKeycode(keysym, *new_state, NULL);
+ if (key != 0)
+ return key;
+
+ return 0;
+}
+
+int vncIsLockModifier(KeyCode keycode, unsigned state)
+{
+ XkbDescPtr xkb;
+ XkbAction *act;
+
+ xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
+
+ act = XkbKeyActionPtr(xkb, keycode, state);
+ if (act == NULL)
+ return 0;
+
+ if (act->type != XkbSA_LockMods)
+ return 0;
+
+ return 1;
+}
+
+int vncIsAffectedByNumLock(KeyCode keycode)
+{
+ unsigned state;
+
+ KeyCode numlock_keycode;
+ unsigned numlock_mask;
+
+ XkbDescPtr xkb;
+ XkbAction *act;
+
+ unsigned group;
+ XkbKeyTypeRec *type;
+
+ /* Group state is still important */
+ state = vncGetKeyboardState();
+ state &= ~0xff;
+
+ /*
+ * Not sure if hunting for a virtual modifier called "NumLock",
+ * or following the keysym Num_Lock is the best approach. We
+ * try the latter.
+ */
+ numlock_keycode = vncKeysymToKeycode(XK_Num_Lock, state, NULL);
+ if (numlock_keycode == 0)
+ return 0;
+
+ xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
+
+ act = XkbKeyActionPtr(xkb, numlock_keycode, state);
+ if (act == NULL)
+ return 0;
+ if (act->type != XkbSA_LockMods)
+ return 0;
+
+ if (act->mods.flags & XkbSA_UseModMapMods)
+ numlock_mask = xkb->map->modmap[keycode];
+ else
+ numlock_mask = act->mods.mask;
+
+ group = XkbKeyEffectiveGroup(xkb, keycode, state);
+ type = XkbKeyKeyType(xkb, keycode, group);
+ if ((type->mods.mask & numlock_mask) == 0)
+ return 0;
+
+ return 1;
+}
+
+KeyCode vncAddKeysym(KeySym keysym, unsigned state)
+{
+ DeviceIntPtr master;
+ XkbDescPtr xkb;
+ unsigned int key;
+
+ XkbEventCauseRec cause;
+ XkbChangesRec changes;
+
+ int types[1];
+ KeySym *syms;
+ KeySym upper, lower;
+
+ master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
+ xkb = master->key->xkbInfo->desc;
+ for (key = xkb->max_key_code; key >= xkb->min_key_code; key--) {
+ if (XkbKeyNumGroups(xkb, key) == 0)
+ break;
+ }
+
+ if (key < xkb->min_key_code)
+ return 0;
+
+ memset(&changes, 0, sizeof(changes));
+ memset(&cause, 0, sizeof(cause));
+
+ XkbSetCauseUnknown(&cause);
+
+ /*
+ * Tools like xkbcomp get confused if there isn't a name
+ * assigned to the keycode we're trying to use.
+ */
+ if (xkb->names && xkb->names->keys &&
+ (xkb->names->keys[key].name[0] == '\0')) {
+ xkb->names->keys[key].name[0] = 'I';
+ xkb->names->keys[key].name[1] = '0' + (key / 100) % 10;
+ xkb->names->keys[key].name[2] = '0' + (key / 10) % 10;
+ xkb->names->keys[key].name[3] = '0' + (key / 1) % 10;
+
+ changes.names.changed |= XkbKeyNamesMask;
+ changes.names.first_key = key;
+ changes.names.num_keys = 1;
+ }
+
+ /* FIXME: Verify that ONE_LEVEL/ALPHABETIC isn't screwed up */
+
+ /*
+ * For keysyms that are affected by Lock, we are better off
+ * using ALPHABETIC rather than ONE_LEVEL as the latter
+ * generally cannot produce lower case when Lock is active.
+ */
+ XkbConvertCase(keysym, &lower, &upper);
+ if (upper == lower)
+ types[XkbGroup1Index] = XkbOneLevelIndex;
+ else
+ types[XkbGroup1Index] = XkbAlphabeticIndex;
+
+ XkbChangeTypesOfKey(xkb, key, 1, XkbGroup1Mask, types, &changes.map);
+
+ syms = XkbKeySymsPtr(xkb,key);
+ if (upper == lower)
+ syms[0] = keysym;
+ else {
+ syms[0] = lower;
+ syms[1] = upper;
+ }
+
+ changes.map.changed |= XkbKeySymsMask;
+ changes.map.first_key_sym = key;
+ changes.map.num_key_syms = 1;
+
+ XkbSendNotification(master, &changes, &cause);
+
+ return key;
+}
+
+static void vncXkbProcessDeviceEvent(int screenNum,
+ InternalEvent *event,
+ DeviceIntPtr dev)
+{
+ unsigned int backupctrls;
+
+ if (event->device_event.sourceid == vncKeyboardDev->id) {
+ XkbControlsPtr ctrls;
+
+ /*
+ * We need to bypass AccessX since it is timing sensitive and
+ * the network can cause fake event delays.
+ */
+ ctrls = dev->key->xkbInfo->desc->ctrls;
+ backupctrls = ctrls->enabled_ctrls;
+ ctrls->enabled_ctrls &= ~XkbAllFilteredEventsMask;
+
+ /*
+ * This flag needs to be set for key repeats to be properly
+ * respected.
+ */
+ if ((event->device_event.type == ET_KeyPress) &&
+ key_is_down(dev, event->device_event.detail.key, KEY_PROCESSED))
+ event->device_event.key_repeat = TRUE;
+ }
+
+ dev->public.processInputProc(event, dev);
+
+ if (event->device_event.sourceid == vncKeyboardDev->id) {
+ XkbControlsPtr ctrls;
+
+ ctrls = dev->key->xkbInfo->desc->ctrls;
+ ctrls->enabled_ctrls = backupctrls;
+ }
+}
+
+#endif /* XORG >= 117 */
+++ /dev/null
-/* Copyright (C) 2009 TightVNC Team
- * Copyright (C) 2009 Red Hat, Inc.
- * Copyright 2013 Pierre Ossman for Cendio AB
- *
- * 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.
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include "Input.h"
-#include "xorg-version.h"
-
-#if XORG >= 17
-
-extern "C" {
-#define public c_public
-#define class c_class
-#include "xkbsrv.h"
-#include "xkbstr.h"
-#include "eventstr.h"
-#include "scrnintstr.h"
-#include "mi.h"
-#include <X11/keysym.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#undef public
-#undef class
-}
-
-#ifndef KEYBOARD_OR_FLOAT
-#define KEYBOARD_OR_FLOAT MASTER_KEYBOARD
-#endif
-
-/* Stolen from libX11 */
-static Bool
-XkbTranslateKeyCode(register XkbDescPtr xkb, KeyCode key,
- register unsigned int mods, unsigned int *mods_rtrn,
- KeySym *keysym_rtrn)
-{
- XkbKeyTypeRec *type;
- int col,nKeyGroups;
- unsigned preserve,effectiveGroup;
- KeySym *syms;
-
- if (mods_rtrn!=NULL)
- *mods_rtrn = 0;
-
- nKeyGroups= XkbKeyNumGroups(xkb,key);
- if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) {
- if (keysym_rtrn!=NULL)
- *keysym_rtrn = NoSymbol;
- return False;
- }
-
- syms = XkbKeySymsPtr(xkb,key);
-
- /* find the offset of the effective group */
- col = 0;
- effectiveGroup= XkbGroupForCoreState(mods);
- if ( effectiveGroup>=nKeyGroups ) {
- unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
- switch (XkbOutOfRangeGroupAction(groupInfo)) {
- default:
- effectiveGroup %= nKeyGroups;
- break;
- case XkbClampIntoRange:
- effectiveGroup = nKeyGroups-1;
- break;
- case XkbRedirectIntoRange:
- effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
- if (effectiveGroup>=nKeyGroups)
- effectiveGroup= 0;
- break;
- }
- }
- col= effectiveGroup*XkbKeyGroupsWidth(xkb,key);
- type = XkbKeyKeyType(xkb,key,effectiveGroup);
-
- preserve= 0;
- if (type->map) { /* find the column (shift level) within the group */
- register int i;
- register XkbKTMapEntryPtr entry;
- for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
- if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) {
- col+= entry->level;
- if (type->preserve)
- preserve= type->preserve[i].mask;
- break;
- }
- }
- }
-
- if (keysym_rtrn!=NULL)
- *keysym_rtrn= syms[col];
- if (mods_rtrn)
- *mods_rtrn= type->mods.mask&(~preserve);
-
- return (syms[col]!=NoSymbol);
-}
-
-static XkbAction *XkbKeyActionPtr(XkbDescPtr xkb, KeyCode key, unsigned int mods)
-{
- XkbKeyTypeRec *type;
- int col,nKeyGroups;
- unsigned effectiveGroup;
- XkbAction *acts;
-
- if (!XkbKeyHasActions(xkb, key))
- return NULL;
-
- nKeyGroups= XkbKeyNumGroups(xkb,key);
- if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0))
- return NULL;
-
- acts = XkbKeyActionsPtr(xkb,key);
-
- /* find the offset of the effective group */
- col = 0;
- effectiveGroup= XkbGroupForCoreState(mods);
- if ( effectiveGroup>=nKeyGroups ) {
- unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
- switch (XkbOutOfRangeGroupAction(groupInfo)) {
- default:
- effectiveGroup %= nKeyGroups;
- break;
- case XkbClampIntoRange:
- effectiveGroup = nKeyGroups-1;
- break;
- case XkbRedirectIntoRange:
- effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
- if (effectiveGroup>=nKeyGroups)
- effectiveGroup= 0;
- break;
- }
- }
- col= effectiveGroup*XkbKeyGroupsWidth(xkb,key);
- type = XkbKeyKeyType(xkb,key,effectiveGroup);
-
- if (type->map) { /* find the column (shift level) within the group */
- register int i;
- register XkbKTMapEntryPtr entry;
- for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
- if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) {
- col+= entry->level;
- break;
- }
- }
- }
-
- return &acts[col];
-}
-
-static unsigned XkbKeyEffectiveGroup(XkbDescPtr xkb, KeyCode key, unsigned int mods)
-{
- int nKeyGroups;
- unsigned effectiveGroup;
-
- nKeyGroups= XkbKeyNumGroups(xkb,key);
- if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0))
- return 0;
-
- effectiveGroup= XkbGroupForCoreState(mods);
- if ( effectiveGroup>=nKeyGroups ) {
- unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
- switch (XkbOutOfRangeGroupAction(groupInfo)) {
- default:
- effectiveGroup %= nKeyGroups;
- break;
- case XkbClampIntoRange:
- effectiveGroup = nKeyGroups-1;
- break;
- case XkbRedirectIntoRange:
- effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
- if (effectiveGroup>=nKeyGroups)
- effectiveGroup= 0;
- break;
- }
- }
-
- return effectiveGroup;
-}
-
-void InputDevice::PrepareInputDevices(void)
-{
- /*
- * Not ideal since these callbacks do not stack, but it's the only
- * decent way we can reliably catch events for both the slave and
- * master device.
- */
- mieqSetHandler(ET_KeyPress, vncXkbProcessDeviceEvent);
- mieqSetHandler(ET_KeyRelease, vncXkbProcessDeviceEvent);
-}
-
-unsigned InputDevice::getKeyboardState(void)
-{
- DeviceIntPtr master;
-
- master = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT);
- return XkbStateFieldFromRec(&master->key->xkbInfo->state);
-}
-
-unsigned InputDevice::getLevelThreeMask(void)
-{
- unsigned state;
- KeyCode keycode;
- XkbDescPtr xkb;
- XkbAction *act;
-
- /* Group state is still important */
- state = getKeyboardState();
- state &= ~0xff;
-
- keycode = keysymToKeycode(XK_ISO_Level3_Shift, state, NULL);
- if (keycode == 0) {
- keycode = keysymToKeycode(XK_Mode_switch, state, NULL);
- if (keycode == 0)
- return 0;
- }
-
- xkb = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
-
- act = XkbKeyActionPtr(xkb, keycode, state);
- if (act == NULL)
- return 0;
- if (act->type != XkbSA_SetMods)
- return 0;
-
- if (act->mods.flags & XkbSA_UseModMapMods)
- return xkb->map->modmap[keycode];
- else
- return act->mods.mask;
-}
-
-KeyCode InputDevice::pressShift(void)
-{
- unsigned state;
-
- XkbDescPtr xkb;
- unsigned int key;
-
- state = getKeyboardState();
- if (state & ShiftMask)
- return 0;
-
- xkb = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
- for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
- XkbAction *act;
- unsigned char mask;
-
- act = XkbKeyActionPtr(xkb, key, state);
- if (act == NULL)
- continue;
-
- if (act->type != XkbSA_SetMods)
- continue;
-
- if (act->mods.flags & XkbSA_UseModMapMods)
- mask = xkb->map->modmap[key];
- else
- mask = act->mods.mask;
-
- if ((mask & ShiftMask) == ShiftMask)
- return key;
- }
-
- return 0;
-}
-
-std::list<KeyCode> InputDevice::releaseShift(void)
-{
- unsigned state;
- std::list<KeyCode> keys;
-
- DeviceIntPtr master;
- XkbDescPtr xkb;
- unsigned int key;
-
- state = getKeyboardState();
- if (!(state & ShiftMask))
- return keys;
-
- master = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT);
- xkb = master->key->xkbInfo->desc;
- for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
- XkbAction *act;
- unsigned char mask;
-
- if (!key_is_down(master, key, KEY_PROCESSED))
- continue;
-
- act = XkbKeyActionPtr(xkb, key, state);
- if (act == NULL)
- continue;
-
- if (act->type != XkbSA_SetMods)
- continue;
-
- if (act->mods.flags & XkbSA_UseModMapMods)
- mask = xkb->map->modmap[key];
- else
- mask = act->mods.mask;
-
- if (!(mask & ShiftMask))
- continue;
-
- keys.push_back(key);
- }
-
- return keys;
-}
-
-KeyCode InputDevice::pressLevelThree(void)
-{
- unsigned state, mask;
-
- KeyCode keycode;
- XkbDescPtr xkb;
- XkbAction *act;
-
- mask = getLevelThreeMask();
- if (mask == 0)
- return 0;
-
- state = getKeyboardState();
- if (state & mask)
- return 0;
-
- keycode = keysymToKeycode(XK_ISO_Level3_Shift, state, NULL);
- if (keycode == 0) {
- keycode = keysymToKeycode(XK_Mode_switch, state, NULL);
- if (keycode == 0)
- return 0;
- }
-
- xkb = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
-
- act = XkbKeyActionPtr(xkb, keycode, state);
- if (act == NULL)
- return 0;
- if (act->type != XkbSA_SetMods)
- return 0;
-
- return keycode;
-}
-
-std::list<KeyCode> InputDevice::releaseLevelThree(void)
-{
- unsigned state, mask;
- std::list<KeyCode> keys;
-
- DeviceIntPtr master;
- XkbDescPtr xkb;
- unsigned int key;
-
- mask = getLevelThreeMask();
- if (mask == 0)
- return keys;
-
- state = getKeyboardState();
- if (!(state & mask))
- return keys;
-
- master = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT);
- xkb = master->key->xkbInfo->desc;
- for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
- XkbAction *act;
- unsigned char key_mask;
-
- if (!key_is_down(master, key, KEY_PROCESSED))
- continue;
-
- act = XkbKeyActionPtr(xkb, key, state);
- if (act == NULL)
- continue;
-
- if (act->type != XkbSA_SetMods)
- continue;
-
- if (act->mods.flags & XkbSA_UseModMapMods)
- key_mask = xkb->map->modmap[key];
- else
- key_mask = act->mods.mask;
-
- if (!(key_mask & mask))
- continue;
-
- keys.push_back(key);
- }
-
- return keys;
-}
-
-KeyCode InputDevice::keysymToKeycode(KeySym keysym, unsigned state,
- unsigned *new_state)
-{
- XkbDescPtr xkb;
- unsigned int key;
- KeySym ks;
- unsigned level_three_mask;
-
- if (new_state != NULL)
- *new_state = state;
-
- xkb = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
- for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
- unsigned int state_out;
- KeySym dummy;
-
- XkbTranslateKeyCode(xkb, key, state, &state_out, &ks);
- if (ks == NoSymbol)
- continue;
-
- /*
- * Despite every known piece of documentation on
- * XkbTranslateKeyCode() stating that mods_rtrn returns
- * the unconsumed modifiers, in reality it always
- * returns the _potentially consumed_ modifiers.
- */
- state_out = state & ~state_out;
- if (state_out & LockMask)
- XkbConvertCase(ks, &dummy, &ks);
-
- if (ks == keysym)
- return key;
- }
-
- if (new_state == NULL)
- return 0;
-
- *new_state = (state & ~ShiftMask) |
- ((state & ShiftMask) ? 0 : ShiftMask);
- key = keysymToKeycode(keysym, *new_state, NULL);
- if (key != 0)
- return key;
-
- level_three_mask = getLevelThreeMask();
- if (level_three_mask == 0)
- return 0;
-
- *new_state = (state & ~level_three_mask) |
- ((state & level_three_mask) ? 0 : level_three_mask);
- key = keysymToKeycode(keysym, *new_state, NULL);
- if (key != 0)
- return key;
-
- *new_state = (state & ~(ShiftMask | level_three_mask)) |
- ((state & ShiftMask) ? 0 : ShiftMask) |
- ((state & level_three_mask) ? 0 : level_three_mask);
- key = keysymToKeycode(keysym, *new_state, NULL);
- if (key != 0)
- return key;
-
- return 0;
-}
-
-bool InputDevice::isLockModifier(KeyCode keycode, unsigned state)
-{
- XkbDescPtr xkb;
- XkbAction *act;
-
- xkb = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
-
- act = XkbKeyActionPtr(xkb, keycode, state);
- if (act == NULL)
- return false;
-
- if (act->type != XkbSA_LockMods)
- return false;
-
- return true;
-}
-
-bool InputDevice::isAffectedByNumLock(KeyCode keycode)
-{
- unsigned state;
-
- KeyCode numlock_keycode;
- unsigned numlock_mask;
-
- XkbDescPtr xkb;
- XkbAction *act;
-
- unsigned group;
- XkbKeyTypeRec *type;
-
- /* Group state is still important */
- state = getKeyboardState();
- state &= ~0xff;
-
- /*
- * Not sure if hunting for a virtual modifier called "NumLock",
- * or following the keysym Num_Lock is the best approach. We
- * try the latter.
- */
- numlock_keycode = keysymToKeycode(XK_Num_Lock, state, NULL);
- if (numlock_keycode == 0)
- return false;
-
- xkb = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
-
- act = XkbKeyActionPtr(xkb, numlock_keycode, state);
- if (act == NULL)
- return false;
- if (act->type != XkbSA_LockMods)
- return false;
-
- if (act->mods.flags & XkbSA_UseModMapMods)
- numlock_mask = xkb->map->modmap[keycode];
- else
- numlock_mask = act->mods.mask;
-
- group = XkbKeyEffectiveGroup(xkb, keycode, state);
- type = XkbKeyKeyType(xkb, keycode, group);
- if ((type->mods.mask & numlock_mask) == 0)
- return false;
-
- return true;
-}
-
-KeyCode InputDevice::addKeysym(KeySym keysym, unsigned state)
-{
- DeviceIntPtr master;
- XkbDescPtr xkb;
- unsigned int key;
-
- XkbEventCauseRec cause;
- XkbChangesRec changes;
-
- int types[1];
- KeySym *syms;
- KeySym upper, lower;
-
- master = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT);
- xkb = master->key->xkbInfo->desc;
- for (key = xkb->max_key_code; key >= xkb->min_key_code; key--) {
- if (XkbKeyNumGroups(xkb, key) == 0)
- break;
- }
-
- if (key < xkb->min_key_code)
- return 0;
-
- memset(&changes, 0, sizeof(changes));
- memset(&cause, 0, sizeof(cause));
-
- XkbSetCauseUnknown(&cause);
-
- /*
- * Tools like xkbcomp get confused if there isn't a name
- * assigned to the keycode we're trying to use.
- */
- if (xkb->names && xkb->names->keys &&
- (xkb->names->keys[key].name[0] == '\0')) {
- xkb->names->keys[key].name[0] = 'I';
- xkb->names->keys[key].name[1] = '0' + (key / 100) % 10;
- xkb->names->keys[key].name[2] = '0' + (key / 10) % 10;
- xkb->names->keys[key].name[3] = '0' + (key / 1) % 10;
-
- changes.names.changed |= XkbKeyNamesMask;
- changes.names.first_key = key;
- changes.names.num_keys = 1;
- }
-
- /* FIXME: Verify that ONE_LEVEL/ALPHABETIC isn't screwed up */
-
- /*
- * For keysyms that are affected by Lock, we are better off
- * using ALPHABETIC rather than ONE_LEVEL as the latter
- * generally cannot produce lower case when Lock is active.
- */
- XkbConvertCase(keysym, &lower, &upper);
- if (upper == lower)
- types[XkbGroup1Index] = XkbOneLevelIndex;
- else
- types[XkbGroup1Index] = XkbAlphabeticIndex;
-
- XkbChangeTypesOfKey(xkb, key, 1, XkbGroup1Mask, types, &changes.map);
-
- syms = XkbKeySymsPtr(xkb,key);
- if (upper == lower)
- syms[0] = keysym;
- else {
- syms[0] = lower;
- syms[1] = upper;
- }
-
- changes.map.changed |= XkbKeySymsMask;
- changes.map.first_key_sym = key;
- changes.map.num_key_syms = 1;
-
- XkbSendNotification(master, &changes, &cause);
-
- return key;
-}
-
-void InputDevice::vncXkbProcessDeviceEvent(int screenNum,
- InternalEvent *event,
- DeviceIntPtr dev)
-{
- unsigned int backupctrls;
-
- if (event->device_event.sourceid == singleton.keyboardDev->id) {
- XkbControlsPtr ctrls;
-
- /*
- * We need to bypass AccessX since it is timing sensitive and
- * the network can cause fake event delays.
- */
- ctrls = dev->key->xkbInfo->desc->ctrls;
- backupctrls = ctrls->enabled_ctrls;
- ctrls->enabled_ctrls &= ~XkbAllFilteredEventsMask;
-
- /*
- * This flag needs to be set for key repeats to be properly
- * respected.
- */
- if ((event->device_event.type == ET_KeyPress) &&
- key_is_down(dev, event->device_event.detail.key, KEY_PROCESSED))
- event->device_event.key_repeat = TRUE;
- }
-
- dev->c_public.processInputProc(event, dev);
-
- if (event->device_event.sourceid == singleton.keyboardDev->id) {
- XkbControlsPtr ctrls;
-
- ctrls = dev->key->xkbInfo->desc->ctrls;
- ctrls->enabled_ctrls = backupctrls;
- }
-}
-
-#endif /* XORG >= 117 */
XREGION_LIB=$(LIB_DIR)/Xregion/libXregion.la
COMMON_LIBS=$(NETWORK_LIB) $(RFB_LIB) $(RDR_LIB) $(XREGION_LIB)
-# Hack to get the C headers to work when included from C++ code
-AM_CXXFLAGS = -fpermissive
-
noinst_LTLIBRARIES = libvnccommon.la
-HDRS = RegionHelper.h vncExtInit.h vncHooks.h XserverDesktop.h xorg-version.h \
- Input.h
+HDRS = vncExtInit.h vncHooks.h \
+ vncBlockHandler.h XorgGlue.h \
+ XserverDesktop.h xorg-version.h \
+ Input.h RFBGlue.h
-libvnccommon_la_SOURCES = $(HDRS) vncExtInit.cc vncHooks.cc XserverDesktop.cc \
- Input.cc InputCore.cc InputXKB.cc
+libvnccommon_la_SOURCES = $(HDRS) vncExt.c vncExtInit.cc vncHooks.c \
+ vncBlockHandler.c XorgGlue.c RFBGlue.cc XserverDesktop.cc \
+ Input.c InputCore.c InputXKB.c
libvnccommon_la_CPPFLAGS = -DVENDOR_RELEASE="$(VENDOR_RELEASE)" \
-DVENDOR_STRING="\"$(VENDOR_STRING)\"" -I$(TIGERVNC_SRCDIR)/common -UHAVE_CONFIG_H \
man1_MANS = Xvnc.man
-Xvnc_SOURCES = xvnc.cc \
+Xvnc_SOURCES = xvnc.c \
$(top_srcdir)/Xi/stubs.c $(top_srcdir)/mi/miinitext.c \
$(top_srcdir)/fb/fbcmap_mi.c buildtime.c
-nodist_Xvnc_SOURCES = fbrop.h fb.h pixman.h
-
Xvnc_CPPFLAGS = $(XVNC_CPPFLAGS) -DTIGERVNC -DNO_MODULE_EXTS \
-UHAVE_CONFIG_H \
-DXFree86Server -DVENDOR_RELEASE="$(VENDOR_RELEASE)" \
libvnc_la_LTLIBRARIES = libvnc.la
libvnc_ladir = $(moduledir)/extensions
-libvnc_la_SOURCES = xf86vncModule.cc
+libvnc_la_SOURCES = vncModule.c
libvnc_la_CPPFLAGS = $(XVNC_CPPFLAGS) -I$(TIGERVNC_SRCDIR)/common -UHAVE_CONFIG_H \
-I$(top_srcdir)/hw/xfree86/common \
libvnc_la_LIBADD = libvnccommon.la $(COMMON_LIBS)
EXTRA_DIST = Xvnc.man
-
-# C++ hacks
-BUILT_SOURCES = $(nodist_Xvnc_SOURCES)
-
-fb.h: $(top_srcdir)/fb/fb.h
- cat $(top_srcdir)/fb/fb.h | sed -e 's,and,c_and,g' -e 's,xor,c_xor,g' > $(srcdir)/fb.h
-
-pixman.h:
- for i in ${XSERVERLIBS_CFLAGS}; do \
- if [[ "$$i" =~ "pixman" ]]; then \
- PIXMANINCDIR=`echo $$i | sed s/-I//g`; \
- fi; \
- done; \
- if [ ! "$$PIXMANINCDIR" = "" ]; then \
- cat $$PIXMANINCDIR/pixman.h | sed 's/xor/c_xor/' > $(srcdir)/pixman.h; \
- else \
- echo Pixman include directory not set in XSERVERLIBS_CFLAGS \(perhaps Pixman was not found by configure?\); \
- fi
-
-fbrop.h: $(top_srcdir)/fb/fbrop.h
- cat $(top_srcdir)/fb/fbrop.h | sed -e 's,and,c_and,g' -e 's,xor,c_xor,g' > $(srcdir)/fbrop.h
--- /dev/null
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2011-2015 Pierre Ossman for Cendio AB
+ *
+ * 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 <stdlib.h>
+
+#include <network/TcpSocket.h>
+#include <rfb/Configuration.h>
+#include <rfb/LogWriter.h>
+#include <rfb/Logger_stdio.h>
+
+#include "RFBGlue.h"
+
+using namespace rfb;
+
+// Loggers used by C code must be created here
+static LogWriter inputLog("Input");
+
+void vncInitRFB(void)
+{
+ rfb::initStdIOLoggers();
+ rfb::LogWriter::setLogParams("*:stderr:30");
+ rfb::Configuration::enableServerParams();
+}
+
+void vncLogError(const char *name, const char *format, ...)
+{
+ LogWriter *vlog;
+ va_list ap;
+ vlog = LogWriter::getLogWriter(name);
+ if (vlog == NULL)
+ return;
+ va_start(ap, format);
+ vlog->error(format, ap);
+ va_end(ap);
+}
+
+void vncLogStatus(const char *name, const char *format, ...)
+{
+ LogWriter *vlog;
+ va_list ap;
+ vlog = LogWriter::getLogWriter(name);
+ if (vlog == NULL)
+ return;
+ va_start(ap, format);
+ vlog->status(format, ap);
+ va_end(ap);
+}
+
+void vncLogInfo(const char *name, const char *format, ...)
+{
+ LogWriter *vlog;
+ va_list ap;
+ vlog = LogWriter::getLogWriter(name);
+ if (vlog == NULL)
+ return;
+ va_start(ap, format);
+ vlog->info(format, ap);
+ va_end(ap);
+}
+
+void vncLogDebug(const char *name, const char *format, ...)
+{
+ LogWriter *vlog;
+ va_list ap;
+ vlog = LogWriter::getLogWriter(name);
+ if (vlog == NULL)
+ return;
+ va_start(ap, format);
+ vlog->debug(format, ap);
+ va_end(ap);
+}
+
+int vncSetParam(const char *name, const char *value)
+{
+ return rfb::Configuration::setParam(name, value);
+}
+
+int vncSetParamSimple(const char *nameAndValue)
+{
+ return rfb::Configuration::setParam(nameAndValue);
+}
+
+char* vncGetParam(const char *name)
+{
+ rfb::VoidParameter *param;
+ char *value;
+ char *ret;
+
+ // Hack to avoid exposing password!
+ if (strcasecmp(name, "Password") == 0)
+ return NULL;
+
+ param = rfb::Configuration::getParam(name);
+ if (param == NULL)
+ return NULL;
+
+ value = param->getValueStr();
+ if (value == NULL)
+ return NULL;
+
+ ret = strdup(value);
+
+ delete [] value;
+
+ return ret;
+}
+
+const char* vncGetParamDesc(const char *name)
+{
+ rfb::VoidParameter *param;
+
+ param = rfb::Configuration::getParam(name);
+ if (param == NULL)
+ return NULL;
+
+ return param->getDescription();
+}
+
+int vncGetParamCount(void)
+{
+ int count;
+
+ count = 0;
+ for (ParameterIterator i; i.param; i.next())
+ count++;
+
+ return count;
+}
+
+char *vncGetParamList(void)
+{
+ int len;
+ char *data, *ptr;
+
+ len = 0;
+
+ for (ParameterIterator i; i.param; i.next()) {
+ int l = strlen(i.param->getName());
+ if (l <= 255)
+ len += l + 1;
+ }
+
+ data = (char*)malloc(len + 1);
+ if (data == NULL)
+ return NULL;
+
+ ptr = data;
+ for (ParameterIterator i; i.param; i.next()) {
+ int l = strlen(i.param->getName());
+ if (l <= 255) {
+ *ptr++ = l;
+ memcpy(ptr, i.param->getName(), l);
+ ptr += l;
+ }
+ }
+ *ptr = '\0';
+
+ return data;
+}
+
+void vncListParams(int width, int nameWidth)
+{
+ rfb::Configuration::listParams(width, nameWidth);
+}
+
+int vncGetSocketPort(int fd)
+{
+ return network::TcpSocket::getSockPort(fd);
+}
+
+int vncIsTCPPortUsed(int port)
+{
+ try {
+ network::TcpListener l(NULL, port);
+ } catch (rdr::Exception& e) {
+ return 0;
+ }
+ return 1;
+}
--- /dev/null
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2011-2015 Pierre Ossman for Cendio AB
+ *
+ * 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 RFB_GLUE_H
+#define RFB_GLUE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void vncInitRFB(void);
+
+#ifdef __GNUC__
+# define __printf_attr(a, b) __attribute__((__format__ (__printf__, a, b)))
+#else
+# define __printf_attr(a, b)
+#endif // __GNUC__
+
+void vncLogError(const char *name, const char *format, ...) __printf_attr(2, 3);
+void vncLogStatus(const char *name, const char *format, ...) __printf_attr(2, 3);
+void vncLogInfo(const char *name, const char *format, ...) __printf_attr(2, 3);
+void vncLogDebug(const char *name, const char *format, ...) __printf_attr(2, 3);
+
+int vncSetParam(const char *name, const char *value);
+int vncSetParamSimple(const char *nameAndValue);
+char* vncGetParam(const char *name);
+const char* vncGetParamDesc(const char *name);
+
+int vncGetParamCount(void);
+char *vncGetParamList(void);
+void vncListParams(int width, int nameWidth);
+
+int vncGetSocketPort(int fd);
+int vncIsTCPPortUsed(int port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+++ /dev/null
-/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-#ifndef __REGIONHELPER_H__
-#define __REGIONHELPER_H__
-
-// RegionHelper is a class which helps in using X server regions by
-// automatically freeing them in the destructor. It also fixes a problem with
-// REGION_INIT when given an empty rectangle.
-
-// REGION_NULL was introduced in the Xorg tree as the way to initialise an
-// empty region. If it's not already defined do it the old way. Note that the
-// old way causes a segfault in the new tree...
-#ifndef REGION_NULL
-#define REGION_NULL(pScreen,pReg) REGION_INIT(pScreen,pReg,NullBox,0)
-#endif
-
-class RegionHelper {
-public:
-
- // constructor from a single rect
- RegionHelper(ScreenPtr pScreen_, BoxPtr rect, int size)
- : pScreen(pScreen_), reg(0)
- {
- init(rect, size);
- }
-
- // constructor from an existing X server region
- RegionHelper(ScreenPtr pScreen_, RegionPtr pRegion)
- : pScreen(pScreen_), reg(®Rec)
- {
- REGION_NULL(pScreen, reg);
- REGION_COPY(pScreen, reg, pRegion);
- }
-
- // constructor from an array of rectangles
- RegionHelper(ScreenPtr pScreen_, int nrects, xRectanglePtr rects,
- int ctype=CT_NONE)
- : pScreen(pScreen_)
- {
- reg = RECTS_TO_REGION(pScreen, nrects, rects, ctype);
- }
-
- // constructor for calling init() later
- RegionHelper(ScreenPtr pScreen_) : pScreen(pScreen_), reg(0) {
- }
-
- void init(BoxPtr rect, int size) {
- reg = ®Rec;
- if (!rect || (rect && (rect->x2 == rect->x1 || rect->y2 == rect->y1))) {
- REGION_NULL(pScreen, reg);
- } else {
- REGION_INIT(pScreen, reg, rect, size);
- }
- }
-
- // destructor frees as appropriate
- ~RegionHelper() {
- if (reg == ®Rec) {
- REGION_UNINIT(pScreen, reg);
- } else if (reg) {
- REGION_DESTROY(pScreen, reg);
- }
- }
- ScreenPtr pScreen;
- RegionRec regRec;
- RegionPtr reg;
-};
-
-#endif
--- /dev/null
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2011-2015 Pierre Ossman for Cendio AB
+ *
+ * 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <assert.h>
+
+#include "scrnintstr.h"
+#ifdef RANDR
+#include "randrstr.h"
+#endif
+
+#include "XorgGlue.h"
+
+#ifdef RANDR
+extern RRModePtr vncRandRModeGet(int width, int height);
+#endif
+
+const char *vncGetDisplay(void)
+{
+ return display;
+}
+
+unsigned long vncGetServerGeneration(void)
+{
+ return serverGeneration;
+}
+
+int vncGetScreenCount(void)
+{
+ return screenInfo.numScreens;
+}
+
+void vncGetScreenFormat(int scrIdx, int *depth, int *bpp,
+ int *trueColour, int *bigEndian,
+ int *redMask, int *greenMask, int *blueMask)
+{
+ int i;
+ VisualPtr vis = NULL;
+
+ assert(depth);
+ assert(bpp);
+ assert(trueColour);
+ assert(bigEndian);
+ assert(redMask);
+ assert(greenMask);
+ assert(blueMask);
+
+ *depth = screenInfo.screens[scrIdx]->rootDepth;
+
+ for (i = 0; i < screenInfo.numPixmapFormats; i++) {
+ if (screenInfo.formats[i].depth == *depth) {
+ *bpp = screenInfo.formats[i].bitsPerPixel;
+ break;
+ }
+ }
+
+ if (i == screenInfo.numPixmapFormats)
+ FatalError("No pixmap format for root depth\n");
+
+ *bigEndian = (screenInfo.imageByteOrder == MSBFirst);
+
+ for (i = 0; i < screenInfo.screens[scrIdx]->numVisuals; i++) {
+ if (screenInfo.screens[scrIdx]->visuals[i].vid ==
+ screenInfo.screens[scrIdx]->rootVisual) {
+ vis = &screenInfo.screens[scrIdx]->visuals[i];
+ break;
+ }
+ }
+
+ if (i == screenInfo.screens[scrIdx]->numVisuals)
+ FatalError("No visual record for root visual\n");
+
+ *trueColour = (vis->class == TrueColor);
+
+ *redMask = vis->redMask;
+ *greenMask = vis->greenMask;
+ *blueMask = vis->blueMask;
+}
+
+int vncGetScreenWidth(int scrIdx)
+{
+ return screenInfo.screens[scrIdx]->width;
+}
+
+int vncGetScreenHeight(int scrIdx)
+{
+ return screenInfo.screens[scrIdx]->height;
+}
+
+int vncRandRResizeScreen(int scrIdx, int width, int height)
+{
+#ifdef RANDR
+ ScreenPtr pScreen = screenInfo.screens[scrIdx];
+ /* Try to retain DPI when we resize */
+ return RRScreenSizeSet(pScreen, width, height,
+ pScreen->mmWidth * width / pScreen->width,
+ pScreen->mmHeight * height / pScreen->height);
+#else
+ return -1;
+#endif
+}
+
+void vncRandRUpdateSetTime(int scrIdx)
+{
+#ifdef RANDR
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+ rp->lastSetTime = currentTime;
+#endif
+}
+
+int vncRandRHasOutputClones(int scrIdx)
+{
+#ifdef RANDR
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+ for (int i = 0;i < rp->numCrtcs;i++) {
+ if (rp->crtcs[i]->numOutputs > 1)
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+int vncRandRGetOutputCount(int scrIdx)
+{
+#ifdef RANDR
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+ return rp->numOutputs;
+#else
+ return 0;
+#endif
+}
+
+int vncRandRGetAvailableOutputs(int scrIdx)
+{
+#ifdef RANDR
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+
+ int availableOutputs;
+ RRCrtcPtr *usedCrtcs;
+ int numUsed;
+
+ int i, j, k;
+
+ usedCrtcs = malloc(sizeof(RRCrtcPtr) * rp->numCrtcs);
+ if (usedCrtcs == NULL)
+ return 0;
+
+ /*
+ * This gets slightly complicated because we might need to hook a CRTC
+ * up to the output, but also check that we don't try to use the same
+ * CRTC for multiple outputs.
+ */
+ availableOutputs = 0;
+ numUsed = 0;
+ for (i = 0;i < rp->numOutputs;i++) {
+ RROutputPtr output;
+
+ output = rp->outputs[i];
+
+ if (output->crtc != NULL)
+ availableOutputs++;
+ else {
+ for (j = 0;j < output->numCrtcs;j++) {
+ if (output->crtcs[j]->numOutputs != 0)
+ continue;
+
+ for (k = 0;k < numUsed;k++) {
+ if (usedCrtcs[k] == output->crtcs[j])
+ break;
+ }
+ if (k != numUsed)
+ continue;
+
+ availableOutputs++;
+
+ usedCrtcs[numUsed] = output->crtcs[j];
+ numUsed++;
+
+ break;
+ }
+ }
+ }
+
+ free(usedCrtcs);
+
+ return availableOutputs;
+#else
+ return 0;
+#endif
+}
+
+const char *vncRandRGetOutputName(int scrIdx, int outputIdx)
+{
+#ifdef RANDR
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+ return rp->outputs[outputIdx]->name;
+#else
+ return "";
+#endif
+}
+
+int vncRandRIsOutputEnabled(int scrIdx, int outputIdx)
+{
+#ifdef RANDR
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+
+ if (rp->outputs[outputIdx]->crtc == NULL)
+ return 0;
+ if (rp->outputs[outputIdx]->crtc->mode == NULL)
+ return 0;
+
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+int vncRandRIsOutputUsable(int scrIdx, int outputIdx)
+{
+#ifdef RANDR
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+
+ RROutputPtr output;
+ int i;
+
+ output = rp->outputs[outputIdx];
+ if (output->crtc != NULL)
+ return 1;
+
+ /* Any unused CRTCs? */
+ for (i = 0;i < output->numCrtcs;i++) {
+ if (output->crtcs[i]->numOutputs == 0)
+ return 1;
+ }
+#endif
+
+ return 0;
+}
+
+int vncRandRDisableOutput(int scrIdx, int outputIdx)
+{
+#ifdef RANDR
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+ RRCrtcPtr crtc;
+
+ crtc = rp->outputs[outputIdx]->crtc;
+ if (crtc == NULL)
+ return 0;
+
+ return RRCrtcSet(crtc, NULL, crtc->x, crtc->y, crtc->rotation, 0, NULL);
+#else
+ return -1;
+#endif
+}
+
+intptr_t vncRandRGetOutputId(int scrIdx, int outputIdx)
+{
+#ifdef RANDR
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+ return (intptr_t)rp->outputs[outputIdx];
+#else
+ return 0;
+#endif
+}
+
+void vncRandRGetOutputDimensions(int scrIdx, int outputIdx,
+ int *x, int *y, int *width, int *height)
+{
+#ifdef RANDR
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+
+ *x = rp->outputs[outputIdx]->crtc->x;
+ *y = rp->outputs[outputIdx]->crtc->y;
+ *width = rp->outputs[outputIdx]->crtc->mode->mode.width;
+ *height = rp->outputs[outputIdx]->crtc->mode->mode.height;
+#endif
+}
+
+#ifdef RANDR
+static RRModePtr findRandRMode(RROutputPtr output, int width, int height)
+{
+ RRModePtr mode;
+
+ for (int i = 0;i < output->numModes;i++) {
+ if ((output->modes[i]->mode.width == width) &&
+ (output->modes[i]->mode.height == height))
+ return output->modes[i];
+ }
+
+ mode = vncRandRModeGet(width, height);
+ if (mode != NULL)
+ return mode;
+
+ return NULL;
+}
+#endif
+
+int vncRandRReconfigureOutput(int scrIdx, int outputIdx, int x, int y,
+ int width, int height)
+{
+#ifdef RANDR
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+
+ RROutputPtr output;
+ RRCrtcPtr crtc;
+ RRModePtr mode;
+
+ int i;
+
+ output = rp->outputs[outputIdx];
+ crtc = output->crtc;
+
+ /* Need a CRTC? */
+ if (crtc == NULL) {
+ for (i = 0;i < output->numCrtcs;i++) {
+ if (output->crtcs[i]->numOutputs != 0)
+ continue;
+
+ crtc = output->crtcs[i];
+ break;
+ }
+
+ /* Couldn't find one... */
+ if (crtc == NULL)
+ return -1;
+ }
+
+ mode = crtc->mode;
+
+ /* Need to switch mode? */
+ if ((mode == NULL) ||
+ (mode->mode.width != width) || (mode->mode.height != height)) {
+ mode = findRandRMode(output, width, height);
+ if (mode == NULL)
+ return -1;
+ }
+
+ /* Reconfigure new mode and position */
+ return RRCrtcSet(crtc, mode, x, y, crtc->rotation, 1, &output);
+#else
+ return -1;
+#endif
+}
--- /dev/null
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2011-2015 Pierre Ossman for Cendio AB
+ *
+ * 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 XORG_GLUE_H
+#define XORG_GLUE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *vncGetDisplay(void);
+unsigned long vncGetServerGeneration(void);
+
+int vncGetScreenCount(void);
+
+void vncGetScreenFormat(int scrIdx, int *depth, int *bpp,
+ int *trueColour, int *bigEndian,
+ int *redMask, int *greenMask, int *blueMask);
+
+int vncGetScreenWidth(int scrIdx);
+int vncGetScreenHeight(int scrIdx);
+
+int vncRandRResizeScreen(int scrIdx, int width, int height);
+void vncRandRUpdateSetTime(int scrIdx);
+
+int vncRandRHasOutputClones(int scrIdx);
+
+int vncRandRGetOutputCount(int scrIdx);
+int vncRandRGetAvailableOutputs(int scrIdx);
+
+const char *vncRandRGetOutputName(int scrIdx, int outputIdx);
+
+int vncRandRIsOutputEnabled(int scrIdx, int outputIdx);
+int vncRandRIsOutputUsable(int scrIdx, int outputIdx);
+
+int vncRandRDisableOutput(int scrIdx, int outputIdx);
+int vncRandRReconfigureOutput(int scrIdx, int outputIdx, int x, int y,
+ int width, int height);
+
+intptr_t vncRandRGetOutputId(int scrIdx, int outputIdx);
+void vncRandRGetOutputDimensions(int scrIdx, int outputIdx,
+ int *x, int *y, int *width, int *height);
+
+// This one hides in xvnc.c or vncModule.c
+int vncRandRCreateOutputs(int scrIdx, int extraOutputs);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2009-2011 Pierre Ossman for Cendio AB
+ * Copyright 2009-2015 Pierre Ossman for Cendio AB
* Copyright 2014 Brian P. Hinz
*
* This is free software; you can redistribute it and/or modify
// XserverDesktop.cxx
//
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
#include <assert.h>
#include <stdio.h>
+#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <pwd.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 <rfb/ServerCore.h>
+
#include "XserverDesktop.h"
#include "vncExtInit.h"
-#include "xorg-version.h"
+#include "vncHooks.h"
+#include "XorgGlue.h"
#include "Input.h"
-extern "C" {
-#define public c_public
-#define class c_class
-
-#ifdef RANDR
-#include "randrstr.h"
-#endif
-#include "cursorstr.h"
-#undef public
-#undef class
-}
+// Hack to catch when inetd has let us go
+extern "C" void vncClientGone(int fd);
using namespace rfb;
using namespace network;
static LogWriter vlog("XserverDesktop");
-IntParameter queryConnectTimeout("QueryConnectTimeout",
- "Number of seconds to show the Accept Connection dialog before "
- "rejecting the connection",
- 10);
-
-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) {}
};
-XserverDesktop::XserverDesktop(ScreenPtr pScreen_,
+XserverDesktop::XserverDesktop(int screenIndex_,
network::TcpListener* listener_,
network::TcpListener* httpListener_,
const char* name, const rfb::PixelFormat &pf,
+ int width, int height,
void* fbptr, int stride)
- : pScreen(pScreen_),
+ : screenIndex(screenIndex_),
server(0), httpServer(0),
listener(listener_), httpListener(httpListener_),
- deferredUpdateTimerSet(false),
- grabbing(false), ignoreHooks_(false), directFbptr(true),
+ deferredUpdateTimerSet(false), directFbptr(true),
queryConnectId(0)
{
format = pf;
server = new VNCServerST(name, this);
- setFramebuffer(pScreen->width, pScreen->height, fbptr, stride);
+ setFramebuffer(width, height, fbptr, stride);
server->setQueryConnectionHandler(this);
if (httpListener)
ScreenSet XserverDesktop::computeScreenLayout()
{
ScreenSet layout;
-
-#ifdef RANDR
- rrScrPrivPtr rp = rrGetScrPriv(pScreen);
OutputIdMap newIdMap;
- for (int i = 0;i < rp->numOutputs;i++) {
- RROutputPtr output;
- RRCrtcPtr crtc;
-
- output = rp->outputs[i];
- crtc = output->crtc;
+ for (int i = 0;i < vncRandRGetOutputCount(screenIndex);i++) {
+ intptr_t outputId;
+ int x, y, width, height;
/* Disabled? */
- if ((crtc == NULL) || (crtc->mode == NULL))
+ if (!vncRandRIsOutputEnabled(screenIndex, i))
continue;
+ outputId = vncRandRGetOutputId(screenIndex, i);
+
/* Known output? */
- if (outputIdMap.count(output) == 1)
- newIdMap[output] = outputIdMap[output];
+ if (outputIdMap.count(outputId) == 1)
+ newIdMap[outputId] = outputIdMap[outputId];
else {
rdr::U32 id;
OutputIdMap::const_iterator iter;
break;
}
- newIdMap[output] = id;
+ newIdMap[outputId] = id;
}
- layout.add_screen(Screen(newIdMap[output], crtc->x, crtc->y,
- crtc->mode->mode.width,
- crtc->mode->mode.height,
- 0));
+ vncRandRGetOutputDimensions(screenIndex, i, &x, &y, &width, &height);
+
+ layout.add_screen(Screen(newIdMap[outputId], x, y, width, height, 0));
}
/* Only keep the entries that are currently active */
outputIdMap = newIdMap;
-#endif
/*
* Make sure we have something to display. Hopefully it's just temporary
* that we have no active outputs...
*/
if (layout.num_screens() == 0)
- layout.add_screen(Screen(0, 0, 0, pScreen->width, pScreen->height, 0));
+ layout.add_screen(Screen(0, 0, 0, vncGetScreenWidth(screenIndex),
+ vncGetScreenHeight(screenIndex), 0));
return layout;
}
-#ifdef RANDR
-
-extern RRModePtr vncRandRModeGet(int width, int height);
-
-RRModePtr XserverDesktop::findRandRMode(RROutputPtr output, int width, int height)
-{
- RRModePtr mode;
-
- for (int i = 0;i < output->numModes;i++) {
- if ((output->modes[i]->mode.width == width) &&
- (output->modes[i]->mode.height == height))
- return output->modes[i];
- }
-
- mode = vncRandRModeGet(width, height);
- if (mode != NULL)
- return mode;
-
- return NULL;
-}
-
-#endif
-
char* XserverDesktop::substitute(const char* varName)
{
if (strcmp(varName, "$$") == 0) {
strncpy(str, uts.nodename, 240);
str[239] = '\0'; /* Ensure string is zero-terminated */
strcat(str, ":");
- strncat(str, display, 10);
+ strncat(str, vncGetDisplay(), 10);
return str;
}
if (strcmp(varName, "$USER") == 0) {
rfb::VNCServerST::queryResult
XserverDesktop::queryConnection(network::Socket* sock,
const char* userName,
- char** reason) {
+ char** reason)
+{
+ int count;
+
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);
+ queryConnectId = (uint32_t)(intptr_t)sock;
+ queryConnectSocket = sock;
+
+ count = vncNotifyQueryConnect();
+ if (count == 0) {
+ *reason = strDup("Unable to query the local user to accept the connection.");
+ return rfb::VNCServerST::REJECT;
+ }
+
return rfb::VNCServerST::PENDING;
}
}
}
-void XserverDesktop::setCursor(CursorPtr cursor)
+void XserverDesktop::setCursor(int width, int height, int hotX, int hotY,
+ const unsigned char *rgbaData)
{
- try {
- int w = cursor->bits->width;
- int h = cursor->bits->height;
-
- rdr::U8* cursorData = new rdr::U8[w * h * (getPF().bpp / 8)];
-
- int rfbMaskBytesPerRow = (w + 7) / 8;
+ rdr::U8* cursorData;
+ rdr::U8* cursorMask;
+ int rfbMaskBytesPerRow;
- rdr::U8* cursorMask = new rdr::U8[rfbMaskBytesPerRow * h];
+ rdr::U8 *out;
+ const unsigned char *in;
+ rdr::U8 rgb[3];
-#ifdef ARGB_CURSOR
- if (cursor->bits->argb) {
- rdr::U8 *out;
- CARD32 *in;
+ cursorData = new rdr::U8[width * height * (getPF().bpp / 8)];
- rdr::U8 rgb[3];
+ rfbMaskBytesPerRow = (width + 7) / 8;
- memset(cursorMask, 0, rfbMaskBytesPerRow * h);
+ cursorMask = new rdr::U8[rfbMaskBytesPerRow * height];
- in = cursor->bits->argb;
- out = cursorData;
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++) {
- rgb[0] = (*in >> 16) & 0xff;
- rgb[1] = (*in >> 8) & 0xff;
- rgb[2] = (*in >> 0) & 0xff;
+ memset(cursorMask, 0, rfbMaskBytesPerRow * height);
- getPF().bufferFromRGB(out, rgb, 1);
+ in = rgbaData;
+ out = cursorData;
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ rgb[0] = *in++;
+ rgb[1] = *in++;
+ rgb[2] = *in++;
- if (((*in >> 24) & 0xff) > 127)
- cursorMask[y * rfbMaskBytesPerRow + x/8] |= 0x80>>(x%8);
+ getPF().bufferFromRGB(out, rgb, 1);
- in++;
- out += getPF().bpp/8;
- }
- }
- } else {
-#endif
- rdr::U8 rgb[3];
- rdr::U8 fg[4], bg[4];
-
- rdr::U8* buffer;
-
- rgb[0] = cursor->foreRed;
- rgb[1] = cursor->foreGreen;
- rgb[2] = cursor->foreBlue;
- getPF().bufferFromRGB(fg, rgb, 1);
-
- rgb[0] = cursor->backRed;
- rgb[1] = cursor->backGreen;
- rgb[2] = cursor->backBlue;
- getPF().bufferFromRGB(bg, rgb, 1);
-
- int xMaskBytesPerRow = BitmapBytePad(w);
-
- buffer = cursorData;
-
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++) {
- rdr::U8 *pixel;
- int byte = y * xMaskBytesPerRow + x / 8;
-#if (BITMAP_BIT_ORDER == MSBFirst)
- int bit = 7 - x % 8;
-#else
- int bit = x % 8;
-#endif
-
- if (cursor->bits->source[byte] & (1 << bit))
- pixel = fg;
- else
- pixel = bg;
-
- memcpy(buffer, pixel, getPF().bpp/8);
- buffer += getPF().bpp/8;
- }
- }
+ if (*in++ > 127)
+ cursorMask[y * rfbMaskBytesPerRow + x/8] |= 0x80>>(x%8);
- 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
- }
-#ifdef ARGB_CURSOR
+ out += getPF().bpp/8;
}
-#endif
+ }
- server->setCursor(cursor->bits->width, cursor->bits->height,
- Point(cursor->bits->xhot, cursor->bits->yhot),
- cursorData, cursorMask);
- delete [] cursorData;
- delete [] cursorMask;
+ try {
+ server->setCursor(width, height, Point(hotX, hotY), cursorData, cursorMask);
} catch (rdr::Exception& e) {
vlog.error("XserverDesktop::setCursor: %s",e.str());
}
+
+ delete [] cursorData;
+ delete [] cursorMask;
}
-void XserverDesktop::add_changed(RegionPtr reg)
+void XserverDesktop::add_changed(const rfb::Region ®ion)
{
- 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);
+ server->add_changed(region);
} catch (rdr::Exception& e) {
vlog.error("XserverDesktop::add_changed: %s",e.str());
}
}
-void XserverDesktop::add_copied(RegionPtr dst, int dx, int dy)
+void XserverDesktop::add_copied(const rfb::Region &dest, const rfb::Point &delta)
{
- 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));
+ server->add_copied(dest, delta);
} catch (rdr::Exception& e) {
vlog.error("XserverDesktop::add_copied: %s",e.str());
}
}
-static struct timeval XserverDesktopTimeout;
-
-void XserverDesktop::blockHandler(fd_set* fds, OSTimePtr timeout)
+void XserverDesktop::readBlockHandler(fd_set* fds, struct timeval ** timeout)
{
// We don't have a good callback for when we can init input devices[1],
// so we abuse the fact that this routine will be called first thing
// once the dix is done initialising.
// [1] Technically Xvnc has InitInput(), but libvnc.so has nothing.
- vncInputDevice->InitInputDevice();
+ vncInitInputDevice();
try {
int nextTimeout;
((*timeout)->tv_sec > (nextTimeout/1000)) ||
(((*timeout)->tv_sec == (nextTimeout/1000)) &&
((*timeout)->tv_usec > ((nextTimeout%1000)*1000)))) {
- XserverDesktopTimeout.tv_sec = nextTimeout/1000;
- XserverDesktopTimeout.tv_usec = (nextTimeout%1000)*1000;
- *timeout = &XserverDesktopTimeout;
+ dixTimeout.tv_sec = nextTimeout/1000;
+ dixTimeout.tv_usec = (nextTimeout%1000)*1000;
+ *timeout = &dixTimeout;
}
}
}
}
-void XserverDesktop::wakeupHandler(fd_set* fds, int nfds)
+void XserverDesktop::readWakeupHandler(fd_set* fds, int nfds)
{
try {
// First check for file descriptors with something to do
}
// We are responsible for propagating mouse movement between clients
- if (!oldCursorPos.equals(vncInputDevice->getPointerPos())) {
- oldCursorPos = vncInputDevice->getPointerPos();
+ int cursorX, cursorY;
+ vncGetPointerPos(&cursorX, &cursorY);
+ if (oldCursorPos.x != cursorX || oldCursorPos.y != cursorY) {
+ oldCursorPos.x = cursorX;
+ oldCursorPos.y = cursorY;
server->setCursorPos(oldCursorPos);
}
}
}
}
-void XserverDesktop::writeBlockHandler(fd_set* fds)
+void XserverDesktop::writeBlockHandler(fd_set* fds, struct timeval ** timeout)
{
try {
std::list<Socket*> sockets;
}
-int XserverDesktop::getQueryTimeout(void* opaqueId,
- const char** address,
- const char** username)
+void XserverDesktop::getQueryConnect(uint32_t* opaqueId,
+ const char** address,
+ const char** username,
+ int *timeout)
{
- 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;
+ *opaqueId = queryConnectId;
+
+ if (queryConnectId == 0) {
+ *address = "";
+ *username = "";
+ *timeout = 0;
+ } else {
+ *address = queryConnectAddress.buf;
+ *username = queryConnectUsername.buf;
+ *timeout = rfb::Server::queryConnectTimeout;
}
- return 0;
}
-void XserverDesktop::approveConnection(void* opaqueId, bool accept,
+void XserverDesktop::approveConnection(uint32_t opaqueId, bool accept,
const char* rejectMsg)
{
if (queryConnectId == opaqueId) {
- server->approveConnection((network::Socket*)opaqueId, accept, rejectMsg);
+ server->approveConnection(queryConnectSocket, accept, rejectMsg);
queryConnectId = 0;
}
}
void XserverDesktop::pointerEvent(const Point& pos, int buttonMask)
{
- vncInputDevice->PointerMove(pos);
- vncInputDevice->PointerButtonAction(buttonMask);
+ vncPointerMove(pos.x, pos.y);
+ vncPointerButtonAction(buttonMask);
}
void XserverDesktop::clientCutText(const char* str, int len)
vncClientCutText(str, len);
}
-extern RROutputPtr vncRandROutputCreate(ScreenPtr pScreen);
-
unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
const rfb::ScreenSet& layout)
{
-#ifndef RANDR
- return rfb::resultProhibited;
-#else
+ int ret;
int availableOutputs;
- Bool ret;
- rrScrPrivPtr rp = rrGetScrPriv(pScreen);
+ // RandR support?
+ if (vncRandRGetOutputCount(screenIndex) == 0)
+ return rfb::resultProhibited;
/*
* First check that we don't have any active clone modes. That's just
* too messy to deal with.
*/
- for (int i = 0;i < rp->numCrtcs;i++) {
- if (rp->crtcs[i]->numOutputs > 1) {
- vlog.error("Clone mode active. Refusing to touch screen layout.");
- return rfb::resultInvalid;
- }
+ if (vncRandRHasOutputClones(screenIndex)) {
+ vlog.error("Clone mode active. Refusing to touch screen layout.");
+ return rfb::resultInvalid;
}
- /*
- * Next count how many useful outputs we have...
- *
- * This gets slightly complicated because we might need to hook a CRTC
- * up to the output, but also check that we don't try to use the same
- * CRTC for multiple outputs.
- */
- std::set<RRCrtcPtr> usedCrtcs;
- availableOutputs = 0;
- for (int i = 0;i < rp->numOutputs;i++) {
- RROutputPtr output;
-
- output = rp->outputs[i];
-
- if (output->crtc != NULL)
- availableOutputs++;
- else {
- for (int j = 0;j < output->numCrtcs;j++) {
- if (output->crtcs[j]->numOutputs != 0)
- continue;
- if (usedCrtcs.count(output->crtcs[j]) != 0)
- continue;
-
- availableOutputs++;
- usedCrtcs.insert(output->crtcs[j]);
-
- break;
- }
- }
- }
+ /* Next count how many useful outputs we have... */
+ availableOutputs = vncRandRGetAvailableOutputs(screenIndex);
/* Try to create more outputs if needed... (only works on Xvnc) */
if (layout.num_screens() > availableOutputs) {
- for (int i = 0;i < (layout.num_screens() - availableOutputs);i++) {
- RROutputPtr output;
- output = vncRandROutputCreate(pScreen);
- if (output == NULL) {
- vlog.error("Unable to create more screens, as needed by the new client layout.");
- return rfb::resultInvalid;
- }
+ ret = vncRandRCreateOutputs(screenIndex,
+ layout.num_screens() - availableOutputs);
+ if (ret < 0) {
+ vlog.error("Unable to create more screens, as needed by the new client layout.");
+ return rfb::resultInvalid;
}
}
/* First we might need to resize the screen */
- if ((fb_width != pScreen->width) || (fb_height != pScreen->height)) {
- /* Try to retain DPI when we resize */
- ret = RRScreenSizeSet(pScreen, fb_width, fb_height,
- pScreen->mmWidth * fb_width / pScreen->width,
- pScreen->mmHeight * fb_height / pScreen->height);
+ if ((fb_width != vncGetScreenWidth(screenIndex)) ||
+ (fb_height != vncGetScreenHeight(screenIndex))) {
+ ret = vncRandRResizeScreen(screenIndex, fb_width, fb_height);
if (!ret) {
vlog.error("Failed to resize screen to %dx%d", fb_width, fb_height);
return rfb::resultInvalid;
}
/* Next, reconfigure all known outputs, and turn off the other ones */
- for (int i = 0;i < rp->numOutputs;i++) {
- RROutputPtr output;
- RRCrtcPtr crtc;
- RRModePtr mode;
+ for (int i = 0;i < vncRandRGetOutputCount(screenIndex);i++) {
+ intptr_t output;
ScreenSet::const_iterator iter;
- output = rp->outputs[i];
- crtc = output->crtc;
+ output = vncRandRGetOutputId(screenIndex, i);
/* Known? */
if (outputIdMap.count(output) == 0)
continue;
- /* A known output should have a CRTC, but double check... */
- if (crtc == NULL) {
- vlog.error("Existing output '%s' has unexpectedly been disabled",
- output->name);
- continue;
- }
-
/* Find the corresponding screen... */
for (iter = layout.begin();iter != layout.end();++iter) {
if (iter->id == outputIdMap[output])
/* Missing? */
if (iter == layout.end()) {
/* Disable and move on... */
- ret = RRCrtcSet(crtc, NULL, crtc->x, crtc->y, crtc->rotation, 0, NULL);
+ ret = vncRandRDisableOutput(screenIndex, i);
if (!ret) {
- vlog.error("Failed to disable unused CRTC for output '%s'",
- output->name);
+ vlog.error("Failed to disable unused output '%s'",
+ vncRandRGetOutputName(screenIndex, i));
return rfb::resultInvalid;
}
outputIdMap.erase(output);
continue;
}
- /* Need to switch mode? */
- if ((crtc->mode->mode.width == iter->dimensions.width()) &&
- (crtc->mode->mode.height == iter->dimensions.height()))
- mode = crtc->mode;
- else {
- mode = findRandRMode(output, iter->dimensions.width(),
- iter->dimensions.height());
- if (mode == NULL) {
- vlog.error("Failed to find a suitable mode for %dx%d for output '%s'",
- iter->dimensions.width(), iter->dimensions.height(),
- output->name);
- return rfb::resultInvalid;
- }
- }
-
/* Reconfigure new mode and position */
- ret = RRCrtcSet(crtc, mode, iter->dimensions.tl.x, iter->dimensions.tl.y,
- crtc->rotation, crtc->numOutputs, crtc->outputs);
+ ret = vncRandRReconfigureOutput(screenIndex, i,
+ iter->dimensions.tl.x,
+ iter->dimensions.tl.y,
+ iter->dimensions.width(),
+ iter->dimensions.height());
if (!ret) {
vlog.error("Failed to reconfigure output '%s' to %dx%d+%d+%d",
- output->name,
+ vncRandRGetOutputName(screenIndex, i),
iter->dimensions.width(), iter->dimensions.height(),
iter->dimensions.tl.x, iter->dimensions.tl.y);
return rfb::resultInvalid;
ScreenSet::const_iterator iter;
for (iter = layout.begin();iter != layout.end();++iter) {
OutputIdMap::const_iterator oi;
-
- RROutputPtr output;
- RRCrtcPtr crtc;
- RRModePtr mode;
-
+ intptr_t output;
int i;
/* Does this screen have an output already? */
continue;
/* Find an unused output */
- for (i = 0;i < rp->numOutputs;i++) {
- output = rp->outputs[i];
- crtc = output->crtc;
+ for (i = 0;i < vncRandRGetOutputCount(screenIndex);i++) {
+ output = vncRandRGetOutputId(screenIndex, i);
/* In use? */
if (outputIdMap.count(output) == 1)
continue;
- /* Need a CRTC? */
- if (crtc == NULL) {
- for (int j = 0;j < output->numCrtcs;j++) {
- if (output->crtcs[j]->numOutputs != 0)
- continue;
-
- crtc = output->crtcs[j];
- break;
- }
-
- /* Couldn't find one... */
- if (crtc == NULL)
- continue;
-
- ret = RRCrtcSet(crtc, NULL, 0, 0, RR_Rotate_0,
- 1, &output);
- if (!ret) {
- vlog.error("Failed to associate a CRTC with output '%s'",
- output->name);
- return rfb::resultInvalid;
- }
- }
+ /* Can it be used? */
+ if (!vncRandRIsOutputUsable(screenIndex, i))
+ continue;
break;
}
/* Shouldn't happen */
- if (i == rp->numOutputs)
+ if (i == vncRandRGetOutputCount(screenIndex))
return rfb::resultInvalid;
- mode = findRandRMode(output, iter->dimensions.width(),
- iter->dimensions.height());
- if (mode == NULL) {
- vlog.error("Failed to find a suitable mode for %dx%d for output '%s'",
- iter->dimensions.width(), iter->dimensions.height(),
- output->name);
- return rfb::resultInvalid;
- }
-
/*
* Make sure we already have an entry for this, or
* computeScreenLayout() will think it is a brand new output and
outputIdMap[output] = iter->id;
/* Reconfigure new mode and position */
- ret = RRCrtcSet(crtc, mode, iter->dimensions.tl.x, iter->dimensions.tl.y,
- crtc->rotation, crtc->numOutputs, crtc->outputs);
+ ret = vncRandRReconfigureOutput(screenIndex, i,
+ iter->dimensions.tl.x,
+ iter->dimensions.tl.y,
+ iter->dimensions.width(),
+ iter->dimensions.height());
if (!ret) {
vlog.error("Failed to reconfigure output '%s' to %dx%d+%d+%d",
- output->name,
+ vncRandRGetOutputName(screenIndex, i),
iter->dimensions.width(), iter->dimensions.height(),
iter->dimensions.tl.x, iter->dimensions.tl.y);
return rfb::resultInvalid;
* This is normally done in the X11 request handlers, which is
* why we have to deal with it manually here.
*/
- rp->lastSetTime = currentTime;
+ vncRandRUpdateSetTime(screenIndex);
return rfb::resultSuccess;
-#endif
}
void XserverDesktop::grabRegion(const rfb::Region& region)
{
- if (directFbptr) return;
- if (!pScreen->GetImage) {
- vlog.error("VNC error: pScreen->GetImage == 0");
+ if (directFbptr)
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++) {
- DrawablePtr pDrawable;
-#if XORG < 19
- pDrawable = (DrawablePtr) WindowTable[pScreen->myNum];
-#else
- pDrawable = (DrawablePtr) pScreen->root;
-#endif
-
- (*pScreen->GetImage) (pDrawable, i->tl.x, y, i->width(), 1,
- ZPixmap, (unsigned long)~0L,
- ((char*)data
- + y * bytesPerRow + i->tl.x * bytesPerPixel));
- }
+ rdr::U8 *buffer;
+ int stride;
+
+ buffer = getBufferRW(*i, &stride);
+ vncGetScreenImage(screenIndex, i->tl.x, i->tl.y, i->width(), i->height(),
+ (char*)buffer, stride * format.bpp/8);
+ commitBufferRW(*i);
}
- grabbing = false;
}
void XserverDesktop::keyEvent(rdr::U32 keysym, bool down)
{
- if (down)
- vncInputDevice->KeyboardPress(keysym);
- else
- vncInputDevice->KeyboardRelease(keysym);
+ vncKeyboardEvent(keysym, down);
}
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2009-2011 Pierre Ossman for Cendio AB
+ * Copyright 2009-2015 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include <map>
+#include <stdint.h>
+
#include <rfb/SDesktop.h>
#include <rfb/HTTPServer.h>
#include <rfb/PixelBuffer.h>
#include <rdr/SubstitutingInStream.h>
#include "Input.h"
-extern "C" {
-#define class c_class
-#include <scrnintstr.h>
-#include <os.h>
-#ifdef RANDR
-#include <randrstr.h>
-#endif
-#undef class
-}
-
namespace rfb {
class VNCServerST;
}
public rfb::VNCServerST::QueryConnectionHandler {
public:
- XserverDesktop(ScreenPtr pScreen, network::TcpListener* listener,
+ XserverDesktop(int screenIndex, network::TcpListener* listener,
network::TcpListener* httpListener_,
const char* name, const rfb::PixelFormat &pf,
- void* fbptr, int stride);
+ int width, int height, void* fbptr, int stride);
virtual ~XserverDesktop();
// methods called from X server code
void bell();
void serverCutText(const char* str, int len);
void setDesktopName(const char* name);
- void setCursor(CursorPtr cursor);
- void add_changed(RegionPtr reg);
- void add_copied(RegionPtr dst, int dx, int dy);
- void ignoreHooks(bool b) { ignoreHooks_ = b; }
- void blockHandler(fd_set* fds, OSTimePtr timeout);
- void wakeupHandler(fd_set* fds, int nfds);
- void writeBlockHandler(fd_set* fds);
+ void setCursor(int width, int height, int hotX, int hotY,
+ const unsigned char *rgbaData);
+ void add_changed(const rfb::Region ®ion);
+ void add_copied(const rfb::Region &dest, const rfb::Point &delta);
+ void readBlockHandler(fd_set* fds, struct timeval ** timeout);
+ void readWakeupHandler(fd_set* fds, int nfds);
+ void writeBlockHandler(fd_set* fds, struct timeval ** timeout);
void writeWakeupHandler(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);
+ // getQueryConnect()
+ // Returns information about the currently waiting query
+ // (or an id of 0 if there is none waiting)
+ void getQueryConnect(uint32_t* opaqueId, const char** address,
+ const char** username, int *timeout);
// approveConnection()
// Used by X server code to supply the result of a query.
- void approveConnection(void* opaqueId, bool accept,
+ void approveConnection(uint32_t opaqueId, bool accept,
const char* rejectMsg=0);
// rfb::SDesktop callbacks
private:
rfb::ScreenSet computeScreenLayout();
-#ifdef RANDR
- RRModePtr findRandRMode(RROutputPtr output, int width, int height);
-#endif
- ScreenPtr pScreen;
+ int screenIndex;
rfb::VNCServerST* server;
rfb::HTTPServer* httpServer;
network::TcpListener* listener;
network::TcpListener* httpListener;
bool deferredUpdateTimerSet;
- bool grabbing;
- bool ignoreHooks_;
bool directFbptr;
+ struct timeval dixTimeout;
- void* queryConnectId;
+ uint32_t queryConnectId;
+ network::Socket* queryConnectSocket;
rfb::CharArray queryConnectAddress;
rfb::CharArray queryConnectUsername;
#ifdef RANDR
- typedef std::map<RROutputPtr, rdr::U32> OutputIdMap;
+ typedef std::map<intptr_t, rdr::U32> OutputIdMap;
OutputIdMap outputIdMap;
#endif
--- /dev/null
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2011-2014 Pierre Ossman for Cendio AB
+ *
+ * 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <errno.h>
+
+#include <X11/Xpoll.h>
+
+#include "dix.h"
+#include "scrnintstr.h"
+
+#include "vncExtInit.h"
+#include "vncBlockHandler.h"
+
+static void vncBlockHandler(void * data, OSTimePtr t, void * readmask);
+static void vncWakeupHandler(void * data, int nfds, void * readmask);
+void vncWriteBlockHandler(fd_set *fds);
+void vncWriteWakeupHandler(int nfds, fd_set *fds);
+
+void vncRegisterBlockHandlers(void)
+{
+ if (!RegisterBlockAndWakeupHandlers(vncBlockHandler, vncWakeupHandler, 0))
+ FatalError("RegisterBlockAndWakeupHandlers() failed\n");
+}
+
+static void vncWriteBlockHandlerFallback(OSTimePtr timeout);
+static void vncWriteWakeupHandlerFallback(void);
+
+//
+// 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(void * data, OSTimePtr timeout, void * readmask)
+{
+ fd_set* fds = (fd_set*)readmask;
+
+ vncWriteBlockHandlerFallback(timeout);
+
+ vncCallReadBlockHandlers(fds, timeout);
+}
+
+static void vncWakeupHandler(void * data, int nfds, void * readmask)
+{
+ fd_set* fds = (fd_set*)readmask;
+
+ vncCallReadWakeupHandlers(fds, nfds);
+
+ vncWriteWakeupHandlerFallback();
+}
+
+//
+// vncWriteBlockHandler - extra hack to be able to get the main select loop
+// to monitor writeable fds and not just readable. This requirers a modified
+// Xorg and might therefore not be called. When it is called though, it will
+// do so before vncBlockHandler (and vncWriteWakeupHandler called after
+// vncWakeupHandler).
+//
+
+static Bool needFallback = TRUE;
+static fd_set fallbackFds;
+static struct timeval tw;
+
+void vncWriteBlockHandler(fd_set *fds)
+{
+ struct timeval *dummy;
+
+ needFallback = FALSE;
+
+ dummy = NULL;
+ vncCallWriteBlockHandlers(fds, &dummy);
+}
+
+void vncWriteWakeupHandler(int nfds, fd_set *fds)
+{
+ vncCallWriteWakeupHandlers(fds, nfds);
+}
+
+static void vncWriteBlockHandlerFallback(OSTimePtr timeout)
+{
+ if (!needFallback)
+ return;
+
+ FD_ZERO(&fallbackFds);
+ vncWriteBlockHandler(&fallbackFds);
+
+ if (!XFD_ANYSET(&fallbackFds))
+ return;
+
+ if ((*timeout == NULL) ||
+ ((*timeout)->tv_sec > 0) || ((*timeout)->tv_usec > 10000)) {
+ tw.tv_sec = 0;
+ tw.tv_usec = 10000;
+ *timeout = &tw;
+ }
+}
+
+static void vncWriteWakeupHandlerFallback(void)
+{
+ int ret;
+ struct timeval timeout;
+
+ if (!needFallback)
+ return;
+
+ if (!XFD_ANYSET(&fallbackFds))
+ return;
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ ret = select(XFD_SETSIZE, NULL, &fallbackFds, NULL, &timeout);
+ if (ret < 0) {
+ ErrorF("vncWriteWakeupHandlerFallback(): select: %s\n",
+ strerror(errno));
+ return;
+ }
+
+ if (ret == 0)
+ return;
+
+ vncWriteWakeupHandler(ret, &fallbackFds);
+}
--- /dev/null
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2011-2014 Pierre Ossman for Cendio AB
+ *
+ * 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 VNCBLOCKHANDLER_H
+#define VNCBLOCKHANDLER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void vncRegisterBlockHandlers(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2011-2015 Pierre Ossman for Cendio AB
+ *
+ * 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#define NEED_EVENTS
+#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"
+
+#include "xorg-version.h"
+
+#include "vncExtInit.h"
+#include "RFBGlue.h"
+
+static int ProcVncExtDispatch(ClientPtr client);
+static int SProcVncExtDispatch(ClientPtr client);
+static void vncResetProc(ExtensionEntry* extEntry);
+
+static void vncClientStateChange(CallbackListPtr*, void *, void *);
+
+static void vncSelectionCallback(CallbackListPtr *callbacks,
+ void * data, void * args);
+
+static int vncErrorBase = 0;
+static int vncEventBase = 0;
+
+int vncNoClipboard = 0;
+
+static char* clientCutText = NULL;
+static int clientCutTextLen = 0;
+
+static struct VncInputSelect* vncInputSelectHead = NULL;
+
+struct VncInputSelect {
+ ClientPtr client;
+ Window window;
+ int mask;
+ struct VncInputSelect* next;
+};
+
+int vncAddExtension(void)
+{
+ ExtensionEntry* extEntry;
+
+ extEntry = AddExtension(VNCEXTNAME, VncExtNumberEvents, VncExtNumberErrors,
+ ProcVncExtDispatch, SProcVncExtDispatch, vncResetProc,
+ StandardMinorOpcode);
+ if (!extEntry) {
+ ErrorF("vncAddExtension: AddExtension failed\n");
+ return -1;
+ }
+
+ vncErrorBase = extEntry->errorBase;
+ vncEventBase = extEntry->eventBase;
+
+ if (!AddCallback(&ClientStateCallback, vncClientStateChange, 0)) {
+ FatalError("Add ClientStateCallback failed\n");
+ }
+
+ if (!AddCallback(&SelectionCallback, vncSelectionCallback, 0)) {
+ FatalError("Add SelectionCallback failed\n");
+ }
+
+ return 0;
+}
+
+int vncNotifyQueryConnect(void)
+{
+ int count;
+ xVncExtQueryConnectNotifyEvent ev;
+
+ ev.type = vncEventBase + VncExtQueryConnectNotify;
+
+ count = 0;
+ for (struct VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) {
+ if (cur->mask & VncExtQueryConnectMask) {
+ ev.sequenceNumber = cur->client->sequence;
+ ev.window = cur->window;
+ if (cur->client->swapped) {
+#if XORG < 112
+ int n;
+ swaps(&ev.sequenceNumber, n);
+ swapl(&ev.window, n);
+#else
+ swaps(&ev.sequenceNumber);
+ swapl(&ev.window);
+#endif
+ }
+ WriteToClient(cur->client, sizeof(xVncExtQueryConnectNotifyEvent),
+ (char *)&ev);
+ count++;
+ }
+ }
+
+ return count;
+}
+
+void vncClientCutText(const char* str, int len)
+{
+ if (clientCutText != NULL)
+ free(clientCutText);
+ clientCutTextLen = 0;
+
+ clientCutText = malloc(len);
+ if (clientCutText == NULL) {
+ ErrorF("Could not allocate clipboard buffer\n");
+ return;
+ }
+
+ memcpy(clientCutText, str, len);
+ clientCutTextLen = len;
+
+ xVncExtClientCutTextNotifyEvent ev;
+ ev.type = vncEventBase + VncExtClientCutTextNotify;
+ for (struct 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) {
+#if XORG < 112
+ int n;
+ swaps(&ev.sequenceNumber, n);
+ swapl(&ev.window, n);
+ swapl(&ev.time, n);
+#else
+ swaps(&ev.sequenceNumber);
+ swapl(&ev.window);
+ swapl(&ev.time);
+#endif
+ }
+ WriteToClient(cur->client, sizeof(xVncExtClientCutTextNotifyEvent),
+ (char *)&ev);
+ }
+ }
+}
+
+static int ProcVncExtSetParam(ClientPtr client)
+{
+ char *param;
+
+ REQUEST(xVncExtSetParamReq);
+ REQUEST_FIXED_SIZE(xVncExtSetParamReq, stuff->paramLen);
+
+ param = malloc(stuff->paramLen+1);
+ if (param == NULL)
+ return BadAlloc;
+ strncpy(param, (char*)&stuff[1], stuff->paramLen);
+ param[stuff->paramLen] = '\0';
+
+ xVncExtSetParamReply rep;
+ rep.type = X_Reply;
+ rep.length = 0;
+ rep.success = 0;
+ rep.sequenceNumber = client->sequence;
+
+ /*
+ * Allow to change only certain parameters.
+ * Changing other parameters (for example PAM service name)
+ * could have negative security impact.
+ */
+ if (strncasecmp(param, "desktop", 7) != 0 &&
+ strncasecmp(param, "AcceptPointerEvents", 19) != 0 &&
+ (vncNoClipboard || strncasecmp(param, "SendCutText", 11) != 0) &&
+ (vncNoClipboard || strncasecmp(param, "AcceptCutText", 13) != 0))
+ goto deny;
+
+ vncSetParamSimple(param);
+ rep.success = 1;
+
+ // Send DesktopName update if desktop name has been changed
+ if (strncasecmp(param, "desktop", 7) != 0)
+ vncUpdateDesktopName();
+
+deny:
+ free(param);
+
+ if (client->swapped) {
+#if XORG < 112
+ int n;
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+#else
+ swaps(&rep.sequenceNumber);
+ swapl(&rep.length);
+#endif
+ }
+ WriteToClient(client, sizeof(xVncExtSetParamReply), (char *)&rep);
+ return (client->noClientException);
+}
+
+static int SProcVncExtSetParam(ClientPtr client)
+{
+ REQUEST(xVncExtSetParamReq);
+#if XORG < 112
+ register char n;
+ swaps(&stuff->length, n);
+#else
+ swaps(&stuff->length);
+#endif
+ REQUEST_AT_LEAST_SIZE(xVncExtSetParamReq);
+ return ProcVncExtSetParam(client);
+}
+
+static int ProcVncExtGetParam(ClientPtr client)
+{
+ char* param;
+ char* value;
+ size_t len;
+
+ REQUEST(xVncExtGetParamReq);
+ REQUEST_FIXED_SIZE(xVncExtGetParamReq, stuff->paramLen);
+
+ param = malloc(stuff->paramLen+1);
+ if (param == NULL)
+ return BadAlloc;
+ strncpy(param, (char*)&stuff[1], stuff->paramLen);
+ param[stuff->paramLen] = 0;
+
+ value = vncGetParam(param);
+ len = value ? strlen(value) : 0;
+
+ free(param);
+
+ xVncExtGetParamReply rep;
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ rep.success = 0;
+ if (value)
+ rep.success = 1;
+ rep.length = (len + 3) >> 2;
+ rep.valueLen = len;
+ if (client->swapped) {
+#if XORG < 112
+ int n;
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swaps(&rep.valueLen, n);
+#else
+ swaps(&rep.sequenceNumber);
+ swapl(&rep.length);
+ swaps(&rep.valueLen);
+#endif
+ }
+ WriteToClient(client, sizeof(xVncExtGetParamReply), (char *)&rep);
+ if (value)
+ WriteToClient(client, len, value);
+ free(value);
+ return (client->noClientException);
+}
+
+static int SProcVncExtGetParam(ClientPtr client)
+{
+ REQUEST(xVncExtGetParamReq);
+#if XORG < 112
+ register char n;
+ swaps(&stuff->length, n);
+#else
+ swaps(&stuff->length);
+#endif
+ REQUEST_AT_LEAST_SIZE(xVncExtGetParamReq);
+ return ProcVncExtGetParam(client);
+}
+
+static int ProcVncExtGetParamDesc(ClientPtr client)
+{
+ char* param;
+ const char* desc;
+ size_t len;
+
+ REQUEST(xVncExtGetParamDescReq);
+ REQUEST_FIXED_SIZE(xVncExtGetParamDescReq, stuff->paramLen);
+
+ param = malloc(stuff->paramLen+1);
+ if (param == NULL)
+ return BadAlloc;
+ strncpy(param, (char*)&stuff[1], stuff->paramLen);
+ param[stuff->paramLen] = 0;
+
+ desc = vncGetParamDesc(param);
+ len = desc ? strlen(desc) : 0;
+
+ free(param);
+
+ xVncExtGetParamDescReply rep;
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ rep.success = 0;
+ if (desc)
+ rep.success = 1;
+ rep.length = (len + 3) >> 2;
+ rep.descLen = len;
+ if (client->swapped) {
+#if XORG < 112
+ int n;
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swaps(&rep.descLen, n);
+#else
+ swaps(&rep.sequenceNumber);
+ swapl(&rep.length);
+ swaps(&rep.descLen);
+#endif
+ }
+ WriteToClient(client, sizeof(xVncExtGetParamDescReply), (char *)&rep);
+ if (desc)
+ WriteToClient(client, len, (char*)desc);
+ return (client->noClientException);
+}
+
+static int SProcVncExtGetParamDesc(ClientPtr client)
+{
+ REQUEST(xVncExtGetParamDescReq);
+#if XORG < 112
+ register char n;
+ swaps(&stuff->length, n);
+#else
+ swaps(&stuff->length);
+#endif
+ REQUEST_AT_LEAST_SIZE(xVncExtGetParamDescReq);
+ return ProcVncExtGetParamDesc(client);
+}
+
+static int ProcVncExtListParams(ClientPtr client)
+{
+ REQUEST(xVncExtListParamsReq);
+ REQUEST_SIZE_MATCH(xVncExtListParamsReq);
+
+ xVncExtListParamsReply rep;
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+
+ char *params;
+ size_t len;
+
+ params = vncGetParamList();
+ if (params == NULL)
+ return BadAlloc;
+
+ len = strlen(params);
+
+ rep.length = (len + 3) >> 2;
+ rep.nParams = vncGetParamCount();
+ if (client->swapped) {
+#if XORG < 112
+ int n;
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swaps(&rep.nParams, n);
+#else
+ swaps(&rep.sequenceNumber);
+ swapl(&rep.length);
+ swaps(&rep.nParams);
+#endif
+ }
+ WriteToClient(client, sizeof(xVncExtListParamsReply), (char *)&rep);
+ WriteToClient(client, len, (char*)params);
+ free(params);
+ return (client->noClientException);
+}
+
+static int SProcVncExtListParams(ClientPtr client)
+{
+ REQUEST(xVncExtListParamsReq);
+#if XORG < 112
+ register char n;
+ swaps(&stuff->length, n);
+#else
+ swaps(&stuff->length);
+#endif
+ REQUEST_SIZE_MATCH(xVncExtListParamsReq);
+ return ProcVncExtListParams(client);
+}
+
+static int ProcVncExtSetServerCutText(ClientPtr client)
+{
+ REQUEST(xVncExtSetServerCutTextReq);
+ REQUEST_FIXED_SIZE(xVncExtSetServerCutTextReq, stuff->textLen);
+ vncServerCutText((const char*)&stuff[1], stuff->textLen);
+ return (client->noClientException);
+}
+
+static int SProcVncExtSetServerCutText(ClientPtr client)
+{
+ REQUEST(xVncExtSetServerCutTextReq);
+#if XORG < 112
+ register char n;
+ swaps(&stuff->length, n);
+#else
+ swaps(&stuff->length);
+#endif
+ REQUEST_AT_LEAST_SIZE(xVncExtSetServerCutTextReq);
+#if XORG < 112
+ swapl(&stuff->textLen, n);
+#else
+ swapl(&stuff->textLen);
+#endif
+ return ProcVncExtSetServerCutText(client);
+}
+
+static int ProcVncExtGetClientCutText(ClientPtr client)
+{
+ REQUEST(xVncExtGetClientCutTextReq);
+ REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq);
+
+ xVncExtGetClientCutTextReply rep;
+ rep.type = X_Reply;
+ rep.length = (clientCutTextLen + 3) >> 2;
+ rep.sequenceNumber = client->sequence;
+ rep.textLen = clientCutTextLen;
+ if (client->swapped) {
+#if XORG < 112
+ int n;
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swapl(&rep.textLen, n);
+#else
+ swaps(&rep.sequenceNumber);
+ swapl(&rep.length);
+ swapl(&rep.textLen);
+#endif
+ }
+ WriteToClient(client, sizeof(xVncExtGetClientCutTextReply), (char *)&rep);
+ if (clientCutText)
+ WriteToClient(client, clientCutTextLen, clientCutText);
+ return (client->noClientException);
+}
+
+static int SProcVncExtGetClientCutText(ClientPtr client)
+{
+ REQUEST(xVncExtGetClientCutTextReq);
+#if XORG < 112
+ register char n;
+ swaps(&stuff->length, n);
+#else
+ swaps(&stuff->length);
+#endif
+ REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq);
+ return ProcVncExtGetClientCutText(client);
+}
+
+static int ProcVncExtSelectInput(ClientPtr client)
+{
+ struct VncInputSelect** nextPtr;
+ struct VncInputSelect* cur;
+ REQUEST(xVncExtSelectInputReq);
+ REQUEST_SIZE_MATCH(xVncExtSelectInputReq);
+ nextPtr = &vncInputSelectHead;
+ for (cur = vncInputSelectHead; cur; cur = *nextPtr) {
+ if (cur->client == client && cur->window == stuff->window) {
+ cur->mask = stuff->mask;
+ if (!cur->mask) {
+ *nextPtr = cur->next;
+ free(cur);
+ }
+ break;
+ }
+ nextPtr = &cur->next;
+ }
+ if (!cur) {
+ cur = malloc(sizeof(struct VncInputSelect));
+ if (cur == NULL)
+ return BadAlloc;
+ memset(cur, 0, sizeof(struct VncInputSelect));
+
+ cur->client = client;
+ cur->window = stuff->window;
+ cur->mask = stuff->mask;
+
+ cur->next = vncInputSelectHead;
+ vncInputSelectHead = cur;
+ }
+ return (client->noClientException);
+}
+
+static int SProcVncExtSelectInput(ClientPtr client)
+{
+ REQUEST(xVncExtSelectInputReq);
+#if XORG < 112
+ register char n;
+ swaps(&stuff->length, n);
+#else
+ swaps(&stuff->length);
+#endif
+ REQUEST_SIZE_MATCH(xVncExtSelectInputReq);
+#if XORG < 112
+ swapl(&stuff->window, n);
+ swapl(&stuff->mask, n);
+#else
+ swapl(&stuff->window);
+ swapl(&stuff->mask);
+#endif
+ return ProcVncExtSelectInput(client);
+}
+
+static int ProcVncExtConnect(ClientPtr client)
+{
+ char *address;
+
+ REQUEST(xVncExtConnectReq);
+ REQUEST_FIXED_SIZE(xVncExtConnectReq, stuff->strLen);
+
+ address = malloc(stuff->strLen+1);
+ if (address == NULL)
+ return BadAlloc;
+ strncpy(address, (char*)&stuff[1], stuff->strLen);
+ address[stuff->strLen] = 0;
+
+ xVncExtConnectReply rep;
+ rep.success = 0;
+ if (vncConnectClient(address) == 0)
+ rep.success = 1;
+
+ rep.type = X_Reply;
+ rep.length = 0;
+ rep.sequenceNumber = client->sequence;
+ if (client->swapped) {
+#if XORG < 112
+ int n;
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+#else
+ swaps(&rep.sequenceNumber);
+ swapl(&rep.length);
+#endif
+ }
+ WriteToClient(client, sizeof(xVncExtConnectReply), (char *)&rep);
+
+ free(address);
+
+ return (client->noClientException);
+}
+
+static int SProcVncExtConnect(ClientPtr client)
+{
+ REQUEST(xVncExtConnectReq);
+#if XORG < 112
+ register char n;
+ swaps(&stuff->length, n);
+#else
+ swaps(&stuff->length);
+#endif
+ REQUEST_AT_LEAST_SIZE(xVncExtConnectReq);
+ return ProcVncExtConnect(client);
+}
+
+
+static int ProcVncExtGetQueryConnect(ClientPtr client)
+{
+ REQUEST(xVncExtGetQueryConnectReq);
+ REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq);
+
+ uint32_t opaqueId;
+ const char *qcAddress, *qcUsername;
+ int qcTimeout;
+
+ vncGetQueryConnect(&opaqueId, &qcAddress, &qcUsername, &qcTimeout);
+
+ xVncExtGetQueryConnectReply rep;
+ 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)(long)opaqueId;
+ rep.length = ((rep.userLen + 3) >> 2) + ((rep.addrLen + 3) >> 2);
+ if (client->swapped) {
+#if XORG < 112
+ int n;
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.addrLen, n);
+ swapl(&rep.userLen, n);
+ swapl(&rep.timeout, n);
+ swapl(&rep.opaqueId, n);
+ swapl(&rep.length, n);
+#else
+ swaps(&rep.sequenceNumber);
+ swapl(&rep.addrLen);
+ swapl(&rep.userLen);
+ swapl(&rep.timeout);
+ swapl(&rep.opaqueId);
+ swapl(&rep.length);
+#endif
+ }
+ 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)
+{
+ REQUEST(xVncExtGetQueryConnectReq);
+#if XORG < 112
+ register char n;
+ swaps(&stuff->length, n);
+#else
+ swaps(&stuff->length);
+#endif
+ REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq);
+ return ProcVncExtGetQueryConnect(client);
+}
+
+
+static int ProcVncExtApproveConnect(ClientPtr client)
+{
+ REQUEST(xVncExtApproveConnectReq);
+ REQUEST_SIZE_MATCH(xVncExtApproveConnectReq);
+ vncApproveConnection(stuff->opaqueId, stuff->approve);
+ // Inform other clients of the event and tidy up
+ vncNotifyQueryConnect();
+ return (client->noClientException);
+}
+
+static int SProcVncExtApproveConnect(ClientPtr client)
+{
+ REQUEST(xVncExtApproveConnectReq);
+#if XORG < 112
+ register char n;
+ swaps(&stuff->length, n);
+ swapl(&stuff->opaqueId, n);
+#else
+ swaps(&stuff->length);
+ swapl(&stuff->opaqueId);
+#endif
+ 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;
+ }
+}
+
+static void vncResetProc(ExtensionEntry* extEntry)
+{
+}
+
+static void vncClientStateChange(CallbackListPtr * l, void * d, void * p)
+{
+ ClientPtr client = ((NewClientInfoRec*)p)->client;
+ if (client->clientState == ClientStateGone) {
+ struct VncInputSelect** nextPtr = &vncInputSelectHead;
+ for (struct VncInputSelect* cur = vncInputSelectHead; cur; cur = *nextPtr) {
+ if (cur->client == client) {
+ *nextPtr = cur->next;
+ free(cur);
+ continue;
+ }
+ nextPtr = &cur->next;
+ }
+ }
+}
+
+static void SendSelectionChangeEvent(Atom selection)
+{
+ xVncExtSelectionChangeNotifyEvent ev;
+ ev.type = vncEventBase + VncExtSelectionChangeNotify;
+ for (struct 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) {
+#if XORG < 112
+ int n;
+ swaps(&ev.sequenceNumber, n);
+ swapl(&ev.window, n);
+ swapl(&ev.selection, n);
+#else
+ swaps(&ev.sequenceNumber);
+ swapl(&ev.window);
+ swapl(&ev.selection);
+#endif
+ }
+ WriteToClient(cur->client, sizeof(xVncExtSelectionChangeNotifyEvent),
+ (char *)&ev);
+ }
+ }
+}
+
+static void vncSelectionCallback(CallbackListPtr *callbacks, void * data, void * args)
+{
+ SelectionInfoRec *info = (SelectionInfoRec *) args;
+ Selection *selection = info->selection;
+
+ SendSelectionChangeEvent(selection->selection);
+}
+
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2011 Pierre Ossman for Cendio AB
+ * Copyright 2011-2015 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* USA.
*/
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
#include <stdio.h>
#include <errno.h>
-extern "C" {
-#define class c_class
-#define public c_public
-#define NEED_EVENTS
-#include <X11/X.h>
-#include <X11/Xproto.h>
-#include <X11/Xpoll.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
-#undef public
-}
-
#include <rfb/Configuration.h>
#include <rfb/Logger_stdio.h>
#include <rfb/LogWriter.h>
#include <rfb/ServerCore.h>
#include <rdr/HexOutStream.h>
#include <rfb/LogWriter.h>
-#undef max
-#undef min
+#include <rfb/Hostname.h>
+#include <rfb/Region.h>
#include <network/TcpSocket.h>
#include "XserverDesktop.h"
-#include "vncHooks.h"
#include "vncExtInit.h"
-#include "xorg-version.h"
-
-extern "C" {
-
- extern void vncExtensionInit();
- static void vncResetProc(ExtensionEntry* extEntry);
- static void vncBlockHandler(void * data, OSTimePtr t, void * readmask);
- static void vncWakeupHandler(void * data, int nfds, void * readmask);
- void vncWriteBlockHandler(fd_set *fds);
- void vncWriteWakeupHandler(int nfds, fd_set *fds);
- static void vncClientStateChange(CallbackListPtr*, void *, void *);
- static void SendSelectionChangeEvent(Atom selection);
- static int ProcVncExtDispatch(ClientPtr client);
- static int SProcVncExtDispatch(ClientPtr client);
- static void vncSelectionCallback(CallbackListPtr *callbacks, void * data,
- void * args);
-
- extern char *listenaddr;
-}
+#include "vncHooks.h"
+#include "vncBlockHandler.h"
+#include "XorgGlue.h"
using namespace rfb;
static rfb::LogWriter vlog("vncext");
+// We can't safely get this from Xorg
+#define MAXSCREENS 16
+
static unsigned long vncExtGeneration = 0;
static bool initialised = false;
static XserverDesktop* desktop[MAXSCREENS] = { 0, };
void* vncFbptr[MAXSCREENS] = { 0, };
int vncFbstride[MAXSCREENS];
-static char* clientCutText = 0;
-static int clientCutTextLen = 0;
-bool noclipboard = false;
-
-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 vncErrorBase = 0;
-static int vncEventBase = 0;
int vncInetdSock = -1;
rfb::StringParameter httpDir("httpd",
rfb::BoolParameter localhostOnly("localhost",
"Only allow connections from localhost",
false);
+rfb::StringParameter interface("interface",
+ "listen on the specified network address",
+ "all");
+rfb::BoolParameter avoidShiftNumLock("AvoidShiftNumLock",
+ "Avoid fake Shift presses for keys affected by NumLock.",
+ true);
-static PixelFormat vncGetPixelFormat(ScreenPtr pScreen)
+static PixelFormat vncGetPixelFormat(int scrIdx)
{
int depth, bpp;
int trueColour, bigEndian;
+ int redMask, greenMask, blueMask;
+
int redShift, greenShift, blueShift;
int redMax, greenMax, blueMax;
- int i;
- VisualPtr vis = NULL;
-
- depth = pScreen->rootDepth;
-
- for (i = 0; i < screenInfo.numPixmapFormats; i++) {
- if (screenInfo.formats[i].depth == depth) {
- bpp = screenInfo.formats[i].bitsPerPixel;
- break;
- }
- }
-
- if (i == screenInfo.numPixmapFormats) {
- fprintf(stderr,"no pixmap format for root depth???\n");
- abort();
- }
-
- bigEndian = (screenInfo.imageByteOrder == MSBFirst);
-
- 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();
- }
-
- trueColour = (vis->c_class == TrueColor);
+ vncGetScreenFormat(scrIdx, &depth, &bpp, &trueColour, &bigEndian,
+ &redMask, &greenMask, &blueMask);
if (!trueColour) {
- fprintf(stderr,"pseudocolour not supported");
+ vlog.error("pseudocolour not supported");
abort();
}
- redShift = ffs(vis->redMask) - 1;
- greenShift = ffs(vis->greenMask) - 1;
- blueShift = ffs(vis->blueMask) - 1;
- redMax = vis->redMask >> redShift;
- greenMax = vis->greenMask >> greenShift;
- blueMax = vis->blueMask >> blueShift;
+ redShift = ffs(redMask) - 1;
+ greenShift = ffs(greenMask) - 1;
+ blueShift = ffs(blueMask) - 1;
+ redMax = redMask >> redShift;
+ greenMax = greenMask >> greenShift;
+ blueMax = blueMask >> blueShift;
return PixelFormat(bpp, depth, bigEndian, trueColour,
redMax, greenMax, blueMax,
redShift, greenShift, blueShift);
}
-void vncExtensionInit()
+void vncExtensionInit(void)
{
- if (vncExtGeneration == serverGeneration) {
+ int ret;
+
+ if (vncExtGeneration == vncGetServerGeneration()) {
vlog.error("vncExtensionInit: called twice in same generation?");
return;
}
- vncExtGeneration = serverGeneration;
+ vncExtGeneration = vncGetServerGeneration();
- ExtensionEntry* extEntry
- = AddExtension(VNCEXTNAME, VncExtNumberEvents, VncExtNumberErrors,
- ProcVncExtDispatch, SProcVncExtDispatch, vncResetProc,
- StandardMinorOpcode);
- if (!extEntry) {
- ErrorF("vncExtInit: AddExtension failed\n");
+ if (vncGetScreenCount() > MAXSCREENS) {
+ vlog.error("vncExtensionInit: too many screens");
return;
}
- vncErrorBase = extEntry->errorBase;
- vncEventBase = extEntry->eventBase;
-
- vlog.info("VNC extension running!");
-
- if (!AddCallback(&ClientStateCallback, vncClientStateChange, 0)) {
- FatalError("Add ClientStateCallback failed\n");
+ if (sizeof(ShortRect) != sizeof(struct UpdateRect)) {
+ vlog.error("vncExtensionInit: Incompatible ShortRect size");
+ return;
}
- if (!AddCallback(&SelectionCallback, vncSelectionCallback, 0)) {
- FatalError("Add SelectionCallback failed\n");
- }
+ ret = vncAddExtension();
+ if (ret == -1)
+ return;
+
+ vlog.info("VNC extension running!");
try {
if (!initialised) {
initialised = true;
}
- for (int scr = 0; scr < screenInfo.numScreens; scr++) {
+ for (int scr = 0; scr < vncGetScreenCount(); scr++) {
if (!desktop[scr]) {
network::TcpListener* listener = 0;
}
} else {
int port = rfbport;
- if (port == 0) port = 5900 + atoi(display);
+ if (port == 0) port = 5900 + atoi(vncGetDisplay());
port += 1000 * scr;
- listener = new network::TcpListener(listenaddr, port, localhostOnly);
+ if (strcasecmp(interface, "all") == 0)
+ listener = new network::TcpListener(NULL, port, localhostOnly);
+ else
+ listener = new network::TcpListener(interface, port, localhostOnly);
vlog.info("Listening for VNC connections on %s interface(s), port %d",
- listenaddr == NULL ? "all" : listenaddr, port);
+ (const char*)interface, port);
CharArray httpDirStr(httpDir.getData());
if (httpDirStr.buf[0]) {
port = httpPort;
- if (port == 0) port = 5800 + atoi(display);
+ if (port == 0) port = 5800 + atoi(vncGetDisplay());
port += 1000 * scr;
- httpListener = new network::TcpListener(listenaddr, port, localhostOnly);
+ httpListener = new network::TcpListener(interface, port, localhostOnly);
vlog.info("Listening for HTTP connections on %s interface(s), port %d",
- listenaddr == NULL ? "all" : listenaddr, port);
+ (const char*)interface, port);
}
}
CharArray desktopNameStr(desktopName.getData());
- PixelFormat pf = vncGetPixelFormat(screenInfo.screens[scr]);
+ PixelFormat pf = vncGetPixelFormat(scr);
- desktop[scr] = new XserverDesktop(screenInfo.screens[scr],
+ desktop[scr] = new XserverDesktop(scr,
listener,
httpListener,
desktopNameStr.buf,
pf,
+ vncGetScreenWidth(scr),
+ vncGetScreenHeight(scr),
vncFbptr[scr],
vncFbstride[scr]);
vlog.info("created VNC server for screen %d", scr);
}
}
- vncHooksInit(screenInfo.screens[scr], desktop[scr]);
+ vncHooksInit(scr);
}
-
- RegisterBlockAndWakeupHandlers(vncBlockHandler, vncWakeupHandler, 0);
-
} catch (rdr::Exception& e) {
vlog.error("vncExtInit: %s",e.str());
}
-}
-static void vncResetProc(ExtensionEntry* extEntry)
-{
-}
-
-static void vncSelectionCallback(CallbackListPtr *callbacks, void * data, void * args)
-{
- SelectionInfoRec *info = (SelectionInfoRec *) args;
- Selection *selection = info->selection;
-
- SendSelectionChangeEvent(selection->selection);
+ vncRegisterBlockHandlers();
}
-static void vncWriteBlockHandlerFallback(OSTimePtr timeout);
-static void vncWriteWakeupHandlerFallback();
-
-//
-// 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(void * data, OSTimePtr timeout, void * readmask)
+void vncCallReadBlockHandlers(fd_set * fds, struct timeval ** timeout)
{
- fd_set* fds = (fd_set*)readmask;
-
- vncWriteBlockHandlerFallback(timeout);
-
- for (int scr = 0; scr < screenInfo.numScreens; scr++)
+ for (int scr = 0; scr < vncGetScreenCount(); scr++)
if (desktop[scr])
- desktop[scr]->blockHandler(fds, timeout);
+ desktop[scr]->readBlockHandler(fds, timeout);
}
-static void vncWakeupHandler(void * data, int nfds, void * readmask)
+void vncCallReadWakeupHandlers(fd_set * fds, int nfds)
{
- fd_set* fds = (fd_set*)readmask;
-
- for (int scr = 0; scr < screenInfo.numScreens; scr++) {
- if (desktop[scr]) {
- desktop[scr]->wakeupHandler(fds, nfds);
- }
- }
-
- vncWriteWakeupHandlerFallback();
+ for (int scr = 0; scr < vncGetScreenCount(); scr++)
+ if (desktop[scr])
+ desktop[scr]->readWakeupHandler(fds, nfds);
}
-//
-// vncWriteBlockHandler - extra hack to be able to get the main select loop
-// to monitor writeable fds and not just readable. This requirers a modified
-// Xorg and might therefore not be called. When it is called though, it will
-// do so before vncBlockHandler (and vncWriteWakeupHandler called after
-// vncWakeupHandler).
-//
-
-static bool needFallback = true;
-static fd_set fallbackFds;
-static struct timeval tw;
-
-void vncWriteBlockHandler(fd_set *fds)
+void vncCallWriteBlockHandlers(fd_set * fds, struct timeval ** timeout)
{
- needFallback = false;
-
- for (int scr = 0; scr < screenInfo.numScreens; scr++)
+ for (int scr = 0; scr < vncGetScreenCount(); scr++)
if (desktop[scr])
- desktop[scr]->writeBlockHandler(fds);
+ desktop[scr]->writeBlockHandler(fds, timeout);
}
-void vncWriteWakeupHandler(int nfds, fd_set *fds)
+void vncCallWriteWakeupHandlers(fd_set * fds, int nfds)
{
- for (int scr = 0; scr < screenInfo.numScreens; scr++) {
- if (desktop[scr]) {
+ for (int scr = 0; scr < vncGetScreenCount(); scr++)
+ if (desktop[scr])
desktop[scr]->writeWakeupHandler(fds, nfds);
- }
- }
}
-static void vncWriteBlockHandlerFallback(OSTimePtr timeout)
+int vncGetAvoidShiftNumLock(void)
{
- if (!needFallback)
- return;
-
- FD_ZERO(&fallbackFds);
- vncWriteBlockHandler(&fallbackFds);
- needFallback = true;
-
- if (!XFD_ANYSET(&fallbackFds))
- return;
-
- if ((*timeout == NULL) ||
- ((*timeout)->tv_sec > 0) || ((*timeout)->tv_usec > 10000)) {
- tw.tv_sec = 0;
- tw.tv_usec = 10000;
- *timeout = &tw;
- }
+ return (bool)avoidShiftNumLock;
}
-static void vncWriteWakeupHandlerFallback()
+void vncUpdateDesktopName(void)
{
- int ret;
- struct timeval timeout;
-
- if (!needFallback)
- return;
-
- if (!XFD_ANYSET(&fallbackFds))
- return;
-
- timeout.tv_sec = 0;
- timeout.tv_usec = 0;
-
- ret = select(XFD_SETSIZE, NULL, &fallbackFds, NULL, &timeout);
- if (ret < 0) {
- ErrorF("vncWriteWakeupHandlerFallback(): select: %s\n",
- strerror(errno));
- return;
+ for (int scr = 0; scr < vncGetScreenCount(); scr++) {
+ if (desktop[scr] == NULL)
+ continue;
+ desktop[scr]->setDesktopName(desktopName);
}
-
- if (ret == 0)
- return;
-
- vncWriteWakeupHandler(ret, &fallbackFds);
}
-static void vncClientStateChange(CallbackListPtr*, void *, void * p)
+void vncServerCutText(const char *text, size_t len)
{
- 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;
- }
+ for (int scr = 0; scr < vncGetScreenCount(); scr++) {
+ if (desktop[scr] == NULL)
+ continue;
+ desktop[scr]->serverCutText(text, len);
}
}
-void vncBell()
+int vncConnectClient(const char *addr)
{
- for (int scr = 0; scr < screenInfo.numScreens; scr++) {
- if (desktop[scr]) {
- desktop[scr]->bell();
- }
- }
-}
+ if (desktop[0] == NULL)
+ return -1;
-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) {
-#if XORG < 112
- int n;
- swaps(&ev.sequenceNumber, n);
- swapl(&ev.window, n);
- swapl(&ev.time, n);
-#else
- swaps(&ev.sequenceNumber);
- swapl(&ev.window);
- swapl(&ev.time);
-#endif
- }
- WriteToClient(cur->client, sizeof(xVncExtClientCutTextNotifyEvent),
- (char *)&ev);
+ if (strlen(addr) == 0) {
+ try {
+ desktop[0]->disconnectClients();
+ } catch (rdr::Exception& e) {
+ vlog.error("Disconnecting all clients: %s",e.str());
+ return -1;
}
+ return 0;
}
-}
-
-static CARD32 queryConnectTimerCallback(OsTimerPtr timer,
- CARD32 now, void * 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;
-}
+ char *host;
+ int port;
-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;
- }
+ getHostAndPort(addr, &host, &port, 5500);
- // 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) {
-#if XORG < 112
- int n;
- swaps(&ev.sequenceNumber, n);
- swapl(&ev.window, n);
-#else
- swaps(&ev.sequenceNumber);
- swapl(&ev.window);
-#endif
- }
- 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) {
-#if XORG < 112
- int n;
- swaps(&ev.sequenceNumber, n);
- swapl(&ev.window, n);
- swapl(&ev.selection, n);
-#else
- swaps(&ev.sequenceNumber);
- swapl(&ev.window);
- swapl(&ev.selection);
-#endif
- }
- WriteToClient(cur->client, sizeof(xVncExtSelectionChangeNotifyEvent),
- (char *)&ev);
- }
- }
-}
-
-static int ProcVncExtSetParam(ClientPtr client)
-{
- char* value1 = 0;
- char* value2 = 0;
- rfb::VoidParameter *desktop1, *desktop2;
-
- 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;
- rep.type = X_Reply;
- rep.length = 0;
- rep.success = 0;
- rep.sequenceNumber = client->sequence;
-
- // Retrieve desktop name before setting
- desktop1 = rfb::Configuration::getParam("desktop");
- if (desktop1)
- value1 = desktop1->getValueStr();
-
- /*
- * Allow to change only certain parameters.
- * Changing other parameters (for example PAM service name)
- * could have negative security impact.
- */
- if (strncasecmp(param.buf, "desktop", 7) != 0 &&
- strncasecmp(param.buf, "AcceptPointerEvents", 19) != 0 &&
- (noclipboard || strncasecmp(param.buf, "SendCutText", 11) != 0) &&
- (noclipboard || strncasecmp(param.buf, "AcceptCutText", 13) != 0))
- goto deny;
-
- rep.success = rfb::Configuration::setParam(param.buf);
-
- // Send DesktopName update if desktop name has been changed
- desktop2 = rfb::Configuration::getParam("desktop");
- if (desktop2)
- value2 = desktop2->getValueStr();
- if (value1 && value2 && strcmp(value1, value2)) {
- for (int scr = 0; scr < screenInfo.numScreens; scr++) {
- if (desktop[scr]) {
- desktop[scr]->setDesktopName(value2);
- }
- }
- }
- if (value1)
- delete [] value1;
- if (value2)
- delete [] value2;
-
-deny:
- if (client->swapped) {
-#if XORG < 112
- int n;
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.length, n);
-#else
- swaps(&rep.sequenceNumber);
- swapl(&rep.length);
-#endif
- }
- WriteToClient(client, sizeof(xVncExtSetParamReply), (char *)&rep);
- return (client->noClientException);
-}
-
-static int SProcVncExtSetParam(ClientPtr client)
-{
- REQUEST(xVncExtSetParamReq);
-#if XORG < 112
- register char n;
- swaps(&stuff->length, n);
-#else
- swaps(&stuff->length);
-#endif
- 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;
- 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) {
-#if XORG < 112
- int n;
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.length, n);
- swaps(&rep.valueLen, n);
-#else
- swaps(&rep.sequenceNumber);
- swapl(&rep.length);
- swaps(&rep.valueLen);
-#endif
- }
- WriteToClient(client, sizeof(xVncExtGetParamReply), (char *)&rep);
- if (value)
- WriteToClient(client, len, value);
- delete [] value;
- return (client->noClientException);
-}
-
-static int SProcVncExtGetParam(ClientPtr client)
-{
- REQUEST(xVncExtGetParamReq);
-#if XORG < 112
- register char n;
- swaps(&stuff->length, n);
-#else
- swaps(&stuff->length);
-#endif
- 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;
- 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) {
-#if XORG < 112
- int n;
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.length, n);
- swaps(&rep.descLen, n);
-#else
- swaps(&rep.sequenceNumber);
- swapl(&rep.length);
- swaps(&rep.descLen);
-#endif
+ try {
+ network::Socket* sock = new network::TcpSocket(host, port);
+ delete [] host;
+ desktop[0]->addClient(sock, true);
+ } catch (rdr::Exception& e) {
+ vlog.error("Reverse connection: %s",e.str());
+ return -1;
}
- WriteToClient(client, sizeof(xVncExtGetParamDescReply), (char *)&rep);
- if (desc)
- WriteToClient(client, len, (char*)desc);
- return (client->noClientException);
-}
-static int SProcVncExtGetParamDesc(ClientPtr client)
-{
- REQUEST(xVncExtGetParamDescReq);
-#if XORG < 112
- register char n;
- swaps(&stuff->length, n);
-#else
- swaps(&stuff->length);
-#endif
- REQUEST_AT_LEAST_SIZE(xVncExtGetParamDescReq);
- return ProcVncExtGetParamDesc(client);
+ return 0;
}
-static int ProcVncExtListParams(ClientPtr client)
+void vncGetQueryConnect(uint32_t *opaqueId, const char**username,
+ const char **address, int *timeout)
{
- REQUEST(xVncExtListParamsReq);
- REQUEST_SIZE_MATCH(xVncExtListParamsReq);
-
- xVncExtListParamsReply rep;
- rep.type = X_Reply;
- rep.sequenceNumber = client->sequence;
-
- int nParams = 0;
- int len = 0;
- for (ParameterIterator i; 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) {
-#if XORG < 112
- int n;
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.length, n);
- swaps(&rep.nParams, n);
-#else
- swaps(&rep.sequenceNumber);
- swapl(&rep.length);
- swaps(&rep.nParams);
-#endif
- }
- WriteToClient(client, sizeof(xVncExtListParamsReply), (char *)&rep);
- rdr::U8* data = new rdr::U8[len];
- rdr::U8* ptr = data;
- for (ParameterIterator i; i.param; i.next()) {
- int l = strlen(i.param->getName());
- if (l <= 255) {
- *ptr++ = l;
- memcpy(ptr, i.param->getName(), l);
- ptr += l;
- }
+ for (int scr = 0; scr < vncGetScreenCount(); scr++) {
+ if (desktop[scr] == NULL)
+ continue;
+ desktop[scr]->getQueryConnect(opaqueId, username, address, timeout);
+ if (opaqueId != 0)
+ break;
}
- WriteToClient(client, len, (char*)data);
- delete [] data;
- return (client->noClientException);
}
-static int SProcVncExtListParams(ClientPtr client)
+void vncApproveConnection(uint32_t opaqueId, int approve)
{
- REQUEST(xVncExtListParamsReq);
-#if XORG < 112
- register char n;
- swaps(&stuff->length, n);
-#else
- swaps(&stuff->length);
-#endif
- 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);
- }
+ for (int scr = 0; scr < vncGetScreenCount(); scr++) {
+ if (desktop[scr] == NULL)
+ continue;
+ desktop[scr]->approveConnection(opaqueId, approve,
+ "Connection rejected by local user");
}
- delete [] str;
- return (client->noClientException);
-}
-
-static int SProcVncExtSetServerCutText(ClientPtr client)
-{
- REQUEST(xVncExtSetServerCutTextReq);
-#if XORG < 112
- register char n;
- swaps(&stuff->length, n);
-#else
- swaps(&stuff->length);
-#endif
- REQUEST_AT_LEAST_SIZE(xVncExtSetServerCutTextReq);
-#if XORG < 112
- swapl(&stuff->textLen, n);
-#else
- swapl(&stuff->textLen);
-#endif
- return ProcVncExtSetServerCutText(client);
}
-static int ProcVncExtGetClientCutText(ClientPtr client)
+void vncBell()
{
- REQUEST(xVncExtGetClientCutTextReq);
- REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq);
-
- xVncExtGetClientCutTextReply rep;
- rep.type = X_Reply;
- rep.length = (clientCutTextLen + 3) >> 2;
- rep.sequenceNumber = client->sequence;
- rep.textLen = clientCutTextLen;
- if (client->swapped) {
-#if XORG < 112
- int n;
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.length, n);
- swapl(&rep.textLen, n);
-#else
- swaps(&rep.sequenceNumber);
- swapl(&rep.length);
- swapl(&rep.textLen);
-#endif
+ for (int scr = 0; scr < vncGetScreenCount(); scr++) {
+ if (desktop[scr] == NULL)
+ continue;
+ desktop[scr]->bell();
}
- WriteToClient(client, sizeof(xVncExtGetClientCutTextReply), (char *)&rep);
- if (clientCutText)
- WriteToClient(client, clientCutTextLen, clientCutText);
- return (client->noClientException);
-}
-
-static int SProcVncExtGetClientCutText(ClientPtr client)
-{
- REQUEST(xVncExtGetClientCutTextReq);
-#if XORG < 112
- register char n;
- swaps(&stuff->length, n);
-#else
- swaps(&stuff->length);
-#endif
- REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq);
- return ProcVncExtGetClientCutText(client);
}
-static int ProcVncExtSelectInput(ClientPtr client)
+void vncAddChanged(int scrIdx, const struct UpdateRect *extents,
+ int nRects, const struct UpdateRect *rects)
{
- 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);
-}
+ Region reg;
-static int SProcVncExtSelectInput(ClientPtr client)
-{
- REQUEST(xVncExtSelectInputReq);
-#if XORG < 112
- register char n;
- swaps(&stuff->length, n);
-#else
- swaps(&stuff->length);
-#endif
- REQUEST_SIZE_MATCH(xVncExtSelectInputReq);
-#if XORG < 112
- swapl(&stuff->window, n);
- swapl(&stuff->mask, n);
-#else
- swapl(&stuff->window);
- swapl(&stuff->mask);
-#endif
- return ProcVncExtSelectInput(client);
+ reg.setExtentsAndOrderedRects((ShortRect*)extents,
+ nRects, (ShortRect*)rects);
+ desktop[scrIdx]->add_changed(reg);
}
-static int ProcVncExtConnect(ClientPtr client)
+void vncAddCopied(int scrIdx, const struct UpdateRect *extents,
+ int nRects, const struct UpdateRect *rects,
+ int dx, int dy)
{
- 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());
- }
- }
- }
+ Region reg;
- rep.type = X_Reply;
- rep.length = 0;
- rep.sequenceNumber = client->sequence;
- if (client->swapped) {
-#if XORG < 112
- int n;
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.length, n);
-#else
- swaps(&rep.sequenceNumber);
- swapl(&rep.length);
-#endif
- }
- WriteToClient(client, sizeof(xVncExtConnectReply), (char *)&rep);
- return (client->noClientException);
+ reg.setExtentsAndOrderedRects((ShortRect*)extents,
+ nRects, (ShortRect*)rects);
+ desktop[scrIdx]->add_copied(reg, rfb::Point(dx, dy));
}
-static int SProcVncExtConnect(ClientPtr client)
+void vncSetCursor(int scrIdx, int width, int height, int hotX, int hotY,
+ const unsigned char *rgbaData)
{
- REQUEST(xVncExtConnectReq);
-#if XORG < 112
- register char n;
- swaps(&stuff->length, n);
-#else
- swaps(&stuff->length);
-#endif
- REQUEST_AT_LEAST_SIZE(xVncExtConnectReq);
- return ProcVncExtConnect(client);
+ desktop[scrIdx]->setCursor(width, height, hotX, hotY, rgbaData);
}
-
-static int ProcVncExtGetQueryConnect(ClientPtr client)
+void vncPreScreenResize(int scrIdx)
{
- 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;
- 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)(long)queryConnectId;
- rep.length = ((rep.userLen + 3) >> 2) + ((rep.addrLen + 3) >> 2);
- if (client->swapped) {
-#if XORG < 112
- int n;
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.addrLen, n);
- swapl(&rep.userLen, n);
- swapl(&rep.timeout, n);
- swapl(&rep.opaqueId, n);
- swapl(&rep.length, n);
-#else
- swaps(&rep.sequenceNumber);
- swapl(&rep.addrLen);
- swapl(&rep.userLen);
- swapl(&rep.timeout);
- swapl(&rep.opaqueId);
- swapl(&rep.length);
-#endif
- }
- 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);
+ // We need to prevent the RFB core from accessing the framebuffer
+ // for a while as there might be updates thrown our way inside
+ // the routines that change the screen (i.e. before we have a
+ // pointer to the new framebuffer).
+ desktop[scrIdx]->blockUpdates();
}
-static int SProcVncExtGetQueryConnect(ClientPtr client)
+void vncPostScreenResize(int scrIdx, int success, int width, int height)
{
- REQUEST(xVncExtGetQueryConnectReq);
-#if XORG < 112
- register char n;
- swaps(&stuff->length, n);
-#else
- swaps(&stuff->length);
-#endif
- REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq);
- return ProcVncExtGetQueryConnect(client);
-}
-
-
-static int ProcVncExtApproveConnect(ClientPtr client)
-{
- REQUEST(xVncExtApproveConnectReq);
- REQUEST_SIZE_MATCH(xVncExtApproveConnectReq);
- if ((CARD32)(long)queryConnectId == 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);
+ if (success) {
+ // Let the RFB core know of the new dimensions and framebuffer
+ desktop[scrIdx]->setFramebuffer(width, height,
+ vncFbptr[scrIdx], vncFbstride[scrIdx]);
}
- return (client->noClientException);
-}
-
-static int SProcVncExtApproveConnect(ClientPtr client)
-{
- REQUEST(xVncExtApproveConnectReq);
-#if XORG < 112
- register char n;
- swaps(&stuff->length, n);
- swapl(&stuff->opaqueId, n);
-#else
- swaps(&stuff->length);
- swapl(&stuff->opaqueId);
-#endif
- REQUEST_SIZE_MATCH(xVncExtApproveConnectReq);
- return ProcVncExtApproveConnect(client);
-}
+ desktop[scrIdx]->unblockUpdates();
-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;
+ if (success) {
+ // Mark entire screen as changed
+ desktop[scrIdx]->add_changed(Region(Rect(0, 0, width, height)));
}
}
-static int SProcVncExtDispatch(ClientPtr client)
+void vncRefreshScreenLayout(int scrIdx)
{
- 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;
- }
+ desktop[scrIdx]->refreshScreenLayout();
}
-
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2011-2015 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#ifndef __VNCEXTINIT_H__
#define __VNCEXTINIT_H__
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
+#include <stdint.h>
+#include <sys/select.h>
+
+// Only from C++
+#ifdef __cplusplus
+namespace rfb { class StringParameter; };
+
+extern rfb::StringParameter httpDir;
#endif
-#include <rfb/Configuration.h>
-#include "XserverDesktop.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// vncExt.c
+extern int vncNoClipboard;
+
+int vncAddExtension(void);
-extern void vncClientCutText(const char* str, int len);
-extern void vncQueryConnect(XserverDesktop* desktop, void* opaqueId);
-extern void vncClientGone(int fd);
-extern void vncBell();
+int vncNotifyQueryConnect(void);
+
+void vncClientCutText(const char* str, int len);
+
+// vncExtInit.cc
extern void* vncFbptr[];
extern int vncFbstride[];
-extern bool noclipboard;
+
extern int vncInetdSock;
-extern rfb::StringParameter httpDir;
+
+void vncExtensionInit(void);
+
+void vncCallReadBlockHandlers(fd_set * fds, struct timeval ** timeout);
+void vncCallReadWakeupHandlers(fd_set * fds, int nfds);
+void vncCallWriteBlockHandlers(fd_set * fds, struct timeval ** timeout);
+void vncCallWriteWakeupHandlers(fd_set * fds, int nfds);
+
+int vncGetAvoidShiftNumLock(void);
+
+void vncUpdateDesktopName(void);
+
+void vncServerCutText(const char *text, size_t len);
+
+int vncConnectClient(const char *addr);
+
+void vncGetQueryConnect(uint32_t *opaqueId, const char**username,
+ const char **address, int *timeout);
+void vncApproveConnection(uint32_t opaqueId, int approve);
+
+void vncBell(void);
+
+// Must match rfb::ShortRect in common/rfb/Region.h, and BoxRec in the
+// Xorg source.
+struct UpdateRect {
+ short x1, y1, x2, y2;
+};
+
+void vncAddChanged(int scrIdx, const struct UpdateRect *extents,
+ int nRects, const struct UpdateRect *rects);
+void vncAddCopied(int scrIdx, const struct UpdateRect *extents,
+ int nRects, const struct UpdateRect *rects,
+ int dx, int dy);
+
+void vncSetCursor(int scrIdx, int width, int height, int hotX, int hotY,
+ const unsigned char *rgbaData);
+
+void vncPreScreenResize(int scrIdx);
+void vncPostScreenResize(int scrIdx, int success, int width, int height);
+void vncRefreshScreenLayout(int scrIdx);
+
+#ifdef __cplusplus
+}
+#endif
#endif
--- /dev/null
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2009-2015 Pierre Ossman for Cendio AB
+ *
+ * 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stdio.h>
+
+#include "vncHooks.h"
+#include "vncExtInit.h"
+
+#include "xorg-version.h"
+
+#include "scrnintstr.h"
+#include "windowstr.h"
+#include "cursorstr.h"
+#include "gcstruct.h"
+#include "regionstr.h"
+#include "dixfontstr.h"
+#include "colormapst.h"
+#ifdef RENDER
+#include "picturestr.h"
+#endif
+#ifdef RANDR
+#include "randrstr.h"
+#endif
+
+#define DBGPRINT(x) //(fprintf x)
+
+// 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
+
+// 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
+
+// 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 _vncHooksScreenRec {
+ int ignoreHooks;
+
+ CloseScreenProcPtr CloseScreen;
+ CreateGCProcPtr CreateGC;
+ CopyWindowProcPtr CopyWindow;
+ ClearToBackgroundProcPtr ClearToBackground;
+#if XORG < 110
+ RestoreAreasProcPtr RestoreAreas;
+#endif
+ DisplayCursorProcPtr DisplayCursor;
+ ScreenBlockHandlerProcPtr BlockHandler;
+#ifdef RENDER
+ CompositeProcPtr Composite;
+ GlyphsProcPtr Glyphs;
+#endif
+#ifdef RANDR
+ RRSetConfigProcPtr RandRSetConfig;
+ RRScreenSetSizeProcPtr RandRScreenSetSize;
+ RRCrtcSetProcPtr RandRCrtcSet;
+#endif
+} vncHooksScreenRec, *vncHooksScreenPtr;
+
+typedef struct _vncHooksGCRec {
+#if XORG >= 116
+ const GCFuncs *wrappedFuncs;
+ const GCOps *wrappedOps;
+#else
+ GCFuncs *wrappedFuncs;
+ GCOps *wrappedOps;
+#endif
+} vncHooksGCRec, *vncHooksGCPtr;
+
+#if XORG == 15
+static DevPrivateKey vncHooksScreenPrivateKey = &vncHooksScreenPrivateKey;
+static DevPrivateKey vncHooksGCPrivateKey = &vncHooksGCPrivateKey;
+#elif XORG < 19
+static int vncHooksScreenPrivateKeyIndex;
+static int vncHooksGCPrivateKeyIndex;
+static DevPrivateKey vncHooksScreenPrivateKey = &vncHooksScreenPrivateKeyIndex;
+static DevPrivateKey vncHooksGCPrivateKey = &vncHooksGCPrivateKeyIndex;
+#else
+static DevPrivateKeyRec vncHooksScreenKeyRec;
+static DevPrivateKeyRec vncHooksGCKeyRec;
+#define vncHooksScreenPrivateKey (&vncHooksScreenKeyRec)
+#define vncHooksGCPrivateKey (&vncHooksGCKeyRec)
+#endif
+
+#define vncHooksScreenPrivate(pScreen) \
+ (vncHooksScreenPtr) dixLookupPrivate(&(pScreen)->devPrivates, \
+ vncHooksScreenPrivateKey)
+#define vncHooksGCPrivate(pGC) \
+ (vncHooksGCPtr) dixLookupPrivate(&(pGC)->devPrivates, \
+ vncHooksGCPrivateKey)
+
+// screen functions
+
+#if XORG <= 112
+static Bool vncHooksCloseScreen(int i, ScreenPtr pScreen);
+#else
+static Bool vncHooksCloseScreen(ScreenPtr pScreen);
+#endif
+static Bool vncHooksCreateGC(GCPtr pGC);
+static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
+ RegionPtr pOldRegion);
+static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w,
+ int h, Bool generateExposures);
+#if XORG < 110
+static RegionPtr vncHooksRestoreAreas(WindowPtr pWin, RegionPtr prgnExposed);
+#endif
+static Bool vncHooksDisplayCursor(
+#if XORG >= 16
+ DeviceIntPtr pDev,
+#endif
+ ScreenPtr pScreen, CursorPtr cursor);
+#if XORG <= 112
+static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout,
+ pointer pReadmask);
+#else
+static void vncHooksBlockHandler(ScreenPtr pScreen, void * pTimeout,
+ void * pReadmask);
+#endif
+#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);
+static void vncHooksGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
+ PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlists,
+ GlyphListPtr lists, GlyphPtr * glyphs);
+#endif
+#ifdef RANDR
+static Bool vncHooksRandRSetConfig(ScreenPtr pScreen, Rotation rotation,
+ int rate, RRScreenSizePtr pSize);
+static Bool vncHooksRandRScreenSetSize(ScreenPtr pScreen,
+ CARD16 width, CARD16 height,
+ CARD32 mmWidth, CARD32 mmHeight);
+static Bool vncHooksRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc,
+ RRModePtr mode, int x, int y,
+ Rotation rotation, int numOutputs,
+ RROutputPtr *outputs);
+#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, void * 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, void * pglyphBase);
+static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
+ int y, unsigned int nglyph,
+ CharInfoPtr *ppci, void * 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.
+
+int vncHooksInit(int scrIdx)
+{
+ ScreenPtr pScreen;
+ vncHooksScreenPtr vncHooksScreen;
+
+#ifdef RENDER
+ PictureScreenPtr ps;
+#endif
+#ifdef RANDR
+ rrScrPrivPtr rp;
+#endif
+
+ pScreen = screenInfo.screens[scrIdx];
+
+ if (sizeof(BoxRec) != sizeof(struct UpdateRect)) {
+ ErrorF("vncHooksInit: Incompatible BoxRec size\n");
+ return FALSE;
+ }
+
+#if XORG < 19
+ if (!dixRequestPrivate(vncHooksScreenPrivateKey, sizeof(vncHooksScreenRec))) {
+ ErrorF("vncHooksInit: Allocation of vncHooksScreen failed\n");
+ return FALSE;
+ }
+ if (!dixRequestPrivate(vncHooksGCPrivateKey, sizeof(vncHooksGCRec))) {
+ ErrorF("vncHooksInit: Allocation of vncHooksGCRec failed\n");
+ return FALSE;
+ }
+
+#else
+ if (!dixRegisterPrivateKey(&vncHooksScreenKeyRec, PRIVATE_SCREEN,
+ sizeof(vncHooksScreenRec))) {
+ ErrorF("vncHooksInit: Allocation of vncHooksScreen failed\n");
+ return FALSE;
+ }
+ if (!dixRegisterPrivateKey(&vncHooksGCKeyRec, PRIVATE_GC,
+ sizeof(vncHooksGCRec))) {
+ ErrorF("vncHooksInit: Allocation of vncHooksGCRec failed\n");
+ return FALSE;
+ }
+
+#endif
+
+ vncHooksScreen = vncHooksScreenPrivate(pScreen);
+
+ vncHooksScreen->ignoreHooks = 0;
+
+ vncHooksScreen->CloseScreen = pScreen->CloseScreen;
+ vncHooksScreen->CreateGC = pScreen->CreateGC;
+ vncHooksScreen->CopyWindow = pScreen->CopyWindow;
+ vncHooksScreen->ClearToBackground = pScreen->ClearToBackground;
+#if XORG < 110
+ vncHooksScreen->RestoreAreas = pScreen->RestoreAreas;
+#endif
+ vncHooksScreen->DisplayCursor = pScreen->DisplayCursor;
+ vncHooksScreen->BlockHandler = pScreen->BlockHandler;
+#ifdef RENDER
+ ps = GetPictureScreenIfSet(pScreen);
+ if (ps) {
+ vncHooksScreen->Composite = ps->Composite;
+ vncHooksScreen->Glyphs = ps->Glyphs;
+ }
+#endif
+#ifdef RANDR
+ rp = rrGetScrPriv(pScreen);
+ if (rp) {
+ vncHooksScreen->RandRSetConfig = rp->rrSetConfig;
+ vncHooksScreen->RandRScreenSetSize = rp->rrScreenSetSize;
+ vncHooksScreen->RandRCrtcSet = rp->rrCrtcSet;
+ }
+#endif
+
+ pScreen->CloseScreen = vncHooksCloseScreen;
+ pScreen->CreateGC = vncHooksCreateGC;
+ pScreen->CopyWindow = vncHooksCopyWindow;
+ pScreen->ClearToBackground = vncHooksClearToBackground;
+#if XORG < 110
+ pScreen->RestoreAreas = vncHooksRestoreAreas;
+#endif
+ pScreen->DisplayCursor = vncHooksDisplayCursor;
+ pScreen->BlockHandler = vncHooksBlockHandler;
+#ifdef RENDER
+ if (ps) {
+ ps->Composite = vncHooksComposite;
+ ps->Glyphs = vncHooksGlyphs;
+ }
+#endif
+#ifdef RANDR
+ if (rp) {
+ /* Some RandR callbacks are optional */
+ if (rp->rrSetConfig)
+ rp->rrSetConfig = vncHooksRandRSetConfig;
+ if (rp->rrScreenSetSize)
+ rp->rrScreenSetSize = vncHooksRandRScreenSetSize;
+ if (rp->rrCrtcSet)
+ rp->rrCrtcSet = vncHooksRandRCrtcSet;
+ }
+#endif
+
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// vncGetScreenImage() grabs a chunk of data from the main screen into the
+// provided buffer. It lives here rather than in XorgGlue.c because it
+// temporarily pauses the hooks.
+
+void vncGetScreenImage(int scrIdx, int x, int y, int width, int height,
+ char *buffer, int strideBytes)
+{
+ ScreenPtr pScreen = screenInfo.screens[scrIdx];
+ vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
+
+ int i;
+
+ vncHooksScreen->ignoreHooks++;
+
+ // We do one line at a time since GetImage() cannot handle stride
+ for (i = y; i < y + height; i++) {
+ DrawablePtr pDrawable;
+#if XORG < 19
+ pDrawable = (DrawablePtr) WindowTable[scrIdx];
+#else
+ pDrawable = (DrawablePtr) pScreen->root;
+#endif
+
+ (*pScreen->GetImage) (pDrawable, x, i, width, 1,
+ ZPixmap, (unsigned long)~0L, buffer);
+
+ buffer += strideBytes;
+ }
+
+ vncHooksScreen->ignoreHooks--;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Helper functions for adding changes and copies
+//
+
+static inline void add_changed(ScreenPtr pScreen, RegionPtr reg)
+{
+ vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
+ if (vncHooksScreen->ignoreHooks)
+ return;
+ vncAddChanged(pScreen->myNum,
+ (const struct UpdateRect*)REGION_EXTENTS(pScreen, reg),
+ REGION_NUM_RECTS(reg),
+ (const struct UpdateRect*)REGION_RECTS(reg));
+}
+
+static inline void add_copied(ScreenPtr pScreen, RegionPtr dst,
+ int dx, int dy)
+{
+ vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
+ if (vncHooksScreen->ignoreHooks)
+ return;
+ vncAddCopied(pScreen->myNum,
+ (const struct UpdateRect*)REGION_EXTENTS(pScreen, dst),
+ REGION_NUM_RECTS(dst),
+ (const struct UpdateRect*)REGION_RECTS(dst), dx, dy);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// screen functions
+//
+
+// SCREEN_UNWRAP and SCREEN_REWRAP unwrap and rewrap the given screen function.
+
+#define SCREEN_UNWRAP(scrn,field) \
+ ScreenPtr pScreen = scrn; \
+ vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen); \
+ 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
+
+#if XORG <= 112
+static Bool vncHooksCloseScreen(int i, ScreenPtr pScreen_)
+#else
+static Bool vncHooksCloseScreen(ScreenPtr pScreen_)
+#endif
+{
+#ifdef RENDER
+ PictureScreenPtr ps;
+#endif
+#ifdef RANDR
+ rrScrPrivPtr rp;
+#endif
+
+ SCREEN_UNWRAP(pScreen_, CloseScreen);
+
+ pScreen->CreateGC = vncHooksScreen->CreateGC;
+ pScreen->CopyWindow = vncHooksScreen->CopyWindow;
+ pScreen->ClearToBackground = vncHooksScreen->ClearToBackground;
+#if XORG < 110
+ pScreen->RestoreAreas = vncHooksScreen->RestoreAreas;
+#endif
+ pScreen->DisplayCursor = vncHooksScreen->DisplayCursor;
+ pScreen->BlockHandler = vncHooksScreen->BlockHandler;
+#ifdef RENDER
+ ps = GetPictureScreenIfSet(pScreen);
+ if (ps) {
+ ps->Composite = vncHooksScreen->Composite;
+ ps->Glyphs = vncHooksScreen->Glyphs;
+ }
+#endif
+#ifdef RANDR
+ rp = rrGetScrPriv(pScreen);
+ if (rp) {
+ rp->rrSetConfig = vncHooksScreen->RandRSetConfig;
+ rp->rrScreenSetSize = vncHooksScreen->RandRScreenSetSize;
+ rp->rrCrtcSet = vncHooksScreen->RandRCrtcSet;
+ }
+#endif
+
+ DBGPRINT((stderr,"vncHooksCloseScreen: unwrapped screen functions\n"));
+
+#if XORG <= 112
+ return (*pScreen->CloseScreen)(i, pScreen);
+#else
+ return (*pScreen->CloseScreen)(pScreen);
+#endif
+}
+
+// CreateGC - wrap the "GC funcs"
+
+static Bool vncHooksCreateGC(GCPtr pGC)
+{
+ vncHooksGCPtr vncHooksGC = vncHooksGCPrivate(pGC);
+ Bool ret;
+
+ SCREEN_UNWRAP(pGC->pScreen, CreateGC);
+
+ ret = (*pScreen->CreateGC) (pGC);
+
+ vncHooksGC->wrappedOps = 0;
+ vncHooksGC->wrappedFuncs = pGC->funcs;
+ pGC->funcs = &vncHooksGCFuncs;
+
+ SCREEN_REWRAP(CreateGC);
+
+ return ret;
+}
+
+// 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)
+{
+ int dx, dy;
+ BoxRec screen_box;
+ RegionRec copied, screen_rgn;
+
+ SCREEN_UNWRAP(pWin->drawable.pScreen, CopyWindow);
+
+ REGION_NULL(pScreen, &copied);
+ REGION_COPY(pScreen, &copied, pOldRegion);
+
+ screen_box.x1 = 0;
+ screen_box.y1 = 0;
+ screen_box.x2 = pScreen->width;
+ screen_box.y2 = pScreen->height;
+
+ REGION_INIT(pScreen, &screen_rgn, &screen_box, 1);
+
+ dx = pWin->drawable.x - ptOldOrg.x;
+ dy = pWin->drawable.y - ptOldOrg.y;
+
+ // RFB tracks copies in terms of destination rectangle, not source.
+ // We also need to copy with changes to the Window's clipping region.
+ // Finally, make sure we don't get copies to or from regions outside
+ // the framebuffer.
+ REGION_INTERSECT(pScreen, &copied, &copied, &screen_rgn);
+ REGION_TRANSLATE(pScreen, &copied, dx, dy);
+ REGION_INTERSECT(pScreen, &copied, &copied, &screen_rgn);
+ REGION_INTERSECT(pScreen, &copied, &copied, &pWin->borderClip);
+
+ (*pScreen->CopyWindow) (pWin, ptOldOrg, pOldRegion);
+
+ if (REGION_NOTEMPTY(pScreen, &copied))
+ add_copied(pScreen, &copied, dx, dy);
+
+ REGION_UNINIT(pScreen, &copied);
+ REGION_UNINIT(pScreen, &screen_rgn);
+
+ 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)
+{
+ BoxRec box;
+ RegionRec reg;
+
+ SCREEN_UNWRAP(pWin->drawable.pScreen, ClearToBackground);
+
+ 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);
+
+ REGION_INIT(pScreen, ®, &box, 0);
+ REGION_INTERSECT(pScreen, ®, ®, &pWin->clipList);
+
+ (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures);
+
+ if (!generateExposures) {
+ add_changed(pScreen, ®);
+ }
+
+ REGION_UNINIT(pScreen, ®);
+
+ SCREEN_REWRAP(ClearToBackground);
+}
+
+#if XORG < 110
+// RestoreAreas - changed region is the given region
+
+static RegionPtr vncHooksRestoreAreas(WindowPtr pWin, RegionPtr pRegion)
+{
+ RegionRec reg;
+
+ SCREEN_UNWRAP(pWin->drawable.pScreen, RestoreAreas);
+
+ REGION_NULL(pScreen, ®);
+ REGION_COPY(pScreen, ®, pRegion);
+
+ RegionPtr result = (*pScreen->RestoreAreas) (pWin, pRegion);
+
+ add_changed(pScreen, ®);
+
+ REGION_UNINIT(pScreen, ®);
+
+ SCREEN_REWRAP(RestoreAreas);
+
+ return result;
+}
+#endif
+
+// DisplayCursor - get the cursor shape
+
+static Bool vncHooksDisplayCursor(
+#if XORG >= 16
+ DeviceIntPtr pDev,
+#endif
+ ScreenPtr pScreen_, CursorPtr cursor)
+{
+ Bool ret;
+
+ SCREEN_UNWRAP(pScreen_, DisplayCursor);
+
+ ret = (*pScreen->DisplayCursor) (
+#if XORG >= 16
+ pDev,
+#endif
+ pScreen, cursor);
+
+#if XORG >= 16
+ /*
+ * XXX DIX calls this function with NULL argument to remove cursor sprite from
+ * screen. Should we handle this in setCursor as well?
+ */
+ if (cursor != NullCursor)
+#endif
+ {
+ int width, height;
+ int hotX, hotY;
+
+ unsigned char *rgbaData;
+
+ width = cursor->bits->width;
+ height = cursor->bits->height;
+
+ hotX = cursor->bits->xhot;
+ hotY = cursor->bits->yhot;
+
+ rgbaData = malloc(width * height * 4);
+ if (rgbaData == NULL)
+ goto out;
+
+#ifdef ARGB_CURSOR
+ if (cursor->bits->argb) {
+ unsigned char *out;
+ CARD32 *in;
+ int i;
+
+ in = cursor->bits->argb;
+ out = rgbaData;
+ for (i = 0; i < width*height; i++) {
+ out[0] = (*in >> 16) & 0xff;
+ out[1] = (*in >> 8) & 0xff;
+ out[2] = (*in >> 0) & 0xff;
+ out[3] = (*in >> 24) & 0xff;
+ out += 4;
+ in++;
+ }
+ } else {
+#endif
+ unsigned char *out;
+ int xMaskBytesPerRow;
+
+ xMaskBytesPerRow = BitmapBytePad(width);
+
+ out = rgbaData;
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int byte = y * xMaskBytesPerRow + x / 8;
+#if (BITMAP_BIT_ORDER == MSBFirst)
+ int bit = 7 - x % 8;
+#else
+ int bit = x % 8;
+#endif
+
+ if (cursor->bits->source[byte] & (1 << bit)) {
+ out[0] = cursor->foreRed;
+ out[1] = cursor->foreGreen;
+ out[2] = cursor->foreBlue;
+ } else {
+ out[0] = cursor->backRed;
+ out[1] = cursor->backGreen;
+ out[2] = cursor->backBlue;
+ }
+
+ if (cursor->bits->mask[byte] & (1 << bit))
+ out[3] = 0xff;
+ else
+ out[3] = 0x00;
+
+ out += 4;
+ }
+ }
+#ifdef ARGB_CURSOR
+ }
+#endif
+
+ vncSetCursor(pScreen->myNum, width, height, hotX, hotY, rgbaData);
+ }
+
+out:
+ SCREEN_REWRAP(DisplayCursor);
+
+ return ret;
+}
+
+// BlockHandler - ignore any changes during the block handler - it's likely
+// these are just drawing the cursor.
+
+#if XORG <= 112
+static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout,
+ pointer pReadmask)
+#else
+static void vncHooksBlockHandler(ScreenPtr pScreen_, void * pTimeout,
+ void * pReadmask)
+#endif
+{
+#if XORG <= 112
+ SCREEN_UNWRAP(screenInfo.screens[i], BlockHandler);
+#else
+ SCREEN_UNWRAP(pScreen_, BlockHandler);
+#endif
+
+ vncHooksScreen->ignoreHooks++;
+
+#if XORG <= 112
+ (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
+#else
+ (*pScreen->BlockHandler) (pScreen, pTimeout, pReadmask);
+#endif
+
+ vncHooksScreen->ignoreHooks--;
+
+ SCREEN_REWRAP(BlockHandler);
+}
+
+#ifdef RENDER
+
+// Composite - The core of XRENDER
+
+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 = vncHooksScreenPrivate(pScreen);
+ PictureScreenPtr ps = GetPictureScreen(pScreen);
+
+ RegionRec changed;
+
+ if (pDst->pDrawable->type == DRAWABLE_WINDOW &&
+ ((WindowPtr) pDst->pDrawable)->viewable) {
+ BoxRec box;
+
+ box.x1 = max(pDst->pDrawable->x + xDst, 0);
+ box.y1 = max(pDst->pDrawable->y + yDst, 0);
+ box.x2 = min(box.x1 + width, pScreen->width);
+ box.y2 = min(box.y1 + height, pScreen->height);
+
+ REGION_INIT(pScreen, &changed, &box, 0);
+ } else {
+ REGION_NULL(pScreen, &changed);
+ }
+
+
+ ps->Composite = vncHooksScreen->Composite;
+ (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc,
+ xMask, yMask, xDst, yDst, width, height);
+ ps->Composite = vncHooksComposite;
+
+ if (REGION_NOTEMPTY(pScreen, &changed))
+ add_changed(pScreen, &changed);
+
+ REGION_UNINIT(pScreen, &changed);
+}
+
+static int
+GlyphCount(int nlist, GlyphListPtr list, GlyphPtr * glyphs)
+{
+ int count;
+
+ count = 0;
+ while (nlist--) {
+ count += list->len;
+ list++;
+ }
+
+ return count;
+}
+
+static RegionPtr
+GlyphsToRegion(ScreenPtr pScreen, int nlist, GlyphListPtr list, GlyphPtr *glyphs)
+{
+ int n;
+ GlyphPtr glyph;
+ int x, y;
+
+ int nrects = GlyphCount(nlist, list, glyphs);
+ xRectangle rects[nrects];
+ xRectanglePtr rect;
+
+ x = 0;
+ y = 0;
+ rect = &rects[0];
+ while (nlist--) {
+ x += list->xOff;
+ y += list->yOff;
+ n = list->len;
+ list++;
+ while (n--) {
+ glyph = *glyphs++;
+ rect->x = x - glyph->info.x;
+ rect->y = y - glyph->info.y;
+ rect->width = glyph->info.width;
+ rect->height = glyph->info.height;
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ rect++;
+ }
+ }
+
+ return RECTS_TO_REGION(pScreen, nrects, rects, CT_NONE);
+}
+
+// Glyphs - Glyph specific version of Composite (caches and whatnot)
+
+void vncHooksGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
+ PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlists,
+ GlyphListPtr lists, GlyphPtr * glyphs)
+{
+ ScreenPtr pScreen = pDst->pDrawable->pScreen;
+ vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
+ PictureScreenPtr ps = GetPictureScreen(pScreen);
+
+ RegionPtr changed;
+
+ if (pDst->pDrawable->type == DRAWABLE_WINDOW &&
+ ((WindowPtr) pDst->pDrawable)->viewable) {
+ BoxRec fbbox;
+ RegionRec fbreg;
+
+ changed = GlyphsToRegion(pScreen, nlists, lists, glyphs);
+ REGION_TRANSLATE(pScreen, changed,
+ pDst->pDrawable->x, pDst->pDrawable->y);
+
+ fbbox.x1 = 0;
+ fbbox.y1 = 0;
+ fbbox.x2 = pScreen->width;
+ fbbox.y2 = pScreen->height;
+ REGION_INIT(pScreen, &fbreg, &fbbox, 0);
+
+ REGION_INTERSECT(pScreen, changed, changed, &fbreg);
+
+ REGION_UNINIT(pScreen, &fbreg);
+ } else {
+ changed = REGION_CREATE(pScreen, NullBox, 0);
+ }
+
+ ps->Glyphs = vncHooksScreen->Glyphs;
+ (*ps->Glyphs)(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlists, lists, glyphs);
+ ps->Glyphs = vncHooksGlyphs;
+
+ if (REGION_NOTEMPTY(pScreen, changed))
+ add_changed(pScreen, changed);
+
+ REGION_DESTROY(pScreen, changed);
+}
+
+#endif /* RENDER */
+
+// RandRSetConfig - follow any framebuffer changes
+
+#ifdef RANDR
+
+static Bool vncHooksRandRSetConfig(ScreenPtr pScreen, Rotation rotation,
+ int rate, RRScreenSizePtr pSize)
+{
+ vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
+ rrScrPrivPtr rp = rrGetScrPriv(pScreen);
+ Bool ret;
+
+ vncPreScreenResize(pScreen->myNum);
+
+ rp->rrSetConfig = vncHooksScreen->RandRSetConfig;
+ ret = (*rp->rrSetConfig)(pScreen, rotation, rate, pSize);
+ rp->rrSetConfig = vncHooksRandRSetConfig;
+
+ vncPostScreenResize(pScreen->myNum, ret, pScreen->width, pScreen->height);
+
+ if (!ret)
+ return FALSE;
+
+ return TRUE;
+}
+
+static Bool vncHooksRandRScreenSetSize(ScreenPtr pScreen,
+ CARD16 width, CARD16 height,
+ CARD32 mmWidth, CARD32 mmHeight)
+{
+ vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
+ rrScrPrivPtr rp = rrGetScrPriv(pScreen);
+ Bool ret;
+
+ vncPreScreenResize(pScreen->myNum);
+
+ rp->rrScreenSetSize = vncHooksScreen->RandRScreenSetSize;
+ ret = (*rp->rrScreenSetSize)(pScreen, width, height, mmWidth, mmHeight);
+ rp->rrScreenSetSize = vncHooksRandRScreenSetSize;
+
+ vncPostScreenResize(pScreen->myNum, ret, pScreen->width, pScreen->height);
+
+ if (!ret)
+ return FALSE;
+
+ return TRUE;
+}
+
+static Bool vncHooksRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc,
+ RRModePtr mode, int x, int y,
+ Rotation rotation, int num_outputs,
+ RROutputPtr *outputs)
+{
+ vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
+ rrScrPrivPtr rp = rrGetScrPriv(pScreen);
+ Bool ret;
+
+ rp->rrCrtcSet = vncHooksScreen->RandRCrtcSet;
+ ret = (*rp->rrCrtcSet)(pScreen, crtc, mode, x, y, rotation,
+ num_outputs, outputs);
+ rp->rrCrtcSet = vncHooksRandRCrtcSet;
+
+ if (!ret)
+ return FALSE;
+
+ vncRefreshScreenLayout(pScreen->myNum);
+
+ return TRUE;
+}
+
+#endif /* RANDR */
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// GC "funcs"
+//
+
+// Unwrap and rewrap helpers
+
+#define GC_FUNC_PROLOGUE(pGC, name)\
+ vncHooksGCPtr pGCPriv = vncHooksGCPrivate(pGC);\
+ (pGC)->funcs = pGCPriv->wrappedFuncs;\
+ if(pGCPriv->wrappedOps)\
+ (pGC)->ops = pGCPriv->wrappedOps; \
+ DBGPRINT((stderr,"vncHooks" #name " called\n"))
+
+#define GC_FUNC_EPILOGUE(pGC)\
+ pGCPriv->wrappedFuncs = (pGC)->funcs;\
+ (pGC)->funcs = &vncHooksGCFuncs;\
+ if(pGCPriv->wrappedOps) {\
+ pGCPriv->wrappedOps = (pGC)->ops;\
+ (pGC)->ops = &vncHooksGCOps;\
+ }
+
+// ValidateGC - wrap the "ops" if a viewable window OR the screen pixmap
+
+static void vncHooksValidateGC(GCPtr pGC, unsigned long changes,
+ DrawablePtr pDrawable)
+{
+ GC_FUNC_PROLOGUE(pGC, ValidateGC);
+ (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
+ if ((pDrawable->type == DRAWABLE_WINDOW &&
+ ((WindowPtr) pDrawable)->viewable) ||
+ (pDrawable == &pGC->pScreen->GetScreenPixmap(pGC->pScreen)->drawable)) {
+ pGCPriv->wrappedOps = pGC->ops;
+ DBGPRINT((stderr,"vncHooksValidateGC: wrapped GC ops\n"));
+ } else {
+ pGCPriv->wrappedOps = NULL;
+ }
+ GC_FUNC_EPILOGUE(pGC);
+}
+
+// Other GC funcs - just unwrap and call on
+
+static void vncHooksChangeGC(GCPtr pGC, unsigned long mask) {
+ GC_FUNC_PROLOGUE(pGC, ChangeGC);
+ (*pGC->funcs->ChangeGC) (pGC, mask);
+ GC_FUNC_EPILOGUE(pGC);
+}
+static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst) {
+ GC_FUNC_PROLOGUE(dst, CopyGC);
+ (*dst->funcs->CopyGC) (src, mask, dst);
+ GC_FUNC_EPILOGUE(dst);
+}
+static void vncHooksDestroyGC(GCPtr pGC) {
+ GC_FUNC_PROLOGUE(pGC, DestroyGC);
+ (*pGC->funcs->DestroyGC) (pGC);
+ GC_FUNC_EPILOGUE(pGC);
+}
+static void vncHooksChangeClip(GCPtr pGC, int type, void * pValue, int nrects)
+{
+ GC_FUNC_PROLOGUE(pGC, ChangeClip);
+ (*pGC->funcs->ChangeClip) (pGC, type, pValue, nrects);
+ GC_FUNC_EPILOGUE(pGC);
+}
+static void vncHooksDestroyClip(GCPtr pGC) {
+ GC_FUNC_PROLOGUE(pGC, DestroyClip);
+ (*pGC->funcs->DestroyClip) (pGC);
+ GC_FUNC_EPILOGUE(pGC);
+}
+static void vncHooksCopyClip(GCPtr dst, GCPtr src) {
+ GC_FUNC_PROLOGUE(dst, CopyClip);
+ (*dst->funcs->CopyClip) (dst, src);
+ GC_FUNC_EPILOGUE(dst);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// GC "ops"
+//
+
+// Unwrap and rewrap helpers
+
+#define GC_OP_PROLOGUE(pGC, name)\
+ vncHooksGCPtr pGCPriv = vncHooksGCPrivate(pGC);\
+ GCFuncs *oldFuncs = pGC->funcs;\
+ pGC->funcs = pGCPriv->wrappedFuncs;\
+ pGC->ops = pGCPriv->wrappedOps; \
+ DBGPRINT((stderr,"vncHooks" #name " called\n"))
+
+#define GC_OP_EPILOGUE(pGC)\
+ pGCPriv->wrappedOps = pGC->ops;\
+ pGC->funcs = oldFuncs;\
+ pGC->ops = &vncHooksGCOps
+
+// FillSpans - assume the entire clip region is damaged. 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)
+{
+ RegionRec reg;
+
+ GC_OP_PROLOGUE(pGC, FillSpans);
+
+ REGION_NULL(pGC->pScreen, ®);
+ REGION_COPY(pGC->pScreen, ®, pGC->pCompositeClip);
+
+ if (pDrawable->type == DRAWABLE_WINDOW)
+ REGION_INTERSECT(pScreen, ®, ®, &((WindowPtr)pDrawable)->borderClip);
+
+ (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted);
+
+ add_changed(pGC->pScreen, ®);
+
+ REGION_UNINIT(pGC->pScreen, ®);
+
+ GC_OP_EPILOGUE(pGC);
+}
+
+// SetSpans - assume the entire clip region is damaged. 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)
+{
+ RegionRec reg;
+
+ GC_OP_PROLOGUE(pGC, SetSpans);
+
+ REGION_NULL(pGC->pScreen, ®);
+ REGION_COPY(pGC->pScreen, ®, pGC->pCompositeClip);
+
+ if (pDrawable->type == DRAWABLE_WINDOW)
+ REGION_INTERSECT(pScreen, ®, ®, &((WindowPtr)pDrawable)->borderClip);
+
+ (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
+
+ add_changed(pGC->pScreen, ®);
+
+ REGION_UNINIT(pGC->pScreen, ®);
+
+ GC_OP_EPILOGUE(pGC);
+}
+
+// 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)
+{
+ BoxRec box;
+ RegionRec reg;
+
+ GC_OP_PROLOGUE(pGC, PutImage);
+
+ box.x1 = x + pDrawable->x;
+ box.y1 = y + pDrawable->y;
+ box.x2 = box.x1 + w;
+ box.y2 = box.y1 + h;
+
+ REGION_INIT(pGC->pScreen, ®, &box, 0);
+ REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip);
+
+ (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, leftPad, format,
+ pBits);
+
+ add_changed(pGC->pScreen, ®);
+
+ REGION_UNINIT(pGC->pScreen, ®);
+
+ GC_OP_EPILOGUE(pGC);
+}
+
+// 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)
+{
+ BoxRec box;
+ RegionRec dst, src, changed;
+
+ RegionPtr ret;
+
+ GC_OP_PROLOGUE(pGC, CopyArea);
+
+ box.x1 = dstx + pDst->x;
+ box.y1 = dsty + pDst->y;
+ box.x2 = box.x1 + w;
+ box.y2 = box.y1 + h;
+
+ REGION_INIT(pGC->pScreen, &dst, &box, 0);
+ REGION_INTERSECT(pGC->pScreen, &dst, &dst, pGC->pCompositeClip);
+
+ // The source of the data has to be something that's on screen.
+ // This means either a window, or the screen pixmap.
+ if ((pSrc->pScreen == pGC->pScreen) &&
+ ((pSrc->type == DRAWABLE_WINDOW) ||
+ (pSrc == &pGC->pScreen->GetScreenPixmap(pGC->pScreen)->drawable))) {
+ box.x1 = srcx + pSrc->x;
+ box.y1 = srcy + pSrc->y;
+ box.x2 = box.x1 + w;
+ box.y2 = box.y1 + h;
+
+ REGION_INIT(pGC->pScreen, &src, &box, 0);
+
+ if ((pSrc->type == DRAWABLE_WINDOW) &&
+ REGION_NOTEMPTY(pScreen, &((WindowPtr)pSrc)->clipList)) {
+ REGION_INTERSECT(pScreen, &src, &src, &((WindowPtr)pSrc)->clipList);
+ }
+
+ REGION_TRANSLATE(pScreen, &src,
+ dstx + pDst->x - srcx - pSrc->x,
+ dsty + pDst->y - srcy - pSrc->y);
+ } else {
+ REGION_NULL(pGC->pScreen, &src);
+ }
+
+ REGION_NULL(pGC->pScreen, &changed);
+
+ REGION_SUBTRACT(pScreen, &changed, &dst, &src);
+ REGION_INTERSECT(pScreen, &dst, &dst, &src);
+
+ ret = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty);
+
+ if (REGION_NOTEMPTY(pScreen, &dst))
+ add_copied(pGC->pScreen, &dst,
+ dstx + pDst->x - srcx - pSrc->x,
+ dsty + pDst->y - srcy - pSrc->y);
+
+ if (REGION_NOTEMPTY(pScreen, &changed))
+ add_changed(pGC->pScreen, &changed);
+
+ REGION_UNINIT(pGC->pScreen, &dst);
+ REGION_UNINIT(pGC->pScreen, &src);
+ REGION_UNINIT(pGC->pScreen, &changed);
+
+ GC_OP_EPILOGUE(pGC);
+
+ return ret;
+}
+
+
+// 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)
+{
+ BoxRec box;
+ RegionRec reg;
+
+ RegionPtr ret;
+
+ GC_OP_PROLOGUE(pGC, CopyPlane);
+
+ box.x1 = dstx + pDst->x;
+ box.y1 = dsty + pDst->y;
+ box.x2 = box.x1 + w;
+ box.y2 = box.y1 + h;
+
+ REGION_INIT(pGC->pScreen, ®, &box, 0);
+ REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip);
+
+ ret = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h,
+ dstx, dsty, plane);
+
+ add_changed(pGC->pScreen, ®);
+
+ REGION_UNINIT(pGC->pScreen, ®);
+
+ GC_OP_EPILOGUE(pGC);
+
+ return ret;
+}
+
+// PolyPoint - changed region is the bounding rect, clipped by pCompositeClip
+
+static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode,
+ int npt, xPoint *pts)
+{
+ int minX, minY, maxX, maxY;
+ int i;
+
+ BoxRec box;
+ RegionRec reg;
+
+ GC_OP_PROLOGUE(pGC, PolyPoint);
+
+ if (npt == 0) {
+ (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
+ goto out;
+ }
+
+ minX = pts[0].x;
+ maxX = pts[0].x;
+ minY = pts[0].y;
+ maxY = pts[0].y;
+
+ if (mode == CoordModePrevious) {
+ int x = pts[0].x;
+ int y = pts[0].y;
+
+ for (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 (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;
+ }
+ }
+
+ box.x1 = minX + pDrawable->x;
+ box.y1 = minY + pDrawable->y;
+ box.x2 = maxX + 1 + pDrawable->x;
+ box.y2 = maxY + 1 + pDrawable->y;
+
+ REGION_INIT(pGC->pScreen, ®, &box, 0);
+ REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip);
+
+ (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
+
+ add_changed(pGC->pScreen, ®);
+
+ REGION_UNINIT(pGC->pScreen, ®);
+
+out:
+ GC_OP_EPILOGUE(pGC);
+}
+
+// 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)
+{
+ int nRegRects;
+ xRectangle regRects[MAX_RECTS_PER_OP];
+
+ int lw;
+
+ RegionPtr reg;
+
+ GC_OP_PROLOGUE(pGC, Polylines);
+
+ if (npt == 0) {
+ (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts);
+ goto out;
+ }
+
+ nRegRects = npt - 1;
+
+ 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;
+
+ int prevX, prevY, curX, curY;
+ int rectX1, rectY1, rectX2, rectY2;
+ int minX, minY, maxX, maxY;
+
+ int i;
+
+ extra = lw / 2;
+ if (pGC->joinStyle == JoinMiter) {
+ extra = 6 * lw;
+ }
+
+ prevX = ppts[0].x + pDrawable->x;
+ prevY = ppts[0].y + pDrawable->y;
+ minX = maxX = prevX;
+ minY = maxY = prevY;
+
+ for (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;
+ }
+ }
+
+ reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE);
+ REGION_INTERSECT(pGC->pScreen, reg, reg, pGC->pCompositeClip);
+
+ (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts);
+
+ add_changed(pGC->pScreen, reg);
+
+ REGION_DESTROY(pGC->pScreen, reg);
+
+out:
+ GC_OP_EPILOGUE(pGC);
+}
+
+// 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)
+{
+ xRectangle regRects[MAX_RECTS_PER_OP];
+ int nRegRects;
+
+ int lw, extra;
+
+ int rectX1, rectY1, rectX2, rectY2;
+ int minX, minY, maxX, maxY;
+
+ int i;
+
+ RegionPtr reg;
+
+ GC_OP_PROLOGUE(pGC, PolySegment);
+
+ if (nseg == 0) {
+ (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs);
+ goto out;
+ }
+
+ nRegRects = nseg;
+
+ lw = pGC->lineWidth;
+ extra = lw / 2;
+
+ minX = maxX = segs[0].x1;
+ minY = maxY = segs[0].y1;
+
+ for (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;
+ }
+
+ reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE);
+ REGION_INTERSECT(pGC->pScreen, reg, reg, pGC->pCompositeClip);
+
+ (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs);
+
+ add_changed(pGC->pScreen, reg);
+
+ REGION_DESTROY(pGC->pScreen, reg);
+
+out:
+ GC_OP_EPILOGUE(pGC);
+}
+
+// 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)
+{
+ xRectangle regRects[MAX_RECTS_PER_OP*4];
+ int nRegRects;
+
+ int lw, extra;
+
+ int rectX1, rectY1, rectX2, rectY2;
+ int minX, minY, maxX, maxY;
+
+ int i;
+
+ RegionPtr reg;
+
+ GC_OP_PROLOGUE(pGC, PolyRectangle);
+
+ if (nrects == 0) {
+ (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects);
+ goto out;
+ }
+
+ nRegRects = nrects * 4;
+
+ lw = pGC->lineWidth;
+ extra = lw / 2;
+
+ minX = maxX = rects[0].x;
+ minY = maxY = rects[0].y;
+
+ for (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;
+ }
+
+ reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE);
+ REGION_INTERSECT(pGC->pScreen, reg, reg, pGC->pCompositeClip);
+
+ (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects);
+
+ add_changed(pGC->pScreen, reg);
+
+ REGION_DESTROY(pGC->pScreen, reg);
+
+out:
+ GC_OP_EPILOGUE(pGC);
+}
+
+// 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)
+{
+ xRectangle regRects[MAX_RECTS_PER_OP];
+ int nRegRects;
+
+ int lw, extra;
+
+ int rectX1, rectY1, rectX2, rectY2;
+ int minX, minY, maxX, maxY;
+
+ int i;
+
+ RegionPtr reg;
+
+ GC_OP_PROLOGUE(pGC, PolyArc);
+
+ if (narcs == 0) {
+ (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs);
+ goto out;
+ }
+
+ nRegRects = narcs;
+
+ lw = pGC->lineWidth;
+ if (lw == 0)
+ lw = 1;
+ extra = lw / 2;
+
+ minX = maxX = arcs[0].x;
+ minY = maxY = arcs[0].y;
+
+ for (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;
+ }
+
+ reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE);
+ REGION_INTERSECT(pGC->pScreen, reg, reg, pGC->pCompositeClip);
+
+ (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs);
+
+ add_changed(pGC->pScreen, reg);
+
+ REGION_DESTROY(pGC->pScreen, reg);
+
+out:
+ GC_OP_EPILOGUE(pGC);
+}
+
+
+// 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)
+{
+ int minX, minY, maxX, maxY;
+ int i;
+
+ BoxRec box;
+ RegionRec reg;
+
+ GC_OP_PROLOGUE(pGC, FillPolygon);
+
+ if (count == 0) {
+ (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
+ goto out;
+ }
+
+ minX = pts[0].x;
+ maxX = pts[0].x;
+ minY = pts[0].y;
+ maxY = pts[0].y;
+
+ if (mode == CoordModePrevious) {
+ int x = pts[0].x;
+ int y = pts[0].y;
+
+ for (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 (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;
+ }
+ }
+
+ box.x1 = minX + pDrawable->x;
+ box.y1 = minY + pDrawable->y;
+ box.x2 = maxX + 1 + pDrawable->x;
+ box.y2 = maxY + 1 + pDrawable->y;
+
+ REGION_INIT(pGC->pScreen, ®, &box, 0);
+ REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip);
+
+ (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
+
+ add_changed(pGC->pScreen, ®);
+
+ REGION_UNINIT(pGC->pScreen, ®);
+
+out:
+ GC_OP_EPILOGUE(pGC);
+}
+
+// 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)
+{
+ xRectangle regRects[MAX_RECTS_PER_OP];
+ int nRegRects;
+ int rectX1, rectY1, rectX2, rectY2;
+ int minX, minY, maxX, maxY;
+ int i;
+
+ RegionPtr reg;
+
+ GC_OP_PROLOGUE(pGC, PolyFillRect);
+
+ if (nrects == 0) {
+ (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects);
+ goto out;
+ }
+
+ nRegRects = nrects;
+ minX = maxX = rects[0].x;
+ minY = maxY = rects[0].y;
+
+ for (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;
+ }
+
+ reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE);
+ REGION_INTERSECT(pGC->pScreen, reg, reg, pGC->pCompositeClip);
+
+ (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects);
+
+ add_changed(pGC->pScreen, reg);
+
+ REGION_DESTROY(pGC->pScreen, reg);
+
+out:
+ GC_OP_EPILOGUE(pGC);
+}
+
+// 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)
+{
+ xRectangle regRects[MAX_RECTS_PER_OP];
+ int nRegRects;
+
+ int lw, extra;
+
+ int rectX1, rectY1, rectX2, rectY2;
+ int minX, minY, maxX, maxY;
+
+ int i;
+
+ RegionPtr reg;
+
+ GC_OP_PROLOGUE(pGC, PolyFillArc);
+
+ if (narcs == 0) {
+ (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs);
+ goto out;
+ }
+
+ nRegRects = narcs;
+
+ lw = pGC->lineWidth;
+ if (lw == 0)
+ lw = 1;
+ extra = lw / 2;
+
+ minX = maxX = arcs[0].x;
+ minY = maxY = arcs[0].y;
+
+ for (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;
+ }
+
+ reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE);
+ REGION_INTERSECT(pGC->pScreen, reg, reg, pGC->pCompositeClip);
+
+ (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs);
+
+ add_changed(pGC->pScreen, reg);
+
+ REGION_DESTROY(pGC->pScreen, reg);
+
+out:
+ GC_OP_EPILOGUE(pGC);
+}
+
+// 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 = max(FONTASCENT(font), FONTMAXBOUNDS(font, ascent));
+ int descent = max(FONTDESCENT(font), FONTMAXBOUNDS(font, descent));
+ int charWidth = max(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)
+{
+ int ret;
+ BoxRec box;
+ RegionRec reg;
+
+ GC_OP_PROLOGUE(pGC, PolyText8);
+
+ if (count == 0) {
+ ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
+ goto out;
+ }
+
+ GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
+
+ REGION_INIT(pGC->pScreen, ®, &box, 0);
+ REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip);
+
+ ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
+
+ add_changed(pGC->pScreen, ®);
+
+ REGION_UNINIT(pGC->pScreen, ®);
+
+out:
+ GC_OP_EPILOGUE(pGC);
+
+ 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)
+{
+ int ret;
+ BoxRec box;
+ RegionRec reg;
+
+ GC_OP_PROLOGUE(pGC, PolyText16);
+
+ if (count == 0) {
+ ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
+ goto out;
+ }
+
+ GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
+
+ REGION_INIT(pGC->pScreen, ®, &box, 0);
+ REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip);
+
+ ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
+
+ add_changed(pGC->pScreen, ®);
+
+ REGION_UNINIT(pGC->pScreen, ®);
+
+out:
+ GC_OP_EPILOGUE(pGC);
+
+ 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)
+{
+ BoxRec box;
+ RegionRec reg;
+
+ GC_OP_PROLOGUE(pGC, ImageText8);
+
+ if (count == 0) {
+ (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
+ goto out;
+ }
+
+ GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
+
+ REGION_INIT(pGC->pScreen, ®, &box, 0);
+ REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip);
+
+ (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
+
+ add_changed(pGC->pScreen, ®);
+
+ REGION_UNINIT(pGC->pScreen, ®);
+
+out:
+ GC_OP_EPILOGUE(pGC);
+}
+
+// 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)
+{
+ BoxRec box;
+ RegionRec reg;
+
+ GC_OP_PROLOGUE(pGC, ImageText16);
+
+ if (count == 0) {
+ (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
+ goto out;
+ }
+
+ GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
+
+ REGION_INIT(pGC->pScreen, ®, &box, 0);
+ REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip);
+
+ (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
+
+ add_changed(pGC->pScreen, ®);
+
+ REGION_UNINIT(pGC->pScreen, ®);
+
+out:
+ GC_OP_EPILOGUE(pGC);
+}
+
+// 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, void * pglyphBase)
+{
+ BoxRec box;
+ RegionRec reg;
+
+ GC_OP_PROLOGUE(pGC, ImageGlyphBlt);
+
+ if (nglyph == 0) {
+ (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase);
+ goto out;
+ }
+
+ GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box);
+
+ REGION_INIT(pGC->pScreen, ®, &box, 0);
+ REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip);
+
+ (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+
+ add_changed(pGC->pScreen, ®);
+
+ REGION_UNINIT(pGC->pScreen, ®);
+
+out:
+ GC_OP_EPILOGUE(pGC);
+}
+
+// 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, void * pglyphBase)
+{
+ BoxRec box;
+ RegionRec reg;
+
+ GC_OP_PROLOGUE(pGC, PolyGlyphBlt);
+
+ if (nglyph == 0) {
+ (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase);
+ goto out;
+ }
+
+ GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box);
+
+ REGION_INIT(pGC->pScreen, ®, &box, 0);
+ REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip);
+
+ (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+
+ add_changed(pGC->pScreen, ®);
+
+ REGION_UNINIT(pGC->pScreen, ®);
+
+out:
+ GC_OP_EPILOGUE(pGC);
+}
+
+// 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)
+{
+ BoxRec box;
+ RegionRec reg;
+
+ GC_OP_PROLOGUE(pGC, PushPixels);
+
+ box.x1 = x + pDrawable->x;
+ box.y1 = y + pDrawable->y;
+ box.x2 = box.x1 + w;
+ box.y2 = box.y1 + h;
+
+ REGION_INIT(pGC->pScreen, ®, &box, 0);
+ REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip);
+
+ (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y);
+
+ add_changed(pGC->pScreen, ®);
+
+ REGION_UNINIT(pGC->pScreen, ®);
+
+ GC_OP_EPILOGUE(pGC);
+}
+++ /dev/null
-/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2009 Pierre Ossman for Cendio AB
- *
- * 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.
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <stdio.h>
-#include "XserverDesktop.h"
-#include "vncHooks.h"
-#include "vncExtInit.h"
-#include "xorg-version.h"
-
-extern "C" {
-#define class c_class
-#define private c_private
-#define public c_public
-#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 RANDR
-#include "randrstr.h"
-#endif
-
-#undef class
-#undef private
-#undef public
-}
-
-#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
-
-// 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;
- CopyWindowProcPtr CopyWindow;
- ClearToBackgroundProcPtr ClearToBackground;
-#if XORG < 110
- RestoreAreasProcPtr RestoreAreas;
-#endif
- DisplayCursorProcPtr DisplayCursor;
- ScreenBlockHandlerProcPtr BlockHandler;
-#ifdef RENDER
- CompositeProcPtr Composite;
- GlyphsProcPtr Glyphs;
-#endif
-#ifdef RANDR
- RRSetConfigProcPtr RandRSetConfig;
- RRScreenSetSizeProcPtr RandRScreenSetSize;
- RRCrtcSetProcPtr RandRCrtcSet;
-#endif
-} vncHooksScreenRec, *vncHooksScreenPtr;
-
-typedef struct {
-#if XORG >= 116
- const GCFuncs *wrappedFuncs;
- const GCOps *wrappedOps;
-#else
- GCFuncs *wrappedFuncs;
- GCOps *wrappedOps;
-#endif
-} vncHooksGCRec, *vncHooksGCPtr;
-
-#if XORG == 15
-static DevPrivateKey vncHooksScreenPrivateKey = &vncHooksScreenPrivateKey;
-static DevPrivateKey vncHooksGCPrivateKey = &vncHooksGCPrivateKey;
-#elif XORG < 19
-static int vncHooksScreenPrivateKeyIndex;
-static int vncHooksGCPrivateKeyIndex;
-static DevPrivateKey vncHooksScreenPrivateKey = &vncHooksScreenPrivateKeyIndex;
-static DevPrivateKey vncHooksGCPrivateKey = &vncHooksGCPrivateKeyIndex;
-#else
-static DevPrivateKeyRec vncHooksScreenKeyRec;
-static DevPrivateKeyRec vncHooksGCKeyRec;
-#define vncHooksScreenPrivateKey (&vncHooksScreenKeyRec)
-#define vncHooksGCPrivateKey (&vncHooksGCKeyRec)
-#endif
-
-#define vncHooksScreenPrivate(pScreen) \
- (vncHooksScreenPtr) dixLookupPrivate(&(pScreen)->devPrivates, \
- vncHooksScreenPrivateKey)
-#define vncHooksGCPrivate(pGC) \
- (vncHooksGCPtr) dixLookupPrivate(&(pGC)->devPrivates, \
- vncHooksGCPrivateKey)
-
-// screen functions
-
-#if XORG <= 112
-static Bool vncHooksCloseScreen(int i, ScreenPtr pScreen);
-#else
-static Bool vncHooksCloseScreen(ScreenPtr pScreen);
-#endif
-static Bool vncHooksCreateGC(GCPtr pGC);
-static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
- RegionPtr pOldRegion);
-static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w,
- int h, Bool generateExposures);
-#if XORG < 110
-static RegionPtr vncHooksRestoreAreas(WindowPtr pWin, RegionPtr prgnExposed);
-#endif
-static Bool vncHooksDisplayCursor(
-#if XORG >= 16
- DeviceIntPtr pDev,
-#endif
- ScreenPtr pScreen, CursorPtr cursor);
-#if XORG <= 112
-static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout,
- pointer pReadmask);
-#else
-static void vncHooksBlockHandler(ScreenPtr pScreen, void * pTimeout,
- void * pReadmask);
-#endif
-#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);
-static void vncHooksGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
- PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlists,
- GlyphListPtr lists, GlyphPtr * glyphs);
-#endif
-#ifdef RANDR
-static Bool vncHooksRandRSetConfig(ScreenPtr pScreen, Rotation rotation,
- int rate, RRScreenSizePtr pSize);
-static Bool vncHooksRandRScreenSetSize(ScreenPtr pScreen,
- CARD16 width, CARD16 height,
- CARD32 mmWidth, CARD32 mmHeight);
-static Bool vncHooksRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc,
- RRModePtr mode, int x, int y,
- Rotation rotation, int numOutputs,
- RROutputPtr *outputs);
-#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, void * 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, void * pglyphBase);
-static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
- int y, unsigned int nglyph,
- CharInfoPtr *ppci, void * 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 XORG < 19
- if (!dixRequestPrivate(vncHooksScreenPrivateKey, sizeof(vncHooksScreenRec))) {
- ErrorF("vncHooksInit: Allocation of vncHooksScreen failed\n");
- return FALSE;
- }
- if (!dixRequestPrivate(vncHooksGCPrivateKey, sizeof(vncHooksGCRec))) {
- ErrorF("vncHooksInit: Allocation of vncHooksGCRec failed\n");
- return FALSE;
- }
-
-#else
- if (!dixRegisterPrivateKey(&vncHooksScreenKeyRec, PRIVATE_SCREEN,
- sizeof(vncHooksScreenRec))) {
- ErrorF("vncHooksInit: Allocation of vncHooksScreen failed\n");
- return FALSE;
- }
- if (!dixRegisterPrivateKey(&vncHooksGCKeyRec, PRIVATE_GC,
- sizeof(vncHooksGCRec))) {
- ErrorF("vncHooksInit: Allocation of vncHooksGCRec failed\n");
- return FALSE;
- }
-
-#endif
-
- vncHooksScreen = vncHooksScreenPrivate(pScreen);
-
- vncHooksScreen->desktop = desktop;
-
- vncHooksScreen->CloseScreen = pScreen->CloseScreen;
- vncHooksScreen->CreateGC = pScreen->CreateGC;
- vncHooksScreen->CopyWindow = pScreen->CopyWindow;
- vncHooksScreen->ClearToBackground = pScreen->ClearToBackground;
-#if XORG < 110
- vncHooksScreen->RestoreAreas = pScreen->RestoreAreas;
-#endif
- vncHooksScreen->DisplayCursor = pScreen->DisplayCursor;
- vncHooksScreen->BlockHandler = pScreen->BlockHandler;
-#ifdef RENDER
- PictureScreenPtr ps;
- ps = GetPictureScreenIfSet(pScreen);
- if (ps) {
- vncHooksScreen->Composite = ps->Composite;
- vncHooksScreen->Glyphs = ps->Glyphs;
- }
-#endif
-#ifdef RANDR
- rrScrPrivPtr rp;
- rp = rrGetScrPriv(pScreen);
- if (rp) {
- vncHooksScreen->RandRSetConfig = rp->rrSetConfig;
- vncHooksScreen->RandRScreenSetSize = rp->rrScreenSetSize;
- vncHooksScreen->RandRCrtcSet = rp->rrCrtcSet;
- }
-#endif
-
- pScreen->CloseScreen = vncHooksCloseScreen;
- pScreen->CreateGC = vncHooksCreateGC;
- pScreen->CopyWindow = vncHooksCopyWindow;
- pScreen->ClearToBackground = vncHooksClearToBackground;
-#if XORG < 110
- pScreen->RestoreAreas = vncHooksRestoreAreas;
-#endif
- pScreen->DisplayCursor = vncHooksDisplayCursor;
- pScreen->BlockHandler = vncHooksBlockHandler;
-#ifdef RENDER
- if (ps) {
- ps->Composite = vncHooksComposite;
- ps->Glyphs = vncHooksGlyphs;
- }
-#endif
-#ifdef RANDR
- if (rp) {
- /* Some RandR callbacks are optional */
- if (rp->rrSetConfig)
- rp->rrSetConfig = vncHooksRandRSetConfig;
- if (rp->rrScreenSetSize)
- rp->rrScreenSetSize = vncHooksRandRScreenSetSize;
- if (rp->rrCrtcSet)
- rp->rrCrtcSet = vncHooksRandRCrtcSet;
- }
-#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 = vncHooksScreenPrivate(pScreen); \
- 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
-
-#if XORG <= 112
-static Bool vncHooksCloseScreen(int i, ScreenPtr pScreen_)
-#else
-static Bool vncHooksCloseScreen(ScreenPtr pScreen_)
-#endif
-{
- SCREEN_UNWRAP(pScreen_, CloseScreen);
-
- pScreen->CreateGC = vncHooksScreen->CreateGC;
- pScreen->CopyWindow = vncHooksScreen->CopyWindow;
- pScreen->ClearToBackground = vncHooksScreen->ClearToBackground;
-#if XORG < 110
- pScreen->RestoreAreas = vncHooksScreen->RestoreAreas;
-#endif
- pScreen->DisplayCursor = vncHooksScreen->DisplayCursor;
- pScreen->BlockHandler = vncHooksScreen->BlockHandler;
-#ifdef RENDER
- PictureScreenPtr ps;
- ps = GetPictureScreenIfSet(pScreen);
- if (ps) {
- ps->Composite = vncHooksScreen->Composite;
- ps->Glyphs = vncHooksScreen->Glyphs;
- }
-#endif
-#ifdef RANDR
- rrScrPrivPtr rp;
- rp = rrGetScrPriv(pScreen);
- if (rp) {
- rp->rrSetConfig = vncHooksScreen->RandRSetConfig;
- rp->rrScreenSetSize = vncHooksScreen->RandRScreenSetSize;
- rp->rrCrtcSet = vncHooksScreen->RandRCrtcSet;
- }
-#endif
-
- DBGPRINT((stderr,"vncHooksCloseScreen: unwrapped screen functions\n"));
-
-#if XORG <= 112
- return (*pScreen->CloseScreen)(i, pScreen);
-#else
- return (*pScreen->CloseScreen)(pScreen);
-#endif
-}
-
-// CreateGC - wrap the "GC funcs"
-
-static Bool vncHooksCreateGC(GCPtr pGC)
-{
- SCREEN_UNWRAP(pGC->pScreen, CreateGC);
-
- vncHooksGCPtr vncHooksGC = vncHooksGCPrivate(pGC);
-
- Bool ret = (*pScreen->CreateGC) (pGC);
-
- vncHooksGC->wrappedOps = 0;
- vncHooksGC->wrappedFuncs = pGC->funcs;
- pGC->funcs = &vncHooksGCFuncs;
-
- SCREEN_REWRAP(CreateGC);
-
- return ret;
-}
-
-// 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);
-
- int dx, dy;
- RegionHelper copied(pScreen, pOldRegion);
-
- BoxRec screen_box = {0, 0, pScreen->width, pScreen->height};
- RegionHelper screen_rgn(pScreen, &screen_box, 1);
-
- dx = pWin->drawable.x - ptOldOrg.x;
- dy = pWin->drawable.y - ptOldOrg.y;
-
- // RFB tracks copies in terms of destination rectangle, not source.
- // We also need to copy with changes to the Window's clipping region.
- // Finally, make sure we don't get copies to or from regions outside
- // the framebuffer.
- REGION_INTERSECT(pScreen, copied.reg, copied.reg, screen_rgn.reg);
- REGION_TRANSLATE(pScreen, copied.reg, dx, dy);
- REGION_INTERSECT(pScreen, copied.reg, copied.reg, screen_rgn.reg);
- REGION_INTERSECT(pScreen, copied.reg, copied.reg, &pWin->borderClip);
-
- (*pScreen->CopyWindow) (pWin, ptOldOrg, pOldRegion);
-
- if (REGION_NOTEMPTY(pScreen, copied.reg))
- 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);
-}
-
-#if XORG < 110
-// 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;
-}
-#endif
-
-// DisplayCursor - get the cursor shape
-
-static Bool vncHooksDisplayCursor(
-#if XORG >= 16
- DeviceIntPtr pDev,
-#endif
- ScreenPtr pScreen_, CursorPtr cursor)
-{
- SCREEN_UNWRAP(pScreen_, DisplayCursor);
-
- Bool ret = (*pScreen->DisplayCursor) (
-#if XORG >= 16
- pDev,
-#endif
- pScreen, cursor);
-#if XORG >= 16
- /*
- * XXX DIX calls this function with NULL argument to remove cursor sprite from
- * screen. Should we handle this in setCursor as well?
- */
- if (cursor != NullCursor) {
-#endif
- vncHooksScreen->desktop->setCursor(cursor);
-#if XORG >= 16
- }
-#endif
-
- SCREEN_REWRAP(DisplayCursor);
-
- return ret;
-}
-
-// BlockHandler - ignore any changes during the block handler - it's likely
-// these are just drawing the cursor.
-
-#if XORG <= 112
-static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout,
- pointer pReadmask)
-#else
-static void vncHooksBlockHandler(ScreenPtr pScreen_, void * pTimeout,
- void * pReadmask)
-#endif
-{
-#if XORG <= 112
- SCREEN_UNWRAP(screenInfo.screens[i], BlockHandler);
-#else
- SCREEN_UNWRAP(pScreen_, BlockHandler);
-#endif
-
- vncHooksScreen->desktop->ignoreHooks(true);
-
-#if XORG <= 112
- (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
-#else
- (*pScreen->BlockHandler) (pScreen, pTimeout, pReadmask);
-#endif
-
- vncHooksScreen->desktop->ignoreHooks(false);
-
- SCREEN_REWRAP(BlockHandler);
-}
-
-#ifdef RENDER
-
-// Composite - The core of XRENDER
-
-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 = vncHooksScreenPrivate(pScreen);
- PictureScreenPtr ps = GetPictureScreen(pScreen);
-
- RegionHelper changed(pScreen);
-
- if (pDst->pDrawable->type == DRAWABLE_WINDOW &&
- ((WindowPtr) pDst->pDrawable)->viewable) {
- BoxRec box;
- rfb::Rect rect1, rect2;
-
- rect1.setXYWH(pDst->pDrawable->x + xDst,
- pDst->pDrawable->y + yDst,
- width,
- height);
-
- rect2 = rect1.intersect(vncHooksScreen->desktop->getRect());
-
- box.x1 = rect2.tl.x;
- box.y1 = rect2.tl.y;
- box.x2 = rect2.br.x;
- box.y2 = rect2.br.y;
-
- changed.init(&box, 0);
- } else {
- changed.init(NullBox, 0);
- }
-
-
- ps->Composite = vncHooksScreen->Composite;
- (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc,
- xMask, yMask, xDst, yDst, width, height);
- ps->Composite = vncHooksComposite;
-
- if (REGION_NOTEMPTY(pScreen, changed.reg))
- vncHooksScreen->desktop->add_changed(changed.reg);
-}
-
-static int
-GlyphCount(int nlist, GlyphListPtr list, GlyphPtr * glyphs)
-{
- int count;
-
- count = 0;
- while (nlist--) {
- count += list->len;
- list++;
- }
-
- return count;
-}
-
-static RegionPtr
-GlyphsToRegion(ScreenPtr pScreen, int nlist, GlyphListPtr list, GlyphPtr *glyphs)
-{
- int n;
- GlyphPtr glyph;
- int x, y;
-
- int nrects = GlyphCount(nlist, list, glyphs);
- xRectangle rects[nrects];
- xRectanglePtr rect;
-
- x = 0;
- y = 0;
- rect = &rects[0];
- while (nlist--) {
- x += list->xOff;
- y += list->yOff;
- n = list->len;
- list++;
- while (n--) {
- glyph = *glyphs++;
- rect->x = x - glyph->info.x;
- rect->y = y - glyph->info.y;
- rect->width = glyph->info.width;
- rect->height = glyph->info.height;
- x += glyph->info.xOff;
- y += glyph->info.yOff;
- rect++;
- }
- }
-
- return RECTS_TO_REGION(pScreen, nrects, rects, CT_NONE);
-}
-
-// Glyphs - Glyph specific version of Composite (caches and whatnot)
-
-void vncHooksGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
- PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlists,
- GlyphListPtr lists, GlyphPtr * glyphs)
-{
- ScreenPtr pScreen = pDst->pDrawable->pScreen;
- vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
- PictureScreenPtr ps = GetPictureScreen(pScreen);
-
- RegionHelper changed(pScreen);
-
- if (pDst->pDrawable->type == DRAWABLE_WINDOW &&
- ((WindowPtr) pDst->pDrawable)->viewable) {
- rfb::Rect fbrect;
- BoxRec fbbox;
- RegionRec fbreg;
-
- changed.reg = GlyphsToRegion(pScreen, nlists, lists, glyphs);
- REGION_TRANSLATE(pScreen, changed.reg,
- pDst->pDrawable->x, pDst->pDrawable->y);
-
- fbrect = vncHooksScreen->desktop->getRect();
- fbbox.x1 = fbrect.tl.x;
- fbbox.y1 = fbrect.tl.y;
- fbbox.x2 = fbrect.br.x;
- fbbox.y2 = fbrect.br.y;
- REGION_INIT(pScreen, &fbreg, &fbbox, 0);
-
- REGION_INTERSECT(pScreen, changed.reg, changed.reg, &fbreg);
-
- REGION_UNINIT(pScreen, &fbreg);
- } else {
- changed.init(NullBox, 0);
- }
-
- ps->Glyphs = vncHooksScreen->Glyphs;
- (*ps->Glyphs)(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlists, lists, glyphs);
- ps->Glyphs = vncHooksGlyphs;
-
- if (REGION_NOTEMPTY(pScreen, changed.reg))
- vncHooksScreen->desktop->add_changed(changed.reg);
-}
-
-#endif /* RENDER */
-
-// RandRSetConfig - follow any framebuffer changes
-
-#ifdef RANDR
-
-static void vncPreScreenResize(ScreenPtr pScreen)
-{
- vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
-
- // We need to prevent the RFB core from accessing the framebuffer
- // for a while as there might be updates thrown our way inside
- // the routines that change the screen (i.e. before we have a
- // pointer to the new framebuffer).
- vncHooksScreen->desktop->blockUpdates();
-}
-
-static void vncPostScreenResize(ScreenPtr pScreen, Bool success)
-{
- vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
-
- RegionRec reg;
- BoxRec box;
-
- if (success) {
- // Let the RFB core know of the new dimensions and framebuffer
- vncHooksScreen->desktop->setFramebuffer(pScreen->width, pScreen->height,
- vncFbptr[pScreen->myNum],
- vncFbstride[pScreen->myNum]);
- }
-
- vncHooksScreen->desktop->unblockUpdates();
-
- if (success) {
- // Mark entire screen as changed
- box.x1 = 0;
- box.y1 = 0;
- box.x2 = pScreen->width;
- box.y2 = pScreen->height;
- REGION_INIT(pScreen, ®, &box, 1);
-
- vncHooksScreen->desktop->add_changed(®);
- }
-}
-
-static Bool vncHooksRandRSetConfig(ScreenPtr pScreen, Rotation rotation,
- int rate, RRScreenSizePtr pSize)
-{
- vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
- rrScrPrivPtr rp = rrGetScrPriv(pScreen);
- Bool ret;
-
- vncPreScreenResize(pScreen);
-
- rp->rrSetConfig = vncHooksScreen->RandRSetConfig;
- ret = (*rp->rrSetConfig)(pScreen, rotation, rate, pSize);
- rp->rrSetConfig = vncHooksRandRSetConfig;
-
- vncPostScreenResize(pScreen, ret);
-
- if (!ret)
- return FALSE;
-
- return TRUE;
-}
-
-static Bool vncHooksRandRScreenSetSize(ScreenPtr pScreen,
- CARD16 width, CARD16 height,
- CARD32 mmWidth, CARD32 mmHeight)
-{
- vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
- rrScrPrivPtr rp = rrGetScrPriv(pScreen);
- Bool ret;
-
- vncPreScreenResize(pScreen);
-
- rp->rrScreenSetSize = vncHooksScreen->RandRScreenSetSize;
- ret = (*rp->rrScreenSetSize)(pScreen, width, height, mmWidth, mmHeight);
- rp->rrScreenSetSize = vncHooksRandRScreenSetSize;
-
- vncPostScreenResize(pScreen, ret);
-
- if (!ret)
- return FALSE;
-
- return TRUE;
-}
-
-static Bool vncHooksRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc,
- RRModePtr mode, int x, int y,
- Rotation rotation, int num_outputs,
- RROutputPtr *outputs)
-{
- vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
- rrScrPrivPtr rp = rrGetScrPriv(pScreen);
- Bool ret;
-
- rp->rrCrtcSet = vncHooksScreen->RandRCrtcSet;
- ret = (*rp->rrCrtcSet)(pScreen, crtc, mode, x, y, rotation,
- num_outputs, outputs);
- rp->rrCrtcSet = vncHooksRandRCrtcSet;
-
- if (!ret)
- return FALSE;
-
- vncHooksScreen->desktop->refreshScreenLayout();
-
- return TRUE;
-}
-
-#endif /* RANDR */
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// 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 = vncHooksGCPrivate(pGC);
- 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 OR the screen pixmap
-
-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) ||
- (pDrawable == &pGC->pScreen->GetScreenPixmap(pGC->pScreen)->drawable)) {
- 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, void * 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 = vncHooksGCPrivate(pGC);
- 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;
-#if XORG >= 116
- const GCFuncs* oldFuncs;
-#else
- GCFuncs* oldFuncs;
-#endif
- ScreenPtr pScreen;
-};
-
-#define GC_OP_UNWRAPPER(pDrawable, pGC, name) \
- GCOpUnwrapper u(pDrawable, pGC); \
- ScreenPtr pScreen = (pDrawable)->pScreen; \
- vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen); \
- DBGPRINT((stderr,"vncHooks" #name " called\n"));
-
-
-// FillSpans - assume the entire clip region is damaged. 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, pGC->pCompositeClip);
-
- if (pDrawable->type == DRAWABLE_WINDOW)
- REGION_INTERSECT(pScreen, changed.reg, changed.reg,
- &((WindowPtr)pDrawable)->borderClip);
-
- (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted);
-
- vncHooksScreen->desktop->add_changed(changed.reg);
-}
-
-// SetSpans - assume the entire clip region is damaged. 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, pGC->pCompositeClip);
-
- if (pDrawable->type == DRAWABLE_WINDOW)
- REGION_INTERSECT(pScreen, changed.reg, changed.reg,
- &((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, pGC->pCompositeClip);
-
- (*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, pGC->pCompositeClip);
-
- RegionHelper src(pScreen);
-
- // The source of the data has to be something that's on screen.
- // This means either a window, or the screen pixmap.
- if ((pSrc->pScreen == pScreen) &&
- ((pSrc->type == DRAWABLE_WINDOW) ||
- (pSrc == &pScreen->GetScreenPixmap(pScreen)->drawable))) {
- box.x1 = srcx + pSrc->x;
- box.y1 = srcy + pSrc->y;
- box.x2 = box.x1 + w;
- box.y2 = box.y1 + h;
-
- src.init(&box, 0);
-
- if ((pSrc->type == DRAWABLE_WINDOW) &&
- REGION_NOTEMPTY(pScreen, &((WindowPtr)pSrc)->clipList)) {
- 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, pGC->pCompositeClip);
-
- 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, pGC->pCompositeClip);
-
- (*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, pGC->pCompositeClip);
-
- (*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, pGC->pCompositeClip);
-
- (*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, pGC->pCompositeClip);
-
- (*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, pGC->pCompositeClip);
-
- (*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, pGC->pCompositeClip);
-
- (*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, pGC->pCompositeClip);
-
- (*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, pGC->pCompositeClip);
-
- (*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, pGC->pCompositeClip);
-
- 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, pGC->pCompositeClip);
-
- 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, pGC->pCompositeClip);
-
- (*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, pGC->pCompositeClip);
-
- (*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, void * 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, pGC->pCompositeClip);
-
- (*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, void * 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, pGC->pCompositeClip);
-
- (*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, pGC->pCompositeClip);
-
- (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y);
-
- vncHooksScreen->desktop->add_changed(changed.reg);
-}
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2009-2015 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#ifndef __VNCHOOKS_H__
#define __VNCHOOKS_H__
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
+#ifdef __cplusplus
+extern "C" {
#endif
-extern "C" {
-#include <screenint.h>
- extern Bool vncHooksInit(ScreenPtr pScreen, XserverDesktop* desktop);
+int vncHooksInit(int scrIdx);
+
+void vncGetScreenImage(int scrIdx, int x, int y, int width, int height,
+ char *buffer, int strideBytes);
+
+#ifdef __cplusplus
}
+#endif
#endif
--- /dev/null
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2015 Pierre Ossman for Cendio AB
+ *
+ * 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "opaque.h"
+#ifdef RANDR
+#include "randrstr.h"
+#endif
+
+#include "xorg-version.h"
+
+#include "xf86.h"
+#include "xf86Module.h"
+
+#include "vncExtInit.h"
+#include "RFBGlue.h"
+
+static void vncModuleInit(INITARGS);
+
+static MODULESETUPPROTO(vncSetup);
+
+ExtensionModule vncExt =
+{
+ vncModuleInit,
+ "VNC",
+#if XORG < 112
+ NULL,
+ NULL,
+#endif
+ NULL
+};
+
+static XF86ModuleVersionInfo vncVersRec =
+{
+ "vnc",
+ "Constantin Kaplinsky",
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XORG_VERSION_CURRENT,
+ 1, 0, 0,
+ ABI_CLASS_EXTENSION, /* needs the server extension ABI */
+ ABI_EXTENSION_VERSION,
+ MOD_CLASS_EXTENSION,
+ {0,0,0,0}
+};
+
+_X_EXPORT XF86ModuleData vncModuleData = { &vncVersRec, vncSetup, NULL };
+
+static void *
+vncSetup(void * module, void * opts, int *errmaj, int *errmin) {
+#if XORG >= 116
+ LoadExtensionList(&vncExt, 1, FALSE);
+#else
+ LoadExtension(&vncExt, FALSE);
+#endif
+ /* Need a non-NULL return value to indicate success */
+ return (void *)1;
+}
+
+static void vncModuleInit(INITARGS)
+{
+ static char once = 0;
+
+ if (!once) {
+ once++;
+
+ vncInitRFB();
+
+ for (int scr = 0; scr < screenInfo.numScreens; scr++) {
+ ScrnInfoPtr pScrn;
+ XF86OptionPtr option;
+
+ pScrn = xf86Screens[scr];
+ option = pScrn->options;
+ while (option != NULL) {
+ vncSetParam(xf86OptionName(option), xf86OptionValue(option));
+ option = xf86NextOption(option);
+ }
+ }
+ }
+
+ vncExtensionInit();
+}
+
+#ifdef RANDR
+RRModePtr vncRandRModeGet(int width, int height)
+{
+ return NULL;
+}
+
+int vncRandRCreateOutputs(int scrIdx, int extraOutputs)
+{
+ return -1;
+}
+#endif
+++ /dev/null
-/* 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.
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <rfb/Configuration.h>
-#include <rfb/Logger_stdio.h>
-#include <rfb/LogWriter.h>
-#include <rfb/ScreenSet.h>
-#include <rfb/screenTypes.h>
-
-#include "xorg-version.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"
-#ifdef RANDR
-#include "randrstr.h"
-#endif /* RANDR */
-#undef class
-#undef private
-#undef bool
-#undef new
-
-using namespace rfb;
-
-extern void vncExtensionInit();
-static void vncExtensionInitWithParams(INITARGS);
-
-char *listenaddr = NULL;
-
-static MODULESETUPPROTO(vncSetup);
-
-ExtensionModule vncExt =
-{
- vncExtensionInitWithParams,
- "VNC",
-#if XORG < 112
- NULL,
- NULL,
-#endif
- NULL
-};
-
-static XF86ModuleVersionInfo vncVersRec =
-{
- "vnc",
- "Constantin Kaplinsky",
- MODINFOSTRING1,
- MODINFOSTRING2,
- XORG_VERSION_CURRENT,
- 1, 0, 0,
- ABI_CLASS_EXTENSION, /* needs the server extension ABI */
- ABI_EXTENSION_VERSION,
- MOD_CLASS_EXTENSION,
- {0,0,0,0}
-};
-
-_X_EXPORT XF86ModuleData vncModuleData = { &vncVersRec, vncSetup, NULL };
-
-static void *
-vncSetup(void * module, void * opts, int *errmaj, int *errmin) {
-#if XORG >= 116
- LoadExtensionList(&vncExt, 1, FALSE);
-#else
- LoadExtension(&vncExt, FALSE);
-#endif
- /* Need a non-NULL return value to indicate success */
- return (void *)1;
-}
-
-static void vncExtensionInitWithParams(INITARGS)
-{
- static char once = 0;
-
- if (!once) {
- once++;
- rfb::initStdIOLoggers();
- rfb::LogWriter::setLogParams("*:stderr:30");
- rfb::Configuration::enableServerParams();
-
- for (int scr = 0; scr < screenInfo.numScreens; scr++) {
- ScrnInfoPtr pScrn = xf86Screens[scr];
-
- for (ParameterIterator i; i.param; i.next()) {
- const char *val;
-#if XORG < 112
- val = xf86FindOptionValue(pScrn->options, i.param->getName());
-#else
- val = xf86FindOptionValue((XF86OptionPtr)pScrn->options, i.param->getName());
-#endif
- if (val)
- i.param->setParam(val);
- }
- }
- }
-
- vncExtensionInit();
-}
-}
-
-RRModePtr vncRandRModeGet(int width, int height)
-{
- return NULL;
-}
-
-RROutputPtr vncRandROutputCreate(ScreenPtr pScreen)
-{
- return NULL;
-}
--- /dev/null
+/* Copyright (c) 1993 X Consortium
+ Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ Copyright 2009-2015 Pierre Ossman for Cendio AB
+
+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.
+
+*/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "vncExtInit.h"
+#include "RFBGlue.h"
+#include "xorg-version.h"
+
+#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"
+#if XORG < 114
+#include "mibstore.h"
+#endif
+#include "colormapst.h"
+#include "gcstruct.h"
+#include "input.h"
+#include "mipointer.h"
+#include "micmap.h"
+#include <sys/types.h>
+#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"
+#ifdef RANDR
+#include "randrstr.h"
+#endif /* RANDR */
+#include <X11/keysym.h>
+ extern char buildtime[];
+#if XORG >= 17
+#undef VENDOR_RELEASE
+#undef VENDOR_STRING
+#include "version-config.h"
+#endif
+#include "site.h"
+
+#if XORG >= 110
+#define Xalloc malloc
+#define Xfree free
+#endif
+
+#define XVNCVERSION "TigerVNC 1.4.80"
+#define XVNCCOPYRIGHT ("Copyright (C) 1999-2013 TigerVNC Team and many others (see README.txt)\n" \
+ "See http://www.tigervnc.org for information on TigerVNC.\n")
+
+
+extern int monitorResolution;
+
+#define VFB_DEFAULT_WIDTH 1024
+#define VFB_DEFAULT_HEIGHT 768
+#define VFB_DEFAULT_DEPTH 24
+#define VFB_DEFAULT_WHITEPIXEL 0xffffffff
+#define VFB_DEFAULT_BLACKPIXEL 0
+#define VFB_DEFAULT_LINEBIAS 0
+#define XWD_WINDOW_NAME_LEN 60
+
+typedef struct
+{
+ int width;
+ int height;
+
+ int depth;
+
+ /* Computed when allocated */
+
+ int paddedBytesWidth;
+ int paddedWidth;
+
+ int bitsPerPixel;
+
+ /* Private */
+
+ int sizeInBytes;
+
+ void *pfbMemory;
+
+#ifdef HAS_SHM
+ int shmid;
+#endif
+} vfbFramebufferInfo, *vfbFramebufferInfoPtr;
+
+typedef struct
+{
+ int scrnum;
+
+ Pixel blackPixel;
+ Pixel whitePixel;
+
+ unsigned int lineBias;
+
+ CloseScreenProcPtr closeScreen;
+
+ vfbFramebufferInfo fb;
+
+ Bool pixelFormatDefined;
+ Bool rgbNotBgr;
+ int redBits, greenBits, blueBits;
+} vfbScreenInfo, *vfbScreenInfoPtr;
+
+static int vfbNumScreens;
+static vfbScreenInfo vfbScreens[MAXSCREENS];
+static Bool vfbPixmapDepths[33];
+typedef enum { NORMAL_MEMORY_FB, SHARED_MEMORY_FB } fbMemType;
+static fbMemType fbmemtype = NORMAL_MEMORY_FB;
+static int lastScreen = -1;
+static Bool Render = TRUE;
+
+static Bool displaySpecified = FALSE;
+static char displayNumStr[16];
+
+static int vncVerbose = DEFAULT_LOG_VERBOSITY;
+
+
+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].blackPixel = VFB_DEFAULT_BLACKPIXEL;
+ vfbScreens[i].whitePixel = VFB_DEFAULT_WHITEPIXEL;
+ vfbScreens[i].lineBias = VFB_DEFAULT_LINEBIAS;
+ vfbScreens[i].fb.width = VFB_DEFAULT_WIDTH;
+ vfbScreens[i].fb.height = VFB_DEFAULT_HEIGHT;
+ vfbScreens[i].fb.pfbMemory = NULL;
+ vfbScreens[i].fb.depth = VFB_DEFAULT_DEPTH;
+ vfbScreens[i].pixelFormatDefined = FALSE;
+ }
+ 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;
+}
+
+static void vfbFreeFramebufferMemory(vfbFramebufferInfoPtr pfb);
+
+#ifdef DPMSExtension
+ /* Why support DPMS? Because stupid modern desktop environments
+ such as Unity 2D on Ubuntu 11.10 crashes if DPMS is not
+ available. (DPMSSet is called by dpms.c, but the return value
+ is ignored.) */
+int DPMSSet(ClientPtr client, int level)
+{
+ return Success;
+}
+
+Bool DPMSSupported()
+{
+ /* Causes DPMSCapable to return false, meaning no devices are DPMS
+ capable */
+ return FALSE;
+}
+#endif
+
+#if XORG < 111
+void ddxGiveUp()
+#else
+void ddxGiveUp(enum ExitCode error)
+#endif
+{
+ int i;
+
+ /* clean up the framebuffers */
+ for (i = 0; i < vfbNumScreens; i++)
+ vfbFreeFramebufferMemory(&vfbScreens[i].fb);
+}
+
+void
+#if XORG < 111
+AbortDDX()
+#else
+AbortDDX(enum ExitCode error)
+#endif
+{
+#if XORG < 111
+ ddxGiveUp();
+#else
+ ddxGiveUp(error);
+#endif
+}
+
+#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
+#if XORG < 113
+OsVendorFatalError()
+#else
+OsVendorFatalError(const char *f, va_list args)
+#endif
+{
+}
+
+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_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("-noclipboard disable clipboard settings modification via vncconfig utility\n");
+ ErrorF("-verbose [n] verbose startup messages\n");
+ ErrorF("-quiet minimal startup messages\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");
+ vncListParams(79, 14);
+}
+
+/* ddxInitGlobals - called by |InitGlobals| from os/util.c */
+void ddxInitGlobals(void)
+{
+}
+
+static
+Bool displayNumFree(int num)
+{
+ char file[256];
+ if (vncIsTCPPortUsed(6000+num))
+ return FALSE;
+ 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;
+ vncInitRFB();
+ }
+
+ 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].fb.width,
+ &vfbScreens[screenNum].fb.height,
+ &vfbScreens[screenNum].fb.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_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].fb.width,
+ &vfbScreens[0].fb.height) != 2) {
+ ErrorF("Invalid geometry %s\n", argv[i]);
+ UseMsg();
+ }
+ return 2;
+ }
+
+ if (strcmp(argv[i], "-depth") == 0)
+ {
+ if (++i >= argc) UseMsg();
+ vfbScreens[0].fb.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).fb.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 = vncGetSocketPort(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 (strcmp(argv[i], "-noclipboard") == 0) {
+ vncNoClipboard = 1;
+ return 1;
+ }
+
+ if (!strcmp(argv[i], "-verbose")) {
+ if (++i < argc && argv[i]) {
+ char *end;
+ long val;
+
+ val = strtol(argv[i], &end, 0);
+ if (*end == '\0') {
+ vncVerbose = val;
+ LogSetParameter(XLOG_VERBOSITY, vncVerbose);
+ return 2;
+ }
+ }
+ vncVerbose++;
+ LogSetParameter(XLOG_VERBOSITY, vncVerbose);
+ return 1;
+ }
+
+ if (!strcmp(argv[i], "-quiet")) {
+ vncVerbose = -1;
+ LogSetParameter(XLOG_VERBOSITY, vncVerbose);
+ return 1;
+ }
+
+ if (vncSetParamSimple(argv[i]))
+ return 1;
+
+ if (argv[i][0] == '-' && i+1 < argc) {
+ if (vncSetParam(&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
+
+#if XORG < 113
+static ColormapPtr InstalledMaps[MAXSCREENS];
+#else
+static DevPrivateKeyRec cmapScrPrivateKeyRec;
+#define cmapScrPrivateKey (&cmapScrPrivateKeyRec)
+#define GetInstalledColormap(s) ((ColormapPtr) dixLookupPrivate(&(s)->devPrivates, cmapScrPrivateKey))
+#define SetInstalledColormap(s,c) (dixSetPrivate(&(s)->devPrivates, cmapScrPrivateKey, c))
+#endif
+
+static int
+vfbListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps)
+{
+ /* By the time we are processing requests, we can guarantee that there
+ * is always a colormap installed */
+#if XORG < 113
+ *pmaps = InstalledMaps[pScreen->myNum]->mid;
+#else
+ *pmaps = GetInstalledColormap(pScreen)->mid;
+#endif
+ return (1);
+}
+
+
+static void
+vfbInstallColormap(ColormapPtr pmap)
+{
+#if XORG < 113
+ int index = pmap->pScreen->myNum;
+#endif
+ ColormapPtr oldpmap;
+
+#if XORG < 113
+ oldpmap = InstalledMaps[index];
+#else
+ oldpmap = GetInstalledColormap(pmap->pScreen);
+#endif
+
+ if (pmap != oldpmap)
+ {
+ int entries;
+ VisualPtr pVisual;
+ Pixel * ppix;
+ xrgb * prgb;
+ xColorItem *defs;
+ int i;
+
+ if(oldpmap != (ColormapPtr)None)
+ WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid);
+ /* Install pmap */
+#if XORG < 113
+ InstalledMaps[index] = pmap;
+#else
+ SetInstalledColormap(pmap->pScreen, pmap);
+#endif
+ WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid);
+
+ entries = pmap->pVisual->ColormapEntries;
+ pVisual = pmap->pVisual;
+
+ ppix = (Pixel *)xalloc(entries * sizeof(Pixel));
+ prgb = (xrgb *)xalloc(entries * sizeof(xrgb));
+ defs = (xColorItem *)xalloc(entries * sizeof(xColorItem));
+
+ for (i = 0; i < entries; i++) ppix[i] = i;
+ /* XXX truecolor */
+#if XORG < 19
+ QueryColors(pmap, entries, ppix, prgb);
+#else
+ QueryColors(pmap, entries, ppix, prgb, serverClient);
+#endif
+
+ 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);
+
+ xfree(ppix);
+ xfree(prgb);
+ xfree(defs);
+ }
+}
+
+static void
+vfbUninstallColormap(ColormapPtr pmap)
+{
+#if XORG < 113
+ ColormapPtr curpmap = InstalledMaps[pmap->pScreen->myNum];
+#else
+ ColormapPtr curpmap = GetInstalledColormap(pmap->pScreen);
+#endif
+
+ if(pmap == curpmap)
+ {
+ if (pmap->mid != pmap->pScreen->defColormap)
+ {
+#if XORG < 111
+ curpmap = (ColormapPtr) LookupIDByType(pmap->pScreen->defColormap,
+ RT_COLORMAP);
+#else
+ dixLookupResourceByType((void * *) &curpmap, pmap->pScreen->defColormap,
+ RT_COLORMAP, serverClient, DixUnknownAccess);
+#endif
+ (*pmap->pScreen->InstallColormap)(curpmap);
+ }
+ }
+}
+
+static Bool
+vfbSaveScreen(ScreenPtr pScreen, int on)
+{
+ return TRUE;
+}
+
+#ifdef HAS_SHM
+static void
+vfbAllocateSharedMemoryFramebuffer(vfbFramebufferInfoPtr pfb)
+{
+ /* create the shared memory segment */
+
+ pfb->shmid = shmget(IPC_PRIVATE, pfb->sizeInBytes, IPC_CREAT|0777);
+ if (pfb->shmid < 0) {
+ perror("shmget");
+ ErrorF("shmget %d bytes failed, errno %d", pfb->sizeInBytes, errno);
+ return;
+ }
+
+ /* try to attach it */
+
+ pfb->pfbMemory = shmat(pfb->shmid, 0, 0);
+ if (-1 == (long)pfb->pfbMemory) {
+ perror("shmat");
+ ErrorF("shmat failed, errno %d", errno);
+ pfb->pfbMemory = NULL;
+ return;
+ }
+}
+#endif /* HAS_SHM */
+
+
+static void *
+vfbAllocateFramebufferMemory(vfbFramebufferInfoPtr pfb)
+{
+ if (pfb->pfbMemory != NULL)
+ return pfb->pfbMemory; /* already done */
+
+ /* Compute memory layout */
+ pfb->paddedBytesWidth = PixmapBytePad(pfb->width, pfb->depth);
+ pfb->bitsPerPixel = vfbBitsPerPixel(pfb->depth);
+ pfb->paddedWidth = pfb->paddedBytesWidth * 8 / pfb->bitsPerPixel;
+ pfb->sizeInBytes = pfb->paddedBytesWidth * pfb->height;
+
+ /* And allocate buffer */
+ switch (fbmemtype) {
+#ifdef HAS_SHM
+ case SHARED_MEMORY_FB:
+ vfbAllocateSharedMemoryFramebuffer(pfb);
+ break;
+#else
+ case SHARED_MEMORY_FB:
+ break;
+#endif
+ case NORMAL_MEMORY_FB:
+ pfb->pfbMemory = Xalloc(pfb->sizeInBytes);
+ break;
+ }
+
+ /* This will be NULL if any of the above failed */
+ return pfb->pfbMemory;
+}
+
+static void
+vfbFreeFramebufferMemory(vfbFramebufferInfoPtr pfb)
+{
+ if ((pfb == NULL) || (pfb->pfbMemory == NULL))
+ return;
+
+ switch (fbmemtype) {
+#ifdef HAS_SHM
+ case SHARED_MEMORY_FB:
+ if (-1 == shmdt(pfb->pfbMemory)) {
+ perror("shmdt");
+ ErrorF("shmdt failed, errno %d", errno);
+ }
+ break;
+#else /* HAS_SHM */
+ case SHARED_MEMORY_FB:
+ break;
+#endif /* HAS_SHM */
+ case NORMAL_MEMORY_FB:
+ Xfree(pfb->pfbMemory);
+ break;
+ }
+
+ pfb->pfbMemory = NULL;
+}
+
+static Bool
+vfbCursorOffScreen (ScreenPtr *ppScreen, int *x, int *y)
+{
+ return FALSE;
+}
+
+static void
+vfbCrossScreen (ScreenPtr pScreen, Bool entering)
+{
+}
+
+static Bool vfbRealizeCursor(
+#if XORG >= 16
+ DeviceIntPtr pDev,
+#endif
+ ScreenPtr pScreen, CursorPtr pCursor) {
+ return TRUE;
+}
+
+static Bool vfbUnrealizeCursor(
+#if XORG >= 16
+ DeviceIntPtr pDev,
+#endif
+ ScreenPtr pScreen, CursorPtr pCursor) {
+ return TRUE;
+}
+
+static void vfbSetCursor(
+#if XORG >= 16
+ DeviceIntPtr pDev,
+#endif
+ ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
+{
+}
+
+static void vfbMoveCursor(
+#if XORG >= 16
+ DeviceIntPtr pDev,
+#endif
+ ScreenPtr pScreen, int x, int y)
+{
+}
+
+#if XORG >= 16
+static Bool
+vfbDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen)
+{
+ return TRUE;
+}
+
+static void
+vfbDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen)
+{
+}
+#endif
+
+static miPointerSpriteFuncRec vfbPointerSpriteFuncs = {
+ vfbRealizeCursor,
+ vfbUnrealizeCursor,
+ vfbSetCursor,
+ vfbMoveCursor
+#if XORG >= 16
+ , vfbDeviceCursorInitialize,
+ vfbDeviceCursorCleanup
+#endif
+};
+
+static miPointerScreenFuncRec vfbPointerCursorFuncs = {
+ vfbCursorOffScreen,
+ vfbCrossScreen,
+ miPointerWarpCursor
+};
+
+#ifdef RANDR
+
+static Bool vncRandRGetInfo (ScreenPtr pScreen, Rotation *rotations)
+{
+ // We update all information right away, so there is nothing to
+ // do here.
+ return TRUE;
+}
+
+/* from hw/xfree86/common/xf86Helper.c */
+
+#include "mivalidate.h"
+static void
+xf86SetRootClip (ScreenPtr pScreen, Bool enable)
+{
+#if XORG < 19
+ WindowPtr pWin = WindowTable[pScreen->myNum];
+#else
+ WindowPtr pWin = pScreen->root;
+#endif
+ WindowPtr pChild;
+ Bool WasViewable = (Bool)(pWin->viewable);
+ Bool anyMarked = FALSE;
+#if XORG < 110
+ RegionPtr pOldClip = NULL, bsExposed;
+#ifdef DO_SAVE_UNDERS
+ Bool dosave = FALSE;
+#endif
+#endif
+ WindowPtr pLayerWin;
+ BoxRec box;
+
+ if (WasViewable)
+ {
+ for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib)
+ {
+ (void) (*pScreen->MarkOverlappedWindows)(pChild,
+ pChild,
+ &pLayerWin);
+ }
+ (*pScreen->MarkWindow) (pWin);
+ anyMarked = TRUE;
+ if (pWin->valdata)
+ {
+ if (HasBorder (pWin))
+ {
+ RegionPtr borderVisible;
+
+ borderVisible = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_SUBTRACT(pScreen, borderVisible,
+ &pWin->borderClip, &pWin->winSize);
+ pWin->valdata->before.borderVisible = borderVisible;
+ }
+ pWin->valdata->before.resized = TRUE;
+ }
+ }
+
+ /*
+ * Use REGION_BREAK to avoid optimizations in ValidateTree
+ * that assume the root borderClip can't change well, normally
+ * it doesn't...)
+ */
+ if (enable)
+ {
+ box.x1 = 0;
+ box.y1 = 0;
+ box.x2 = pScreen->width;
+ box.y2 = pScreen->height;
+ REGION_INIT (pScreen, &pWin->winSize, &box, 1);
+ REGION_INIT (pScreen, &pWin->borderSize, &box, 1);
+ if (WasViewable)
+ REGION_RESET(pScreen, &pWin->borderClip, &box);
+ pWin->drawable.width = pScreen->width;
+ pWin->drawable.height = pScreen->height;
+ REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList);
+ }
+ else
+ {
+ REGION_EMPTY(pScreen, &pWin->borderClip);
+ REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList);
+ }
+
+ ResizeChildrenWinSize (pWin, 0, 0, 0, 0);
+
+ if (WasViewable)
+ {
+#if XORG < 110
+ if (pWin->backStorage)
+ {
+ pOldClip = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_COPY(pScreen, pOldClip, &pWin->clipList);
+ }
+#endif
+
+ if (pWin->firstChild)
+ {
+ anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild,
+ pWin->firstChild,
+ (WindowPtr *)NULL);
+ }
+ else
+ {
+ (*pScreen->MarkWindow) (pWin);
+ anyMarked = TRUE;
+ }
+
+#if XORG < 110 && defined(DO_SAVE_UNDERS)
+ if (DO_SAVE_UNDERS(pWin))
+ {
+ dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pLayerWin);
+ }
+#endif /* DO_SAVE_UNDERS */
+
+ if (anyMarked)
+ (*pScreen->ValidateTree)(pWin, NullWindow, VTOther);
+ }
+
+#if XORG < 110
+ if (pWin->backStorage &&
+ ((pWin->backingStore == Always) || WasViewable))
+ {
+ if (!WasViewable)
+ pOldClip = &pWin->clipList; /* a convenient empty region */
+ bsExposed = (*pScreen->TranslateBackingStore)
+ (pWin, 0, 0, pOldClip,
+ pWin->drawable.x, pWin->drawable.y);
+ if (WasViewable)
+ REGION_DESTROY(pScreen, pOldClip);
+ if (bsExposed)
+ {
+ RegionPtr valExposed = NullRegion;
+
+ if (pWin->valdata)
+ valExposed = &pWin->valdata->after.exposed;
+ (*pScreen->WindowExposures) (pWin, valExposed, bsExposed);
+ if (valExposed)
+ REGION_EMPTY(pScreen, valExposed);
+ REGION_DESTROY(pScreen, bsExposed);
+ }
+ }
+#endif
+ if (WasViewable)
+ {
+ if (anyMarked)
+ (*pScreen->HandleExposures)(pWin);
+
+#if XORG < 110 && defined(DO_SAVE_UNDERS)
+ if (dosave)
+ (*pScreen->PostChangeSaveUnder)(pLayerWin, pLayerWin);
+#endif /* DO_SAVE_UNDERS */
+ if (anyMarked && pScreen->PostValidateTree)
+ (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther);
+ }
+ if (pWin->realized)
+ WindowsRestructured ();
+ FlushAllOutput ();
+}
+
+RRModePtr vncRandRModeGet(int width, int height);
+static Bool vncRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc, RRModePtr mode,
+ int x, int y, Rotation rotation, int num_outputs,
+ RROutputPtr *outputs);
+
+static Bool vncRandRScreenSetSize(ScreenPtr pScreen,
+ CARD16 width, CARD16 height,
+ CARD32 mmWidth, CARD32 mmHeight)
+{
+ vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
+ vfbFramebufferInfo fb;
+ rrScrPrivPtr rp = rrGetScrPriv(pScreen);
+ PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
+ void *pbits;
+ Bool ret;
+ int oldwidth, oldheight, oldmmWidth, oldmmHeight;
+
+ /* Prevent updates while we fiddle */
+ xf86SetRootClip(pScreen, FALSE);
+
+ /* Store current state in case we fail */
+ oldwidth = pScreen->width;
+ oldheight = pScreen->height;
+ oldmmWidth = pScreen->mmWidth;
+ oldmmHeight = pScreen->mmHeight;
+
+ /* Then set the new dimensions */
+ pScreen->width = width;
+ pScreen->height = height;
+ pScreen->mmWidth = mmWidth;
+ pScreen->mmHeight = mmHeight;
+
+ /* Allocate a new framebuffer */
+ memset(&fb, 0, sizeof(vfbFramebufferInfo));
+
+ fb.width = pScreen->width;
+ fb.height = pScreen->height;
+ fb.depth = pvfb->fb.depth;
+
+ pbits = vfbAllocateFramebufferMemory(&fb);
+ if (!pbits) {
+ /* Allocation failed. Restore old state */
+ pScreen->width = oldwidth;
+ pScreen->height = oldheight;
+ pScreen->mmWidth = oldmmWidth;
+ pScreen->mmHeight = oldmmHeight;
+
+ xf86SetRootClip(pScreen, TRUE);
+
+ return FALSE;
+ }
+
+ /* Update root pixmap with the new dimensions and buffer */
+ ret = pScreen->ModifyPixmapHeader(rootPixmap, fb.width, fb.height,
+ -1, -1, fb.paddedBytesWidth, pbits);
+ if (!ret) {
+ /* Update failed. Free the new framebuffer and restore old state */
+ vfbFreeFramebufferMemory(&fb);
+
+ pScreen->width = oldwidth;
+ pScreen->height = oldheight;
+ pScreen->mmWidth = oldmmWidth;
+ pScreen->mmHeight = oldmmHeight;
+
+ xf86SetRootClip(pScreen, TRUE);
+
+ return FALSE;
+ }
+
+ /* Free the old framebuffer and keep the info about the new one */
+ vfbFreeFramebufferMemory(&pvfb->fb);
+ memcpy(&pvfb->fb, &fb, sizeof(vfbFramebufferInfo));
+
+ /* Let VNC get the new framebuffer (actual update is in vncHooks.cc) */
+ vncFbptr[pScreen->myNum] = pbits;
+ vncFbstride[pScreen->myNum] = fb.paddedWidth;
+
+ /* Restore ability to update screen, now with new dimensions */
+ xf86SetRootClip(pScreen, TRUE);
+
+ /*
+ * Let RandR know we changed something (it doesn't assume that
+ * TRUE means something changed for some reason...).
+ */
+ RRScreenSizeNotify(pScreen);
+
+ /* Crop all CRTCs to the new screen */
+ for (int i = 0;i < rp->numCrtcs;i++) {
+ RRCrtcPtr crtc;
+ RRModePtr mode;
+
+ crtc = rp->crtcs[i];
+
+ /* Disabled? */
+ if (crtc->mode == NULL)
+ continue;
+
+ /* Fully inside? */
+ if ((crtc->x + crtc->mode->mode.width <= width) &&
+ (crtc->y + crtc->mode->mode.height <= height))
+ continue;
+
+ /* Fully outside? */
+ if ((crtc->x >= width) || (crtc->y >= height)) {
+ /* Disable it */
+ ret = vncRandRCrtcSet(pScreen, crtc, NULL,
+ crtc->x, crtc->y, crtc->rotation, 0, NULL);
+ if (!ret)
+ ErrorF("Warning: Unable to disable CRTC that is outside of new screen dimensions");
+ continue;
+ }
+
+ /* Just needs to be resized */
+ mode = vncRandRModeGet(width - crtc->x, height - crtc->y);
+ if (mode == NULL) {
+ ErrorF("Warning: Unable to create custom mode for %dx%d",
+ width - crtc->x, height - crtc->y);
+ continue;
+ }
+
+ ret = vncRandRCrtcSet(pScreen, crtc, mode,
+ crtc->x, crtc->y, crtc->rotation,
+ crtc->numOutputs, crtc->outputs);
+ RRModeDestroy(mode);
+ if (!ret)
+ ErrorF("Warning: Unable to crop CRTC to new screen dimensions");
+ }
+
+ return TRUE;
+}
+
+static Bool vncRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc, RRModePtr mode,
+ int x, int y, Rotation rotation, int num_outputs,
+ RROutputPtr *outputs)
+{
+ Bool ret;
+ int i;
+
+ /*
+ * Some applications get confused by a connected output without a
+ * mode or CRTC, so we need to fiddle with the connection state as well.
+ */
+ for (i = 0;i < crtc->numOutputs;i++)
+ RROutputSetConnection(crtc->outputs[i], RR_Disconnected);
+
+ for (i = 0;i < num_outputs;i++) {
+ if (mode != NULL)
+ RROutputSetConnection(outputs[i], RR_Connected);
+ else
+ RROutputSetConnection(outputs[i], RR_Disconnected);
+ }
+
+ /* Let RandR know we approve, and let it update its internal state */
+ ret = RRCrtcNotify(crtc, mode, x, y, rotation,
+#if XORG >= 16
+ NULL,
+#endif
+ num_outputs, outputs);
+ if (!ret)
+ return FALSE;
+
+ return TRUE;
+}
+
+static Bool vncRandROutputValidateMode(ScreenPtr pScreen,
+ RROutputPtr output, RRModePtr mode)
+{
+ /* We have no hardware so any mode works */
+ return TRUE;
+}
+
+static void vncRandRModeDestroy(ScreenPtr pScreen, RRModePtr mode)
+{
+ /* We haven't allocated anything so nothing to destroy */
+}
+
+static const int vncRandRWidths[] = { 1920, 1920, 1600, 1680, 1400, 1360, 1280, 1280, 1280, 1280, 1024, 800, 640 };
+static const int vncRandRHeights[] = { 1200, 1080, 1200, 1050, 1050, 768, 1024, 960, 800, 720, 768, 600, 480 };
+
+static int vncRandRIndex = 0;
+
+/* This is a global symbol since XserverDesktop also uses it */
+RRModePtr vncRandRModeGet(int width, int height)
+{
+ xRRModeInfo modeInfo;
+ char name[100];
+ RRModePtr mode;
+
+ memset(&modeInfo, 0, sizeof(modeInfo));
+ sprintf(name, "%dx%d", width, height);
+
+ modeInfo.width = width;
+ modeInfo.height = height;
+ modeInfo.hTotal = width;
+ modeInfo.vTotal = height;
+ modeInfo.dotClock = ((CARD32)width * (CARD32)height * 60);
+ modeInfo.nameLength = strlen(name);
+ mode = RRModeGet(&modeInfo, name);
+ if (mode == NULL)
+ return NULL;
+
+ return mode;
+}
+
+static RRCrtcPtr vncRandRCrtcCreate(ScreenPtr pScreen)
+{
+ RRCrtcPtr crtc;
+ RROutputPtr output;
+ RRModePtr mode;
+ char name[100];
+
+ /* First we create the CRTC... */
+ crtc = RRCrtcCreate(pScreen, NULL);
+
+ /* We don't actually support gamma, but xrandr complains when it is missing */
+ RRCrtcGammaSetSize (crtc, 256);
+
+ /* Then we create a dummy output for it... */
+ sprintf(name, "VNC-%d", vncRandRIndex);
+ vncRandRIndex++;
+
+ output = RROutputCreate(pScreen, name, strlen(name), NULL);
+
+ RROutputSetCrtcs(output, &crtc, 1);
+ RROutputSetConnection(output, RR_Disconnected);
+
+ /* Make sure the CRTC has this output set */
+ vncRandRCrtcSet(pScreen, crtc, NULL, 0, 0, RR_Rotate_0, 1, &output);
+
+ /* Populate a list of default modes */
+ RRModePtr modes[sizeof(vncRandRWidths)/sizeof(*vncRandRWidths)];
+ int num_modes;
+
+ num_modes = 0;
+ for (int i = 0;i < sizeof(vncRandRWidths)/sizeof(*vncRandRWidths);i++) {
+ mode = vncRandRModeGet(vncRandRWidths[i], vncRandRHeights[i]);
+ if (mode != NULL) {
+ modes[num_modes] = mode;
+ num_modes++;
+ }
+ }
+
+ RROutputSetModes(output, modes, num_modes, 0);
+
+ return crtc;
+}
+
+/* Used from XserverDesktop when it needs more outputs... */
+int vncRandRCreateOutputs(int scrIdx, int extraOutputs)
+{
+ RRCrtcPtr crtc;
+
+ while (extraOutputs > 0) {
+ crtc = vncRandRCrtcCreate(screenInfo.screens[scrIdx]);
+ if (crtc == NULL)
+ return -1;
+ extraOutputs--;
+ }
+
+ return 0;
+}
+
+static Bool vncRandRInit(ScreenPtr pScreen)
+{
+ RRCrtcPtr crtc;
+ RRModePtr mode;
+ Bool ret;
+
+ if (!RRInit())
+ return FALSE;
+
+ /* These are completely arbitrary */
+ RRScreenSetSizeRange(pScreen, 32, 32, 32768, 32768);
+
+ /*
+ * Start with a single CRTC with a single output. More will be
+ * allocated as needed...
+ */
+ crtc = vncRandRCrtcCreate(pScreen);
+
+ /* Make sure the current screen size is the active mode */
+ mode = vncRandRModeGet(pScreen->width, pScreen->height);
+ if (mode == NULL)
+ return FALSE;
+
+ ret = vncRandRCrtcSet(pScreen, crtc, mode, 0, 0, RR_Rotate_0,
+ crtc->numOutputs, crtc->outputs);
+ RRModeDestroy(mode);
+ if (!ret)
+ return FALSE;
+
+ return TRUE;
+}
+
+#endif
+
+static Bool
+#if XORG < 113
+vfbCloseScreen(int index, ScreenPtr pScreen)
+#else
+vfbCloseScreen(ScreenPtr pScreen)
+#endif
+{
+#if XORG < 113
+ vfbScreenInfoPtr pvfb = &vfbScreens[index];
+#else
+ vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
+#endif
+ int i;
+
+ pScreen->CloseScreen = pvfb->closeScreen;
+
+ /*
+ * XXX probably lots of stuff to clean. For now,
+ * clear installed colormaps so that server reset works correctly.
+ */
+#if XORG < 113
+ for (i = 0; i < MAXSCREENS; i++)
+ InstalledMaps[i] = NULL;
+
+ return pScreen->CloseScreen(index, pScreen);
+#else
+ for (i = 0; i < screenInfo.numScreens; i++)
+ SetInstalledColormap(screenInfo.screens[i], NULL);
+
+ /*
+ * fb overwrites miCloseScreen, so do this here
+ */
+ if (pScreen->devPrivate)
+ (*pScreen->DestroyPixmap) ((PixmapPtr) pScreen->devPrivate);
+ pScreen->devPrivate = NULL;
+
+ return pScreen->CloseScreen(pScreen);
+#endif
+}
+
+static Bool
+#if XORG < 113
+vfbScreenInit(int index, ScreenPtr pScreen, int argc, char **argv)
+#else
+vfbScreenInit(ScreenPtr pScreen, int argc, char **argv)
+#endif
+{
+#if XORG < 113
+ vfbScreenInfoPtr pvfb = &vfbScreens[index];
+#else
+ vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
+#endif
+ int dpi;
+ int ret;
+ void *pbits;
+
+#if XORG >= 113
+ if (!dixRegisterPrivateKey(&cmapScrPrivateKeyRec, PRIVATE_SCREEN, 0))
+ return FALSE;
+#endif
+
+ /* 96 is the default used by most other systems */
+ dpi = 96;
+ if (monitorResolution)
+ dpi = monitorResolution;
+
+ pbits = vfbAllocateFramebufferMemory(&pvfb->fb);
+ if (!pbits) return FALSE;
+#if XORG < 113
+ vncFbptr[index] = pbits;
+ vncFbstride[index] = pvfb->fb.paddedWidth;
+#else
+ vncFbptr[pScreen->myNum] = pbits;
+ vncFbstride[pScreen->myNum] = pvfb->fb.paddedWidth;
+#endif
+
+ miSetPixmapDepths();
+
+ switch (pvfb->fb.depth) {
+ case 8:
+ miSetVisualTypesAndMasks (8,
+ ((1 << StaticGray) |
+ (1 << GrayScale) |
+ (1 << StaticColor) |
+ (1 << PseudoColor) |
+ (1 << TrueColor) |
+ (1 << DirectColor)),
+ 8, PseudoColor, 0, 0, 0);
+ break;
+ case 16:
+ miSetVisualTypesAndMasks (16,
+ ((1 << TrueColor) |
+ (1 << DirectColor)),
+ 8, TrueColor, 0xf800, 0x07e0, 0x001f);
+ break;
+ case 24:
+ miSetVisualTypesAndMasks (24,
+ ((1 << TrueColor) |
+ (1 << DirectColor)),
+ 8, TrueColor, 0xff0000, 0x00ff00, 0x0000ff);
+ break;
+ case 32:
+ miSetVisualTypesAndMasks (32,
+ ((1 << TrueColor) |
+ (1 << DirectColor)),
+ 8, TrueColor, 0xff000000, 0x00ff0000, 0x0000ff00);
+ break;
+ default:
+ return FALSE;
+ }
+
+ ret = fbScreenInit(pScreen, pbits, pvfb->fb.width, pvfb->fb.height,
+ dpi, dpi, pvfb->fb.paddedWidth, pvfb->fb.bitsPerPixel);
+
+#ifdef RENDER
+ if (ret && Render)
+ ret = fbPictureInit (pScreen, 0, 0);
+#endif
+
+ if (!ret) return FALSE;
+
+#if XORG < 110
+ miInitializeBackingStore(pScreen);
+#endif
+
+ /*
+ * 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;
+
+ miPointerInitialize(pScreen, &vfbPointerSpriteFuncs, &vfbPointerCursorFuncs,
+ FALSE);
+
+ pScreen->blackPixel = pvfb->blackPixel;
+ pScreen->whitePixel = pvfb->whitePixel;
+
+ if (!pvfb->pixelFormatDefined) {
+ switch (pvfb->fb.depth) {
+ case 16:
+ pvfb->pixelFormatDefined = TRUE;
+ pvfb->rgbNotBgr = TRUE;
+ pvfb->blueBits = pvfb->redBits = 5;
+ pvfb->greenBits = 6;
+ break;
+ case 24:
+ case 32:
+ pvfb->pixelFormatDefined = TRUE;
+ pvfb->rgbNotBgr = TRUE;
+ pvfb->blueBits = pvfb->redBits = pvfb->greenBits = 8;
+ break;
+ }
+ }
+
+ 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);
+ if (!ret) return FALSE;
+
+ miSetZeroLineBias(pScreen, pvfb->lineBias);
+
+ pvfb->closeScreen = pScreen->CloseScreen;
+ pScreen->CloseScreen = vfbCloseScreen;
+
+#ifdef RANDR
+ rrScrPrivPtr rp;
+
+ ret = RRScreenInit(pScreen);
+ if (!ret) return FALSE;
+
+ rp = rrGetScrPriv(pScreen);
+
+ rp->rrGetInfo = vncRandRGetInfo;
+ rp->rrSetConfig = NULL;
+ rp->rrScreenSetSize = vncRandRScreenSetSize;
+ rp->rrCrtcSet = vncRandRCrtcSet;
+ rp->rrOutputValidateMode = vncRandROutputValidateMode;
+ rp->rrModeDestroy = vncRandRModeDestroy;
+
+ ret = vncRandRInit(pScreen);
+ if (!ret) return FALSE;
+#endif
+
+
+ return TRUE;
+
+} /* end vfbScreenInit */
+
+
+static void vfbClientStateChange(CallbackListPtr *a, void *b, void *c) {
+ dispatchException &= ~DE_RESET;
+}
+
+#if XORG >= 113
+#ifdef GLXEXT
+extern void GlxExtensionInit(void);
+
+static ExtensionModule glxExt = {
+ GlxExtensionInit,
+ "GLX",
+ &noGlxExtension
+};
+#endif
+#endif
+
+void
+InitOutput(ScreenInfo *screenInfo, int argc, char **argv)
+{
+ int i;
+ int NumFormats = 0;
+
+ ErrorF("\nXvnc %s - built %s\n%s", XVNCVERSION, buildtime, XVNCCOPYRIGHT);
+ ErrorF("Underlying X server release %d, %s\n\n", VENDOR_RELEASE,
+ VENDOR_STRING);
+
+#if XORG >= 113
+#ifdef GLXEXT
+ if (serverGeneration == 1)
+#if XORG >= 116
+ LoadExtensionList(&glxExt, 1, TRUE);
+#else
+ LoadExtension(&glxExt, TRUE);
+#endif
+#endif
+#endif
+
+ /* initialize pixmap formats */
+
+ /* must have a pixmap depth to match every screen depth */
+ for (i = 0; i < vfbNumScreens; i++)
+ {
+ vfbPixmapDepths[vfbScreens[i].fb.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 */
+
+/* this is just to get the server to link on AIX */
+#ifdef AIXV3
+int SelectWaitTime = 10000; /* usec */
+#endif
+
+void DDXRingBell(int percent, int pitch, int duration)
+{
+ if (percent > 0)
+ vncBell();
+}
+
+Bool LegalModifier(unsigned int key, DeviceIntPtr pDev)
+{
+ return TRUE;
+}
+
+void ProcessInputEvents()
+{
+ mieqProcessInputEvents();
+#if XORG == 15
+ miPointerUpdate();
+#endif
+}
+
+// InitInput is called after InitExtensions, so we're guaranteed that
+// vncExtensionInit() has already been called.
+
+void InitInput(int argc, char *argv[])
+{
+ mieqInit ();
+}
+
+#if XORG > 17
+void CloseInput(void)
+{
+}
+#endif
+
+void vncClientGone(int fd)
+{
+ if (fd == vncInetdSock) {
+ ErrorF("inetdSock client gone\n");
+ GiveUp(0);
+ }
+}
+++ /dev/null
-/* Copyright (c) 1993 X Consortium
- Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- Copyright 2009 Pierre Ossman for Cendio AB
-
-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.
-
-*/
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <rfb/Configuration.h>
-#include <rfb/Logger_stdio.h>
-#include <rfb/LogWriter.h>
-#include <network/TcpSocket.h>
-#include "vncExtInit.h"
-#include "xorg-version.h"
-
-extern "C" {
-#define class c_class
-#define public c_public
-#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"
-#if XORG < 114
-#include "mibstore.h"
-#endif
-#include "colormapst.h"
-#include "gcstruct.h"
-#include "input.h"
-#include "mipointer.h"
-#define new New
-#include "micmap.h"
-#undef new
-#include <sys/types.h>
-#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"
-#ifdef RANDR
-#include "randrstr.h"
-#endif /* RANDR */
-#include <X11/keysym.h>
- extern char buildtime[];
-#if XORG >= 17
-#undef VENDOR_RELEASE
-#undef VENDOR_STRING
-#include "version-config.h"
-#endif
-#include "site.h"
-#undef class
-#undef public
-}
-
-#if XORG >= 110
-#define Xalloc malloc
-#define Xfree free
-#endif
-
-#define XVNCVERSION "TigerVNC 1.4.80"
-#define XVNCCOPYRIGHT ("Copyright (C) 1999-2013 TigerVNC Team and many others (see README.txt)\n" \
- "See http://www.tigervnc.org for information on TigerVNC.\n")
-
-
-extern int monitorResolution;
-
-#define VFB_DEFAULT_WIDTH 1024
-#define VFB_DEFAULT_HEIGHT 768
-#define VFB_DEFAULT_DEPTH 24
-#define VFB_DEFAULT_WHITEPIXEL 0xffffffff
-#define VFB_DEFAULT_BLACKPIXEL 0
-#define VFB_DEFAULT_LINEBIAS 0
-#define XWD_WINDOW_NAME_LEN 60
-
-typedef struct
-{
- int width;
- int height;
-
- int depth;
-
- /* Computed when allocated */
-
- int paddedBytesWidth;
- int paddedWidth;
-
- int bitsPerPixel;
-
- /* Private */
-
- int sizeInBytes;
-
- void *pfbMemory;
-
-#ifdef HAS_SHM
- int shmid;
-#endif
-} vfbFramebufferInfo, *vfbFramebufferInfoPtr;
-
-typedef struct
-{
- int scrnum;
-
- Pixel blackPixel;
- Pixel whitePixel;
-
- unsigned int lineBias;
-
- CloseScreenProcPtr closeScreen;
-
- vfbFramebufferInfo fb;
-
- Bool pixelFormatDefined;
- Bool rgbNotBgr;
- int redBits, greenBits, blueBits;
-} vfbScreenInfo, *vfbScreenInfoPtr;
-
-static int vfbNumScreens;
-static vfbScreenInfo vfbScreens[MAXSCREENS];
-static Bool vfbPixmapDepths[33];
-typedef enum { NORMAL_MEMORY_FB, SHARED_MEMORY_FB } fbMemType;
-static fbMemType fbmemtype = NORMAL_MEMORY_FB;
-static int lastScreen = -1;
-static Bool Render = TRUE;
-
-static bool displaySpecified = false;
-static char displayNumStr[16];
-
-char *listenaddr = NULL;
-
-static int vncVerbose = DEFAULT_LOG_VERBOSITY;
-
-
-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].blackPixel = VFB_DEFAULT_BLACKPIXEL;
- vfbScreens[i].whitePixel = VFB_DEFAULT_WHITEPIXEL;
- vfbScreens[i].lineBias = VFB_DEFAULT_LINEBIAS;
- vfbScreens[i].fb.width = VFB_DEFAULT_WIDTH;
- vfbScreens[i].fb.height = VFB_DEFAULT_HEIGHT;
- vfbScreens[i].fb.pfbMemory = NULL;
- vfbScreens[i].fb.depth = VFB_DEFAULT_DEPTH;
- vfbScreens[i].pixelFormatDefined = FALSE;
- }
- 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;
-}
-
-static void vfbFreeFramebufferMemory(vfbFramebufferInfoPtr pfb);
-
-extern "C" {
-
-#ifdef DPMSExtension
- /* Why support DPMS? Because stupid modern desktop environments
- such as Unity 2D on Ubuntu 11.10 crashes if DPMS is not
- available. (DPMSSet is called by dpms.c, but the return value
- is ignored.) */
-int DPMSSet(ClientPtr client, int level)
-{
- return Success;
-}
-
-Bool DPMSSupported()
-{
- /* Causes DPMSCapable to return false, meaning no devices are DPMS
- capable */
- return FALSE;
-}
-#endif
-
-#if XORG < 111
-void ddxGiveUp()
-#else
-void ddxGiveUp(enum ExitCode error)
-#endif
-{
- int i;
-
- /* clean up the framebuffers */
- for (i = 0; i < vfbNumScreens; i++)
- vfbFreeFramebufferMemory(&vfbScreens[i].fb);
-}
-
-void
-#if XORG < 111
-AbortDDX()
-#else
-AbortDDX(enum ExitCode error)
-#endif
-{
-#if XORG < 111
- ddxGiveUp();
-#else
- ddxGiveUp(error);
-#endif
-}
-
-#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
-#if XORG < 113
-OsVendorFatalError()
-#else
-OsVendorFatalError(const char *f, va_list args)
-#endif
-{
-}
-
-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_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("-interface IP_address listen on specified interface\n");
- ErrorF("-noclipboard disable clipboard settings modification via vncconfig utility\n");
- ErrorF("-verbose [n] verbose startup messages\n");
- ErrorF("-quiet minimal startup messages\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(NULL, 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");
- rfb::Configuration::enableServerParams();
- }
-
- 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].fb.width,
- &vfbScreens[screenNum].fb.height,
- &vfbScreens[screenNum].fb.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_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].fb.width,
- &vfbScreens[0].fb.height) != 2) {
- ErrorF("Invalid geometry %s\n", argv[i]);
- UseMsg();
- }
- return 2;
- }
-
- if (strcmp(argv[i], "-depth") == 0)
- {
- if (++i >= argc) UseMsg();
- vfbScreens[0].fb.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).fb.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 (strcmp(argv[i], "-interface") == 0 ||
- strcmp(argv[i], "-i") == 0) {
- if (++i >= argc) {
- UseMsg();
- return 2;
- }
-
- if (listenaddr != NULL) /* Only first -interface is valid */
- return 2;
-
- listenaddr = strdup(argv[i]);
- if (listenaddr == NULL)
- FatalError("Not enough memory");
-
- return 2;
- }
-
- if (strcmp(argv[i], "-noclipboard") == 0) {
- noclipboard = true;
- return 1;
- }
-
- if (!strcmp(argv[i], "-verbose")) {
- if (++i < argc && argv[i]) {
- char *end;
- long val;
-
- val = strtol(argv[i], &end, 0);
- if (*end == '\0') {
- vncVerbose = val;
- LogSetParameter(XLOG_VERBOSITY, vncVerbose);
- return 2;
- }
- }
- vncVerbose++;
- LogSetParameter(XLOG_VERBOSITY, vncVerbose);
- return 1;
- }
-
- if (!strcmp(argv[i], "-quiet")) {
- vncVerbose = -1;
- LogSetParameter(XLOG_VERBOSITY, vncVerbose);
- 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
-
-#if XORG < 113
-static ColormapPtr InstalledMaps[MAXSCREENS];
-#else
-static DevPrivateKeyRec cmapScrPrivateKeyRec;
-#define cmapScrPrivateKey (&cmapScrPrivateKeyRec)
-#define GetInstalledColormap(s) ((ColormapPtr) dixLookupPrivate(&(s)->devPrivates, cmapScrPrivateKey))
-#define SetInstalledColormap(s,c) (dixSetPrivate(&(s)->devPrivates, cmapScrPrivateKey, c))
-#endif
-
-static int
-vfbListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps)
-{
- /* By the time we are processing requests, we can guarantee that there
- * is always a colormap installed */
-#if XORG < 113
- *pmaps = InstalledMaps[pScreen->myNum]->mid;
-#else
- *pmaps = GetInstalledColormap(pScreen)->mid;
-#endif
- return (1);
-}
-
-
-static void
-vfbInstallColormap(ColormapPtr pmap)
-{
-#if XORG < 113
- int index = pmap->pScreen->myNum;
-#endif
- ColormapPtr oldpmap;
-
-#if XORG < 113
- oldpmap = InstalledMaps[index];
-#else
- oldpmap = GetInstalledColormap(pmap->pScreen);
-#endif
-
- if (pmap != oldpmap)
- {
- int entries;
- VisualPtr pVisual;
- Pixel * ppix;
- xrgb * prgb;
- xColorItem *defs;
- int i;
-
- if(oldpmap != (ColormapPtr)None)
- WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid);
- /* Install pmap */
-#if XORG < 113
- InstalledMaps[index] = pmap;
-#else
- SetInstalledColormap(pmap->pScreen, pmap);
-#endif
- WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid);
-
- entries = pmap->pVisual->ColormapEntries;
- pVisual = pmap->pVisual;
-
- ppix = (Pixel *)xalloc(entries * sizeof(Pixel));
- prgb = (xrgb *)xalloc(entries * sizeof(xrgb));
- defs = (xColorItem *)xalloc(entries * sizeof(xColorItem));
-
- for (i = 0; i < entries; i++) ppix[i] = i;
- /* XXX truecolor */
-#if XORG < 19
- QueryColors(pmap, entries, ppix, prgb);
-#else
- QueryColors(pmap, entries, ppix, prgb, serverClient);
-#endif
-
- 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);
-
- xfree(ppix);
- xfree(prgb);
- xfree(defs);
- }
-}
-
-static void
-vfbUninstallColormap(ColormapPtr pmap)
-{
-#if XORG < 113
- ColormapPtr curpmap = InstalledMaps[pmap->pScreen->myNum];
-#else
- ColormapPtr curpmap = GetInstalledColormap(pmap->pScreen);
-#endif
-
- if(pmap == curpmap)
- {
- if (pmap->mid != pmap->pScreen->defColormap)
- {
-#if XORG < 111
- curpmap = (ColormapPtr) LookupIDByType(pmap->pScreen->defColormap,
- RT_COLORMAP);
-#else
- dixLookupResourceByType((void * *) &curpmap, pmap->pScreen->defColormap,
- RT_COLORMAP, serverClient, DixUnknownAccess);
-#endif
- (*pmap->pScreen->InstallColormap)(curpmap);
- }
- }
-}
-
-static Bool
-vfbSaveScreen(ScreenPtr pScreen, int on)
-{
- return TRUE;
-}
-
-#ifdef HAS_SHM
-static void
-vfbAllocateSharedMemoryFramebuffer(vfbFramebufferInfoPtr pfb)
-{
- /* create the shared memory segment */
-
- pfb->shmid = shmget(IPC_PRIVATE, pfb->sizeInBytes, IPC_CREAT|0777);
- if (pfb->shmid < 0) {
- perror("shmget");
- ErrorF("shmget %d bytes failed, errno %d", pfb->sizeInBytes, errno);
- return;
- }
-
- /* try to attach it */
-
- pfb->pfbMemory = shmat(pfb->shmid, 0, 0);
- if (-1 == (long)pfb->pfbMemory) {
- perror("shmat");
- ErrorF("shmat failed, errno %d", errno);
- pfb->pfbMemory = NULL;
- return;
- }
-}
-#endif /* HAS_SHM */
-
-
-static void *
-vfbAllocateFramebufferMemory(vfbFramebufferInfoPtr pfb)
-{
- if (pfb->pfbMemory != NULL)
- return pfb->pfbMemory; /* already done */
-
- /* Compute memory layout */
- pfb->paddedBytesWidth = PixmapBytePad(pfb->width, pfb->depth);
- pfb->bitsPerPixel = vfbBitsPerPixel(pfb->depth);
- pfb->paddedWidth = pfb->paddedBytesWidth * 8 / pfb->bitsPerPixel;
- pfb->sizeInBytes = pfb->paddedBytesWidth * pfb->height;
-
- /* And allocate buffer */
- switch (fbmemtype) {
-#ifdef HAS_SHM
- case SHARED_MEMORY_FB:
- vfbAllocateSharedMemoryFramebuffer(pfb);
- break;
-#else
- case SHARED_MEMORY_FB:
- break;
-#endif
- case NORMAL_MEMORY_FB:
- pfb->pfbMemory = Xalloc(pfb->sizeInBytes);
- break;
- }
-
- /* This will be NULL if any of the above failed */
- return pfb->pfbMemory;
-}
-
-static void
-vfbFreeFramebufferMemory(vfbFramebufferInfoPtr pfb)
-{
- if ((pfb == NULL) || (pfb->pfbMemory == NULL))
- return;
-
- switch (fbmemtype) {
-#ifdef HAS_SHM
- case SHARED_MEMORY_FB:
- if (-1 == shmdt(pfb->pfbMemory)) {
- perror("shmdt");
- ErrorF("shmdt failed, errno %d", errno);
- }
- break;
-#else /* HAS_SHM */
- case SHARED_MEMORY_FB:
- break;
-#endif /* HAS_SHM */
- case NORMAL_MEMORY_FB:
- Xfree(pfb->pfbMemory);
- break;
- }
-
- pfb->pfbMemory = NULL;
-}
-
-static Bool
-vfbCursorOffScreen (ScreenPtr *ppScreen, int *x, int *y)
-{
- return FALSE;
-}
-
-static void
-vfbCrossScreen (ScreenPtr pScreen, Bool entering)
-{
-}
-
-static Bool vfbRealizeCursor(
-#if XORG >= 16
- DeviceIntPtr pDev,
-#endif
- ScreenPtr pScreen, CursorPtr pCursor) {
- return TRUE;
-}
-
-static Bool vfbUnrealizeCursor(
-#if XORG >= 16
- DeviceIntPtr pDev,
-#endif
- ScreenPtr pScreen, CursorPtr pCursor) {
- return TRUE;
-}
-
-static void vfbSetCursor(
-#if XORG >= 16
- DeviceIntPtr pDev,
-#endif
- ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
-{
-}
-
-static void vfbMoveCursor(
-#if XORG >= 16
- DeviceIntPtr pDev,
-#endif
- ScreenPtr pScreen, int x, int y)
-{
-}
-
-#if XORG >= 16
-static Bool
-vfbDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen)
-{
- return TRUE;
-}
-
-static void
-vfbDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen)
-{
-}
-#endif
-
-static miPointerSpriteFuncRec vfbPointerSpriteFuncs = {
- vfbRealizeCursor,
- vfbUnrealizeCursor,
- vfbSetCursor,
- vfbMoveCursor
-#if XORG >= 16
- , vfbDeviceCursorInitialize,
- vfbDeviceCursorCleanup
-#endif
-};
-
-static miPointerScreenFuncRec vfbPointerCursorFuncs = {
- vfbCursorOffScreen,
- vfbCrossScreen,
- miPointerWarpCursor
-};
-
-#ifdef RANDR
-
-static Bool vncRandRGetInfo (ScreenPtr pScreen, Rotation *rotations)
-{
- // We update all information right away, so there is nothing to
- // do here.
- return TRUE;
-}
-
-/* from hw/xfree86/common/xf86Helper.c */
-
-#include "mivalidate.h"
-static void
-xf86SetRootClip (ScreenPtr pScreen, Bool enable)
-{
-#if XORG < 19
- WindowPtr pWin = WindowTable[pScreen->myNum];
-#else
- WindowPtr pWin = pScreen->root;
-#endif
- WindowPtr pChild;
- Bool WasViewable = (Bool)(pWin->viewable);
- Bool anyMarked = FALSE;
-#if XORG < 110
- RegionPtr pOldClip = NULL, bsExposed;
-#ifdef DO_SAVE_UNDERS
- Bool dosave = FALSE;
-#endif
-#endif
- WindowPtr pLayerWin;
- BoxRec box;
-
- if (WasViewable)
- {
- for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib)
- {
- (void) (*pScreen->MarkOverlappedWindows)(pChild,
- pChild,
- &pLayerWin);
- }
- (*pScreen->MarkWindow) (pWin);
- anyMarked = TRUE;
- if (pWin->valdata)
- {
- if (HasBorder (pWin))
- {
- RegionPtr borderVisible;
-
- borderVisible = REGION_CREATE(pScreen, NullBox, 1);
- REGION_SUBTRACT(pScreen, borderVisible,
- &pWin->borderClip, &pWin->winSize);
- pWin->valdata->before.borderVisible = borderVisible;
- }
- pWin->valdata->before.resized = TRUE;
- }
- }
-
- /*
- * Use REGION_BREAK to avoid optimizations in ValidateTree
- * that assume the root borderClip can't change well, normally
- * it doesn't...)
- */
- if (enable)
- {
- box.x1 = 0;
- box.y1 = 0;
- box.x2 = pScreen->width;
- box.y2 = pScreen->height;
- REGION_INIT (pScreen, &pWin->winSize, &box, 1);
- REGION_INIT (pScreen, &pWin->borderSize, &box, 1);
- if (WasViewable)
- REGION_RESET(pScreen, &pWin->borderClip, &box);
- pWin->drawable.width = pScreen->width;
- pWin->drawable.height = pScreen->height;
- REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList);
- }
- else
- {
- REGION_EMPTY(pScreen, &pWin->borderClip);
- REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList);
- }
-
- ResizeChildrenWinSize (pWin, 0, 0, 0, 0);
-
- if (WasViewable)
- {
-#if XORG < 110
- if (pWin->backStorage)
- {
- pOldClip = REGION_CREATE(pScreen, NullBox, 1);
- REGION_COPY(pScreen, pOldClip, &pWin->clipList);
- }
-#endif
-
- if (pWin->firstChild)
- {
- anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild,
- pWin->firstChild,
- (WindowPtr *)NULL);
- }
- else
- {
- (*pScreen->MarkWindow) (pWin);
- anyMarked = TRUE;
- }
-
-#if XORG < 110 && defined(DO_SAVE_UNDERS)
- if (DO_SAVE_UNDERS(pWin))
- {
- dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pLayerWin);
- }
-#endif /* DO_SAVE_UNDERS */
-
- if (anyMarked)
- (*pScreen->ValidateTree)(pWin, NullWindow, VTOther);
- }
-
-#if XORG < 110
- if (pWin->backStorage &&
- ((pWin->backingStore == Always) || WasViewable))
- {
- if (!WasViewable)
- pOldClip = &pWin->clipList; /* a convenient empty region */
- bsExposed = (*pScreen->TranslateBackingStore)
- (pWin, 0, 0, pOldClip,
- pWin->drawable.x, pWin->drawable.y);
- if (WasViewable)
- REGION_DESTROY(pScreen, pOldClip);
- if (bsExposed)
- {
- RegionPtr valExposed = NullRegion;
-
- if (pWin->valdata)
- valExposed = &pWin->valdata->after.exposed;
- (*pScreen->WindowExposures) (pWin, valExposed, bsExposed);
- if (valExposed)
- REGION_EMPTY(pScreen, valExposed);
- REGION_DESTROY(pScreen, bsExposed);
- }
- }
-#endif
- if (WasViewable)
- {
- if (anyMarked)
- (*pScreen->HandleExposures)(pWin);
-
-#if XORG < 110 && defined(DO_SAVE_UNDERS)
- if (dosave)
- (*pScreen->PostChangeSaveUnder)(pLayerWin, pLayerWin);
-#endif /* DO_SAVE_UNDERS */
- if (anyMarked && pScreen->PostValidateTree)
- (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther);
- }
- if (pWin->realized)
- WindowsRestructured ();
- FlushAllOutput ();
-}
-
-RRModePtr vncRandRModeGet(int width, int height);
-static Bool vncRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc, RRModePtr mode,
- int x, int y, Rotation rotation, int num_outputs,
- RROutputPtr *outputs);
-
-static Bool vncRandRScreenSetSize(ScreenPtr pScreen,
- CARD16 width, CARD16 height,
- CARD32 mmWidth, CARD32 mmHeight)
-{
- vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
- vfbFramebufferInfo fb;
- rrScrPrivPtr rp = rrGetScrPriv(pScreen);
- PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
- void *pbits;
- Bool ret;
- int oldwidth, oldheight, oldmmWidth, oldmmHeight;
-
- /* Prevent updates while we fiddle */
- xf86SetRootClip(pScreen, FALSE);
-
- /* Store current state in case we fail */
- oldwidth = pScreen->width;
- oldheight = pScreen->height;
- oldmmWidth = pScreen->mmWidth;
- oldmmHeight = pScreen->mmHeight;
-
- /* Then set the new dimensions */
- pScreen->width = width;
- pScreen->height = height;
- pScreen->mmWidth = mmWidth;
- pScreen->mmHeight = mmHeight;
-
- /* Allocate a new framebuffer */
- memset(&fb, 0, sizeof(vfbFramebufferInfo));
-
- fb.width = pScreen->width;
- fb.height = pScreen->height;
- fb.depth = pvfb->fb.depth;
-
- pbits = vfbAllocateFramebufferMemory(&fb);
- if (!pbits) {
- /* Allocation failed. Restore old state */
- pScreen->width = oldwidth;
- pScreen->height = oldheight;
- pScreen->mmWidth = oldmmWidth;
- pScreen->mmHeight = oldmmHeight;
-
- xf86SetRootClip(pScreen, TRUE);
-
- return FALSE;
- }
-
- /* Update root pixmap with the new dimensions and buffer */
- ret = pScreen->ModifyPixmapHeader(rootPixmap, fb.width, fb.height,
- -1, -1, fb.paddedBytesWidth, pbits);
- if (!ret) {
- /* Update failed. Free the new framebuffer and restore old state */
- vfbFreeFramebufferMemory(&fb);
-
- pScreen->width = oldwidth;
- pScreen->height = oldheight;
- pScreen->mmWidth = oldmmWidth;
- pScreen->mmHeight = oldmmHeight;
-
- xf86SetRootClip(pScreen, TRUE);
-
- return FALSE;
- }
-
- /* Free the old framebuffer and keep the info about the new one */
- vfbFreeFramebufferMemory(&pvfb->fb);
- memcpy(&pvfb->fb, &fb, sizeof(vfbFramebufferInfo));
-
- /* Let VNC get the new framebuffer (actual update is in vncHooks.cc) */
- vncFbptr[pScreen->myNum] = pbits;
- vncFbstride[pScreen->myNum] = fb.paddedWidth;
-
- /* Restore ability to update screen, now with new dimensions */
- xf86SetRootClip(pScreen, TRUE);
-
- /*
- * Let RandR know we changed something (it doesn't assume that
- * TRUE means something changed for some reason...).
- */
- RRScreenSizeNotify(pScreen);
-
- /* Crop all CRTCs to the new screen */
- for (int i = 0;i < rp->numCrtcs;i++) {
- RRCrtcPtr crtc;
- RRModePtr mode;
-
- crtc = rp->crtcs[i];
-
- /* Disabled? */
- if (crtc->mode == NULL)
- continue;
-
- /* Fully inside? */
- if ((crtc->x + crtc->mode->mode.width <= width) &&
- (crtc->y + crtc->mode->mode.height <= height))
- continue;
-
- /* Fully outside? */
- if ((crtc->x >= width) || (crtc->y >= height)) {
- /* Disable it */
- ret = vncRandRCrtcSet(pScreen, crtc, NULL,
- crtc->x, crtc->y, crtc->rotation, 0, NULL);
- if (!ret)
- ErrorF("Warning: Unable to disable CRTC that is outside of new screen dimensions");
- continue;
- }
-
- /* Just needs to be resized */
- mode = vncRandRModeGet(width - crtc->x, height - crtc->y);
- if (mode == NULL) {
- ErrorF("Warning: Unable to create custom mode for %dx%d",
- width - crtc->x, height - crtc->y);
- continue;
- }
-
- ret = vncRandRCrtcSet(pScreen, crtc, mode,
- crtc->x, crtc->y, crtc->rotation,
- crtc->numOutputs, crtc->outputs);
- RRModeDestroy(mode);
- if (!ret)
- ErrorF("Warning: Unable to crop CRTC to new screen dimensions");
- }
-
- return TRUE;
-}
-
-static Bool vncRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc, RRModePtr mode,
- int x, int y, Rotation rotation, int num_outputs,
- RROutputPtr *outputs)
-{
- Bool ret;
- int i;
-
- /*
- * Some applications get confused by a connected output without a
- * mode or CRTC, so we need to fiddle with the connection state as well.
- */
- for (i = 0;i < crtc->numOutputs;i++)
- RROutputSetConnection(crtc->outputs[i], RR_Disconnected);
-
- for (i = 0;i < num_outputs;i++) {
- if (mode != NULL)
- RROutputSetConnection(outputs[i], RR_Connected);
- else
- RROutputSetConnection(outputs[i], RR_Disconnected);
- }
-
- /* Let RandR know we approve, and let it update its internal state */
- ret = RRCrtcNotify(crtc, mode, x, y, rotation,
-#if XORG >= 16
- NULL,
-#endif
- num_outputs, outputs);
- if (!ret)
- return FALSE;
-
- return TRUE;
-}
-
-static Bool vncRandROutputValidateMode(ScreenPtr pScreen,
- RROutputPtr output, RRModePtr mode)
-{
- /* We have no hardware so any mode works */
- return TRUE;
-}
-
-static void vncRandRModeDestroy(ScreenPtr pScreen, RRModePtr mode)
-{
- /* We haven't allocated anything so nothing to destroy */
-}
-
-static const int vncRandRWidths[] = { 1920, 1920, 1600, 1680, 1400, 1360, 1280, 1280, 1280, 1280, 1024, 800, 640 };
-static const int vncRandRHeights[] = { 1200, 1080, 1200, 1050, 1050, 768, 1024, 960, 800, 720, 768, 600, 480 };
-
-static int vncRandRIndex = 0;
-
-/* This is a global symbol since XserverDesktop also uses it */
-RRModePtr vncRandRModeGet(int width, int height)
-{
- xRRModeInfo modeInfo;
- char name[100];
- RRModePtr mode;
-
- memset(&modeInfo, 0, sizeof(modeInfo));
- sprintf(name, "%dx%d", width, height);
-
- modeInfo.width = width;
- modeInfo.height = height;
- modeInfo.hTotal = width;
- modeInfo.vTotal = height;
- modeInfo.dotClock = ((CARD32)width * (CARD32)height * 60);
- modeInfo.nameLength = strlen(name);
- mode = RRModeGet(&modeInfo, name);
- if (mode == NULL)
- return NULL;
-
- return mode;
-}
-
-static RRCrtcPtr vncRandRCrtcCreate(ScreenPtr pScreen)
-{
- RRCrtcPtr crtc;
- RROutputPtr output;
- RRModePtr mode;
- char name[100];
-
- /* First we create the CRTC... */
- crtc = RRCrtcCreate(pScreen, NULL);
-
- /* We don't actually support gamma, but xrandr complains when it is missing */
- RRCrtcGammaSetSize (crtc, 256);
-
- /* Then we create a dummy output for it... */
- sprintf(name, "VNC-%d", vncRandRIndex);
- vncRandRIndex++;
-
- output = RROutputCreate(pScreen, name, strlen(name), NULL);
-
- RROutputSetCrtcs(output, &crtc, 1);
- RROutputSetConnection(output, RR_Disconnected);
-
- /* Make sure the CRTC has this output set */
- vncRandRCrtcSet(pScreen, crtc, NULL, 0, 0, RR_Rotate_0, 1, &output);
-
- /* Populate a list of default modes */
- RRModePtr modes[sizeof(vncRandRWidths)/sizeof(*vncRandRWidths)];
- int num_modes;
-
- num_modes = 0;
- for (int i = 0;i < sizeof(vncRandRWidths)/sizeof(*vncRandRWidths);i++) {
- mode = vncRandRModeGet(vncRandRWidths[i], vncRandRHeights[i]);
- if (mode != NULL) {
- modes[num_modes] = mode;
- num_modes++;
- }
- }
-
- RROutputSetModes(output, modes, num_modes, 0);
-
- return crtc;
-}
-
-/* Used from XserverDesktop when it needs more outputs... */
-RROutputPtr vncRandROutputCreate(ScreenPtr pScreen)
-{
- RRCrtcPtr crtc;
-
- crtc = vncRandRCrtcCreate(pScreen);
- if (crtc == NULL)
- return NULL;
-
- return crtc->outputs[0];
-}
-
-static Bool vncRandRInit(ScreenPtr pScreen)
-{
- RRCrtcPtr crtc;
- RRModePtr mode;
- Bool ret;
-
- if (!RRInit())
- return FALSE;
-
- /* These are completely arbitrary */
- RRScreenSetSizeRange(pScreen, 32, 32, 32768, 32768);
-
- /*
- * Start with a single CRTC with a single output. More will be
- * allocated as needed...
- */
- crtc = vncRandRCrtcCreate(pScreen);
-
- /* Make sure the current screen size is the active mode */
- mode = vncRandRModeGet(pScreen->width, pScreen->height);
- if (mode == NULL)
- return FALSE;
-
- ret = vncRandRCrtcSet(pScreen, crtc, mode, 0, 0, RR_Rotate_0,
- crtc->numOutputs, crtc->outputs);
- RRModeDestroy(mode);
- if (!ret)
- return FALSE;
-
- return TRUE;
-}
-
-#endif
-
-static Bool
-#if XORG < 113
-vfbCloseScreen(int index, ScreenPtr pScreen)
-#else
-vfbCloseScreen(ScreenPtr pScreen)
-#endif
-{
-#if XORG < 113
- vfbScreenInfoPtr pvfb = &vfbScreens[index];
-#else
- vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
-#endif
- int i;
-
- pScreen->CloseScreen = pvfb->closeScreen;
-
- /*
- * XXX probably lots of stuff to clean. For now,
- * clear installed colormaps so that server reset works correctly.
- */
-#if XORG < 113
- for (i = 0; i < MAXSCREENS; i++)
- InstalledMaps[i] = NULL;
-
- return pScreen->CloseScreen(index, pScreen);
-#else
- for (i = 0; i < screenInfo.numScreens; i++)
- SetInstalledColormap(screenInfo.screens[i], NULL);
-
- /*
- * fb overwrites miCloseScreen, so do this here
- */
- if (pScreen->devPrivate)
- (*pScreen->DestroyPixmap) ((PixmapPtr) pScreen->devPrivate);
- pScreen->devPrivate = NULL;
-
- return pScreen->CloseScreen(pScreen);
-#endif
-}
-
-static Bool
-#if XORG < 113
-vfbScreenInit(int index, ScreenPtr pScreen, int argc, char **argv)
-#else
-vfbScreenInit(ScreenPtr pScreen, int argc, char **argv)
-#endif
-{
-#if XORG < 113
- vfbScreenInfoPtr pvfb = &vfbScreens[index];
-#else
- vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
-#endif
- int dpi;
- int ret;
- void *pbits;
-
-#if XORG >= 113
- if (!dixRegisterPrivateKey(&cmapScrPrivateKeyRec, PRIVATE_SCREEN, 0))
- return FALSE;
-#endif
-
- /* 96 is the default used by most other systems */
- dpi = 96;
- if (monitorResolution)
- dpi = monitorResolution;
-
- pbits = vfbAllocateFramebufferMemory(&pvfb->fb);
- if (!pbits) return FALSE;
-#if XORG < 113
- vncFbptr[index] = pbits;
- vncFbstride[index] = pvfb->fb.paddedWidth;
-#else
- vncFbptr[pScreen->myNum] = pbits;
- vncFbstride[pScreen->myNum] = pvfb->fb.paddedWidth;
-#endif
-
- miSetPixmapDepths();
-
- switch (pvfb->fb.depth) {
- case 8:
- miSetVisualTypesAndMasks (8,
- ((1 << StaticGray) |
- (1 << GrayScale) |
- (1 << StaticColor) |
- (1 << PseudoColor) |
- (1 << TrueColor) |
- (1 << DirectColor)),
- 8, PseudoColor, 0, 0, 0);
- break;
- case 16:
- miSetVisualTypesAndMasks (16,
- ((1 << TrueColor) |
- (1 << DirectColor)),
- 8, TrueColor, 0xf800, 0x07e0, 0x001f);
- break;
- case 24:
- miSetVisualTypesAndMasks (24,
- ((1 << TrueColor) |
- (1 << DirectColor)),
- 8, TrueColor, 0xff0000, 0x00ff00, 0x0000ff);
- break;
- case 32:
- miSetVisualTypesAndMasks (32,
- ((1 << TrueColor) |
- (1 << DirectColor)),
- 8, TrueColor, 0xff000000, 0x00ff0000, 0x0000ff00);
- break;
- default:
- return FALSE;
- }
-
- ret = fbScreenInit(pScreen, pbits, pvfb->fb.width, pvfb->fb.height,
- dpi, dpi, pvfb->fb.paddedWidth, pvfb->fb.bitsPerPixel);
-
-#ifdef RENDER
- if (ret && Render)
- ret = fbPictureInit (pScreen, 0, 0);
-#endif
-
- if (!ret) return FALSE;
-
-#if XORG < 110
- miInitializeBackingStore(pScreen);
-#endif
-
- /*
- * 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;
-
- miPointerInitialize(pScreen, &vfbPointerSpriteFuncs, &vfbPointerCursorFuncs,
- FALSE);
-
- pScreen->blackPixel = pvfb->blackPixel;
- pScreen->whitePixel = pvfb->whitePixel;
-
- if (!pvfb->pixelFormatDefined) {
- switch (pvfb->fb.depth) {
- case 16:
- pvfb->pixelFormatDefined = TRUE;
- pvfb->rgbNotBgr = TRUE;
- pvfb->blueBits = pvfb->redBits = 5;
- pvfb->greenBits = 6;
- break;
- case 24:
- case 32:
- pvfb->pixelFormatDefined = TRUE;
- pvfb->rgbNotBgr = TRUE;
- pvfb->blueBits = pvfb->redBits = pvfb->greenBits = 8;
- break;
- }
- }
-
- 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);
- if (!ret) return FALSE;
-
- miSetZeroLineBias(pScreen, pvfb->lineBias);
-
- pvfb->closeScreen = pScreen->CloseScreen;
- pScreen->CloseScreen = vfbCloseScreen;
-
-#ifdef RANDR
- rrScrPrivPtr rp;
-
- ret = RRScreenInit(pScreen);
- if (!ret) return FALSE;
-
- rp = rrGetScrPriv(pScreen);
-
- rp->rrGetInfo = vncRandRGetInfo;
- rp->rrSetConfig = NULL;
- rp->rrScreenSetSize = vncRandRScreenSetSize;
- rp->rrCrtcSet = vncRandRCrtcSet;
- rp->rrOutputValidateMode = vncRandROutputValidateMode;
- rp->rrModeDestroy = vncRandRModeDestroy;
-
- ret = vncRandRInit(pScreen);
- if (!ret) return FALSE;
-#endif
-
-
- return TRUE;
-
-} /* end vfbScreenInit */
-
-
-static void vfbClientStateChange(CallbackListPtr*, void *, void *) {
- dispatchException &= ~DE_RESET;
-}
-
-#if XORG >= 113
-#ifdef GLXEXT
-extern "C" void GlxExtensionInit(void);
-
-static ExtensionModule glxExt = {
- GlxExtensionInit,
- "GLX",
- &noGlxExtension
-};
-#endif
-#endif
-
-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;
-
-#if XORG >= 113
-#ifdef GLXEXT
- if (serverGeneration == 1)
-#if XORG >= 116
- LoadExtensionList(&glxExt, 1, TRUE);
-#else
- LoadExtension(&glxExt, TRUE);
-#endif
-#endif
-#endif
-
- /* initialize pixmap formats */
-
- /* must have a pixmap depth to match every screen depth */
- for (i = 0; i < vfbNumScreens; i++)
- {
- vfbPixmapDepths[vfbScreens[i].fb.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 */
-
-/* this is just to get the server to link on AIX */
-#ifdef AIXV3
-int SelectWaitTime = 10000; /* usec */
-#endif
-
-void DDXRingBell(int percent, int pitch, int duration)
-{
- if (percent > 0)
- vncBell();
-}
-
-Bool LegalModifier(unsigned int key, DeviceIntPtr pDev)
-{
- return TRUE;
-}
-
-void ProcessInputEvents()
-{
- mieqProcessInputEvents();
-#if XORG == 15
- miPointerUpdate();
-#endif
-}
-
-// InitInput is called after InitExtensions, so we're guaranteed that
-// vncExtensionInit() has already been called.
-
-void InitInput(int argc, char *argv[])
-{
- mieqInit ();
-}
-
-#if XORG > 17
-void CloseInput(void)
-{
-}
-#endif