From f8e3b34c69b848781b958c7a4d21175ddc6f90d8 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 26 Jan 2015 14:37:04 +0100 Subject: [PATCH] Restructure Xvnc/libvnc.so code to avoid C++ header hacks The internal Xorg headers are very incompatible with C++ and we've had to resort to all kinds of hacks in order to include them in our C++ code. This approach isn't really viable long term so restructure things so that we have a glue layer written in C that bridges the Xorg core with the RFB classes. --- common/rfb/ServerCore.cxx | 6 +- common/rfb/ServerCore.h | 1 + common/rfb/VNCSConnectionST.cxx | 13 +- common/rfb/VNCSConnectionST.h | 2 + unix/xserver/hw/vnc/{Input.cc => Input.c} | 411 +++--- unix/xserver/hw/vnc/Input.h | 113 +- .../hw/vnc/{InputCore.cc => InputCore.c} | 138 ++- .../hw/vnc/{InputXKB.cc => InputXKB.c} | 161 +-- unix/xserver/hw/vnc/Makefile.am | 41 +- unix/xserver/hw/vnc/RFBGlue.cc | 195 +++ unix/xserver/hw/vnc/RFBGlue.h | 56 + unix/xserver/hw/vnc/RegionHelper.h | 84 -- unix/xserver/hw/vnc/XorgGlue.c | 362 ++++++ unix/xserver/hw/vnc/XorgGlue.h | 67 + unix/xserver/hw/vnc/XserverDesktop.cc | 545 +++----- unix/xserver/hw/vnc/XserverDesktop.h | 61 +- unix/xserver/hw/vnc/vncBlockHandler.c | 143 +++ unix/xserver/hw/vnc/vncBlockHandler.h | 33 + unix/xserver/hw/vnc/vncExt.c | 771 ++++++++++++ unix/xserver/hw/vnc/vncExtInit.cc | 1103 +++-------------- unix/xserver/hw/vnc/vncExtInit.h | 77 +- .../hw/vnc/{vncHooks.cc => vncHooks.c} | 1081 ++++++++++------ unix/xserver/hw/vnc/vncHooks.h | 15 +- .../hw/vnc/{xf86vncModule.cc => vncModule.c} | 65 +- unix/xserver/hw/vnc/{xvnc.cc => xvnc.c} | 106 +- 25 files changed, 3195 insertions(+), 2455 deletions(-) rename unix/xserver/hw/vnc/{Input.cc => Input.c} (62%) rename unix/xserver/hw/vnc/{InputCore.cc => InputCore.c} (79%) rename unix/xserver/hw/vnc/{InputXKB.cc => InputXKB.c} (81%) create mode 100644 unix/xserver/hw/vnc/RFBGlue.cc create mode 100644 unix/xserver/hw/vnc/RFBGlue.h delete mode 100644 unix/xserver/hw/vnc/RegionHelper.h create mode 100644 unix/xserver/hw/vnc/XorgGlue.c create mode 100644 unix/xserver/hw/vnc/XorgGlue.h create mode 100644 unix/xserver/hw/vnc/vncBlockHandler.c create mode 100644 unix/xserver/hw/vnc/vncBlockHandler.h create mode 100644 unix/xserver/hw/vnc/vncExt.c rename unix/xserver/hw/vnc/{vncHooks.cc => vncHooks.c} (72%) rename unix/xserver/hw/vnc/{xf86vncModule.cc => vncModule.c} (65%) rename unix/xserver/hw/vnc/{xvnc.cc => xvnc.c} (96%) diff --git a/common/rfb/ServerCore.cxx b/common/rfb/ServerCore.cxx index b11a352a..6e221d53 100644 --- a/common/rfb/ServerCore.cxx +++ b/common/rfb/ServerCore.cxx @@ -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); diff --git a/common/rfb/ServerCore.h b/common/rfb/ServerCore.h index 5fc996ff..c4d7d537 100644 --- a/common/rfb/ServerCore.h +++ b/common/rfb/ServerCore.h @@ -48,6 +48,7 @@ namespace rfb { static BoolParameter sendCutText; static BoolParameter acceptSetDesktopSize; static BoolParameter queryConnect; + static IntParameter queryConnectTimeout; }; diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx index e30b4f42..746bb901 100644 --- a/common/rfb/VNCSConnectionST.cxx +++ b/common/rfb/VNCSConnectionST.cxx @@ -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()); } diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h index fd1897a6..7b25570d 100644 --- a/common/rfb/VNCSConnectionST.h +++ b/common/rfb/VNCSConnectionST.h @@ -174,6 +174,8 @@ namespace rfb { network::Socket* sock; CharArray peerEndpoint; + Timer queryConnectTimer; + bool inProcessMessages; bool pendingSyncFence, syncFence; diff --git a/unix/xserver/hw/vnc/Input.cc b/unix/xserver/hw/vnc/Input.c similarity index 62% rename from unix/xserver/hw/vnc/Input.cc rename to unix/xserver/hw/vnc/Input.c index 3aae5dbf..db9bf660 100644 --- a/unix/xserver/hw/vnc/Input.cc +++ b/unix/xserver/hw/vnc/Input.c @@ -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 #endif -#include -#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 #include #include -#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<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 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::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::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::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::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"); } /* diff --git a/unix/xserver/hw/vnc/Input.h b/unix/xserver/hw/vnc/Input.h index 90b392cf..11e88710 100644 --- a/unix/xserver/hw/vnc/Input.h +++ b/unix/xserver/hw/vnc/Input.h @@ -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 -#endif - -#include - -#include -#include +#include +#include +#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 releaseShift(void); +unsigned vncGetKeyboardState(void); +unsigned vncGetLevelThreeMask(void); - KeyCode pressLevelThree(void); - std::list 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 diff --git a/unix/xserver/hw/vnc/InputCore.cc b/unix/xserver/hw/vnc/InputCore.c similarity index 79% rename from unix/xserver/hw/vnc/InputCore.cc rename to unix/xserver/hw/vnc/InputCore.c index b565c734..04677665 100644 --- a/unix/xserver/hw/vnc/InputCore.cc +++ b/unix/xserver/hw/vnc/InputCore.c @@ -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 #include #include -#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 InputDevice::releaseShift(void) +size_t vncReleaseShift(KeyCode *keys, size_t maxKeys) { - std::list 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 InputDevice::releaseLevelThree(void) +size_t vncReleaseLevelThree(KeyCode *keys, size_t maxKeys) { - std::list 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 } diff --git a/unix/xserver/hw/vnc/InputXKB.cc b/unix/xserver/hw/vnc/InputXKB.c similarity index 81% rename from unix/xserver/hw/vnc/InputXKB.cc rename to unix/xserver/hw/vnc/InputXKB.c index 92288aa4..e639d5ee 100644 --- a/unix/xserver/hw/vnc/InputXKB.cc +++ b/unix/xserver/hw/vnc/InputXKB.c @@ -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 #endif -#include "Input.h" #include "xorg-version.h" #if XORG >= 17 -extern "C" { -#define public c_public -#define class c_class +#include + +#include +#include +#include + #include "xkbsrv.h" #include "xkbstr.h" #include "eventstr.h" #include "scrnintstr.h" #include "mi.h" -#include -#include -#include -#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 InputDevice::releaseShift(void) +size_t vncReleaseShift(KeyCode *keys, size_t maxKeys) { + size_t count; + unsigned state; - std::list 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 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 InputDevice::releaseLevelThree(void) +size_t vncReleaseLevelThree(KeyCode *keys, size_t maxKeys) { + size_t count; + unsigned state, mask; - std::list 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 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; diff --git a/unix/xserver/hw/vnc/Makefile.am b/unix/xserver/hw/vnc/Makefile.am index 372a57f5..902aabf3 100644 --- a/unix/xserver/hw/vnc/Makefile.am +++ b/unix/xserver/hw/vnc/Makefile.am @@ -7,16 +7,16 @@ NETWORK_LIB=$(LIB_DIR)/network/libnetwork.la XREGION_LIB=$(LIB_DIR)/Xregion/libXregion.la COMMON_LIBS=$(NETWORK_LIB) $(RFB_LIB) $(RDR_LIB) $(XREGION_LIB) -# Hack to get the C headers to work when included from C++ code -AM_CXXFLAGS = -fpermissive - noinst_LTLIBRARIES = libvnccommon.la -HDRS = RegionHelper.h vncExtInit.h vncHooks.h XserverDesktop.h xorg-version.h \ - Input.h +HDRS = vncExtInit.h vncHooks.h \ + vncBlockHandler.h XorgGlue.h \ + XserverDesktop.h xorg-version.h \ + Input.h RFBGlue.h -libvnccommon_la_SOURCES = $(HDRS) vncExtInit.cc vncHooks.cc XserverDesktop.cc \ - Input.cc InputCore.cc InputXKB.cc +libvnccommon_la_SOURCES = $(HDRS) vncExt.c vncExtInit.cc vncHooks.c \ + vncBlockHandler.c XorgGlue.c RFBGlue.cc XserverDesktop.cc \ + Input.c InputCore.c InputXKB.c libvnccommon_la_CPPFLAGS = -DVENDOR_RELEASE="$(VENDOR_RELEASE)" \ -DVENDOR_STRING="\"$(VENDOR_STRING)\"" -I$(TIGERVNC_SRCDIR)/common -UHAVE_CONFIG_H \ @@ -27,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)" \ @@ -47,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 \ @@ -61,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 diff --git a/unix/xserver/hw/vnc/RFBGlue.cc b/unix/xserver/hw/vnc/RFBGlue.cc new file mode 100644 index 00000000..7747d888 --- /dev/null +++ b/unix/xserver/hw/vnc/RFBGlue.cc @@ -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 + +#include +#include +#include +#include + +#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; +} diff --git a/unix/xserver/hw/vnc/RFBGlue.h b/unix/xserver/hw/vnc/RFBGlue.h new file mode 100644 index 00000000..a63afd07 --- /dev/null +++ b/unix/xserver/hw/vnc/RFBGlue.h @@ -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 diff --git a/unix/xserver/hw/vnc/RegionHelper.h b/unix/xserver/hw/vnc/RegionHelper.h deleted file mode 100644 index 61dc89ff..00000000 --- a/unix/xserver/hw/vnc/RegionHelper.h +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -#ifndef __REGIONHELPER_H__ -#define __REGIONHELPER_H__ - -// RegionHelper is a class which helps in using X server regions by -// automatically freeing them in the destructor. It also fixes a problem with -// REGION_INIT when given an empty rectangle. - -// REGION_NULL was introduced in the Xorg tree as the way to initialise an -// empty region. If it's not already defined do it the old way. Note that the -// old way causes a segfault in the new tree... -#ifndef REGION_NULL -#define REGION_NULL(pScreen,pReg) REGION_INIT(pScreen,pReg,NullBox,0) -#endif - -class RegionHelper { -public: - - // constructor from a single rect - RegionHelper(ScreenPtr pScreen_, BoxPtr rect, int size) - : pScreen(pScreen_), reg(0) - { - init(rect, size); - } - - // constructor from an existing X server region - RegionHelper(ScreenPtr pScreen_, RegionPtr pRegion) - : pScreen(pScreen_), reg(®Rec) - { - REGION_NULL(pScreen, reg); - REGION_COPY(pScreen, reg, pRegion); - } - - // constructor from an array of rectangles - RegionHelper(ScreenPtr pScreen_, int nrects, xRectanglePtr rects, - int ctype=CT_NONE) - : pScreen(pScreen_) - { - reg = RECTS_TO_REGION(pScreen, nrects, rects, ctype); - } - - // constructor for calling init() later - RegionHelper(ScreenPtr pScreen_) : pScreen(pScreen_), reg(0) { - } - - void init(BoxPtr rect, int size) { - reg = ®Rec; - if (!rect || (rect && (rect->x2 == rect->x1 || rect->y2 == rect->y1))) { - REGION_NULL(pScreen, reg); - } else { - REGION_INIT(pScreen, reg, rect, size); - } - } - - // destructor frees as appropriate - ~RegionHelper() { - if (reg == ®Rec) { - REGION_UNINIT(pScreen, reg); - } else if (reg) { - REGION_DESTROY(pScreen, reg); - } - } - ScreenPtr pScreen; - RegionRec regRec; - RegionPtr reg; -}; - -#endif diff --git a/unix/xserver/hw/vnc/XorgGlue.c b/unix/xserver/hw/vnc/XorgGlue.c new file mode 100644 index 00000000..630d67df --- /dev/null +++ b/unix/xserver/hw/vnc/XorgGlue.c @@ -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 +#endif + +#include + +#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 +} diff --git a/unix/xserver/hw/vnc/XorgGlue.h b/unix/xserver/hw/vnc/XorgGlue.h new file mode 100644 index 00000000..abca48d4 --- /dev/null +++ b/unix/xserver/hw/vnc/XorgGlue.h @@ -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 diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc index 3ab11034..3774b7f6 100644 --- a/unix/xserver/hw/vnc/XserverDesktop.cc +++ b/unix/xserver/hw/vnc/XserverDesktop.cc @@ -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 -#endif - #include #include +#include #include #include #include @@ -34,65 +31,29 @@ #include #include #include + #include #include #include #include #include #include +#include + #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 ®ion) { - if (ignoreHooks_) return; - if (grabbing) return; try { - rfb::Region rfbReg; - rfbReg.setExtentsAndOrderedRects((ShortRect*)REGION_EXTENTS(pScreen, reg), - REGION_NUM_RECTS(reg), - (ShortRect*)REGION_RECTS(reg)); - server->add_changed(rfbReg); + server->add_changed(region); } catch (rdr::Exception& e) { vlog.error("XserverDesktop::add_changed: %s",e.str()); } } -void XserverDesktop::add_copied(RegionPtr dst, int dx, int dy) +void XserverDesktop::add_copied(const rfb::Region &dest, const rfb::Point &delta) { - if (ignoreHooks_) return; - if (grabbing) return; try { - rfb::Region rfbReg; - rfbReg.setExtentsAndOrderedRects((ShortRect*)REGION_EXTENTS(pScreen, dst), - REGION_NUM_RECTS(dst), - (ShortRect*)REGION_RECTS(dst)); - server->add_copied(rfbReg, rfb::Point(dx, dy)); + server->add_copied(dest, delta); } catch (rdr::Exception& e) { vlog.error("XserverDesktop::add_copied: %s",e.str()); } } -static struct timeval XserverDesktopTimeout; - -void XserverDesktop::blockHandler(fd_set* fds, OSTimePtr timeout) +void XserverDesktop::readBlockHandler(fd_set* fds, struct timeval ** timeout) { // We don't have a good callback for when we can init input devices[1], // so we abuse the fact that this routine will be called first thing // once the dix is done initialising. // [1] Technically Xvnc has InitInput(), but libvnc.so has nothing. - vncInputDevice->InitInputDevice(); + vncInitInputDevice(); try { int nextTimeout; @@ -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 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,42 @@ void XserverDesktop::clientCutText(const char* str, int len) vncClientCutText(str, len); } -extern RROutputPtr vncRandROutputCreate(ScreenPtr pScreen); - unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height, const rfb::ScreenSet& layout) { -#ifndef RANDR - return rfb::resultProhibited; -#else + int ret; int availableOutputs; - Bool ret; - rrScrPrivPtr rp = rrGetScrPriv(pScreen); + // RandR support? + if (vncRandRGetOutputCount(screenIndex) == 0) + return rfb::resultProhibited; /* * First check that we don't have any active clone modes. That's just * too messy to deal with. */ - for (int i = 0;i < rp->numCrtcs;i++) { - if (rp->crtcs[i]->numOutputs > 1) { - vlog.error("Clone mode active. Refusing to touch screen layout."); - return rfb::resultInvalid; - } + if (vncRandRHasOutputClones(screenIndex)) { + vlog.error("Clone mode active. Refusing to touch screen layout."); + return rfb::resultInvalid; } - /* - * Next count how many useful outputs we have... - * - * This gets slightly complicated because we might need to hook a CRTC - * up to the output, but also check that we don't try to use the same - * CRTC for multiple outputs. - */ - std::set usedCrtcs; - availableOutputs = 0; - for (int i = 0;i < rp->numOutputs;i++) { - RROutputPtr output; - - output = rp->outputs[i]; - - if (output->crtc != NULL) - availableOutputs++; - else { - for (int j = 0;j < output->numCrtcs;j++) { - if (output->crtcs[j]->numOutputs != 0) - continue; - if (usedCrtcs.count(output->crtcs[j]) != 0) - continue; - - availableOutputs++; - usedCrtcs.insert(output->crtcs[j]); - - break; - } - } - } + /* Next count how many useful outputs we have... */ + availableOutputs = vncRandRGetAvailableOutputs(screenIndex); /* Try to create more outputs if needed... (only works on Xvnc) */ if (layout.num_screens() > availableOutputs) { - for (int i = 0;i < (layout.num_screens() - availableOutputs);i++) { - RROutputPtr output; - output = vncRandROutputCreate(pScreen); - if (output == NULL) { - vlog.error("Unable to create more screens, as needed by the new client layout."); - return rfb::resultInvalid; - } + ret = vncRandRCreateOutputs(screenIndex, + layout.num_screens() - availableOutputs); + if (ret < 0) { + vlog.error("Unable to create more screens, as needed by the new client layout."); + return rfb::resultInvalid; } } /* First we might need to resize the screen */ - if ((fb_width != pScreen->width) || (fb_height != pScreen->height)) { - /* Try to retain DPI when we resize */ - ret = RRScreenSizeSet(pScreen, fb_width, fb_height, - pScreen->mmWidth * fb_width / pScreen->width, - pScreen->mmHeight * fb_height / pScreen->height); + if ((fb_width != vncGetScreenWidth(screenIndex)) || + (fb_height != vncGetScreenHeight(screenIndex))) { + ret = vncRandRResizeScreen(screenIndex, fb_width, fb_height); if (!ret) { vlog.error("Failed to resize screen to %dx%d", fb_width, fb_height); return rfb::resultInvalid; @@ -844,27 +686,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 +706,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 +735,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 +748,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 +774,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 +793,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 rects; std::vector::iterator i; region.get_rects(&rects); for (i = rects.begin(); i != rects.end(); i++) { - for (int y = i->tl.y; y < i->br.y; y++) { - 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); } diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h index 5b4c2300..7dcaa29e 100644 --- a/unix/xserver/hw/vnc/XserverDesktop.h +++ b/unix/xserver/hw/vnc/XserverDesktop.h @@ -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 +#include + #include #include #include @@ -37,16 +39,6 @@ #include #include "Input.h" -extern "C" { -#define class c_class -#include -#include -#ifdef RANDR -#include -#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 ®ion); + void add_copied(const rfb::Region &dest, const rfb::Point &delta); + void readBlockHandler(fd_set* fds, struct timeval ** timeout); + void readWakeupHandler(fd_set* fds, int nfds); + void writeBlockHandler(fd_set* fds, struct timeval ** timeout); void writeWakeupHandler(fd_set* fds, int nfds); void addClient(network::Socket* sock, bool reverse); void disconnectClients(); // QueryConnect methods called from X server code - // getQueryTimeout() - // Returns the timeout associated with a particular - // connection, identified by an opaque Id passed to the - // X code earlier. Also optionally gets the address and - // name associated with that connection. - // Returns zero if the Id is not recognised. - int getQueryTimeout(void* opaqueId, - const char** address=0, - const char** username=0); + // getQueryConnect() + // Returns information about the currently waiting query + // (or an id of 0 if there is none waiting) + void getQueryConnect(uint32_t* opaqueId, const char** address, + const char** username, int *timeout); // approveConnection() // Used by X server code to supply the result of a query. - void approveConnection(void* opaqueId, bool accept, + void approveConnection(uint32_t opaqueId, bool accept, const char* rejectMsg=0); // rfb::SDesktop callbacks @@ -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 OutputIdMap; + typedef std::map OutputIdMap; OutputIdMap outputIdMap; #endif diff --git a/unix/xserver/hw/vnc/vncBlockHandler.c b/unix/xserver/hw/vnc/vncBlockHandler.c new file mode 100644 index 00000000..c9a7428d --- /dev/null +++ b/unix/xserver/hw/vnc/vncBlockHandler.c @@ -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 +#endif + +#include + +#include + +#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); +} diff --git a/unix/xserver/hw/vnc/vncBlockHandler.h b/unix/xserver/hw/vnc/vncBlockHandler.h new file mode 100644 index 00000000..556528bd --- /dev/null +++ b/unix/xserver/hw/vnc/vncBlockHandler.h @@ -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 diff --git a/unix/xserver/hw/vnc/vncExt.c b/unix/xserver/hw/vnc/vncExt.c new file mode 100644 index 00000000..2330eee8 --- /dev/null +++ b/unix/xserver/hw/vnc/vncExt.c @@ -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 +#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); +} + diff --git a/unix/xserver/hw/vnc/vncExtInit.cc b/unix/xserver/hw/vnc/vncExtInit.cc index ff81321c..22777839 100644 --- a/unix/xserver/hw/vnc/vncExtInit.cc +++ b/unix/xserver/hw/vnc/vncExtInit.cc @@ -1,5 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2011 Pierre Ossman for Cendio AB + * Copyright 2011-2015 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,34 +17,9 @@ * USA. */ -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - #include #include -extern "C" { -#define class c_class -#define public c_public -#define NEED_EVENTS -#include -#include -#include -#include "misc.h" -#include "os.h" -#include "dixstruct.h" -#include "extnsionst.h" -#include "scrnintstr.h" -#include "selection.h" -#define _VNCEXT_SERVER_ -#define _VNCEXT_PROTO_ -#include "vncExt.h" -#undef class -#undef xalloc -#undef public -} - #include #include #include @@ -52,67 +27,29 @@ extern "C" { #include #include #include -#undef max -#undef min +#include +#include #include #include "XserverDesktop.h" -#include "vncHooks.h" #include "vncExtInit.h" -#include "xorg-version.h" - -extern "C" { - - extern void vncExtensionInit(); - static void vncResetProc(ExtensionEntry* extEntry); - static void vncBlockHandler(void * data, OSTimePtr t, void * readmask); - static void vncWakeupHandler(void * data, int nfds, void * readmask); - void vncWriteBlockHandler(fd_set *fds); - void vncWriteWakeupHandler(int nfds, fd_set *fds); - static void vncClientStateChange(CallbackListPtr*, void *, void *); - static void SendSelectionChangeEvent(Atom selection); - static int ProcVncExtDispatch(ClientPtr client); - static int SProcVncExtDispatch(ClientPtr client); - static void vncSelectionCallback(CallbackListPtr *callbacks, void * data, - void * args); - - extern char *listenaddr; -} +#include "vncHooks.h" +#include "vncBlockHandler.h" +#include "XorgGlue.h" using namespace rfb; static rfb::LogWriter vlog("vncext"); +// We can't safely get this from Xorg +#define MAXSCREENS 16 + static unsigned long vncExtGeneration = 0; static bool initialised = false; static XserverDesktop* desktop[MAXSCREENS] = { 0, }; void* vncFbptr[MAXSCREENS] = { 0, }; int vncFbstride[MAXSCREENS]; -static char* clientCutText = 0; -static int clientCutTextLen = 0; -bool noclipboard = false; - -static XserverDesktop* queryConnectDesktop = 0; -static void* queryConnectId = 0; -static int queryConnectTimeout = 0; -static OsTimerPtr queryConnectTimer = 0; - -static struct VncInputSelect* vncInputSelectHead = 0; -struct VncInputSelect { - VncInputSelect(ClientPtr c, Window w, int m) : client(c), window(w), mask(m) - { - next = vncInputSelectHead; - vncInputSelectHead = this; - } - ClientPtr client; - Window window; - int mask; - VncInputSelect* next; -}; - -static int vncErrorBase = 0; -static int vncEventBase = 0; int vncInetdSock = -1; rfb::StringParameter httpDir("httpd", @@ -126,93 +63,67 @@ rfb::StringParameter desktopName("desktop", "Name of VNC desktop","x11"); rfb::BoolParameter localhostOnly("localhost", "Only allow connections from localhost", false); +rfb::StringParameter interface("interface", + "listen on the specified network address", + "all"); +rfb::BoolParameter avoidShiftNumLock("AvoidShiftNumLock", + "Avoid fake Shift presses for keys affected by NumLock.", + true); -static PixelFormat vncGetPixelFormat(ScreenPtr pScreen) +static PixelFormat vncGetPixelFormat(int scrIdx) { int depth, bpp; int trueColour, bigEndian; + int redMask, greenMask, blueMask; + int redShift, greenShift, blueShift; int redMax, greenMax, blueMax; - int i; - VisualPtr vis = NULL; - - depth = pScreen->rootDepth; - - for (i = 0; i < screenInfo.numPixmapFormats; i++) { - if (screenInfo.formats[i].depth == depth) { - bpp = screenInfo.formats[i].bitsPerPixel; - break; - } - } - - if (i == screenInfo.numPixmapFormats) { - fprintf(stderr,"no pixmap format for root depth???\n"); - abort(); - } - - bigEndian = (screenInfo.imageByteOrder == MSBFirst); - - for (i = 0; i < pScreen->numVisuals; i++) { - if (pScreen->visuals[i].vid == pScreen->rootVisual) { - vis = &pScreen->visuals[i]; - break; - } - } - - if (i == pScreen->numVisuals) { - fprintf(stderr,"no visual rec for root visual???\n"); - abort(); - } - - trueColour = (vis->c_class == TrueColor); + vncGetScreenFormat(scrIdx, &depth, &bpp, &trueColour, &bigEndian, + &redMask, &greenMask, &blueMask); if (!trueColour) { - fprintf(stderr,"pseudocolour not supported"); + vlog.error("pseudocolour not supported"); abort(); } - redShift = ffs(vis->redMask) - 1; - greenShift = ffs(vis->greenMask) - 1; - blueShift = ffs(vis->blueMask) - 1; - redMax = vis->redMask >> redShift; - greenMax = vis->greenMask >> greenShift; - blueMax = vis->blueMask >> blueShift; + redShift = ffs(redMask) - 1; + greenShift = ffs(greenMask) - 1; + blueShift = ffs(blueMask) - 1; + redMax = redMask >> redShift; + greenMax = greenMask >> greenShift; + blueMax = blueMask >> blueShift; return PixelFormat(bpp, depth, bigEndian, trueColour, redMax, greenMax, blueMax, redShift, greenShift, blueShift); } -void vncExtensionInit() +void vncExtensionInit(void) { - if (vncExtGeneration == serverGeneration) { + int ret; + + if (vncExtGeneration == vncGetServerGeneration()) { vlog.error("vncExtensionInit: called twice in same generation?"); return; } - vncExtGeneration = serverGeneration; + vncExtGeneration = vncGetServerGeneration(); - ExtensionEntry* extEntry - = AddExtension(VNCEXTNAME, VncExtNumberEvents, VncExtNumberErrors, - ProcVncExtDispatch, SProcVncExtDispatch, vncResetProc, - StandardMinorOpcode); - if (!extEntry) { - ErrorF("vncExtInit: AddExtension failed\n"); + if (vncGetScreenCount() > MAXSCREENS) { + vlog.error("vncExtensionInit: too many screens"); return; } - vncErrorBase = extEntry->errorBase; - vncEventBase = extEntry->eventBase; - - vlog.info("VNC extension running!"); - - if (!AddCallback(&ClientStateCallback, vncClientStateChange, 0)) { - FatalError("Add ClientStateCallback failed\n"); + if (sizeof(ShortRect) != sizeof(struct UpdateRect)) { + vlog.error("vncExtensionInit: Incompatible ShortRect size"); + return; } - if (!AddCallback(&SelectionCallback, vncSelectionCallback, 0)) { - FatalError("Add SelectionCallback failed\n"); - } + ret = vncAddExtension(); + if (ret == -1) + return; + + vlog.info("VNC extension running!"); try { if (!initialised) { @@ -220,7 +131,7 @@ void vncExtensionInit() initialised = true; } - for (int scr = 0; scr < screenInfo.numScreens; scr++) { + for (int scr = 0; scr < vncGetScreenCount(); scr++) { if (!desktop[scr]) { network::TcpListener* listener = 0; @@ -234,30 +145,35 @@ void vncExtensionInit() } } else { int port = rfbport; - if (port == 0) port = 5900 + atoi(display); + if (port == 0) port = 5900 + atoi(vncGetDisplay()); port += 1000 * scr; - listener = new network::TcpListener(listenaddr, port, localhostOnly); + if (strcasecmp(interface, "all") == 0) + listener = new network::TcpListener(NULL, port, localhostOnly); + else + listener = new network::TcpListener(interface, port, localhostOnly); vlog.info("Listening for VNC connections on %s interface(s), port %d", - listenaddr == NULL ? "all" : listenaddr, port); + (const char*)interface, port); CharArray httpDirStr(httpDir.getData()); if (httpDirStr.buf[0]) { port = httpPort; - if (port == 0) port = 5800 + atoi(display); + if (port == 0) port = 5800 + atoi(vncGetDisplay()); port += 1000 * scr; - httpListener = new network::TcpListener(listenaddr, port, localhostOnly); + httpListener = new network::TcpListener(interface, port, localhostOnly); vlog.info("Listening for HTTP connections on %s interface(s), port %d", - listenaddr == NULL ? "all" : listenaddr, port); + (const char*)interface, port); } } CharArray desktopNameStr(desktopName.getData()); - PixelFormat pf = vncGetPixelFormat(screenInfo.screens[scr]); + PixelFormat pf = vncGetPixelFormat(scr); - desktop[scr] = new XserverDesktop(screenInfo.screens[scr], + desktop[scr] = new XserverDesktop(scr, listener, httpListener, desktopNameStr.buf, pf, + vncGetScreenWidth(scr), + vncGetScreenHeight(scr), vncFbptr[scr], vncFbstride[scr]); vlog.info("created VNC server for screen %d", scr); @@ -269,889 +185,182 @@ void vncExtensionInit() } } - vncHooksInit(screenInfo.screens[scr], desktop[scr]); + vncHooksInit(scr); } - - RegisterBlockAndWakeupHandlers(vncBlockHandler, vncWakeupHandler, 0); - } catch (rdr::Exception& e) { vlog.error("vncExtInit: %s",e.str()); } -} -static void vncResetProc(ExtensionEntry* extEntry) -{ -} - -static void vncSelectionCallback(CallbackListPtr *callbacks, void * data, void * args) -{ - SelectionInfoRec *info = (SelectionInfoRec *) args; - Selection *selection = info->selection; - - SendSelectionChangeEvent(selection->selection); + vncRegisterBlockHandlers(); } -static void vncWriteBlockHandlerFallback(OSTimePtr timeout); -static void vncWriteWakeupHandlerFallback(); - -// -// vncBlockHandler - called just before the X server goes into select(). Call -// on to the block handler for each desktop. Then check whether any of the -// selections have changed, and if so, notify any interested X clients. -// - -static void vncBlockHandler(void * data, OSTimePtr timeout, void * readmask) +void vncCallReadBlockHandlers(fd_set * fds, struct timeval ** timeout) { - fd_set* fds = (fd_set*)readmask; - - vncWriteBlockHandlerFallback(timeout); - - for (int scr = 0; scr < screenInfo.numScreens; scr++) + for (int scr = 0; scr < vncGetScreenCount(); scr++) if (desktop[scr]) - desktop[scr]->blockHandler(fds, timeout); + desktop[scr]->readBlockHandler(fds, timeout); } -static void vncWakeupHandler(void * data, int nfds, void * readmask) +void vncCallReadWakeupHandlers(fd_set * fds, int nfds) { - fd_set* fds = (fd_set*)readmask; - - for (int scr = 0; scr < screenInfo.numScreens; scr++) { - if (desktop[scr]) { - desktop[scr]->wakeupHandler(fds, nfds); - } - } - - vncWriteWakeupHandlerFallback(); + for (int scr = 0; scr < vncGetScreenCount(); scr++) + if (desktop[scr]) + desktop[scr]->readWakeupHandler(fds, nfds); } -// -// vncWriteBlockHandler - extra hack to be able to get the main select loop -// to monitor writeable fds and not just readable. This requirers a modified -// Xorg and might therefore not be called. When it is called though, it will -// do so before vncBlockHandler (and vncWriteWakeupHandler called after -// vncWakeupHandler). -// - -static bool needFallback = true; -static fd_set fallbackFds; -static struct timeval tw; - -void vncWriteBlockHandler(fd_set *fds) +void vncCallWriteBlockHandlers(fd_set * fds, struct timeval ** timeout) { - needFallback = false; - - for (int scr = 0; scr < screenInfo.numScreens; scr++) + for (int scr = 0; scr < vncGetScreenCount(); scr++) if (desktop[scr]) - desktop[scr]->writeBlockHandler(fds); + desktop[scr]->writeBlockHandler(fds, timeout); } -void vncWriteWakeupHandler(int nfds, fd_set *fds) +void vncCallWriteWakeupHandlers(fd_set * fds, int nfds) { - for (int scr = 0; scr < screenInfo.numScreens; scr++) { - if (desktop[scr]) { + for (int scr = 0; scr < vncGetScreenCount(); scr++) + if (desktop[scr]) desktop[scr]->writeWakeupHandler(fds, nfds); - } - } } -static void vncWriteBlockHandlerFallback(OSTimePtr timeout) +int vncGetAvoidShiftNumLock(void) { - if (!needFallback) - return; - - FD_ZERO(&fallbackFds); - vncWriteBlockHandler(&fallbackFds); - needFallback = true; - - if (!XFD_ANYSET(&fallbackFds)) - return; - - if ((*timeout == NULL) || - ((*timeout)->tv_sec > 0) || ((*timeout)->tv_usec > 10000)) { - tw.tv_sec = 0; - tw.tv_usec = 10000; - *timeout = &tw; - } + return (bool)avoidShiftNumLock; } -static void vncWriteWakeupHandlerFallback() +void vncUpdateDesktopName(void) { - int ret; - struct timeval timeout; - - if (!needFallback) - return; - - if (!XFD_ANYSET(&fallbackFds)) - return; - - timeout.tv_sec = 0; - timeout.tv_usec = 0; - - ret = select(XFD_SETSIZE, NULL, &fallbackFds, NULL, &timeout); - if (ret < 0) { - ErrorF("vncWriteWakeupHandlerFallback(): select: %s\n", - strerror(errno)); - return; + for (int scr = 0; scr < vncGetScreenCount(); scr++) { + if (desktop[scr] == NULL) + continue; + desktop[scr]->setDesktopName(desktopName); } - - if (ret == 0) - return; - - vncWriteWakeupHandler(ret, &fallbackFds); } -static void vncClientStateChange(CallbackListPtr*, void *, void * p) +void vncServerCutText(const char *text, size_t len) { - ClientPtr client = ((NewClientInfoRec*)p)->client; - if (client->clientState == ClientStateGone) { - VncInputSelect** nextPtr = &vncInputSelectHead; - for (VncInputSelect* cur = vncInputSelectHead; cur; cur = *nextPtr) { - if (cur->client == client) { - *nextPtr = cur->next; - delete cur; - continue; - } - nextPtr = &cur->next; - } + for (int scr = 0; scr < vncGetScreenCount(); scr++) { + if (desktop[scr] == NULL) + continue; + desktop[scr]->serverCutText(text, len); } } -void vncBell() +int vncConnectClient(const char *addr) { - for (int scr = 0; scr < screenInfo.numScreens; scr++) { - if (desktop[scr]) { - desktop[scr]->bell(); - } - } -} + if (desktop[0] == NULL) + return -1; -void vncClientGone(int fd) -{ - if (fd == vncInetdSock) { - fprintf(stderr,"inetdSock client gone\n"); - GiveUp(0); - } -} - -void vncClientCutText(const char* str, int len) -{ - delete [] clientCutText; - clientCutText = new char[len]; - memcpy(clientCutText, str, len); - clientCutTextLen = len; - xVncExtClientCutTextNotifyEvent ev; - ev.type = vncEventBase + VncExtClientCutTextNotify; - for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) { - if (cur->mask & VncExtClientCutTextMask) { - ev.sequenceNumber = cur->client->sequence; - ev.window = cur->window; - ev.time = GetTimeInMillis(); - if (cur->client->swapped) { -#if XORG < 112 - int n; - swaps(&ev.sequenceNumber, n); - swapl(&ev.window, n); - swapl(&ev.time, n); -#else - swaps(&ev.sequenceNumber); - swapl(&ev.window); - swapl(&ev.time); -#endif - } - WriteToClient(cur->client, sizeof(xVncExtClientCutTextNotifyEvent), - (char *)&ev); + if (strlen(addr) == 0) { + try { + desktop[0]->disconnectClients(); + } catch (rdr::Exception& e) { + vlog.error("Disconnecting all clients: %s",e.str()); + return -1; } + return 0; } -} - -static CARD32 queryConnectTimerCallback(OsTimerPtr timer, - CARD32 now, void * arg) -{ - if (queryConnectTimeout) - queryConnectDesktop->approveConnection(queryConnectId, false, "The attempt to prompt the user to accept the connection failed"); - // Re-notify clients, causing them to discover that we're done - vncQueryConnect(queryConnectDesktop, queryConnectId); - return 0; -} + char *host; + int port; -void vncQueryConnect(XserverDesktop* desktop, void* opaqueId) -{ - // Only one query can be processed at any one time - if (queryConnectTimeout && ((desktop != queryConnectDesktop) || - (opaqueId != queryConnectId))) { - desktop->approveConnection(opaqueId, false, - "Another connection is currently being queried."); - return; - } + getHostAndPort(addr, &host, &port, 5500); - // Get the query timeout. If it's zero, there is no query. - queryConnectTimeout = desktop->getQueryTimeout(opaqueId); - queryConnectId = queryConnectTimeout ? opaqueId : 0; - queryConnectDesktop = queryConnectTimeout ? desktop : 0; - - // Notify clients - bool notified = false; - xVncExtQueryConnectNotifyEvent ev; - ev.type = vncEventBase + VncExtQueryConnectNotify; - for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) { - if (cur->mask & VncExtQueryConnectMask) { - ev.sequenceNumber = cur->client->sequence; - ev.window = cur->window; - if (cur->client->swapped) { -#if XORG < 112 - int n; - swaps(&ev.sequenceNumber, n); - swapl(&ev.window, n); -#else - swaps(&ev.sequenceNumber); - swapl(&ev.window); -#endif - } - WriteToClient(cur->client, sizeof(xVncExtQueryConnectNotifyEvent), - (char *)&ev); - notified = true; - } - } - - // If we're being asked to query a connection (rather than to cancel - // a query), and haven't been able to notify clients then reject it. - if (queryConnectTimeout && !notified) { - queryConnectTimeout = 0; - queryConnectId = 0; - queryConnectDesktop = 0; - desktop->approveConnection(opaqueId, false, - "Unable to query the local user to accept the connection."); - return; - } - - // Set a timer so that if no-one ever responds, we will eventually - // reject the connection - // NB: We don't set a timer if sock is null, since that indicates - // that pending queries should be cancelled. - if (queryConnectDesktop) - queryConnectTimer = TimerSet(queryConnectTimer, 0, - queryConnectTimeout*2000, - queryConnectTimerCallback, 0); - else - TimerCancel(queryConnectTimer); -} - -static void SendSelectionChangeEvent(Atom selection) -{ - xVncExtSelectionChangeNotifyEvent ev; - ev.type = vncEventBase + VncExtSelectionChangeNotify; - for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) { - if (cur->mask & VncExtSelectionChangeMask) { - ev.sequenceNumber = cur->client->sequence; - ev.window = cur->window; - ev.selection = selection; - if (cur->client->swapped) { -#if XORG < 112 - int n; - swaps(&ev.sequenceNumber, n); - swapl(&ev.window, n); - swapl(&ev.selection, n); -#else - swaps(&ev.sequenceNumber); - swapl(&ev.window); - swapl(&ev.selection); -#endif - } - WriteToClient(cur->client, sizeof(xVncExtSelectionChangeNotifyEvent), - (char *)&ev); - } - } -} - -static int ProcVncExtSetParam(ClientPtr client) -{ - char* value1 = 0; - char* value2 = 0; - rfb::VoidParameter *desktop1, *desktop2; - - REQUEST(xVncExtSetParamReq); - REQUEST_FIXED_SIZE(xVncExtSetParamReq, stuff->paramLen); - CharArray param(stuff->paramLen+1); - strncpy(param.buf, (char*)&stuff[1], stuff->paramLen); - param.buf[stuff->paramLen] = 0; - - xVncExtSetParamReply rep; - rep.type = X_Reply; - rep.length = 0; - rep.success = 0; - rep.sequenceNumber = client->sequence; - - // Retrieve desktop name before setting - desktop1 = rfb::Configuration::getParam("desktop"); - if (desktop1) - value1 = desktop1->getValueStr(); - - /* - * Allow to change only certain parameters. - * Changing other parameters (for example PAM service name) - * could have negative security impact. - */ - if (strncasecmp(param.buf, "desktop", 7) != 0 && - strncasecmp(param.buf, "AcceptPointerEvents", 19) != 0 && - (noclipboard || strncasecmp(param.buf, "SendCutText", 11) != 0) && - (noclipboard || strncasecmp(param.buf, "AcceptCutText", 13) != 0)) - goto deny; - - rep.success = rfb::Configuration::setParam(param.buf); - - // Send DesktopName update if desktop name has been changed - desktop2 = rfb::Configuration::getParam("desktop"); - if (desktop2) - value2 = desktop2->getValueStr(); - if (value1 && value2 && strcmp(value1, value2)) { - for (int scr = 0; scr < screenInfo.numScreens; scr++) { - if (desktop[scr]) { - desktop[scr]->setDesktopName(value2); - } - } - } - if (value1) - delete [] value1; - if (value2) - delete [] value2; - -deny: - if (client->swapped) { -#if XORG < 112 - int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); -#else - swaps(&rep.sequenceNumber); - swapl(&rep.length); -#endif - } - WriteToClient(client, sizeof(xVncExtSetParamReply), (char *)&rep); - return (client->noClientException); -} - -static int SProcVncExtSetParam(ClientPtr client) -{ - REQUEST(xVncExtSetParamReq); -#if XORG < 112 - register char n; - swaps(&stuff->length, n); -#else - swaps(&stuff->length); -#endif - REQUEST_AT_LEAST_SIZE(xVncExtSetParamReq); - return ProcVncExtSetParam(client); -} - -static int ProcVncExtGetParam(ClientPtr client) -{ - REQUEST(xVncExtGetParamReq); - REQUEST_FIXED_SIZE(xVncExtGetParamReq, stuff->paramLen); - CharArray param(stuff->paramLen+1); - strncpy(param.buf, (char*)&stuff[1], stuff->paramLen); - param.buf[stuff->paramLen] = 0; - - xVncExtGetParamReply rep; - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.success = 0; - int len = 0; - char* value = 0; - rfb::VoidParameter* p = rfb::Configuration::getParam(param.buf); - // Hack to avoid exposing password! - if (strcasecmp(param.buf, "Password") == 0) - p = 0; - if (p) { - value = p->getValueStr(); - rep.success = 1; - len = value ? strlen(value) : 0; - } - rep.length = (len + 3) >> 2; - rep.valueLen = len; - if (client->swapped) { -#if XORG < 112 - int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.valueLen, n); -#else - swaps(&rep.sequenceNumber); - swapl(&rep.length); - swaps(&rep.valueLen); -#endif - } - WriteToClient(client, sizeof(xVncExtGetParamReply), (char *)&rep); - if (value) - WriteToClient(client, len, value); - delete [] value; - return (client->noClientException); -} - -static int SProcVncExtGetParam(ClientPtr client) -{ - REQUEST(xVncExtGetParamReq); -#if XORG < 112 - register char n; - swaps(&stuff->length, n); -#else - swaps(&stuff->length); -#endif - REQUEST_AT_LEAST_SIZE(xVncExtGetParamReq); - return ProcVncExtGetParam(client); -} - -static int ProcVncExtGetParamDesc(ClientPtr client) -{ - REQUEST(xVncExtGetParamDescReq); - REQUEST_FIXED_SIZE(xVncExtGetParamDescReq, stuff->paramLen); - CharArray param(stuff->paramLen+1); - strncpy(param.buf, (char*)&stuff[1], stuff->paramLen); - param.buf[stuff->paramLen] = 0; - - xVncExtGetParamDescReply rep; - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.success = 0; - int len = 0; - const char* desc = 0; - rfb::VoidParameter* p = rfb::Configuration::getParam(param.buf); - if (p) { - desc = p->getDescription(); - rep.success = 1; - len = desc ? strlen(desc) : 0; - } - rep.length = (len + 3) >> 2; - rep.descLen = len; - if (client->swapped) { -#if XORG < 112 - int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.descLen, n); -#else - swaps(&rep.sequenceNumber); - swapl(&rep.length); - swaps(&rep.descLen); -#endif + try { + network::Socket* sock = new network::TcpSocket(host, port); + delete [] host; + desktop[0]->addClient(sock, true); + } catch (rdr::Exception& e) { + vlog.error("Reverse connection: %s",e.str()); + return -1; } - WriteToClient(client, sizeof(xVncExtGetParamDescReply), (char *)&rep); - if (desc) - WriteToClient(client, len, (char*)desc); - return (client->noClientException); -} -static int SProcVncExtGetParamDesc(ClientPtr client) -{ - REQUEST(xVncExtGetParamDescReq); -#if XORG < 112 - register char n; - swaps(&stuff->length, n); -#else - swaps(&stuff->length); -#endif - REQUEST_AT_LEAST_SIZE(xVncExtGetParamDescReq); - return ProcVncExtGetParamDesc(client); + return 0; } -static int ProcVncExtListParams(ClientPtr client) +void vncGetQueryConnect(uint32_t *opaqueId, const char**username, + const char **address, int *timeout) { - REQUEST(xVncExtListParamsReq); - REQUEST_SIZE_MATCH(xVncExtListParamsReq); - - xVncExtListParamsReply rep; - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - - int nParams = 0; - int len = 0; - for (ParameterIterator i; i.param; i.next()) { - int l = strlen(i.param->getName()); - if (l <= 255) { - nParams++; - len += l + 1; - } - } - rep.length = (len + 3) >> 2; - rep.nParams = nParams; - if (client->swapped) { -#if XORG < 112 - int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.nParams, n); -#else - swaps(&rep.sequenceNumber); - swapl(&rep.length); - swaps(&rep.nParams); -#endif - } - WriteToClient(client, sizeof(xVncExtListParamsReply), (char *)&rep); - rdr::U8* data = new rdr::U8[len]; - rdr::U8* ptr = data; - for (ParameterIterator i; i.param; i.next()) { - int l = strlen(i.param->getName()); - if (l <= 255) { - *ptr++ = l; - memcpy(ptr, i.param->getName(), l); - ptr += l; - } + for (int scr = 0; scr < vncGetScreenCount(); scr++) { + if (desktop[scr] == NULL) + continue; + desktop[scr]->getQueryConnect(opaqueId, username, address, timeout); + if (opaqueId != 0) + break; } - WriteToClient(client, len, (char*)data); - delete [] data; - return (client->noClientException); } -static int SProcVncExtListParams(ClientPtr client) +void vncApproveConnection(uint32_t opaqueId, int approve) { - REQUEST(xVncExtListParamsReq); -#if XORG < 112 - register char n; - swaps(&stuff->length, n); -#else - swaps(&stuff->length); -#endif - REQUEST_SIZE_MATCH(xVncExtListParamsReq); - return ProcVncExtListParams(client); -} - -static int ProcVncExtSetServerCutText(ClientPtr client) -{ - REQUEST(xVncExtSetServerCutTextReq); - REQUEST_FIXED_SIZE(xVncExtSetServerCutTextReq, stuff->textLen); - char* str = new char[stuff->textLen+1]; - strncpy(str, (char*)&stuff[1], stuff->textLen); - str[stuff->textLen] = 0; - for (int scr = 0; scr < screenInfo.numScreens; scr++) { - if (desktop[scr]) { - desktop[scr]->serverCutText(str, stuff->textLen); - } + for (int scr = 0; scr < vncGetScreenCount(); scr++) { + if (desktop[scr] == NULL) + continue; + desktop[scr]->approveConnection(opaqueId, approve, + "Connection rejected by local user"); } - delete [] str; - return (client->noClientException); -} - -static int SProcVncExtSetServerCutText(ClientPtr client) -{ - REQUEST(xVncExtSetServerCutTextReq); -#if XORG < 112 - register char n; - swaps(&stuff->length, n); -#else - swaps(&stuff->length); -#endif - REQUEST_AT_LEAST_SIZE(xVncExtSetServerCutTextReq); -#if XORG < 112 - swapl(&stuff->textLen, n); -#else - swapl(&stuff->textLen); -#endif - return ProcVncExtSetServerCutText(client); } -static int ProcVncExtGetClientCutText(ClientPtr client) +void vncBell() { - REQUEST(xVncExtGetClientCutTextReq); - REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq); - - xVncExtGetClientCutTextReply rep; - rep.type = X_Reply; - rep.length = (clientCutTextLen + 3) >> 2; - rep.sequenceNumber = client->sequence; - rep.textLen = clientCutTextLen; - if (client->swapped) { -#if XORG < 112 - int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.textLen, n); -#else - swaps(&rep.sequenceNumber); - swapl(&rep.length); - swapl(&rep.textLen); -#endif + for (int scr = 0; scr < vncGetScreenCount(); scr++) { + if (desktop[scr] == NULL) + continue; + desktop[scr]->bell(); } - WriteToClient(client, sizeof(xVncExtGetClientCutTextReply), (char *)&rep); - if (clientCutText) - WriteToClient(client, clientCutTextLen, clientCutText); - return (client->noClientException); -} - -static int SProcVncExtGetClientCutText(ClientPtr client) -{ - REQUEST(xVncExtGetClientCutTextReq); -#if XORG < 112 - register char n; - swaps(&stuff->length, n); -#else - swaps(&stuff->length); -#endif - REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq); - return ProcVncExtGetClientCutText(client); } -static int ProcVncExtSelectInput(ClientPtr client) +void vncAddChanged(int scrIdx, const struct UpdateRect *extents, + int nRects, const struct UpdateRect *rects) { - REQUEST(xVncExtSelectInputReq); - REQUEST_SIZE_MATCH(xVncExtSelectInputReq); - VncInputSelect** nextPtr = &vncInputSelectHead; - VncInputSelect* cur; - for (cur = vncInputSelectHead; cur; cur = *nextPtr) { - if (cur->client == client && cur->window == stuff->window) { - cur->mask = stuff->mask; - if (!cur->mask) { - *nextPtr = cur->next; - delete cur; - } - break; - } - nextPtr = &cur->next; - } - if (!cur) { - cur = new VncInputSelect(client, stuff->window, stuff->mask); - } - return (client->noClientException); -} + Region reg; -static int SProcVncExtSelectInput(ClientPtr client) -{ - REQUEST(xVncExtSelectInputReq); -#if XORG < 112 - register char n; - swaps(&stuff->length, n); -#else - swaps(&stuff->length); -#endif - REQUEST_SIZE_MATCH(xVncExtSelectInputReq); -#if XORG < 112 - swapl(&stuff->window, n); - swapl(&stuff->mask, n); -#else - swapl(&stuff->window); - swapl(&stuff->mask); -#endif - return ProcVncExtSelectInput(client); + reg.setExtentsAndOrderedRects((ShortRect*)extents, + nRects, (ShortRect*)rects); + desktop[scrIdx]->add_changed(reg); } -static int ProcVncExtConnect(ClientPtr client) +void vncAddCopied(int scrIdx, const struct UpdateRect *extents, + int nRects, const struct UpdateRect *rects, + int dx, int dy) { - REQUEST(xVncExtConnectReq); - REQUEST_FIXED_SIZE(xVncExtConnectReq, stuff->strLen); - CharArray str(stuff->strLen+1); - strncpy(str.buf, (char*)&stuff[1], stuff->strLen); - str.buf[stuff->strLen] = 0; - - xVncExtConnectReply rep; - rep.success = 0; - if (desktop[0]) { - if (stuff->strLen == 0) { - try { - desktop[0]->disconnectClients(); - rep.success = 1; - } catch (rdr::Exception& e) { - vlog.error("Disconnecting all clients: %s",e.str()); - } - } else { - int port = 5500; - for (int i = 0; i < stuff->strLen; i++) { - if (str.buf[i] == ':') { - port = atoi(&str.buf[i+1]); - str.buf[i] = 0; - break; - } - } - - try { - network::Socket* sock = new network::TcpSocket(str.buf, port); - desktop[0]->addClient(sock, true); - rep.success = 1; - } catch (rdr::Exception& e) { - vlog.error("Reverse connection: %s",e.str()); - } - } - } + Region reg; - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - if (client->swapped) { -#if XORG < 112 - int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); -#else - swaps(&rep.sequenceNumber); - swapl(&rep.length); -#endif - } - WriteToClient(client, sizeof(xVncExtConnectReply), (char *)&rep); - return (client->noClientException); + reg.setExtentsAndOrderedRects((ShortRect*)extents, + nRects, (ShortRect*)rects); + desktop[scrIdx]->add_copied(reg, rfb::Point(dx, dy)); } -static int SProcVncExtConnect(ClientPtr client) +void vncSetCursor(int scrIdx, int width, int height, int hotX, int hotY, + const unsigned char *rgbaData) { - REQUEST(xVncExtConnectReq); -#if XORG < 112 - register char n; - swaps(&stuff->length, n); -#else - swaps(&stuff->length); -#endif - REQUEST_AT_LEAST_SIZE(xVncExtConnectReq); - return ProcVncExtConnect(client); + desktop[scrIdx]->setCursor(width, height, hotX, hotY, rgbaData); } - -static int ProcVncExtGetQueryConnect(ClientPtr client) +void vncPreScreenResize(int scrIdx) { - REQUEST(xVncExtGetQueryConnectReq); - REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq); - - const char *qcAddress=0, *qcUsername=0; - int qcTimeout; - if (queryConnectDesktop) - qcTimeout = queryConnectDesktop->getQueryTimeout(queryConnectId, - &qcAddress, &qcUsername); - else - qcTimeout = 0; - - xVncExtGetQueryConnectReply rep; - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.timeout = qcTimeout; - rep.addrLen = qcTimeout ? strlen(qcAddress) : 0; - rep.userLen = qcTimeout ? strlen(qcUsername) : 0; - rep.opaqueId = (CARD32)(long)queryConnectId; - rep.length = ((rep.userLen + 3) >> 2) + ((rep.addrLen + 3) >> 2); - if (client->swapped) { -#if XORG < 112 - int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.addrLen, n); - swapl(&rep.userLen, n); - swapl(&rep.timeout, n); - swapl(&rep.opaqueId, n); - swapl(&rep.length, n); -#else - swaps(&rep.sequenceNumber); - swapl(&rep.addrLen); - swapl(&rep.userLen); - swapl(&rep.timeout); - swapl(&rep.opaqueId); - swapl(&rep.length); -#endif - } - WriteToClient(client, sizeof(xVncExtGetQueryConnectReply), (char *)&rep); - if (qcTimeout) - WriteToClient(client, strlen(qcAddress), (char*)qcAddress); - if (qcTimeout) - WriteToClient(client, strlen(qcUsername), (char*)qcUsername); - return (client->noClientException); + // We need to prevent the RFB core from accessing the framebuffer + // for a while as there might be updates thrown our way inside + // the routines that change the screen (i.e. before we have a + // pointer to the new framebuffer). + desktop[scrIdx]->blockUpdates(); } -static int SProcVncExtGetQueryConnect(ClientPtr client) +void vncPostScreenResize(int scrIdx, int success, int width, int height) { - REQUEST(xVncExtGetQueryConnectReq); -#if XORG < 112 - register char n; - swaps(&stuff->length, n); -#else - swaps(&stuff->length); -#endif - REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq); - return ProcVncExtGetQueryConnect(client); -} - - -static int ProcVncExtApproveConnect(ClientPtr client) -{ - REQUEST(xVncExtApproveConnectReq); - REQUEST_SIZE_MATCH(xVncExtApproveConnectReq); - if ((CARD32)(long)queryConnectId == stuff->opaqueId) { - for (int scr = 0; scr < screenInfo.numScreens; scr++) { - if (desktop[scr]) { - desktop[scr]->approveConnection(queryConnectId, stuff->approve, - "Connection rejected by local user"); - } - } - // Inform other clients of the event and tidy up - vncQueryConnect(queryConnectDesktop, queryConnectId); + if (success) { + // Let the RFB core know of the new dimensions and framebuffer + desktop[scrIdx]->setFramebuffer(width, height, + vncFbptr[scrIdx], vncFbstride[scrIdx]); } - return (client->noClientException); -} - -static int SProcVncExtApproveConnect(ClientPtr client) -{ - REQUEST(xVncExtApproveConnectReq); -#if XORG < 112 - register char n; - swaps(&stuff->length, n); - swapl(&stuff->opaqueId, n); -#else - swaps(&stuff->length); - swapl(&stuff->opaqueId); -#endif - REQUEST_SIZE_MATCH(xVncExtApproveConnectReq); - return ProcVncExtApproveConnect(client); -} + desktop[scrIdx]->unblockUpdates(); -static int ProcVncExtDispatch(ClientPtr client) -{ - REQUEST(xReq); - switch (stuff->data) { - case X_VncExtSetParam: - return ProcVncExtSetParam(client); - case X_VncExtGetParam: - return ProcVncExtGetParam(client); - case X_VncExtGetParamDesc: - return ProcVncExtGetParamDesc(client); - case X_VncExtListParams: - return ProcVncExtListParams(client); - case X_VncExtSetServerCutText: - return ProcVncExtSetServerCutText(client); - case X_VncExtGetClientCutText: - return ProcVncExtGetClientCutText(client); - case X_VncExtSelectInput: - return ProcVncExtSelectInput(client); - case X_VncExtConnect: - return ProcVncExtConnect(client); - case X_VncExtGetQueryConnect: - return ProcVncExtGetQueryConnect(client); - case X_VncExtApproveConnect: - return ProcVncExtApproveConnect(client); - default: - return BadRequest; + if (success) { + // Mark entire screen as changed + desktop[scrIdx]->add_changed(Region(Rect(0, 0, width, height))); } } -static int SProcVncExtDispatch(ClientPtr client) +void vncRefreshScreenLayout(int scrIdx) { - REQUEST(xReq); - switch (stuff->data) { - case X_VncExtSetParam: - return SProcVncExtSetParam(client); - case X_VncExtGetParam: - return SProcVncExtGetParam(client); - case X_VncExtGetParamDesc: - return SProcVncExtGetParamDesc(client); - case X_VncExtListParams: - return SProcVncExtListParams(client); - case X_VncExtSetServerCutText: - return SProcVncExtSetServerCutText(client); - case X_VncExtGetClientCutText: - return SProcVncExtGetClientCutText(client); - case X_VncExtSelectInput: - return SProcVncExtSelectInput(client); - case X_VncExtConnect: - return SProcVncExtConnect(client); - case X_VncExtGetQueryConnect: - return SProcVncExtGetQueryConnect(client); - case X_VncExtApproveConnect: - return SProcVncExtApproveConnect(client); - default: - return BadRequest; - } + desktop[scrIdx]->refreshScreenLayout(); } - diff --git a/unix/xserver/hw/vnc/vncExtInit.h b/unix/xserver/hw/vnc/vncExtInit.h index 931c28f3..6c9857c0 100644 --- a/unix/xserver/hw/vnc/vncExtInit.h +++ b/unix/xserver/hw/vnc/vncExtInit.h @@ -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 +#include +#include + +// Only from C++ +#ifdef __cplusplus +namespace rfb { class StringParameter; }; + +extern rfb::StringParameter httpDir; #endif -#include -#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 diff --git a/unix/xserver/hw/vnc/vncHooks.cc b/unix/xserver/hw/vnc/vncHooks.c similarity index 72% rename from unix/xserver/hw/vnc/vncHooks.cc rename to unix/xserver/hw/vnc/vncHooks.c index f75a2d49..dc2b811a 100644 --- a/unix/xserver/hw/vnc/vncHooks.cc +++ b/unix/xserver/hw/vnc/vncHooks.c @@ -1,5 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2009 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 @@ -22,17 +22,15 @@ #endif #include -#include "XserverDesktop.h" + #include "vncHooks.h" #include "vncExtInit.h" + #include "xorg-version.h" -extern "C" { -#define class c_class -#define private c_private -#define public c_public #include "scrnintstr.h" #include "windowstr.h" +#include "cursorstr.h" #include "gcstruct.h" #include "regionstr.h" #include "dixfontstr.h" @@ -44,15 +42,15 @@ extern "C" { #include "randrstr.h" #endif -#undef class -#undef private -#undef public -} - -#include "RegionHelper.h" - #define DBGPRINT(x) //(fprintf x) +// REGION_NULL was introduced in the Xorg tree as the way to initialise an +// empty region. If it's not already defined do it the old way. Note that the +// old way causes a segfault in the new tree... +#ifndef REGION_NULL +#define REGION_NULL(pScreen,pReg) REGION_INIT(pScreen,pReg,NullBox,0) +#endif + // MAX_RECTS_PER_OP is the maximum number of rectangles we generate from // operations like Polylines and PolySegment. If the operation is more complex // than this, we simply use the bounding box. Ideally it would be a @@ -65,8 +63,8 @@ extern "C" { // functions are each wrapped individually, while the GC "funcs" and "ops" are // wrapped as a unit. -typedef struct { - XserverDesktop* desktop; +typedef struct _vncHooksScreenRec { + int ignoreHooks; CloseScreenProcPtr CloseScreen; CreateGCProcPtr CreateGC; @@ -88,7 +86,7 @@ typedef struct { #endif } vncHooksScreenRec, *vncHooksScreenPtr; -typedef struct { +typedef struct _vncHooksGCRec { #if XORG >= 116 const GCFuncs *wrappedFuncs; const GCOps *wrappedOps; @@ -250,10 +248,25 @@ static GCOps vncHooksGCOps = { // resets. It is called once for each screen, but the indexes are only // allocated once for each server generation. -Bool vncHooksInit(ScreenPtr pScreen, XserverDesktop* desktop) +int vncHooksInit(int scrIdx) { + ScreenPtr pScreen; vncHooksScreenPtr vncHooksScreen; +#ifdef RENDER + PictureScreenPtr ps; +#endif +#ifdef RANDR + rrScrPrivPtr rp; +#endif + + pScreen = screenInfo.screens[scrIdx]; + + if (sizeof(BoxRec) != sizeof(struct UpdateRect)) { + ErrorF("vncHooksInit: Incompatible BoxRec size\n"); + return FALSE; + } + #if XORG < 19 if (!dixRequestPrivate(vncHooksScreenPrivateKey, sizeof(vncHooksScreenRec))) { ErrorF("vncHooksInit: Allocation of vncHooksScreen failed\n"); @@ -280,7 +293,7 @@ Bool vncHooksInit(ScreenPtr pScreen, XserverDesktop* desktop) vncHooksScreen = vncHooksScreenPrivate(pScreen); - vncHooksScreen->desktop = desktop; + vncHooksScreen->ignoreHooks = 0; vncHooksScreen->CloseScreen = pScreen->CloseScreen; vncHooksScreen->CreateGC = pScreen->CreateGC; @@ -292,7 +305,6 @@ Bool vncHooksInit(ScreenPtr pScreen, XserverDesktop* desktop) vncHooksScreen->DisplayCursor = pScreen->DisplayCursor; vncHooksScreen->BlockHandler = pScreen->BlockHandler; #ifdef RENDER - PictureScreenPtr ps; ps = GetPictureScreenIfSet(pScreen); if (ps) { vncHooksScreen->Composite = ps->Composite; @@ -300,7 +312,6 @@ Bool vncHooksInit(ScreenPtr pScreen, XserverDesktop* desktop) } #endif #ifdef RANDR - rrScrPrivPtr rp; rp = rrGetScrPriv(pScreen); if (rp) { vncHooksScreen->RandRSetConfig = rp->rrSetConfig; @@ -339,6 +350,66 @@ Bool vncHooksInit(ScreenPtr pScreen, XserverDesktop* desktop) return TRUE; } +///////////////////////////////////////////////////////////////////////////// +// vncGetScreenImage() grabs a chunk of data from the main screen into the +// provided buffer. It lives here rather than in XorgGlue.c because it +// temporarily pauses the hooks. + +void vncGetScreenImage(int scrIdx, int x, int y, int width, int height, + char *buffer, int strideBytes) +{ + ScreenPtr pScreen = screenInfo.screens[scrIdx]; + vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen); + + int i; + + vncHooksScreen->ignoreHooks++; + + // We do one line at a time since GetImage() cannot handle stride + for (i = y; i < y + height; i++) { + DrawablePtr pDrawable; +#if XORG < 19 + pDrawable = (DrawablePtr) WindowTable[scrIdx]; +#else + pDrawable = (DrawablePtr) pScreen->root; +#endif + + (*pScreen->GetImage) (pDrawable, x, i, width, 1, + ZPixmap, (unsigned long)~0L, buffer); + + buffer += strideBytes; + } + + vncHooksScreen->ignoreHooks--; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Helper functions for adding changes and copies +// + +static inline void add_changed(ScreenPtr pScreen, RegionPtr reg) +{ + vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen); + if (vncHooksScreen->ignoreHooks) + return; + vncAddChanged(pScreen->myNum, + (const struct UpdateRect*)REGION_EXTENTS(pScreen, reg), + REGION_NUM_RECTS(reg), + (const struct UpdateRect*)REGION_RECTS(reg)); +} + +static inline void add_copied(ScreenPtr pScreen, RegionPtr dst, + int dx, int dy) +{ + vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen); + if (vncHooksScreen->ignoreHooks) + return; + vncAddCopied(pScreen->myNum, + (const struct UpdateRect*)REGION_EXTENTS(pScreen, dst), + REGION_NUM_RECTS(dst), + (const struct UpdateRect*)REGION_RECTS(dst), dx, dy); +} ///////////////////////////////////////////////////////////////////////////// @@ -347,9 +418,6 @@ Bool vncHooksInit(ScreenPtr pScreen, XserverDesktop* desktop) // // SCREEN_UNWRAP and SCREEN_REWRAP unwrap and rewrap the given screen function. -// It would be nice to do this with a C++ class, but each function is of a -// distinct type, so it would have to use templates, and it's not worth that -// much pain. #define SCREEN_UNWRAP(scrn,field) \ ScreenPtr pScreen = scrn; \ @@ -369,6 +437,13 @@ static Bool vncHooksCloseScreen(int i, ScreenPtr pScreen_) static Bool vncHooksCloseScreen(ScreenPtr pScreen_) #endif { +#ifdef RENDER + PictureScreenPtr ps; +#endif +#ifdef RANDR + rrScrPrivPtr rp; +#endif + SCREEN_UNWRAP(pScreen_, CloseScreen); pScreen->CreateGC = vncHooksScreen->CreateGC; @@ -380,7 +455,6 @@ static Bool vncHooksCloseScreen(ScreenPtr pScreen_) pScreen->DisplayCursor = vncHooksScreen->DisplayCursor; pScreen->BlockHandler = vncHooksScreen->BlockHandler; #ifdef RENDER - PictureScreenPtr ps; ps = GetPictureScreenIfSet(pScreen); if (ps) { ps->Composite = vncHooksScreen->Composite; @@ -388,7 +462,6 @@ static Bool vncHooksCloseScreen(ScreenPtr pScreen_) } #endif #ifdef RANDR - rrScrPrivPtr rp; rp = rrGetScrPriv(pScreen); if (rp) { rp->rrSetConfig = vncHooksScreen->RandRSetConfig; @@ -410,11 +483,12 @@ static Bool vncHooksCloseScreen(ScreenPtr pScreen_) static Bool vncHooksCreateGC(GCPtr pGC) { - SCREEN_UNWRAP(pGC->pScreen, CreateGC); - vncHooksGCPtr vncHooksGC = vncHooksGCPrivate(pGC); + Bool ret; + + SCREEN_UNWRAP(pGC->pScreen, CreateGC); - Bool ret = (*pScreen->CreateGC) (pGC); + ret = (*pScreen->CreateGC) (pGC); vncHooksGC->wrappedOps = 0; vncHooksGC->wrappedFuncs = pGC->funcs; @@ -432,13 +506,21 @@ static Bool vncHooksCreateGC(GCPtr pGC) static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr pOldRegion) { + int dx, dy; + BoxRec screen_box; + RegionRec copied, screen_rgn; + SCREEN_UNWRAP(pWin->drawable.pScreen, CopyWindow); - int dx, dy; - RegionHelper copied(pScreen, pOldRegion); + REGION_NULL(pScreen, &copied); + REGION_COPY(pScreen, &copied, pOldRegion); + + screen_box.x1 = 0; + screen_box.y1 = 0; + screen_box.x2 = pScreen->width; + screen_box.y2 = pScreen->height; - BoxRec screen_box = {0, 0, pScreen->width, pScreen->height}; - RegionHelper screen_rgn(pScreen, &screen_box, 1); + REGION_INIT(pScreen, &screen_rgn, &screen_box, 1); dx = pWin->drawable.x - ptOldOrg.x; dy = pWin->drawable.y - ptOldOrg.y; @@ -447,15 +529,18 @@ static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, // We also need to copy with changes to the Window's clipping region. // Finally, make sure we don't get copies to or from regions outside // the framebuffer. - REGION_INTERSECT(pScreen, copied.reg, copied.reg, screen_rgn.reg); - REGION_TRANSLATE(pScreen, copied.reg, dx, dy); - REGION_INTERSECT(pScreen, copied.reg, copied.reg, screen_rgn.reg); - REGION_INTERSECT(pScreen, copied.reg, copied.reg, &pWin->borderClip); + REGION_INTERSECT(pScreen, &copied, &copied, &screen_rgn); + REGION_TRANSLATE(pScreen, &copied, dx, dy); + REGION_INTERSECT(pScreen, &copied, &copied, &screen_rgn); + REGION_INTERSECT(pScreen, &copied, &copied, &pWin->borderClip); (*pScreen->CopyWindow) (pWin, ptOldOrg, pOldRegion); - if (REGION_NOTEMPTY(pScreen, copied.reg)) - vncHooksScreen->desktop->add_copied(copied.reg, dx, dy); + if (REGION_NOTEMPTY(pScreen, &copied)) + add_copied(pScreen, &copied, dx, dy); + + REGION_UNINIT(pScreen, &copied); + REGION_UNINIT(pScreen, &screen_rgn); SCREEN_REWRAP(CopyWindow); } @@ -466,24 +551,27 @@ static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w, int h, Bool generateExposures) { + BoxRec box; + RegionRec reg; + SCREEN_UNWRAP(pWin->drawable.pScreen, ClearToBackground); - BoxRec box; box.x1 = x + pWin->drawable.x; box.y1 = y + pWin->drawable.y; box.x2 = w ? (box.x1 + w) : (pWin->drawable.x + pWin->drawable.width); box.y2 = h ? (box.y1 + h) : (pWin->drawable.y + pWin->drawable.height); - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, &pWin->clipList); + REGION_INIT(pScreen, ®, &box, 0); + REGION_INTERSECT(pScreen, ®, ®, &pWin->clipList); (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures); if (!generateExposures) { - vncHooksScreen->desktop->add_changed(changed.reg); + add_changed(pScreen, ®); } + REGION_UNINIT(pScreen, ®); + SCREEN_REWRAP(ClearToBackground); } @@ -492,13 +580,18 @@ static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w, static RegionPtr vncHooksRestoreAreas(WindowPtr pWin, RegionPtr pRegion) { + RegionRec reg; + SCREEN_UNWRAP(pWin->drawable.pScreen, RestoreAreas); - RegionHelper changed(pScreen, pRegion); + REGION_NULL(pScreen, ®); + REGION_COPY(pScreen, ®, pRegion); RegionPtr result = (*pScreen->RestoreAreas) (pWin, pRegion); - vncHooksScreen->desktop->add_changed(changed.reg); + add_changed(pScreen, ®); + + REGION_UNINIT(pScreen, ®); SCREEN_REWRAP(RestoreAreas); @@ -514,25 +607,98 @@ static Bool vncHooksDisplayCursor( #endif ScreenPtr pScreen_, CursorPtr cursor) { + Bool ret; + SCREEN_UNWRAP(pScreen_, DisplayCursor); - Bool ret = (*pScreen->DisplayCursor) ( + ret = (*pScreen->DisplayCursor) ( #if XORG >= 16 pDev, #endif pScreen, cursor); + #if XORG >= 16 /* * XXX DIX calls this function with NULL argument to remove cursor sprite from * screen. Should we handle this in setCursor as well? */ - if (cursor != NullCursor) { + if (cursor != NullCursor) #endif - vncHooksScreen->desktop->setCursor(cursor); -#if XORG >= 16 - } + { + int width, height; + int hotX, hotY; + + unsigned char *rgbaData; + + width = cursor->bits->width; + height = cursor->bits->height; + + hotX = cursor->bits->xhot; + hotY = cursor->bits->yhot; + + rgbaData = malloc(width * height * 4); + if (rgbaData == NULL) + goto out; + +#ifdef ARGB_CURSOR + if (cursor->bits->argb) { + unsigned char *out; + CARD32 *in; + int i; + + in = cursor->bits->argb; + out = rgbaData; + for (i = 0; i < width*height; i++) { + out[0] = (*in >> 16) & 0xff; + out[1] = (*in >> 8) & 0xff; + out[2] = (*in >> 0) & 0xff; + out[3] = (*in >> 24) & 0xff; + out += 4; + in++; + } + } else { +#endif + unsigned char *out; + int xMaskBytesPerRow; + + xMaskBytesPerRow = BitmapBytePad(width); + + out = rgbaData; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + int byte = y * xMaskBytesPerRow + x / 8; +#if (BITMAP_BIT_ORDER == MSBFirst) + int bit = 7 - x % 8; +#else + int bit = x % 8; #endif + if (cursor->bits->source[byte] & (1 << bit)) { + out[0] = cursor->foreRed; + out[1] = cursor->foreGreen; + out[2] = cursor->foreBlue; + } else { + out[0] = cursor->backRed; + out[1] = cursor->backGreen; + out[2] = cursor->backBlue; + } + + if (cursor->bits->mask[byte] & (1 << bit)) + out[3] = 0xff; + else + out[3] = 0x00; + + out += 4; + } + } +#ifdef ARGB_CURSOR + } +#endif + + vncSetCursor(pScreen->myNum, width, height, hotX, hotY, rgbaData); + } + +out: SCREEN_REWRAP(DisplayCursor); return ret; @@ -555,7 +721,7 @@ static void vncHooksBlockHandler(ScreenPtr pScreen_, void * pTimeout, SCREEN_UNWRAP(pScreen_, BlockHandler); #endif - vncHooksScreen->desktop->ignoreHooks(true); + vncHooksScreen->ignoreHooks++; #if XORG <= 112 (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); @@ -563,7 +729,7 @@ static void vncHooksBlockHandler(ScreenPtr pScreen_, void * pTimeout, (*pScreen->BlockHandler) (pScreen, pTimeout, pReadmask); #endif - vncHooksScreen->desktop->ignoreHooks(false); + vncHooksScreen->ignoreHooks--; SCREEN_REWRAP(BlockHandler); } @@ -580,28 +746,20 @@ void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen); PictureScreenPtr ps = GetPictureScreen(pScreen); - RegionHelper changed(pScreen); + RegionRec changed; if (pDst->pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr) pDst->pDrawable)->viewable) { BoxRec box; - rfb::Rect rect1, rect2; - - rect1.setXYWH(pDst->pDrawable->x + xDst, - pDst->pDrawable->y + yDst, - width, - height); - - rect2 = rect1.intersect(vncHooksScreen->desktop->getRect()); - box.x1 = rect2.tl.x; - box.y1 = rect2.tl.y; - box.x2 = rect2.br.x; - box.y2 = rect2.br.y; + box.x1 = max(pDst->pDrawable->x + xDst, 0); + box.y1 = max(pDst->pDrawable->y + yDst, 0); + box.x2 = min(box.x1 + width, pScreen->width); + box.y2 = min(box.y1 + height, pScreen->height); - changed.init(&box, 0); + REGION_INIT(pScreen, &changed, &box, 0); } else { - changed.init(NullBox, 0); + REGION_NULL(pScreen, &changed); } @@ -610,8 +768,10 @@ void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, xMask, yMask, xDst, yDst, width, height); ps->Composite = vncHooksComposite; - if (REGION_NOTEMPTY(pScreen, changed.reg)) - vncHooksScreen->desktop->add_changed(changed.reg); + if (REGION_NOTEMPTY(pScreen, &changed)) + add_changed(pScreen, &changed); + + REGION_UNINIT(pScreen, &changed); } static int @@ -672,38 +832,38 @@ void vncHooksGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen); PictureScreenPtr ps = GetPictureScreen(pScreen); - RegionHelper changed(pScreen); + RegionPtr changed; if (pDst->pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr) pDst->pDrawable)->viewable) { - rfb::Rect fbrect; BoxRec fbbox; RegionRec fbreg; - changed.reg = GlyphsToRegion(pScreen, nlists, lists, glyphs); - REGION_TRANSLATE(pScreen, changed.reg, + changed = GlyphsToRegion(pScreen, nlists, lists, glyphs); + REGION_TRANSLATE(pScreen, changed, pDst->pDrawable->x, pDst->pDrawable->y); - fbrect = vncHooksScreen->desktop->getRect(); - fbbox.x1 = fbrect.tl.x; - fbbox.y1 = fbrect.tl.y; - fbbox.x2 = fbrect.br.x; - fbbox.y2 = fbrect.br.y; + fbbox.x1 = 0; + fbbox.y1 = 0; + fbbox.x2 = pScreen->width; + fbbox.y2 = pScreen->height; REGION_INIT(pScreen, &fbreg, &fbbox, 0); - REGION_INTERSECT(pScreen, changed.reg, changed.reg, &fbreg); + REGION_INTERSECT(pScreen, changed, changed, &fbreg); REGION_UNINIT(pScreen, &fbreg); } else { - changed.init(NullBox, 0); + changed = REGION_CREATE(pScreen, NullBox, 0); } ps->Glyphs = vncHooksScreen->Glyphs; (*ps->Glyphs)(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlists, lists, glyphs); ps->Glyphs = vncHooksGlyphs; - if (REGION_NOTEMPTY(pScreen, changed.reg)) - vncHooksScreen->desktop->add_changed(changed.reg); + if (REGION_NOTEMPTY(pScreen, changed)) + add_changed(pScreen, changed); + + REGION_DESTROY(pScreen, changed); } #endif /* RENDER */ @@ -712,45 +872,6 @@ void vncHooksGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, #ifdef RANDR -static void vncPreScreenResize(ScreenPtr pScreen) -{ - vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen); - - // We need to prevent the RFB core from accessing the framebuffer - // for a while as there might be updates thrown our way inside - // the routines that change the screen (i.e. before we have a - // pointer to the new framebuffer). - vncHooksScreen->desktop->blockUpdates(); -} - -static void vncPostScreenResize(ScreenPtr pScreen, Bool success) -{ - vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen); - - RegionRec reg; - BoxRec box; - - if (success) { - // Let the RFB core know of the new dimensions and framebuffer - vncHooksScreen->desktop->setFramebuffer(pScreen->width, pScreen->height, - vncFbptr[pScreen->myNum], - vncFbstride[pScreen->myNum]); - } - - vncHooksScreen->desktop->unblockUpdates(); - - if (success) { - // Mark entire screen as changed - box.x1 = 0; - box.y1 = 0; - box.x2 = pScreen->width; - box.y2 = pScreen->height; - REGION_INIT(pScreen, ®, &box, 1); - - vncHooksScreen->desktop->add_changed(®); - } -} - static Bool vncHooksRandRSetConfig(ScreenPtr pScreen, Rotation rotation, int rate, RRScreenSizePtr pSize) { @@ -758,13 +879,13 @@ static Bool vncHooksRandRSetConfig(ScreenPtr pScreen, Rotation rotation, rrScrPrivPtr rp = rrGetScrPriv(pScreen); Bool ret; - vncPreScreenResize(pScreen); + vncPreScreenResize(pScreen->myNum); rp->rrSetConfig = vncHooksScreen->RandRSetConfig; ret = (*rp->rrSetConfig)(pScreen, rotation, rate, pSize); rp->rrSetConfig = vncHooksRandRSetConfig; - vncPostScreenResize(pScreen, ret); + vncPostScreenResize(pScreen->myNum, ret, pScreen->width, pScreen->height); if (!ret) return FALSE; @@ -780,13 +901,13 @@ static Bool vncHooksRandRScreenSetSize(ScreenPtr pScreen, rrScrPrivPtr rp = rrGetScrPriv(pScreen); Bool ret; - vncPreScreenResize(pScreen); + vncPreScreenResize(pScreen->myNum); rp->rrScreenSetSize = vncHooksScreen->RandRScreenSetSize; ret = (*rp->rrScreenSetSize)(pScreen, width, height, mmWidth, mmHeight); rp->rrScreenSetSize = vncHooksRandRScreenSetSize; - vncPostScreenResize(pScreen, ret); + vncPostScreenResize(pScreen->myNum, ret, pScreen->width, pScreen->height); if (!ret) return FALSE; @@ -811,7 +932,7 @@ static Bool vncHooksRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc, if (!ret) return FALSE; - vncHooksScreen->desktop->refreshScreenLayout(); + vncRefreshScreenLayout(pScreen->myNum); return TRUE; } @@ -823,76 +944,73 @@ static Bool vncHooksRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc, // GC "funcs" // -// GCFuncUnwrapper is a helper class which unwraps the GC funcs and ops in its -// constructor and rewraps them in its destructor. - -class GCFuncUnwrapper { -public: - GCFuncUnwrapper(GCPtr pGC_) : pGC(pGC_) { - vncHooksGC = vncHooksGCPrivate(pGC); - pGC->funcs = vncHooksGC->wrappedFuncs; - if (vncHooksGC->wrappedOps) - pGC->ops = vncHooksGC->wrappedOps; - } - ~GCFuncUnwrapper() { - vncHooksGC->wrappedFuncs = pGC->funcs; - pGC->funcs = &vncHooksGCFuncs; - if (vncHooksGC->wrappedOps) { - vncHooksGC->wrappedOps = pGC->ops; - pGC->ops = &vncHooksGCOps; +// Unwrap and rewrap helpers + +#define GC_FUNC_PROLOGUE(pGC, name)\ + vncHooksGCPtr pGCPriv = vncHooksGCPrivate(pGC);\ + (pGC)->funcs = pGCPriv->wrappedFuncs;\ + if(pGCPriv->wrappedOps)\ + (pGC)->ops = pGCPriv->wrappedOps; \ + DBGPRINT((stderr,"vncHooks" #name " called\n")) + +#define GC_FUNC_EPILOGUE(pGC)\ + pGCPriv->wrappedFuncs = (pGC)->funcs;\ + (pGC)->funcs = &vncHooksGCFuncs;\ + if(pGCPriv->wrappedOps) {\ + pGCPriv->wrappedOps = (pGC)->ops;\ + (pGC)->ops = &vncHooksGCOps;\ } - } - GCPtr pGC; - vncHooksGCPtr vncHooksGC; -}; - // ValidateGC - wrap the "ops" if a viewable window OR the screen pixmap static void vncHooksValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) { - GCFuncUnwrapper u(pGC); - - DBGPRINT((stderr,"vncHooksValidateGC called\n")); - + GC_FUNC_PROLOGUE(pGC, ValidateGC); (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable); - - u.vncHooksGC->wrappedOps = 0; if ((pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr) pDrawable)->viewable) || (pDrawable == &pGC->pScreen->GetScreenPixmap(pGC->pScreen)->drawable)) { - u.vncHooksGC->wrappedOps = pGC->ops; + pGCPriv->wrappedOps = pGC->ops; DBGPRINT((stderr,"vncHooksValidateGC: wrapped GC ops\n")); - } + } else { + pGCPriv->wrappedOps = NULL; + } + GC_FUNC_EPILOGUE(pGC); } // Other GC funcs - just unwrap and call on static void vncHooksChangeGC(GCPtr pGC, unsigned long mask) { - GCFuncUnwrapper u(pGC); + GC_FUNC_PROLOGUE(pGC, ChangeGC); (*pGC->funcs->ChangeGC) (pGC, mask); + GC_FUNC_EPILOGUE(pGC); } static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst) { - GCFuncUnwrapper u(dst); + GC_FUNC_PROLOGUE(dst, CopyGC); (*dst->funcs->CopyGC) (src, mask, dst); + GC_FUNC_EPILOGUE(dst); } static void vncHooksDestroyGC(GCPtr pGC) { - GCFuncUnwrapper u(pGC); + GC_FUNC_PROLOGUE(pGC, DestroyGC); (*pGC->funcs->DestroyGC) (pGC); + GC_FUNC_EPILOGUE(pGC); } static void vncHooksChangeClip(GCPtr pGC, int type, void * pValue, int nrects) { - GCFuncUnwrapper u(pGC); + GC_FUNC_PROLOGUE(pGC, ChangeClip); (*pGC->funcs->ChangeClip) (pGC, type, pValue, nrects); + GC_FUNC_EPILOGUE(pGC); } static void vncHooksDestroyClip(GCPtr pGC) { - GCFuncUnwrapper u(pGC); + GC_FUNC_PROLOGUE(pGC, DestroyClip); (*pGC->funcs->DestroyClip) (pGC); + GC_FUNC_EPILOGUE(pGC); } static void vncHooksCopyClip(GCPtr dst, GCPtr src) { - GCFuncUnwrapper u(dst); + GC_FUNC_PROLOGUE(dst, CopyClip); (*dst->funcs->CopyClip) (dst, src); + GC_FUNC_EPILOGUE(dst); } @@ -901,40 +1019,19 @@ static void vncHooksCopyClip(GCPtr dst, GCPtr src) { // GC "ops" // -// GCOpUnwrapper is a helper class which unwraps the GC funcs and ops in its -// constructor and rewraps them in its destructor. +// Unwrap and rewrap helpers -class GCOpUnwrapper { -public: - GCOpUnwrapper(DrawablePtr pDrawable, GCPtr pGC_) - : pGC(pGC_), pScreen(pDrawable->pScreen) - { - vncHooksGC = vncHooksGCPrivate(pGC); - oldFuncs = pGC->funcs; - pGC->funcs = vncHooksGC->wrappedFuncs; - pGC->ops = vncHooksGC->wrappedOps; - } - ~GCOpUnwrapper() { - vncHooksGC->wrappedOps = pGC->ops; - pGC->funcs = oldFuncs; - pGC->ops = &vncHooksGCOps; - } - GCPtr pGC; - vncHooksGCPtr vncHooksGC; -#if XORG >= 116 - const GCFuncs* oldFuncs; -#else - GCFuncs* oldFuncs; -#endif - ScreenPtr pScreen; -}; - -#define GC_OP_UNWRAPPER(pDrawable, pGC, name) \ - GCOpUnwrapper u(pDrawable, pGC); \ - ScreenPtr pScreen = (pDrawable)->pScreen; \ - vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen); \ - DBGPRINT((stderr,"vncHooks" #name " called\n")); +#define GC_OP_PROLOGUE(pGC, name)\ + vncHooksGCPtr pGCPriv = vncHooksGCPrivate(pGC);\ + GCFuncs *oldFuncs = pGC->funcs;\ + pGC->funcs = pGCPriv->wrappedFuncs;\ + pGC->ops = pGCPriv->wrappedOps; \ + DBGPRINT((stderr,"vncHooks" #name " called\n")) +#define GC_OP_EPILOGUE(pGC)\ + pGCPriv->wrappedOps = pGC->ops;\ + pGC->funcs = oldFuncs;\ + pGC->ops = &vncHooksGCOps // FillSpans - assume the entire clip region is damaged. This is pessimistic, // but I believe this function is rarely used so it doesn't matter. @@ -943,17 +1040,23 @@ static void vncHooksFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit, DDXPointPtr pptInit, int *pwidthInit, int fSorted) { - GC_OP_UNWRAPPER(pDrawable, pGC, FillSpans); + RegionRec reg; + + GC_OP_PROLOGUE(pGC, FillSpans); - RegionHelper changed(pScreen, pGC->pCompositeClip); + REGION_NULL(pGC->pScreen, ®); + REGION_COPY(pGC->pScreen, ®, pGC->pCompositeClip); if (pDrawable->type == DRAWABLE_WINDOW) - REGION_INTERSECT(pScreen, changed.reg, changed.reg, - &((WindowPtr)pDrawable)->borderClip); + REGION_INTERSECT(pScreen, ®, ®, &((WindowPtr)pDrawable)->borderClip); (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted); - vncHooksScreen->desktop->add_changed(changed.reg); + add_changed(pGC->pScreen, ®); + + REGION_UNINIT(pGC->pScreen, ®); + + GC_OP_EPILOGUE(pGC); } // SetSpans - assume the entire clip region is damaged. This is pessimistic, @@ -963,17 +1066,23 @@ static void vncHooksSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc, DDXPointPtr ppt, int *pwidth, int nspans, int fSorted) { - GC_OP_UNWRAPPER(pDrawable, pGC, SetSpans); + RegionRec reg; - RegionHelper changed(pScreen, pGC->pCompositeClip); + GC_OP_PROLOGUE(pGC, SetSpans); + + REGION_NULL(pGC->pScreen, ®); + REGION_COPY(pGC->pScreen, ®, pGC->pCompositeClip); if (pDrawable->type == DRAWABLE_WINDOW) - REGION_INTERSECT(pScreen, changed.reg, changed.reg, - &((WindowPtr)pDrawable)->borderClip); + REGION_INTERSECT(pScreen, ®, ®, &((WindowPtr)pDrawable)->borderClip); (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); - vncHooksScreen->desktop->add_changed(changed.reg); + add_changed(pGC->pScreen, ®); + + REGION_UNINIT(pGC->pScreen, ®); + + GC_OP_EPILOGUE(pGC); } // PutImage - changed region is the given rectangle, clipped by pCompositeClip @@ -982,22 +1091,27 @@ static void vncHooksPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, int w, int h, int leftPad, int format, char *pBits) { - GC_OP_UNWRAPPER(pDrawable, pGC, PutImage); - BoxRec box; + RegionRec reg; + + GC_OP_PROLOGUE(pGC, PutImage); + box.x1 = x + pDrawable->x; box.y1 = y + pDrawable->y; box.x2 = box.x1 + w; box.y2 = box.y1 + h; - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip); + REGION_INIT(pGC->pScreen, ®, &box, 0); + REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip); (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits); - vncHooksScreen->desktop->add_changed(changed.reg); + add_changed(pGC->pScreen, ®); + + REGION_UNINIT(pGC->pScreen, ®); + + GC_OP_EPILOGUE(pGC); } // CopyArea - destination of the copy is the dest rectangle, clipped by @@ -1008,59 +1122,67 @@ static RegionPtr vncHooksCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty) { - GC_OP_UNWRAPPER(pDst, pGC, CopyArea); - BoxRec box; + RegionRec dst, src, changed; + + RegionPtr ret; + + GC_OP_PROLOGUE(pGC, CopyArea); + box.x1 = dstx + pDst->x; box.y1 = dsty + pDst->y; box.x2 = box.x1 + w; box.y2 = box.y1 + h; - RegionHelper dst(pScreen, &box, 0); - REGION_INTERSECT(pScreen, dst.reg, dst.reg, pGC->pCompositeClip); - - RegionHelper src(pScreen); + REGION_INIT(pGC->pScreen, &dst, &box, 0); + REGION_INTERSECT(pGC->pScreen, &dst, &dst, pGC->pCompositeClip); // The source of the data has to be something that's on screen. // This means either a window, or the screen pixmap. - if ((pSrc->pScreen == pScreen) && + if ((pSrc->pScreen == pGC->pScreen) && ((pSrc->type == DRAWABLE_WINDOW) || - (pSrc == &pScreen->GetScreenPixmap(pScreen)->drawable))) { + (pSrc == &pGC->pScreen->GetScreenPixmap(pGC->pScreen)->drawable))) { box.x1 = srcx + pSrc->x; box.y1 = srcy + pSrc->y; box.x2 = box.x1 + w; box.y2 = box.y1 + h; - src.init(&box, 0); + REGION_INIT(pGC->pScreen, &src, &box, 0); if ((pSrc->type == DRAWABLE_WINDOW) && REGION_NOTEMPTY(pScreen, &((WindowPtr)pSrc)->clipList)) { - REGION_INTERSECT(pScreen, src.reg, src.reg, &((WindowPtr)pSrc)->clipList); + REGION_INTERSECT(pScreen, &src, &src, &((WindowPtr)pSrc)->clipList); } - REGION_TRANSLATE(pScreen, src.reg, + REGION_TRANSLATE(pScreen, &src, dstx + pDst->x - srcx - pSrc->x, dsty + pDst->y - srcy - pSrc->y); } else { - src.init(NullBox, 0); + REGION_NULL(pGC->pScreen, &src); } - RegionHelper changed(pScreen, NullBox, 0); - REGION_SUBTRACT(pScreen, changed.reg, dst.reg, src.reg); - REGION_INTERSECT(pScreen, dst.reg, dst.reg, src.reg); + REGION_NULL(pGC->pScreen, &changed); + + REGION_SUBTRACT(pScreen, &changed, &dst, &src); + REGION_INTERSECT(pScreen, &dst, &dst, &src); - RegionPtr rgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h, - dstx, dsty); + ret = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty); - if (REGION_NOTEMPTY(pScreen, dst.reg)) - vncHooksScreen->desktop->add_copied(dst.reg, - dstx + pDst->x - srcx - pSrc->x, - dsty + pDst->y - srcy - pSrc->y); + if (REGION_NOTEMPTY(pScreen, &dst)) + add_copied(pGC->pScreen, &dst, + dstx + pDst->x - srcx - pSrc->x, + dsty + pDst->y - srcy - pSrc->y); - if (REGION_NOTEMPTY(pScreen, changed.reg)) - vncHooksScreen->desktop->add_changed(changed.reg); + if (REGION_NOTEMPTY(pScreen, &changed)) + add_changed(pGC->pScreen, &changed); - return rgn; + REGION_UNINIT(pGC->pScreen, &dst); + REGION_UNINIT(pGC->pScreen, &src); + REGION_UNINIT(pGC->pScreen, &changed); + + GC_OP_EPILOGUE(pGC); + + return ret; } @@ -1071,23 +1193,31 @@ static RegionPtr vncHooksCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty, unsigned long plane) { - GC_OP_UNWRAPPER(pDst, pGC, CopyPlane); - BoxRec box; + RegionRec reg; + + RegionPtr ret; + + GC_OP_PROLOGUE(pGC, CopyPlane); + box.x1 = dstx + pDst->x; box.y1 = dsty + pDst->y; box.x2 = box.x1 + w; box.y2 = box.y1 + h; - RegionHelper changed(pScreen, &box, 0); + REGION_INIT(pGC->pScreen, ®, &box, 0); + REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip); + + ret = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h, + dstx, dsty, plane); + + add_changed(pGC->pScreen, ®); - REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip); + REGION_UNINIT(pGC->pScreen, ®); - RegionPtr rgn = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h, - dstx, dsty, plane); - vncHooksScreen->desktop->add_changed(changed.reg); + GC_OP_EPILOGUE(pGC); - return rgn; + return ret; } // PolyPoint - changed region is the bounding rect, clipped by pCompositeClip @@ -1095,23 +1225,29 @@ static RegionPtr vncHooksCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, xPoint *pts) { - GC_OP_UNWRAPPER(pDrawable, pGC, PolyPoint); + int minX, minY, maxX, maxY; + int i; + + BoxRec box; + RegionRec reg; + + GC_OP_PROLOGUE(pGC, PolyPoint); if (npt == 0) { (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts); - return; + goto out; } - int minX = pts[0].x; - int maxX = pts[0].x; - int minY = pts[0].y; - int maxY = pts[0].y; + minX = pts[0].x; + maxX = pts[0].x; + minY = pts[0].y; + maxY = pts[0].y; if (mode == CoordModePrevious) { int x = pts[0].x; int y = pts[0].y; - for (int i = 1; i < npt; i++) { + for (i = 1; i < npt; i++) { x += pts[i].x; y += pts[i].y; if (x < minX) minX = x; @@ -1120,7 +1256,7 @@ static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, if (y > maxY) maxY = y; } } else { - for (int i = 1; i < npt; i++) { + for (i = 1; i < npt; i++) { if (pts[i].x < minX) minX = pts[i].x; if (pts[i].x > maxX) maxX = pts[i].x; if (pts[i].y < minY) minY = pts[i].y; @@ -1128,19 +1264,22 @@ static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, } } - BoxRec box; box.x1 = minX + pDrawable->x; box.y1 = minY + pDrawable->y; box.x2 = maxX + 1 + pDrawable->x; box.y2 = maxY + 1 + pDrawable->y; - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip); + REGION_INIT(pGC->pScreen, ®, &box, 0); + REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip); (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts); - vncHooksScreen->desktop->add_changed(changed.reg); + add_changed(pGC->pScreen, ®); + + REGION_UNINIT(pGC->pScreen, ®); + +out: + GC_OP_EPILOGUE(pGC); } // Polylines - changed region is the union of the bounding rects of each line, @@ -1150,18 +1289,25 @@ static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppts) { - GC_OP_UNWRAPPER(pDrawable, pGC, Polylines); + int nRegRects; + xRectangle regRects[MAX_RECTS_PER_OP]; + + int lw; + + RegionPtr reg; + + GC_OP_PROLOGUE(pGC, Polylines); if (npt == 0) { (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts); - return; + goto out; } - int nRegRects = npt - 1; - xRectangle regRects[MAX_RECTS_PER_OP]; + nRegRects = npt - 1; - int lw = pGC->lineWidth; - if (lw == 0) lw = 1; + lw = pGC->lineWidth; + if (lw == 0) + lw = 1; if (npt == 1) { @@ -1181,21 +1327,25 @@ static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, * and converted to int yields 6 * lw */ - int extra = lw / 2; - if (pGC->joinStyle == JoinMiter) { - extra = 6 * lw; - } + int extra; int prevX, prevY, curX, curY; int rectX1, rectY1, rectX2, rectY2; int minX, minY, maxX, maxY; + int i; + + extra = lw / 2; + if (pGC->joinStyle == JoinMiter) { + extra = 6 * lw; + } + prevX = ppts[0].x + pDrawable->x; prevY = ppts[0].y + pDrawable->y; minX = maxX = prevX; minY = maxY = prevY; - for (int i = 0; i < nRegRects; i++) { + for (i = 0; i < nRegRects; i++) { if (mode == CoordModeOrigin) { curX = pDrawable->x + ppts[i+1].x; curY = pDrawable->y + ppts[i+1].y; @@ -1245,13 +1395,17 @@ static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, } } - RegionHelper changed(pScreen, nRegRects, regRects); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip); + reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE); + REGION_INTERSECT(pGC->pScreen, reg, reg, pGC->pCompositeClip); (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts); - vncHooksScreen->desktop->add_changed(changed.reg); + add_changed(pGC->pScreen, reg); + + REGION_DESTROY(pGC->pScreen, reg); + +out: + GC_OP_EPILOGUE(pGC); } // PolySegment - changed region is the union of the bounding rects of each @@ -1261,26 +1415,34 @@ static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, static void vncHooksPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment *segs) { - GC_OP_UNWRAPPER(pDrawable, pGC, PolySegment); + xRectangle regRects[MAX_RECTS_PER_OP]; + int nRegRects; + + int lw, extra; + + int rectX1, rectY1, rectX2, rectY2; + int minX, minY, maxX, maxY; + + int i; + + RegionPtr reg; + + GC_OP_PROLOGUE(pGC, PolySegment); if (nseg == 0) { (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs); - return; + goto out; } - xRectangle regRects[MAX_RECTS_PER_OP]; - int nRegRects = nseg; + nRegRects = nseg; - int lw = pGC->lineWidth; - int extra = lw / 2; - - int rectX1, rectY1, rectX2, rectY2; - int minX, minY, maxX, maxY; + lw = pGC->lineWidth; + extra = lw / 2; minX = maxX = segs[0].x1; minY = maxY = segs[0].y1; - for (int i = 0; i < nseg; i++) { + for (i = 0; i < nseg; i++) { if (segs[i].x1 > segs[i].x2) { rectX1 = pDrawable->x + segs[i].x2 - extra; rectX2 = pDrawable->x + segs[i].x1 + extra + 1; @@ -1318,13 +1480,17 @@ static void vncHooksPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg, nRegRects = 1; } - RegionHelper changed(pScreen, nRegRects, regRects); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip); + reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE); + REGION_INTERSECT(pGC->pScreen, reg, reg, pGC->pCompositeClip); (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs); - vncHooksScreen->desktop->add_changed(changed.reg); + add_changed(pGC->pScreen, reg); + + REGION_DESTROY(pGC->pScreen, reg); + +out: + GC_OP_EPILOGUE(pGC); } // PolyRectangle - changed region is the union of the bounding rects around @@ -1335,26 +1501,34 @@ static void vncHooksPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg, static void vncHooksPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects, xRectangle *rects) { - GC_OP_UNWRAPPER(pDrawable, pGC, PolyRectangle); + xRectangle regRects[MAX_RECTS_PER_OP*4]; + int nRegRects; + + int lw, extra; + + int rectX1, rectY1, rectX2, rectY2; + int minX, minY, maxX, maxY; + + int i; + + RegionPtr reg; + + GC_OP_PROLOGUE(pGC, PolyRectangle); if (nrects == 0) { (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects); - return; + goto out; } - xRectangle regRects[MAX_RECTS_PER_OP*4]; - int nRegRects = nrects * 4; + nRegRects = nrects * 4; - int lw = pGC->lineWidth; - int extra = lw / 2; - - int rectX1, rectY1, rectX2, rectY2; - int minX, minY, maxX, maxY; + lw = pGC->lineWidth; + extra = lw / 2; minX = maxX = rects[0].x; minY = maxY = rects[0].y; - for (int i = 0; i < nrects; i++) { + for (i = 0; i < nrects; i++) { if (nrects <= MAX_RECTS_PER_OP) { regRects[i*4].x = rects[i].x - extra + pDrawable->x; regRects[i*4].y = rects[i].y - extra + pDrawable->y; @@ -1395,13 +1569,17 @@ static void vncHooksPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects, nRegRects = 1; } - RegionHelper changed(pScreen, nRegRects, regRects); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip); + reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE); + REGION_INTERSECT(pGC->pScreen, reg, reg, pGC->pCompositeClip); (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects); - vncHooksScreen->desktop->add_changed(changed.reg); + add_changed(pGC->pScreen, reg); + + REGION_DESTROY(pGC->pScreen, reg); + +out: + GC_OP_EPILOGUE(pGC); } // PolyArc - changed region is the union of bounding rects around each arc, @@ -1411,27 +1589,36 @@ static void vncHooksPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects, static void vncHooksPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *arcs) { - GC_OP_UNWRAPPER(pDrawable, pGC, PolyArc); + xRectangle regRects[MAX_RECTS_PER_OP]; + int nRegRects; + + int lw, extra; + + int rectX1, rectY1, rectX2, rectY2; + int minX, minY, maxX, maxY; + + int i; + + RegionPtr reg; + + GC_OP_PROLOGUE(pGC, PolyArc); if (narcs == 0) { (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs); - return; + goto out; } - xRectangle regRects[MAX_RECTS_PER_OP]; - int nRegRects = narcs; + nRegRects = narcs; - int lw = pGC->lineWidth; - if (lw == 0) lw = 1; - int extra = lw / 2; - - int rectX1, rectY1, rectX2, rectY2; - int minX, minY, maxX, maxY; + lw = pGC->lineWidth; + if (lw == 0) + lw = 1; + extra = lw / 2; minX = maxX = arcs[0].x; minY = maxY = arcs[0].y; - for (int i = 0; i < narcs; i++) { + for (i = 0; i < narcs; i++) { if (narcs <= MAX_RECTS_PER_OP) { regRects[i].x = arcs[i].x - extra + pDrawable->x; regRects[i].y = arcs[i].y - extra + pDrawable->y; @@ -1457,13 +1644,17 @@ static void vncHooksPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, nRegRects = 1; } - RegionHelper changed(pScreen, nRegRects, regRects); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip); + reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE); + REGION_INTERSECT(pGC->pScreen, reg, reg, pGC->pCompositeClip); (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs); - vncHooksScreen->desktop->add_changed(changed.reg); + add_changed(pGC->pScreen, reg); + + REGION_DESTROY(pGC->pScreen, reg); + +out: + GC_OP_EPILOGUE(pGC); } @@ -1473,23 +1664,29 @@ static void vncHooksPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape, int mode, int count, DDXPointPtr pts) { - GC_OP_UNWRAPPER(pDrawable, pGC, FillPolygon); + int minX, minY, maxX, maxY; + int i; + + BoxRec box; + RegionRec reg; + + GC_OP_PROLOGUE(pGC, FillPolygon); if (count == 0) { (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts); - return; + goto out; } - int minX = pts[0].x; - int maxX = pts[0].x; - int minY = pts[0].y; - int maxY = pts[0].y; + minX = pts[0].x; + maxX = pts[0].x; + minY = pts[0].y; + maxY = pts[0].y; if (mode == CoordModePrevious) { int x = pts[0].x; int y = pts[0].y; - for (int i = 1; i < count; i++) { + for (i = 1; i < count; i++) { x += pts[i].x; y += pts[i].y; if (x < minX) minX = x; @@ -1498,7 +1695,7 @@ static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape, if (y > maxY) maxY = y; } } else { - for (int i = 1; i < count; i++) { + for (i = 1; i < count; i++) { if (pts[i].x < minX) minX = pts[i].x; if (pts[i].x > maxX) maxX = pts[i].x; if (pts[i].y < minY) minY = pts[i].y; @@ -1506,19 +1703,22 @@ static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape, } } - BoxRec box; box.x1 = minX + pDrawable->x; box.y1 = minY + pDrawable->y; box.x2 = maxX + 1 + pDrawable->x; box.y2 = maxY + 1 + pDrawable->y; - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip); + REGION_INIT(pGC->pScreen, ®, &box, 0); + REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip); (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts); - vncHooksScreen->desktop->add_changed(changed.reg); + add_changed(pGC->pScreen, ®); + + REGION_UNINIT(pGC->pScreen, ®); + +out: + GC_OP_EPILOGUE(pGC); } // PolyFillRect - changed region is the union of the rectangles, clipped by @@ -1528,21 +1728,26 @@ static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape, static void vncHooksPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects, xRectangle *rects) { - GC_OP_UNWRAPPER(pDrawable, pGC, PolyFillRect); + xRectangle regRects[MAX_RECTS_PER_OP]; + int nRegRects; + int rectX1, rectY1, rectX2, rectY2; + int minX, minY, maxX, maxY; + int i; + + RegionPtr reg; + + GC_OP_PROLOGUE(pGC, PolyFillRect); if (nrects == 0) { (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects); - return; + goto out; } - xRectangle regRects[MAX_RECTS_PER_OP]; - int nRegRects = nrects; - int rectX1, rectY1, rectX2, rectY2; - int minX, minY, maxX, maxY; + nRegRects = nrects; minX = maxX = rects[0].x; minY = maxY = rects[0].y; - for (int i = 0; i < nrects; i++) { + for (i = 0; i < nrects; i++) { if (nrects <= MAX_RECTS_PER_OP) { regRects[i].x = rects[i].x + pDrawable->x; regRects[i].y = rects[i].y + pDrawable->y; @@ -1568,13 +1773,17 @@ static void vncHooksPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects, nRegRects = 1; } - RegionHelper changed(pScreen, nRegRects, regRects); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip); + reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE); + REGION_INTERSECT(pGC->pScreen, reg, reg, pGC->pCompositeClip); (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects); - vncHooksScreen->desktop->add_changed(changed.reg); + add_changed(pGC->pScreen, reg); + + REGION_DESTROY(pGC->pScreen, reg); + +out: + GC_OP_EPILOGUE(pGC); } // PolyFillArc - changed region is the union of bounding rects around each arc, @@ -1584,27 +1793,36 @@ static void vncHooksPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects, static void vncHooksPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *arcs) { - GC_OP_UNWRAPPER(pDrawable, pGC, PolyFillArc); + xRectangle regRects[MAX_RECTS_PER_OP]; + int nRegRects; + + int lw, extra; + + int rectX1, rectY1, rectX2, rectY2; + int minX, minY, maxX, maxY; + + int i; + + RegionPtr reg; + + GC_OP_PROLOGUE(pGC, PolyFillArc); if (narcs == 0) { (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs); - return; + goto out; } - xRectangle regRects[MAX_RECTS_PER_OP]; - int nRegRects = narcs; - - int lw = pGC->lineWidth; - if (lw == 0) lw = 1; - int extra = lw / 2; + nRegRects = narcs; - int rectX1, rectY1, rectX2, rectY2; - int minX, minY, maxX, maxY; + lw = pGC->lineWidth; + if (lw == 0) + lw = 1; + extra = lw / 2; minX = maxX = arcs[0].x; minY = maxY = arcs[0].y; - for (int i = 0; i < narcs; i++) { + for (i = 0; i < narcs; i++) { if (narcs <= MAX_RECTS_PER_OP) { regRects[i].x = arcs[i].x - extra + pDrawable->x; regRects[i].y = arcs[i].y - extra + pDrawable->y; @@ -1630,13 +1848,17 @@ static void vncHooksPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, nRegRects = 1; } - RegionHelper changed(pScreen, nRegRects, regRects); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip); + reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE); + REGION_INTERSECT(pGC->pScreen, reg, reg, pGC->pCompositeClip); (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs); - vncHooksScreen->desktop->add_changed(changed.reg); + add_changed(pGC->pScreen, reg); + + REGION_DESTROY(pGC->pScreen, reg); + +out: + GC_OP_EPILOGUE(pGC); } // GetTextBoundingRect - calculate a bounding rectangle around n chars of a @@ -1645,10 +1867,10 @@ static void vncHooksPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, static void GetTextBoundingRect(DrawablePtr pDrawable, FontPtr font, int x, int y, int nchars, BoxPtr box) { - int ascent = __rfbmax(FONTASCENT(font), FONTMAXBOUNDS(font, ascent)); - int descent = __rfbmax(FONTDESCENT(font), FONTMAXBOUNDS(font, descent)); - int charWidth = __rfbmax(FONTMAXBOUNDS(font,rightSideBearing), - FONTMAXBOUNDS(font,characterWidth)); + int ascent = max(FONTASCENT(font), FONTMAXBOUNDS(font, ascent)); + int descent = max(FONTDESCENT(font), FONTMAXBOUNDS(font, descent)); + int charWidth = max(FONTMAXBOUNDS(font,rightSideBearing), + FONTMAXBOUNDS(font,characterWidth)); box->x1 = pDrawable->x + x; box->y1 = pDrawable->y + y - ascent; @@ -1665,21 +1887,30 @@ static void GetTextBoundingRect(DrawablePtr pDrawable, FontPtr font, int x, static int vncHooksPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y, int count, char *chars) { - GC_OP_UNWRAPPER(pDrawable, pGC, PolyText8); + int ret; + BoxRec box; + RegionRec reg; - if (count == 0) - return (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars); + GC_OP_PROLOGUE(pGC, PolyText8); + + if (count == 0) { + ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars); + goto out; + } - BoxRec box; GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box); - RegionHelper changed(pScreen, &box, 0); + REGION_INIT(pGC->pScreen, ®, &box, 0); + REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip); + + ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars); - REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip); + add_changed(pGC->pScreen, ®); - int ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars); + REGION_UNINIT(pGC->pScreen, ®); - vncHooksScreen->desktop->add_changed(changed.reg); +out: + GC_OP_EPILOGUE(pGC); return ret; } @@ -1690,21 +1921,30 @@ static int vncHooksPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y, static int vncHooksPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y, int count, unsigned short *chars) { - GC_OP_UNWRAPPER(pDrawable, pGC, PolyText16); + int ret; + BoxRec box; + RegionRec reg; - if (count == 0) - return (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars); + GC_OP_PROLOGUE(pGC, PolyText16); + + if (count == 0) { + ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars); + goto out; + } - BoxRec box; GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box); - RegionHelper changed(pScreen, &box, 0); + REGION_INIT(pGC->pScreen, ®, &box, 0); + REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip); + + ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars); - REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip); + add_changed(pGC->pScreen, ®); - int ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars); + REGION_UNINIT(pGC->pScreen, ®); - vncHooksScreen->desktop->add_changed(changed.reg); +out: + GC_OP_EPILOGUE(pGC); return ret; } @@ -1715,23 +1955,29 @@ static int vncHooksPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y, static void vncHooksImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y, int count, char *chars) { - GC_OP_UNWRAPPER(pDrawable, pGC, ImageText8); + BoxRec box; + RegionRec reg; + + GC_OP_PROLOGUE(pGC, ImageText8); if (count == 0) { (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars); - return; + goto out; } - BoxRec box; GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box); - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip); + REGION_INIT(pGC->pScreen, ®, &box, 0); + REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip); (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars); - vncHooksScreen->desktop->add_changed(changed.reg); + add_changed(pGC->pScreen, ®); + + REGION_UNINIT(pGC->pScreen, ®); + +out: + GC_OP_EPILOGUE(pGC); } // ImageText16 - changed region is bounding rect around count chars, clipped by @@ -1740,23 +1986,29 @@ static void vncHooksImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y, static void vncHooksImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y, int count, unsigned short *chars) { - GC_OP_UNWRAPPER(pDrawable, pGC, ImageText16); + BoxRec box; + RegionRec reg; + + GC_OP_PROLOGUE(pGC, ImageText16); if (count == 0) { (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars); - return; + goto out; } - BoxRec box; GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box); - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip); + REGION_INIT(pGC->pScreen, ®, &box, 0); + REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip); (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars); - vncHooksScreen->desktop->add_changed(changed.reg); + add_changed(pGC->pScreen, ®); + + REGION_UNINIT(pGC->pScreen, ®); + +out: + GC_OP_EPILOGUE(pGC); } // ImageGlyphBlt - changed region is bounding rect around nglyph chars, clipped @@ -1766,23 +2018,29 @@ static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppci, void * pglyphBase) { - GC_OP_UNWRAPPER(pDrawable, pGC, ImageGlyphBlt); + BoxRec box; + RegionRec reg; + + GC_OP_PROLOGUE(pGC, ImageGlyphBlt); if (nglyph == 0) { (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase); - return; + goto out; } - BoxRec box; GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box); - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip); + REGION_INIT(pGC->pScreen, ®, &box, 0); + REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip); (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); - vncHooksScreen->desktop->add_changed(changed.reg); + add_changed(pGC->pScreen, ®); + + REGION_UNINIT(pGC->pScreen, ®); + +out: + GC_OP_EPILOGUE(pGC); } // PolyGlyphBlt - changed region is bounding rect around nglyph chars, clipped @@ -1792,23 +2050,29 @@ static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppci, void * pglyphBase) { - GC_OP_UNWRAPPER(pDrawable, pGC, PolyGlyphBlt); + BoxRec box; + RegionRec reg; + + GC_OP_PROLOGUE(pGC, PolyGlyphBlt); if (nglyph == 0) { (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase); - return; + goto out; } - BoxRec box; GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box); - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip); + REGION_INIT(pGC->pScreen, ®, &box, 0); + REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip); (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); - vncHooksScreen->desktop->add_changed(changed.reg); + add_changed(pGC->pScreen, ®); + + REGION_UNINIT(pGC->pScreen, ®); + +out: + GC_OP_EPILOGUE(pGC); } // PushPixels - changed region is the given rectangle, clipped by @@ -1818,19 +2082,24 @@ static void vncHooksPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDrawable, int w, int h, int x, int y) { - GC_OP_UNWRAPPER(pDrawable, pGC, PushPixels); - BoxRec box; + RegionRec reg; + + GC_OP_PROLOGUE(pGC, PushPixels); + box.x1 = x + pDrawable->x; box.y1 = y + pDrawable->y; box.x2 = box.x1 + w; box.y2 = box.y1 + h; - RegionHelper changed(pScreen, &box, 0); - - REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip); + REGION_INIT(pGC->pScreen, ®, &box, 0); + REGION_INTERSECT(pGC->pScreen, ®, ®, pGC->pCompositeClip); (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y); - vncHooksScreen->desktop->add_changed(changed.reg); + add_changed(pGC->pScreen, ®); + + REGION_UNINIT(pGC->pScreen, ®); + + GC_OP_EPILOGUE(pGC); } diff --git a/unix/xserver/hw/vnc/vncHooks.h b/unix/xserver/hw/vnc/vncHooks.h index 30b51dbd..eb096103 100644 --- a/unix/xserver/hw/vnc/vncHooks.h +++ b/unix/xserver/hw/vnc/vncHooks.h @@ -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 +#ifdef __cplusplus +extern "C" { #endif -extern "C" { -#include - 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 diff --git a/unix/xserver/hw/vnc/xf86vncModule.cc b/unix/xserver/hw/vnc/vncModule.c similarity index 65% rename from unix/xserver/hw/vnc/xf86vncModule.cc rename to unix/xserver/hw/vnc/vncModule.c index 6bf5e3d8..051f6b44 100644 --- a/unix/xserver/hw/vnc/xf86vncModule.cc +++ b/unix/xserver/hw/vnc/vncModule.c @@ -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 #endif -#include -#include -#include -#include -#include +#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 diff --git a/unix/xserver/hw/vnc/xvnc.cc b/unix/xserver/hw/vnc/xvnc.c similarity index 96% rename from unix/xserver/hw/vnc/xvnc.cc rename to unix/xserver/hw/vnc/xvnc.c index 0fd7b0cb..3498d0f3 100644 --- a/unix/xserver/hw/vnc/xvnc.cc +++ b/unix/xserver/hw/vnc/xvnc.c @@ -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 #endif -#include -#include -#include -#include #include "vncExtInit.h" +#include "RFBGlue.h" #include "xorg-version.h" -extern "C" { -#define class c_class -#define public c_public #ifdef WIN32 #include #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 #include #include @@ -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 = -= " "--=\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); + } +} -- 2.39.5