Browse Source

Merge branch 'xorgheaders' of https://github.com/CendioOssman/tigervnc

tags/v1.4.90
Pierre Ossman 9 years ago
parent
commit
7e4da45422

+ 4
- 0
common/rfb/LogWriter.h View File

@@ -36,6 +36,10 @@
// is assigned a particular log level.

#define DEF_LOGFUNCTION(name, level) \
inline void name(const char* fmt, va_list ap) { \
if (m_log && (level <= m_level)) \
m_log->write(level, m_name, fmt, ap);\
} \
inline void name(const char* fmt, ...) __printf_attr(2, 3) { \
if (m_log && (level <= m_level)) { \
va_list ap; va_start(ap, fmt); \

+ 13
- 7
common/rfb/ScreenSet.h View File

@@ -22,6 +22,7 @@
#define __RFB_SCREENSET_INCLUDED__

#include <stdio.h>
#include <string.h>

#include <rdr/types.h>
#include <rfb/Rect.h>
@@ -108,15 +109,20 @@ namespace rfb {
return true;
};

inline void debug_print(void) const {
inline void print(char* str, size_t len) const {
char buffer[128];
std::list<Screen>::const_iterator iter;
fprintf(stderr, "%d screens\n", num_screens());
snprintf(buffer, sizeof(buffer), "%d screen(s)\n", num_screens());
str[0] = '\0';
strncat(str, buffer, len - 1 - strlen(str));
for (iter = screens.begin();iter != screens.end();++iter) {
fprintf(stderr, " %10d (0x%08x): %dx%d+%d+%d (flags 0x%08x)\n",
(int)iter->id, (unsigned)iter->id,
iter->dimensions.width(), iter->dimensions.height(),
iter->dimensions.tl.x, iter->dimensions.tl.y,
(unsigned)iter->flags);
snprintf(buffer, sizeof(buffer),
" %10d (0x%08x): %dx%d+%d+%d (flags 0x%08x)\n",
(int)iter->id, (unsigned)iter->id,
iter->dimensions.width(), iter->dimensions.height(),
iter->dimensions.tl.x, iter->dimensions.tl.y,
(unsigned)iter->flags);
strncat(str, buffer, len - 1 - strlen(str));
}
};


+ 5
- 1
common/rfb/ServerCore.cxx View File

@@ -97,4 +97,8 @@ rfb::BoolParameter rfb::Server::queryConnect
("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);

+ 1
- 0
common/rfb/ServerCore.h View File

@@ -48,6 +48,7 @@ namespace rfb {
static BoolParameter sendCutText;
static BoolParameter acceptSetDesktopSize;
static BoolParameter queryConnect;
static IntParameter queryConnectTimeout;

};


+ 0
- 1
common/rfb/Timer.cxx View File

@@ -101,7 +101,6 @@ int Timer::checkTimeouts() {
while (pending.front()->isBefore(now)) {
Timer* timer = pending.front();
pending.pop_front();
vlog.debug("handleTimeout(%p)", timer);
if (timer->cb->handleTimeout(timer)) {
timer->dueTime = addMillis(timer->dueTime, timer->timeoutMs);
if (timer->isBefore(now)) {

+ 10
- 3
common/rfb/VNCSConnectionST.cxx View File

@@ -1,5 +1,5 @@
/* 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
@@ -66,7 +66,8 @@ struct RTTInfo {

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),
@@ -434,8 +435,10 @@ void VNCSConnectionST::queryConnection(const char* userName)
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);
@@ -714,6 +717,10 @@ bool VNCSConnectionST::handleTimeout(Timer* t)
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());
}

+ 2
- 0
common/rfb/VNCSConnectionST.h View File

@@ -174,6 +174,8 @@ namespace rfb {
network::Socket* sock;
CharArray peerEndpoint;

Timer queryConnectTimer;

bool inProcessMessages;

bool pendingSyncFence, syncFence;

unix/xserver/hw/vnc/Input.cc → unix/xserver/hw/vnc/Input.c View File

@@ -1,6 +1,6 @@
/* Copyright (C) 2009 TightVNC Team
* Copyright (C) 2009, 2014 Red Hat, Inc.
* 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
@@ -22,14 +22,11 @@
#include <dix-config.h>
#endif

#include <rfb/LogWriter.h>
#include "Input.h"
#include "xorg-version.h"

#include "Input.h"
#include "vncExtInit.h"

extern "C" {
#define public c_public
#define class c_class
#include "inputstr.h"
#if XORG >= 110
#include "inpututils.h"
@@ -51,26 +48,9 @@ extern _X_EXPORT DevPrivateKey CoreDevicePrivateKey;
#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;
@@ -78,9 +58,91 @@ static xEvent *eventq = NULL;
static EventList *eventq = NULL;
#endif

#if XORG < 111
static void initEventq(void)
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
@@ -92,45 +154,12 @@ static void initEventq(void)
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;
vncPrepareInputDevices();
}

void InputDevice::PointerButtonAction(int buttonMask)
void vncPointerButtonAction(int buttonMask)
{
int i;
#if XORG < 111
@@ -145,17 +174,19 @@ void InputDevice::PointerButtonAction(int buttonMask)
int action = (buttonMask & (1<<i)) ?
ButtonPress : ButtonRelease;
#if XORG < 110
n = GetPointerEvents(eventq, pointerDev, action, i + 1,
n = GetPointerEvents(eventq, vncPointerDev,
action, i + 1,
POINTER_RELATIVE, 0, 0, NULL);
enqueueEvents(pointerDev, n);
enqueueEvents(vncPointerDev, n);
#elif XORG < 111
valuator_mask_set_range(&mask, 0, 0, NULL);
n = GetPointerEvents(eventq, pointerDev, action, i + 1,
n = GetPointerEvents(eventq, vncPointerDev,
action, i + 1,
POINTER_RELATIVE, &mask);
enqueueEvents(pointerDev, n);
enqueueEvents(vncPointerDev, n);
#else
valuator_mask_set_range(&mask, 0, 0, NULL);
QueuePointerEvents(pointerDev, action, i + 1,
QueuePointerEvents(vncPointerDev, action, i + 1,
POINTER_RELATIVE, &mask);
#endif
}
@@ -164,7 +195,7 @@ void InputDevice::PointerButtonAction(int buttonMask)
oldButtonMask = buttonMask;
}

void InputDevice::PointerMove(const rfb::Point &pos)
void vncPointerMove(int x, int y)
{
int valuators[2];
#if XORG < 111
@@ -174,42 +205,64 @@ void InputDevice::PointerMove(const rfb::Point &pos)
ValuatorMask mask;
#endif

if (pos.equals(cursorPos))
if (cursorPosX == x && cursorPosY == y)
return;

valuators[0] = pos.x;
valuators[1] = pos.y;
valuators[0] = x;
valuators[1] = y;
#if XORG < 110
n = GetPointerEvents(eventq, pointerDev, MotionNotify, 0, POINTER_ABSOLUTE, 0,
2, valuators);
enqueueEvents(pointerDev, n);
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, pointerDev, MotionNotify, 0, POINTER_ABSOLUTE,
&mask);
enqueueEvents(pointerDev, n);
n = GetPointerEvents(eventq, vncPointerDev, MotionNotify, 0,
POINTER_ABSOLUTE, &mask);
enqueueEvents(vncPointerDev, n);
#else
valuator_mask_set_range(&mask, 0, 2, valuators);
QueuePointerEvents(pointerDev, MotionNotify, 0, POINTER_ABSOLUTE, &mask);
QueuePointerEvents(vncPointerDev, MotionNotify, 0,
POINTER_ABSOLUTE, &mask);
#endif

cursorPos = pos;
cursorPosX = x;
cursorPosY = y;
}

const rfb::Point &InputDevice::getPointerPos(void)
void vncGetPointerPos(int *x, int *y)
{
if (pointerDev != NULL) {
int x, y;
if (vncPointerDev != NULL)
GetSpritePosition(vncPointerDev, &cursorPosX, &cursorPosY);

GetSpritePosition (pointerDev, &x, &y);
cursorPos.x = x;
cursorPos.y = y;
}
*x = cursorPosX;
*y = cursorPosY;
}

#if XORG < 111
static void enqueueEvents(DeviceIntPtr dev, int n)
{
int i;

return cursorPos;
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 */

int InputDevice::pointerProc(DeviceIntPtr pDevice, int onoff)
static int vncPointerProc(DeviceIntPtr pDevice, int onoff)
{
BYTE map[BUTTONS + 1];
DevicePtr pDev = (DevicePtr)pDevice;
@@ -261,21 +314,21 @@ int InputDevice::pointerProc(DeviceIntPtr pDevice, int onoff)
pDev->on = FALSE;
break;
case DEVICE_CLOSE:
singleton.pointerDev = NULL;
vncPointerDev = NULL;
break;
}

return Success;
}

static void keyboardBell(int percent, DeviceIntPtr device, void * ctrl,
int class_)
static void vncKeyboardBell(int percent, DeviceIntPtr device,
void * ctrl, int class)
{
if (percent > 0)
vncBell();
}

int InputDevice::keyboardProc(DeviceIntPtr pDevice, int onoff)
static int vncKeyboardProc(DeviceIntPtr pDevice, int onoff)
{
#if XORG < 17
KeySymsRec keySyms;
@@ -286,7 +339,7 @@ int InputDevice::keyboardProc(DeviceIntPtr pDevice, int onoff)
switch (onoff) {
case DEVICE_INIT:
#if XORG < 17
GetInitKeyboardMap(&keySyms, modMap);
vncGetInitKeyboardMap(&keySyms, modMap);
#endif
InitKeyboardDeviceStruct(
#if XORG >= 17
@@ -294,7 +347,8 @@ int InputDevice::keyboardProc(DeviceIntPtr pDevice, int onoff)
#else
pDev, &keySyms, modMap,
#endif
keyboardBell, (KbdCtrlProcPtr)NoopDDA);
vncKeyboardBell,
(KbdCtrlProcPtr)NoopDDA);
break;
case DEVICE_ON:
pDev->on = TRUE;
@@ -303,67 +357,14 @@ int InputDevice::keyboardProc(DeviceIntPtr pDevice, int onoff)
pDev->on = FALSE;
break;
case DEVICE_CLOSE:
singleton.keyboardDev = NULL;
vncKeyboardDev = 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)
static inline void pressKey(DeviceIntPtr dev, int kc, Bool down, const char *msg)
{
int action;
#if XORG < 111
@@ -371,7 +372,7 @@ static inline void pressKey(DeviceIntPtr dev, int kc, bool down, const char *msg
#endif

if (msg != NULL)
vlog.debug("%s %d %s", msg, kc, down ? "down" : "up");
LOG_DEBUG("%s %d %s", msg, kc, down ? "down" : "up");

action = down ? KeyPress : KeyRelease;
#if XORG < 111
@@ -432,14 +433,14 @@ static struct altKeysym_t {
};

/*
* 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
* 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 InputDevice::keyEvent(rdr::U32 keysym, bool down)
void vncKeyboardEvent(KeySym keysym, int down)
{
int i;
unsigned state, new_state;
@@ -447,7 +448,8 @@ void InputDevice::keyEvent(rdr::U32 keysym, bool down)

unsigned level_three_mask;
KeyCode shift_press, level_three_press;
std::list<KeyCode> shift_release, level_three_release;
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
@@ -457,7 +459,7 @@ void InputDevice::keyEvent(rdr::U32 keysym, bool down)
for (i = 0;i < 256;i++) {
if (pressedKeys[i] == keysym) {
pressedKeys[i] = NoSymbol;
pressKey(keyboardDev, i, false, "keycode");
pressKey(vncKeyboardDev, i, FALSE, "keycode");
mieqProcessInputEvents();
return;
}
@@ -467,7 +469,7 @@ void InputDevice::keyEvent(rdr::U32 keysym, bool down)
* This can happen quite often as we ignore some
* key presses.
*/
vlog.debug("Unexpected release of keysym 0x%x", keysym);
LOG_DEBUG("Unexpected release of keysym 0x%x", keysym);
return;
}

@@ -479,9 +481,9 @@ void InputDevice::keyEvent(rdr::U32 keysym, bool down)
*/
mieqProcessInputEvents();

state = getKeyboardState();
state = vncGetKeyboardState();

keycode = keysymToKeycode(keysym, state, &new_state);
keycode = vncKeysymToKeycode(keysym, state, &new_state);

/* Try some equivalent keysyms if we couldn't find a perfect match */
if (keycode == 0) {
@@ -495,37 +497,37 @@ void InputDevice::keyEvent(rdr::U32 keysym, bool down)
else
continue;

keycode = keysymToKeycode(altsym, state, &new_state);
keycode = vncKeysymToKeycode(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)");
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 = addKeysym(keysym, state);
keycode = vncAddKeysym(keysym, state);
if (keycode == 0) {
vlog.error("Failure adding new keysym 0x%x", keysym);
LOG_ERROR("Failure adding new keysym 0x%x", keysym);
return;
}

vlog.info("Added unknown keysym 0x%x to keycode %d",
keysym, keycode);
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 = keysymToKeycode(keysym, state, &new_state);
keycode = vncKeysymToKeycode(keysym, state, &new_state);
if (keycode == 0) {
vlog.error("Newly added keysym 0x%x cannot be generated", keysym);
LOG_ERROR("Newly added keysym 0x%x cannot be generated", keysym);
return;
}
}
@@ -542,11 +544,11 @@ void InputDevice::keyEvent(rdr::U32 keysym, bool down)
* can use an alternative keysym.
*/
if (((state & ShiftMask) != (new_state & ShiftMask)) &&
avoidShiftNumLock && isAffectedByNumLock(keycode)) {
vncGetAvoidShiftNumLock() && vncIsAffectedByNumLock(keycode)) {
KeyCode keycode2;
unsigned new_state2;

vlog.debug("Finding alternative to keysym 0x%x to avoid fake shift for numpad", keysym);
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;
@@ -558,19 +560,19 @@ void InputDevice::keyEvent(rdr::U32 keysym, bool down)
else
continue;

keycode2 = keysymToKeycode(altsym, state, &new_state2);
keycode2 = vncKeysymToKeycode(altsym, state, &new_state2);
if (keycode2 == 0)
continue;

if (((state & ShiftMask) != (new_state2 & ShiftMask)) &&
isAffectedByNumLock(keycode2))
vncIsAffectedByNumLock(keycode2))
continue;

break;
}

if (i == sizeof(altKeysym)/sizeof(altKeysym[0]))
vlog.debug("No alternative keysym found");
LOG_DEBUG("No alternative keysym found");
else {
keycode = keycode2;
new_state = new_state2;
@@ -598,65 +600,64 @@ void InputDevice::keyEvent(rdr::U32 keysym, bool down)
* so we need to know what the mask is for level 3 shifts.
*/
if ((new_state & ~ShiftMask) != (state & ~ShiftMask))
level_three_mask = getLevelThreeMask();
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 = pressShift();
shift_press = vncPressShift();
if (shift_press == 0) {
vlog.error("Unable to find a modifier key for Shift");
LOG_ERROR("Unable to find a modifier key for Shift");
return;
}

pressKey(keyboardDev, shift_press, true, "temp shift");
pressKey(vncKeyboardDev, 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");
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 (iter = shift_release.begin();iter != shift_release.end();++iter)
pressKey(keyboardDev, *iter, false, "temp shift");
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 = pressLevelThree();
level_three_press = vncPressLevelThree();
if (level_three_press == 0) {
vlog.error("Unable to find a modifier key for ISO_Level3_Shift/Mode_Switch");
LOG_ERROR("Unable to find a modifier key for ISO_Level3_Shift/Mode_Switch");
return;
}

pressKey(keyboardDev, level_three_press, true, "temp level 3 shift");
pressKey(vncKeyboardDev, 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");
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 (iter = level_three_release.begin();iter != level_three_release.end();++iter)
pressKey(keyboardDev, *iter, false, "temp level 3 shift");
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(keyboardDev, keycode, true, "keycode");
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) {
vlog.error("Keysym 0x%x generated by both keys %d and %d", keysym, i, keycode);
LOG_ERROR("Keysym 0x%x generated by both keys %d and %d", keysym, i, keycode);
pressedKeys[i] = NoSymbol;
}
}
@@ -665,20 +666,18 @@ void InputDevice::keyEvent(rdr::U32 keysym, bool down)

/* 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");
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(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");
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");
}

/*

+ 24
- 89
unix/xserver/hw/vnc/Input.h View File

@@ -1,7 +1,7 @@
/* 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
@@ -23,109 +23,44 @@
#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

unix/xserver/hw/vnc/InputCore.cc → unix/xserver/hw/vnc/InputCore.c View File

@@ -1,6 +1,6 @@
/* Copyright (C) 2009 TightVNC Team
* Copyright (C) 2009 Red Hat, Inc.
* 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
@@ -25,9 +25,6 @@
#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
@@ -46,9 +43,8 @@ extern "C" {
#include <X11/XF86keysym.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#undef public
#undef class
}

extern DeviceIntPtr vncKeyboardDev;

#if XORG < 17

@@ -61,7 +57,7 @@ extern "C" {
#define MAX_KEY 255
#define MAP_LEN (MAX_KEY - MIN_KEY + 1)
#define KEYSYMS_PER_KEY 2
KeySym keyboardMap[MAP_LEN * KEYSYMS_PER_KEY] = {
static KeySym keyboardMap[MAP_LEN * KEYSYMS_PER_KEY] = {
NoSymbol, NoSymbol,
XK_Escape, NoSymbol,
XK_1, XK_exclam,
@@ -174,7 +170,7 @@ KeySym keyboardMap[MAP_LEN * KEYSYMS_PER_KEY] = {
XK_Menu, NoSymbol,
};

void InputDevice::GetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap)
void vncGetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap)
{
int i;

@@ -221,17 +217,17 @@ void InputDevice::GetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap)
keysyms->map = keyboardMap;
}

void InputDevice::PrepareInputDevices(void)
void vncPrepareInputDevices(void)
{
/* Don't need to do anything here */
}

unsigned InputDevice::getKeyboardState(void)
unsigned vncGetKeyboardState(void)
{
return keyboardDev->key->state;
return vncKeyboardDev->key->state;
}

unsigned InputDevice::getLevelThreeMask(void)
unsigned vncGetLevelThreeMask(void)
{
int i, j, k;

@@ -241,12 +237,12 @@ unsigned InputDevice::getLevelThreeMask(void)
int maxKeysPerMod;
CARD8 *modmap;

minKeyCode = keyboardDev->key->curKeySyms.minKeyCode;
mapWidth = keyboardDev->key->curKeySyms.mapWidth;
map = keyboardDev->key->curKeySyms.map;
minKeyCode = vncKeyboardDev->key->curKeySyms.minKeyCode;
mapWidth = vncKeyboardDev->key->curKeySyms.mapWidth;
map = vncKeyboardDev->key->curKeySyms.map;

maxKeysPerMod = keyboardDev->key->maxKeysPerModifier;
modmap = keyboardDev->key->modifierKeyMap;
maxKeysPerMod = vncKeyboardDev->key->maxKeysPerModifier;
modmap = vncKeyboardDev->key->modifierKeyMap;

for (i = 3; i < 8; i++) {
for (k = 0; k < maxKeysPerMod; k++) {
@@ -268,41 +264,44 @@ unsigned InputDevice::getLevelThreeMask(void)
return 0;
}

KeyCode InputDevice::pressShift(void)
KeyCode vncPressShift(void)
{
int maxKeysPerMod;

maxKeysPerMod = keyboardDev->key->maxKeysPerModifier;
return keyboardDev->key->modifierKeyMap[ShiftMapIndex * maxKeysPerMod];
maxKeysPerMod = vncKeyboardDev->key->maxKeysPerModifier;
return vncKeyboardDev->key->modifierKeyMap[ShiftMapIndex * maxKeysPerMod];
}

std::list<KeyCode> InputDevice::releaseShift(void)
size_t vncReleaseShift(KeyCode *keys, size_t maxKeys)
{
std::list<KeyCode> keys;

size_t count;
int maxKeysPerMod;

maxKeysPerMod = keyboardDev->key->maxKeysPerModifier;
count = 0;
maxKeysPerMod = vncKeyboardDev->key->maxKeysPerModifier;
for (int k = 0; k < maxKeysPerMod; k++) {
int keycode;
int index;

index = ShiftMapIndex * maxKeysPerMod + k;

keycode = keyboardDev->key->modifierKeyMap[index];
keycode = vncKeyboardDev->key->modifierKeyMap[index];
if (keycode == 0)
continue;

if (!IS_PRESSED(keyboardDev, keycode))
if (!IS_PRESSED(vncKeyboardDev, keycode))
continue;

keys.push_back(keycode);
if (count >= maxKeys)
return 0;

keys[count++] = keycode;
}

return keys;
return count;
}

KeyCode InputDevice::pressLevelThree(void)
KeyCode vncPressLevelThree(void)
{
unsigned mask, index;
int maxKeysPerMod;
@@ -312,41 +311,44 @@ KeyCode InputDevice::pressLevelThree(void)
return 0;

index = ffs(mask) - 1;
maxKeysPerMod = keyboardDev->key->maxKeysPerModifier;
return keyboardDev->key->modifierKeyMap[index * maxKeysPerMod];
maxKeysPerMod = vncKeyboardDev->key->maxKeysPerModifier;
return vncKeyboardDev->key->modifierKeyMap[index * maxKeysPerMod];
}

std::list<KeyCode> InputDevice::releaseLevelThree(void)
size_t vncReleaseLevelThree(KeyCode *keys, size_t maxKeys)
{
std::list<KeyCode> keys;

size_t count;
unsigned mask, msindex;
int maxKeysPerMod;

mask = getLevelThreeMask();
if (mask == 0)
return keys;
return 0;

msindex = ffs(mask) - 1;

maxKeysPerMod = keyboardDev->key->maxKeysPerModifier;
count = 0;
maxKeysPerMod = vncKeyboardDev->key->maxKeysPerModifier;
for (int k = 0; k < maxKeysPerMod; k++) {
int keycode;
int index;

index = msindex * maxKeysPerMod + k;

keycode = keyboardDev->key->modifierKeyMap[index];
keycode = vncKeyboardDev->key->modifierKeyMap[index];
if (keycode == 0)
continue;

if (!IS_PRESSED(keyboardDev, keycode))
if (!IS_PRESSED(vncKeyboardDev, keycode))
continue;

keys.push_back(keycode);
if (count >= maxKeys)
return 0;

keys[count++] = keycode;
}

return keys;
return count;
}

static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col)
@@ -397,7 +399,7 @@ static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col)
return syms[col];
}

KeyCode InputDevice::keysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state)
KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state)
{
int i, j;
unsigned mask;
@@ -405,9 +407,9 @@ KeyCode InputDevice::keysymToKeycode(KeySym keysym, unsigned state, unsigned *ne
KeySymsPtr keymap;
int mapWidth;

mask = getLevelThreeMask();
mask = vncGetLevelThreeMask();

keymap = &keyboardDev->key->curKeySyms;
keymap = &vncKeyboardDev->key->curKeySyms;

/*
* Column 0 means both shift and "mode_switch" (AltGr) must be released,
@@ -449,7 +451,7 @@ KeyCode InputDevice::keysymToKeycode(KeySym keysym, unsigned state, unsigned *ne
return 0;
}

bool InputDevice::isLockModifier(KeyCode keycode, unsigned state)
int vncIsLockModifier(KeyCode keycode, unsigned state)
{
int i, j, k;

@@ -461,12 +463,12 @@ bool InputDevice::isLockModifier(KeyCode keycode, unsigned state)

int num_lock_index;

minKeyCode = keyboardDev->key->curKeySyms.minKeyCode;
mapWidth = keyboardDev->key->curKeySyms.mapWidth;
map = keyboardDev->key->curKeySyms.map;
minKeyCode = vncKeyboardDev->key->curKeySyms.minKeyCode;
mapWidth = vncKeyboardDev->key->curKeySyms.mapWidth;
map = vncKeyboardDev->key->curKeySyms.map;

maxKeysPerMod = keyboardDev->key->maxKeysPerModifier;
modmap = keyboardDev->key->modifierKeyMap;
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++) {
@@ -474,7 +476,7 @@ bool InputDevice::isLockModifier(KeyCode keycode, unsigned state)

index = LockMapIndex * maxKeysPerMod + k;
if (keycode == modmap[index])
return true;
return 1;
}

/* For Num Lock we need to find the correct modmap entry */
@@ -500,7 +502,7 @@ bool InputDevice::isLockModifier(KeyCode keycode, unsigned state)
done:

if (num_lock_index == 0)
return false;
return 0;

/* Now we can look in the modmap */
for (k = 0; k < maxKeysPerMod; k++) {
@@ -508,43 +510,43 @@ done:

index = num_lock_index * maxKeysPerMod + k;
if (keycode == modmap[index])
return true;
return 1;
}

return false;
return 0;
}

bool InputDevice::isAffectedByNumLock(KeyCode keycode)
int vncIsAffectedByNumLock(KeyCode keycode)
{
KeySymsPtr keymap;
int i, per;
KeySym *syms;

keymap = &keyboardDev->key->curKeySyms;
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 true;
return 1;
if (IsPrivateKeypadKey(syms[i]))
return true;
return 1;
}

return false;
return 0;
}

KeyCode InputDevice::addKeysym(KeySym keysym, unsigned state)
KeyCode vncAddKeysym(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;
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
@@ -570,17 +572,17 @@ KeyCode InputDevice::addKeysym(KeySym keysym, unsigned state)
#if XORG == 15
master = inputInfo.keyboard;
#else
master = keyboardDev->u.master;
master = vncKeyboardDev->u.master;
#endif
void *slave = dixLookupPrivate(&master->devPrivates,
CoreDevicePrivateKey);
if (keyboardDev == slave) {
if (vncKeyboardDev == slave) {
dixSetPrivate(&master->devPrivates,
CoreDevicePrivateKey, NULL);
#if XORG == 15
SwitchCoreKeyboard(keyboardDev);
SwitchCoreKeyboard(vncKeyboardDev);
#else
CopyKeyClass(keyboardDev, master);
CopyKeyClass(vncKeyboardDev, master);
#endif
}


unix/xserver/hw/vnc/InputXKB.cc → unix/xserver/hw/vnc/InputXKB.c View File

@@ -1,6 +1,6 @@
/* Copyright (C) 2009 TightVNC Team
* Copyright (C) 2009 Red Hat, Inc.
* 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
@@ -22,30 +22,34 @@
#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 <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 <X11/keysym.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#undef public
#undef class
}

#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,
@@ -195,7 +199,7 @@ static unsigned XkbKeyEffectiveGroup(XkbDescPtr xkb, KeyCode key, unsigned int m
return effectiveGroup;
}

void InputDevice::PrepareInputDevices(void)
void vncPrepareInputDevices(void)
{
/*
* Not ideal since these callbacks do not stack, but it's the only
@@ -206,15 +210,15 @@ void InputDevice::PrepareInputDevices(void)
mieqSetHandler(ET_KeyRelease, vncXkbProcessDeviceEvent);
}

unsigned InputDevice::getKeyboardState(void)
unsigned vncGetKeyboardState(void)
{
DeviceIntPtr master;

master = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT);
master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
return XkbStateFieldFromRec(&master->key->xkbInfo->state);
}

unsigned InputDevice::getLevelThreeMask(void)
unsigned vncGetLevelThreeMask(void)
{
unsigned state;
KeyCode keycode;
@@ -222,17 +226,17 @@ unsigned InputDevice::getLevelThreeMask(void)
XkbAction *act;

/* Group state is still important */
state = getKeyboardState();
state = vncGetKeyboardState();
state &= ~0xff;

keycode = keysymToKeycode(XK_ISO_Level3_Shift, state, NULL);
keycode = vncKeysymToKeycode(XK_ISO_Level3_Shift, state, NULL);
if (keycode == 0) {
keycode = keysymToKeycode(XK_Mode_switch, state, NULL);
keycode = vncKeysymToKeycode(XK_Mode_switch, state, NULL);
if (keycode == 0)
return 0;
}

xkb = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;

act = XkbKeyActionPtr(xkb, keycode, state);
if (act == NULL)
@@ -246,18 +250,18 @@ unsigned InputDevice::getLevelThreeMask(void)
return act->mods.mask;
}

KeyCode InputDevice::pressShift(void)
KeyCode vncPressShift(void)
{
unsigned state;

XkbDescPtr xkb;
unsigned int key;

state = getKeyboardState();
state = vncGetKeyboardState();
if (state & ShiftMask)
return 0;

xkb = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
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;
@@ -281,20 +285,23 @@ KeyCode InputDevice::pressShift(void)
return 0;
}

std::list<KeyCode> InputDevice::releaseShift(void)
size_t vncReleaseShift(KeyCode *keys, size_t maxKeys)
{
size_t count;

unsigned state;
std::list<KeyCode> keys;

DeviceIntPtr master;
XkbDescPtr xkb;
unsigned int key;

state = getKeyboardState();
state = vncGetKeyboardState();
if (!(state & ShiftMask))
return keys;
return 0;

master = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT);
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;
@@ -318,13 +325,16 @@ std::list<KeyCode> InputDevice::releaseShift(void)
if (!(mask & ShiftMask))
continue;

keys.push_back(key);
if (count >= maxKeys)
return 0;

keys[count++] = key;
}

return keys;
return count;
}

KeyCode InputDevice::pressLevelThree(void)
KeyCode vncPressLevelThree(void)
{
unsigned state, mask;

@@ -332,22 +342,22 @@ KeyCode InputDevice::pressLevelThree(void)
XkbDescPtr xkb;
XkbAction *act;

mask = getLevelThreeMask();
mask = vncGetLevelThreeMask();
if (mask == 0)
return 0;

state = getKeyboardState();
state = vncGetKeyboardState();
if (state & mask)
return 0;

keycode = keysymToKeycode(XK_ISO_Level3_Shift, state, NULL);
keycode = vncKeysymToKeycode(XK_ISO_Level3_Shift, state, NULL);
if (keycode == 0) {
keycode = keysymToKeycode(XK_Mode_switch, state, NULL);
keycode = vncKeysymToKeycode(XK_Mode_switch, state, NULL);
if (keycode == 0)
return 0;
}

xkb = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;

act = XkbKeyActionPtr(xkb, keycode, state);
if (act == NULL)
@@ -358,24 +368,27 @@ KeyCode InputDevice::pressLevelThree(void)
return keycode;
}

std::list<KeyCode> InputDevice::releaseLevelThree(void)
size_t vncReleaseLevelThree(KeyCode *keys, size_t maxKeys)
{
size_t count;

unsigned state, mask;
std::list<KeyCode> keys;

DeviceIntPtr master;
XkbDescPtr xkb;
unsigned int key;

mask = getLevelThreeMask();
mask = vncGetLevelThreeMask();
if (mask == 0)
return keys;
return 0;

state = getKeyboardState();
state = vncGetKeyboardState();
if (!(state & mask))
return keys;
return 0;

master = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT);
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;
@@ -399,14 +412,16 @@ std::list<KeyCode> InputDevice::releaseLevelThree(void)
if (!(key_mask & mask))
continue;

keys.push_back(key);
if (count >= maxKeys)
return 0;

keys[count++] = key;
}

return keys;
return count;
}

KeyCode InputDevice::keysymToKeycode(KeySym keysym, unsigned state,
unsigned *new_state)
KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state)
{
XkbDescPtr xkb;
unsigned int key;
@@ -416,7 +431,7 @@ KeyCode InputDevice::keysymToKeycode(KeySym keysym, unsigned state,
if (new_state != NULL)
*new_state = state;

xkb = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
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;
@@ -444,48 +459,48 @@ KeyCode InputDevice::keysymToKeycode(KeySym keysym, unsigned state,

*new_state = (state & ~ShiftMask) |
((state & ShiftMask) ? 0 : ShiftMask);
key = keysymToKeycode(keysym, *new_state, NULL);
key = vncKeysymToKeycode(keysym, *new_state, NULL);
if (key != 0)
return key;

level_three_mask = getLevelThreeMask();
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 = keysymToKeycode(keysym, *new_state, NULL);
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 = keysymToKeycode(keysym, *new_state, NULL);
key = vncKeysymToKeycode(keysym, *new_state, NULL);
if (key != 0)
return key;

return 0;
}

bool InputDevice::isLockModifier(KeyCode keycode, unsigned state)
int vncIsLockModifier(KeyCode keycode, unsigned state)
{
XkbDescPtr xkb;
XkbAction *act;

xkb = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;

act = XkbKeyActionPtr(xkb, keycode, state);
if (act == NULL)
return false;
return 0;

if (act->type != XkbSA_LockMods)
return false;
return 0;

return true;
return 1;
}

bool InputDevice::isAffectedByNumLock(KeyCode keycode)
int vncIsAffectedByNumLock(KeyCode keycode)
{
unsigned state;

@@ -499,7 +514,7 @@ bool InputDevice::isAffectedByNumLock(KeyCode keycode)
XkbKeyTypeRec *type;

/* Group state is still important */
state = getKeyboardState();
state = vncGetKeyboardState();
state &= ~0xff;

/*
@@ -507,17 +522,17 @@ bool InputDevice::isAffectedByNumLock(KeyCode keycode)
* or following the keysym Num_Lock is the best approach. We
* try the latter.
*/
numlock_keycode = keysymToKeycode(XK_Num_Lock, state, NULL);
numlock_keycode = vncKeysymToKeycode(XK_Num_Lock, state, NULL);
if (numlock_keycode == 0)
return false;
return 0;

xkb = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;

act = XkbKeyActionPtr(xkb, numlock_keycode, state);
if (act == NULL)
return false;
return 0;
if (act->type != XkbSA_LockMods)
return false;
return 0;

if (act->mods.flags & XkbSA_UseModMapMods)
numlock_mask = xkb->map->modmap[keycode];
@@ -527,12 +542,12 @@ bool InputDevice::isAffectedByNumLock(KeyCode keycode)
group = XkbKeyEffectiveGroup(xkb, keycode, state);
type = XkbKeyKeyType(xkb, keycode, group);
if ((type->mods.mask & numlock_mask) == 0)
return false;
return 0;

return true;
return 1;
}

KeyCode InputDevice::addKeysym(KeySym keysym, unsigned state)
KeyCode vncAddKeysym(KeySym keysym, unsigned state)
{
DeviceIntPtr master;
XkbDescPtr xkb;
@@ -545,7 +560,7 @@ KeyCode InputDevice::addKeysym(KeySym keysym, unsigned state)
KeySym *syms;
KeySym upper, lower;

master = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT);
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)
@@ -608,13 +623,13 @@ KeyCode InputDevice::addKeysym(KeySym keysym, unsigned state)
return key;
}

void InputDevice::vncXkbProcessDeviceEvent(int screenNum,
InternalEvent *event,
DeviceIntPtr dev)
static void vncXkbProcessDeviceEvent(int screenNum,
InternalEvent *event,
DeviceIntPtr dev)
{
unsigned int backupctrls;

if (event->device_event.sourceid == singleton.keyboardDev->id) {
if (event->device_event.sourceid == vncKeyboardDev->id) {
XkbControlsPtr ctrls;

/*
@@ -634,9 +649,9 @@ void InputDevice::vncXkbProcessDeviceEvent(int screenNum,
event->device_event.key_repeat = TRUE;
}

dev->c_public.processInputProc(event, dev);
dev->public.processInputProc(event, dev);

if (event->device_event.sourceid == singleton.keyboardDev->id) {
if (event->device_event.sourceid == vncKeyboardDev->id) {
XkbControlsPtr ctrls;

ctrls = dev->key->xkbInfo->desc->ctrls;

+ 9
- 29
unix/xserver/hw/vnc/Makefile.am View File

@@ -9,11 +9,14 @@ COMMON_LIBS=$(NETWORK_LIB) $(RFB_LIB) $(RDR_LIB) $(XREGION_LIB)

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 \
@@ -24,12 +27,10 @@ bin_PROGRAMS = Xvnc

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)" \
@@ -44,7 +45,7 @@ Xvnc_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG)
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 \
@@ -58,24 +59,3 @@ libvnc_la_LDFLAGS = -module -avoid-version
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

+ 195
- 0
unix/xserver/hw/vnc/RFBGlue.cc View File

@@ -0,0 +1,195 @@
/* 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;
}

+ 56
- 0
unix/xserver/hw/vnc/RFBGlue.h View File

@@ -0,0 +1,56 @@
/* 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

+ 0
- 84
unix/xserver/hw/vnc/RegionHelper.h View File

@@ -1,84 +0,0 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __REGIONHELPER_H__
#define __REGIONHELPER_H__

// RegionHelper is a class which helps in using X server regions by
// automatically freeing them in the destructor. It also fixes a problem with
// REGION_INIT when given an empty rectangle.

// REGION_NULL was introduced in the Xorg tree as the way to initialise an
// empty region. If it's not already defined do it the old way. Note that the
// old way causes a segfault in the new tree...
#ifndef REGION_NULL
#define REGION_NULL(pScreen,pReg) REGION_INIT(pScreen,pReg,NullBox,0)
#endif

class RegionHelper {
public:

// constructor from a single rect
RegionHelper(ScreenPtr pScreen_, BoxPtr rect, int size)
: pScreen(pScreen_), reg(0)
{
init(rect, size);
}

// constructor from an existing X server region
RegionHelper(ScreenPtr pScreen_, RegionPtr pRegion)
: pScreen(pScreen_), reg(&regRec)
{
REGION_NULL(pScreen, reg);
REGION_COPY(pScreen, reg, pRegion);
}

// constructor from an array of rectangles
RegionHelper(ScreenPtr pScreen_, int nrects, xRectanglePtr rects,
int ctype=CT_NONE)
: pScreen(pScreen_)
{
reg = RECTS_TO_REGION(pScreen, nrects, rects, ctype);
}

// constructor for calling init() later
RegionHelper(ScreenPtr pScreen_) : pScreen(pScreen_), reg(0) {
}

void init(BoxPtr rect, int size) {
reg = &regRec;
if (!rect || (rect && (rect->x2 == rect->x1 || rect->y2 == rect->y1))) {
REGION_NULL(pScreen, reg);
} else {
REGION_INIT(pScreen, reg, rect, size);
}
}

// destructor frees as appropriate
~RegionHelper() {
if (reg == &regRec) {
REGION_UNINIT(pScreen, reg);
} else if (reg) {
REGION_DESTROY(pScreen, reg);
}
}
ScreenPtr pScreen;
RegionRec regRec;
RegionPtr reg;
};

#endif

+ 362
- 0
unix/xserver/hw/vnc/XorgGlue.c View File

@@ -0,0 +1,362 @@
/* 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
}

+ 67
- 0
unix/xserver/hw/vnc/XorgGlue.h View File

@@ -0,0 +1,67 @@
/* 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

+ 166
- 387
unix/xserver/hw/vnc/XserverDesktop.cc View File

@@ -1,5 +1,5 @@
/* 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
@@ -21,12 +21,9 @@
// 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>
@@ -34,65 +31,29 @@
#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) {}
@@ -132,22 +93,22 @@ public:
};


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)
@@ -206,25 +167,21 @@ void XserverDesktop::refreshScreenLayout()
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;
@@ -239,52 +196,28 @@ ScreenSet XserverDesktop::computeScreenLayout()
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) {
@@ -325,7 +258,7 @@ char* XserverDesktop::substitute(const char* varName)
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) {
@@ -338,17 +271,28 @@ char* XserverDesktop::substitute(const char* varName)
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;
}

@@ -375,148 +319,77 @@ void XserverDesktop::setDesktopName(const char* name)
}
}

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 &region)
{
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;
@@ -565,9 +438,9 @@ void XserverDesktop::blockHandler(fd_set* fds, OSTimePtr timeout)
((*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;
}
}

@@ -576,7 +449,7 @@ void XserverDesktop::blockHandler(fd_set* fds, OSTimePtr timeout)
}
}

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
@@ -625,8 +498,11 @@ void XserverDesktop::wakeupHandler(fd_set* fds, int nfds)
}

// 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);
}
}
@@ -639,7 +515,7 @@ void XserverDesktop::wakeupHandler(fd_set* fds, int nfds)
}
}

void XserverDesktop::writeBlockHandler(fd_set* fds)
void XserverDesktop::writeBlockHandler(fd_set* fds, struct timeval ** timeout)
{
try {
std::list<Socket*> sockets;
@@ -724,26 +600,29 @@ void XserverDesktop::disconnectClients()
}


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;
}
}
@@ -755,8 +634,8 @@ void XserverDesktop::approveConnection(void* opaqueId, bool accept,

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)
@@ -764,79 +643,50 @@ 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;

char buffer[2048];
vlog.debug("Got request for framebuffer resize to %dx%d",
fb_width, fb_height);
layout.print(buffer, sizeof(buffer));
vlog.debug("%s", buffer);

/*
* 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;
}
vlog.debug("Insufficient screens. Need to create %d more.",
layout.num_screens() - availableOutputs);
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;
@@ -844,27 +694,17 @@ unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
}

/* 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])
@@ -874,37 +714,25 @@ unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
/* 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;
@@ -915,11 +743,7 @@ unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
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? */
@@ -932,53 +756,24 @@ unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
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
@@ -987,11 +782,14 @@ unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
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;
@@ -1003,50 +801,31 @@ unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
* 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);
}

+ 23
- 38
unix/xserver/hw/vnc/XserverDesktop.h View File

@@ -1,5 +1,5 @@
/* 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
@@ -29,6 +29,8 @@

#include <map>

#include <stdint.h>

#include <rfb/SDesktop.h>
#include <rfb/HTTPServer.h>
#include <rfb/PixelBuffer.h>
@@ -37,16 +39,6 @@
#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;
}
@@ -58,10 +50,10 @@ class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer,
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
@@ -72,31 +64,27 @@ public:
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 &region);
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
@@ -120,26 +108,23 @@ public:

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


+ 143
- 0
unix/xserver/hw/vnc/vncBlockHandler.c View File

@@ -0,0 +1,143 @@
/* 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);
}

+ 33
- 0
unix/xserver/hw/vnc/vncBlockHandler.h View File

@@ -0,0 +1,33 @@
/* 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

+ 771
- 0
unix/xserver/hw/vnc/vncExt.c View File

@@ -0,0 +1,771 @@
/* 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);
}


+ 156
- 947
unix/xserver/hw/vnc/vncExtInit.cc
File diff suppressed because it is too large
View File


+ 67
- 10
unix/xserver/hw/vnc/vncExtInit.h View File

@@ -1,4 +1,5 @@
/* 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
@@ -18,21 +19,77 @@
#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

unix/xserver/hw/vnc/vncHooks.c
File diff suppressed because it is too large
View File


+ 10
- 5
unix/xserver/hw/vnc/vncHooks.h View File

@@ -1,4 +1,5 @@
/* 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
@@ -18,13 +19,17 @@
#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

unix/xserver/hw/vnc/xf86vncModule.cc → unix/xserver/hw/vnc/vncModule.c View File

@@ -1,4 +1,5 @@
/* 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
@@ -22,41 +23,26 @@
#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 "opaque.h"
#ifdef RANDR
#include "randrstr.h"
#endif

#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);
#include "vncExtInit.h"
#include "RFBGlue.h"

char *listenaddr = NULL;
static void vncModuleInit(INITARGS);

static MODULESETUPPROTO(vncSetup);

ExtensionModule vncExt =
{
vncExtensionInitWithParams,
vncModuleInit,
"VNC",
#if XORG < 112
NULL,
@@ -92,42 +78,39 @@ vncSetup(void * module, void * opts, int *errmaj, int *errmin) {
return (void *)1;
}

static void vncExtensionInitWithParams(INITARGS)
static void vncModuleInit(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];
vncInitRFB();

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);
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;
}

RROutputPtr vncRandROutputCreate(ScreenPtr pScreen)
int vncRandRCreateOutputs(int scrIdx, int extraOutputs)
{
return NULL;
return -1;
}
#endif

unix/xserver/hw/vnc/xvnc.cc → unix/xserver/hw/vnc/xvnc.c View File

@@ -1,6 +1,6 @@
/* Copyright (c) 1993 X Consortium
Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
Copyright 2009 Pierre Ossman for Cendio AB
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
@@ -32,16 +32,10 @@ from the X Consortium.
#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 "RFBGlue.h"
#include "xorg-version.h"

extern "C" {
#define class c_class
#define public c_public
#ifdef WIN32
#include <X11/Xwinsock.h>
#endif
@@ -61,9 +55,7 @@ extern "C" {
#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>
@@ -89,9 +81,6 @@ extern "C" {
#include "version-config.h"
#endif
#include "site.h"
#undef class
#undef public
}

#if XORG >= 110
#define Xalloc malloc
@@ -164,11 +153,9 @@ static fbMemType fbmemtype = NORMAL_MEMORY_FB;
static int lastScreen = -1;
static Bool Render = TRUE;

static bool displaySpecified = false;
static Bool displaySpecified = FALSE;
static char displayNumStr[16];

char *listenaddr = NULL;

static int vncVerbose = DEFAULT_LOG_VERBOSITY;


@@ -212,8 +199,6 @@ vfbBitsPerPixel(int depth)

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
@@ -325,7 +310,6 @@ ddxUseMsg()
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");
@@ -338,8 +322,7 @@ ddxUseMsg()
"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);
}
vncListParams(79, 14);
}

/* ddxInitGlobals - called by |InitGlobals| from os/util.c */
@@ -348,21 +331,21 @@ void ddxInitGlobals(void)
}

static
bool displayNumFree(int num)
Bool displayNumFree(int num)
{
try {
network::TcpListener l(NULL, 6000+num);
} catch (rdr::Exception& e) {
return false;
}
char file[256];
if (vncIsTCPPortUsed(6000+num))
return FALSE;
sprintf(file, "/tmp/.X%d-lock", num);
if (access(file, F_OK) == 0) return false;
if (access(file, F_OK) == 0)
return FALSE;
sprintf(file, "/tmp/.X11-unix/X%d", num);
if (access(file, F_OK) == 0) return false;
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;
if (access(file, F_OK) == 0)
return FALSE;
return TRUE;
}

int
@@ -375,13 +358,11 @@ ddxProcessArgument(int argc, char *argv[], int i)
vfbInitializeDefaultScreens();
vfbInitializePixmapDepths();
firstTime = FALSE;
rfb::initStdIOLoggers();
rfb::LogWriter::setLogParams("*:stderr:30");
rfb::Configuration::enableServerParams();
vncInitRFB();
}

if (argv[i][0] == ':')
displaySpecified = true;
displaySpecified = TRUE;

if (strcmp (argv[i], "-screen") == 0) /* -screen n WxHxD */
{
@@ -574,7 +555,7 @@ ddxProcessArgument(int argc, char *argv[], int i)
close(2);
if (!displaySpecified) {
int port = network::TcpSocket::getSockPort(vncInetdSock);
int port = vncGetSocketPort(vncInetdSock);
int displayNum = port - 5900;
if (displayNum < 0 || displayNum > 99 || !displayNumFree(displayNum)) {
for (displayNum = 1; displayNum < 100; displayNum++)
@@ -591,25 +572,8 @@ ddxProcessArgument(int argc, char *argv[], int i)
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;
vncNoClipboard = 1;
return 1;
}

@@ -636,11 +600,11 @@ ddxProcessArgument(int argc, char *argv[], int i)
return 1;
}

if (rfb::Configuration::setParam(argv[i]))
if (vncSetParamSimple(argv[i]))
return 1;
if (argv[i][0] == '-' && i+1 < argc) {
if (rfb::Configuration::setParam(&argv[i][1], argv[i+1]))
if (vncSetParam(&argv[i][1], argv[i+1]))
return 2;
}
@@ -1337,15 +1301,18 @@ static RRCrtcPtr vncRandRCrtcCreate(ScreenPtr pScreen)
}

/* Used from XserverDesktop when it needs more outputs... */
RROutputPtr vncRandROutputCreate(ScreenPtr pScreen)
int vncRandRCreateOutputs(int scrIdx, int extraOutputs)
{
RRCrtcPtr crtc;

crtc = vncRandRCrtcCreate(pScreen);
if (crtc == NULL)
return NULL;
while (extraOutputs > 0) {
crtc = vncRandRCrtcCreate(screenInfo.screens[scrIdx]);
if (crtc == NULL)
return -1;
extraOutputs--;
}

return crtc->outputs[0];
return 0;
}

static Bool vncRandRInit(ScreenPtr pScreen)
@@ -1596,13 +1563,13 @@ vfbScreenInit(ScreenPtr pScreen, int argc, char **argv)
} /* end vfbScreenInit */


static void vfbClientStateChange(CallbackListPtr*, void *, void *) {
static void vfbClientStateChange(CallbackListPtr *a, void *b, void *c) {
dispatchException &= ~DE_RESET;
}
#if XORG >= 113
#ifdef GLXEXT
extern "C" void GlxExtensionInit(void);
extern void GlxExtensionInit(void);

static ExtensionModule glxExt = {
GlxExtensionInit,
@@ -1615,11 +1582,12 @@ static ExtensionModule glxExt = {
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);
int i;
int NumFormats = 0;

#if XORG >= 113
#ifdef GLXEXT
@@ -1722,3 +1690,11 @@ void CloseInput(void)
{
}
#endif

void vncClientGone(int fd)
{
if (fd == vncInetdSock) {
ErrorF("inetdSock client gone\n");
GiveUp(0);
}
}

+ 5
- 2
vncviewer/DesktopWindow.cxx View File

@@ -798,8 +798,11 @@ void DesktopWindow::remoteResize(int width, int height)
(layout == cc->cp.screenLayout))
return;

vlog.debug("Requesting framebuffer resize from %dx%d to %dx%d (%d screens)",
cc->cp.width, cc->cp.height, width, height, layout.num_screens());
char buffer[2048];
vlog.debug("Requesting framebuffer resize from %dx%d to %dx%d",
cc->cp.width, cc->cp.height, width, height);
layout.print(buffer, sizeof(buffer));
vlog.debug("%s", buffer);

if (!layout.validate(width, height)) {
vlog.error(_("Invalid screen layout computed for resize request!"));

Loading…
Cancel
Save