These two code blocks are not specific to Xvnc/vnc.so, but useful for x0vncserver as well. RandrGlue.h defines the interface on which unixcommon depends on.tags/v1.8.90
@@ -1,5 +1,5 @@ | |||
add_subdirectory(tx) | |||
add_subdirectory(common) | |||
add_subdirectory(vncconfig) | |||
add_subdirectory(vncpasswd) | |||
add_subdirectory(x0vncserver) |
@@ -0,0 +1,14 @@ | |||
include_directories(${CMAKE_SOURCE_DIR}/common) | |||
include_directories(${CMAKE_SOURCE_DIR}/unix/common) | |||
add_library(unixcommon STATIC | |||
randr.cxx) | |||
if(UNIX) | |||
libtool_create_control_file(unixcommon) | |||
endif() | |||
if(NOT WIN32) | |||
set_target_properties(unixcommon | |||
PROPERTIES COMPILE_FLAGS -fPIC) | |||
endif() |
@@ -0,0 +1,64 @@ | |||
/* 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. | |||
*/ | |||
/* | |||
This header defines an interface for X RandR operations. It is | |||
implemented by a corresponding RandrGlue.c, either with internal | |||
calls (for Xvnc/vncmodule.so) or Xlib calls (x0vncserver). | |||
*/ | |||
#ifndef RANDR_GLUE_H | |||
#define RANDR_GLUE_H | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
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); | |||
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); | |||
unsigned int vncRandRGetOutputId(int scrIdx, int outputIdx); | |||
void vncRandRGetOutputDimensions(int scrIdx, int outputIdx, | |||
int *x, int *y, int *width, int *height); | |||
int vncRandRCreateOutputs(int scrIdx, int extraOutputs); | |||
void *vncRandRCreatePreferredMode(void *output, int width, int height); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif |
@@ -0,0 +1,249 @@ | |||
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. | |||
* Copyright 2009-2017 Pierre Ossman for Cendio AB | |||
* Copyright 2014 Brian P. Hinz | |||
* | |||
* 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_CONFIG_H | |||
#include <config.h> | |||
#endif | |||
#include <stdlib.h> | |||
#include <unixcommon.h> | |||
#include <rfb/screenTypes.h> | |||
#include <rfb/LogWriter.h> | |||
#include <RandrGlue.h> | |||
static rfb::LogWriter vlog("RandR"); | |||
rfb::ScreenSet computeScreenLayout(int screenIndex, OutputIdMap *outputIdMap) | |||
{ | |||
rfb::ScreenSet layout; | |||
OutputIdMap newIdMap; | |||
for (int i = 0;i < vncRandRGetOutputCount(screenIndex);i++) { | |||
unsigned int outputId; | |||
int x, y, width, height; | |||
/* Disabled? */ | |||
if (!vncRandRIsOutputEnabled(screenIndex, i)) | |||
continue; | |||
outputId = vncRandRGetOutputId(screenIndex, i); | |||
/* Known output? */ | |||
if (outputIdMap->count(outputId) == 1) | |||
newIdMap[outputId] = (*outputIdMap)[outputId]; | |||
else { | |||
rdr::U32 id; | |||
OutputIdMap::const_iterator iter; | |||
while (true) { | |||
id = rand(); | |||
for (iter = outputIdMap->begin();iter != outputIdMap->end();++iter) { | |||
if (iter->second == id) | |||
break; | |||
} | |||
if (iter == outputIdMap->end()) | |||
break; | |||
} | |||
newIdMap[outputId] = id; | |||
} | |||
vncRandRGetOutputDimensions(screenIndex, i, &x, &y, &width, &height); | |||
layout.add_screen(rfb::Screen(newIdMap[outputId], x, y, width, height, 0)); | |||
} | |||
/* Only keep the entries that are currently active */ | |||
*outputIdMap = newIdMap; | |||
/* | |||
* 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(rfb::Screen(0, 0, 0, vncGetScreenWidth(screenIndex), | |||
vncGetScreenHeight(screenIndex), 0)); | |||
return layout; | |||
} | |||
unsigned int setScreenLayout(int screenIndex, | |||
int fb_width, int fb_height, const rfb::ScreenSet& layout, | |||
OutputIdMap *outputIdMap) | |||
{ | |||
int ret; | |||
int availableOutputs; | |||
// 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. | |||
*/ | |||
if (vncRandRHasOutputClones(screenIndex)) { | |||
vlog.error("Clone mode active. Refusing to touch screen layout."); | |||
return rfb::resultInvalid; | |||
} | |||
/* 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) { | |||
vlog.debug("Insufficient screens. Need to create %d more.", | |||
layout.num_screens() - availableOutputs); | |||
ret = vncRandRCreateOutputs(screenIndex, | |||
layout.num_screens() - availableOutputs); | |||
if (ret < 0) { | |||
vlog.error("Unable to create more screens, as needed by the new client layout."); | |||
return rfb::resultInvalid; | |||
} | |||
} | |||
/* First we might need to resize the screen */ | |||
if ((fb_width != vncGetScreenWidth(screenIndex)) || | |||
(fb_height != vncGetScreenHeight(screenIndex))) { | |||
ret = vncRandRResizeScreen(screenIndex, fb_width, fb_height); | |||
if (!ret) { | |||
vlog.error("Failed to resize screen to %dx%d", fb_width, fb_height); | |||
return rfb::resultInvalid; | |||
} | |||
} | |||
/* Next, reconfigure all known outputs, and turn off the other ones */ | |||
for (int i = 0;i < vncRandRGetOutputCount(screenIndex);i++) { | |||
unsigned int output; | |||
rfb::ScreenSet::const_iterator iter; | |||
output = vncRandRGetOutputId(screenIndex, i); | |||
/* Known? */ | |||
if (outputIdMap->count(output) == 0) | |||
continue; | |||
/* Find the corresponding screen... */ | |||
for (iter = layout.begin();iter != layout.end();++iter) { | |||
if (iter->id == (*outputIdMap)[output]) | |||
break; | |||
} | |||
/* Missing? */ | |||
if (iter == layout.end()) { | |||
/* Disable and move on... */ | |||
ret = vncRandRDisableOutput(screenIndex, i); | |||
if (!ret) { | |||
char *name = vncRandRGetOutputName(screenIndex, i); | |||
vlog.error("Failed to disable unused output '%s'", | |||
name); | |||
free(name); | |||
return rfb::resultInvalid; | |||
} | |||
outputIdMap->erase(output); | |||
continue; | |||
} | |||
/* Reconfigure new mode and position */ | |||
ret = vncRandRReconfigureOutput(screenIndex, i, | |||
iter->dimensions.tl.x, | |||
iter->dimensions.tl.y, | |||
iter->dimensions.width(), | |||
iter->dimensions.height()); | |||
if (!ret) { | |||
char *name = vncRandRGetOutputName(screenIndex, i); | |||
vlog.error("Failed to reconfigure output '%s' to %dx%d+%d+%d", | |||
name, | |||
iter->dimensions.width(), iter->dimensions.height(), | |||
iter->dimensions.tl.x, iter->dimensions.tl.y); | |||
free(name); | |||
return rfb::resultInvalid; | |||
} | |||
} | |||
/* Finally, allocate new outputs for new screens */ | |||
rfb::ScreenSet::const_iterator iter; | |||
for (iter = layout.begin();iter != layout.end();++iter) { | |||
OutputIdMap::const_iterator oi; | |||
unsigned int output; | |||
int i; | |||
/* Does this screen have an output already? */ | |||
for (oi = outputIdMap->begin();oi != outputIdMap->end();++oi) { | |||
if (oi->second == iter->id) | |||
break; | |||
} | |||
if (oi != outputIdMap->end()) | |||
continue; | |||
/* Find an unused output */ | |||
for (i = 0;i < vncRandRGetOutputCount(screenIndex);i++) { | |||
output = vncRandRGetOutputId(screenIndex, i); | |||
/* In use? */ | |||
if (outputIdMap->count(output) == 1) | |||
continue; | |||
/* Can it be used? */ | |||
if (!vncRandRIsOutputUsable(screenIndex, i)) | |||
continue; | |||
break; | |||
} | |||
/* Shouldn't happen */ | |||
if (i == vncRandRGetOutputCount(screenIndex)) | |||
return rfb::resultInvalid; | |||
/* | |||
* Make sure we already have an entry for this, or | |||
* computeScreenLayout() will think it is a brand new output and | |||
* assign it a random id. | |||
*/ | |||
(*outputIdMap)[output] = iter->id; | |||
/* Reconfigure new mode and position */ | |||
ret = vncRandRReconfigureOutput(screenIndex, i, | |||
iter->dimensions.tl.x, | |||
iter->dimensions.tl.y, | |||
iter->dimensions.width(), | |||
iter->dimensions.height()); | |||
if (!ret) { | |||
char *name = vncRandRGetOutputName(screenIndex, i); | |||
vlog.error("Failed to reconfigure output '%s' to %dx%d+%d+%d", | |||
name, | |||
iter->dimensions.width(), iter->dimensions.height(), | |||
iter->dimensions.tl.x, iter->dimensions.tl.y); | |||
free(name); | |||
return rfb::resultInvalid; | |||
} | |||
} | |||
/* | |||
* Update timestamp for when screen layout was last changed. | |||
* This is normally done in the X11 request handlers, which is | |||
* why we have to deal with it manually here. | |||
*/ | |||
vncRandRUpdateSetTime(screenIndex); | |||
return rfb::resultSuccess; | |||
} |
@@ -0,0 +1,40 @@ | |||
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. | |||
* Copyright 2009-2015 Pierre Ossman for Cendio AB | |||
* | |||
* This is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation; either version 2 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* This software is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with this software; if not, write to the Free Software | |||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |||
* USA. | |||
*/ | |||
#ifndef UNIXCOMMON_H | |||
#define UNIXCOMMON_H | |||
#ifdef HAVE_CONFIG_H | |||
#include <config.h> | |||
#endif | |||
#include <map> | |||
#include <rfb/ScreenSet.h> | |||
typedef std::map<unsigned int, rdr::U32> OutputIdMap; | |||
rfb::ScreenSet computeScreenLayout(int screenIndex, OutputIdMap *outputIdMap); | |||
unsigned int setScreenLayout(int screenIndex, | |||
int fb_width, int fb_height, const rfb::ScreenSet& layout, | |||
OutputIdMap *outputIdMap); | |||
#endif /* UNIXCOMMON_H */ |
@@ -6,7 +6,8 @@ RDR_LIB=$(LIB_DIR)/rdr/librdr.la | |||
OS_LIB=$(LIB_DIR)/os/libos.la | |||
NETWORK_LIB=$(LIB_DIR)/network/libnetwork.la | |||
XREGION_LIB=$(LIB_DIR)/Xregion/libXregion.la | |||
COMMON_LIBS=$(NETWORK_LIB) $(RFB_LIB) $(RDR_LIB) $(XREGION_LIB) $(OS_LIB) | |||
UNIXCOMMON_LIB=${top_builddir}/../common/libunixcommon.la | |||
COMMON_LIBS=$(NETWORK_LIB) $(RFB_LIB) $(RDR_LIB) $(XREGION_LIB) $(OS_LIB) $(UNIXCOMMON_LIB) | |||
noinst_LTLIBRARIES = libvnccommon.la | |||
@@ -17,10 +18,10 @@ HDRS = vncExtInit.h vncHooks.h \ | |||
libvnccommon_la_SOURCES = $(HDRS) \ | |||
vncExt.c vncExtInit.cc vncHooks.c vncSelection.c \ | |||
vncBlockHandler.c XorgGlue.c RFBGlue.cc XserverDesktop.cc \ | |||
vncBlockHandler.c XorgGlue.c RandrGlue.c RFBGlue.cc XserverDesktop.cc \ | |||
Input.c InputXKB.c qnum_to_xorgevdev.c qnum_to_xorgkbd.c | |||
libvnccommon_la_CPPFLAGS = -DVENDOR_RELEASE="$(VENDOR_RELEASE)" \ | |||
libvnccommon_la_CPPFLAGS = -DVENDOR_RELEASE="$(VENDOR_RELEASE)" -I$(TIGERVNC_SRCDIR)/unix/common \ | |||
-DVENDOR_STRING="\"$(VENDOR_STRING)\"" -I$(TIGERVNC_SRCDIR)/common -UHAVE_CONFIG_H \ | |||
-I$(TIGERVNC_SRCDIR)/unix/vncconfig $(XVNC_CPPFLAGS) ${XSERVERLIBS_CFLAGS} -I$(includedir) \ | |||
-I$(top_srcdir)/include | |||
@@ -41,7 +42,7 @@ nodist_EXTRA_Xvnc_SOURCES = dummy.cxx | |||
Xvnc_CPPFLAGS = $(XVNC_CPPFLAGS) -DTIGERVNC -DNO_MODULE_EXTS \ | |||
-UHAVE_CONFIG_H \ | |||
-DXFree86Server -DVENDOR_RELEASE="$(VENDOR_RELEASE)" \ | |||
-DVENDOR_STRING="\"$(VENDOR_STRING)\"" -I$(TIGERVNC_SRCDIR)/common \ | |||
-DVENDOR_STRING="\"$(VENDOR_STRING)\"" -I$(TIGERVNC_SRCDIR)/common -I$(TIGERVNC_SRCDIR)/unix/common \ | |||
-I$(top_srcdir)/include ${XSERVERLIBS_CFLAGS} -I$(includedir) | |||
Xvnc_LDADD = $(XVNC_LIBS) libvnccommon.la $(COMMON_LIBS) \ | |||
@@ -58,6 +59,7 @@ libvnc_la_SOURCES = vncModule.c | |||
nodist_EXTRA_libvnc_la_SOURCES = dummy.cxx | |||
libvnc_la_CPPFLAGS = $(XVNC_CPPFLAGS) -I$(TIGERVNC_SRCDIR)/common -UHAVE_CONFIG_H \ | |||
-I$(TIGERVNC_SRCDIR)/unix/common \ | |||
-I$(top_srcdir)/hw/xfree86/common \ | |||
-I$(top_srcdir)/hw/xfree86/os-support \ | |||
-I$(top_srcdir)/hw/xfree86/os-support/bus \ |
@@ -0,0 +1,283 @@ | |||
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. | |||
* Copyright 2011-2015 Pierre Ossman for Cendio AB | |||
* | |||
* This is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation; either version 2 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* This software is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with this software; if not, write to the Free Software | |||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |||
* USA. | |||
*/ | |||
#ifdef HAVE_DIX_CONFIG_H | |||
#include <dix-config.h> | |||
#endif | |||
#include <assert.h> | |||
#include <string.h> | |||
#include "scrnintstr.h" | |||
#ifdef RANDR | |||
#include "randrstr.h" | |||
#endif | |||
#include "RandrGlue.h" | |||
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 | |||
} | |||
char *vncRandRGetOutputName(int scrIdx, int outputIdx) | |||
{ | |||
#ifdef RANDR | |||
rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]); | |||
return strdup(rp->outputs[outputIdx]->name); | |||
#else | |||
return strdup(""); | |||
#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 | |||
} | |||
unsigned int vncRandRGetOutputId(int scrIdx, int outputIdx) | |||
{ | |||
#ifdef RANDR | |||
rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]); | |||
return rp->outputs[outputIdx]->id; | |||
#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]); | |||
int swap; | |||
*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; | |||
switch (rp->outputs[outputIdx]->crtc->rotation & 0xf) { | |||
case RR_Rotate_90: | |||
case RR_Rotate_270: | |||
swap = *width; | |||
*width = *height; | |||
*height = swap; | |||
break; | |||
} | |||
#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; | |||
} | |||
/* Make sure we have the mode we want */ | |||
mode = vncRandRCreatePreferredMode(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 | |||
} |
@@ -22,7 +22,6 @@ | |||
#endif | |||
#include <assert.h> | |||
#include <string.h> | |||
#include "scrnintstr.h" | |||
#ifdef RANDR | |||
@@ -115,253 +114,3 @@ int vncGetScreenY(int scrIdx) | |||
return screenInfo.screens[scrIdx]->y; | |||
} | |||
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 | |||
} | |||
char *vncRandRGetOutputName(int scrIdx, int outputIdx) | |||
{ | |||
#ifdef RANDR | |||
rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]); | |||
return strdup(rp->outputs[outputIdx]->name); | |||
#else | |||
return strdup(""); | |||
#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 | |||
} | |||
unsigned int vncRandRGetOutputId(int scrIdx, int outputIdx) | |||
{ | |||
#ifdef RANDR | |||
rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]); | |||
return rp->outputs[outputIdx]->id; | |||
#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]); | |||
int swap; | |||
*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; | |||
switch (rp->outputs[outputIdx]->crtc->rotation & 0xf) { | |||
case RR_Rotate_90: | |||
case RR_Rotate_270: | |||
swap = *width; | |||
*width = *height; | |||
*height = swap; | |||
break; | |||
} | |||
#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; | |||
} | |||
/* Make sure we have the mode we want */ | |||
mode = vncRandRCreatePreferredMode(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 | |||
} |
@@ -45,34 +45,9 @@ void vncGetScreenFormat(int scrIdx, int *depth, int *bpp, | |||
int vncGetScreenX(int scrIdx); | |||
int vncGetScreenY(int scrIdx); | |||
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); | |||
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); | |||
unsigned int vncRandRGetOutputId(int scrIdx, int outputIdx); | |||
void vncRandRGetOutputDimensions(int scrIdx, int outputIdx, | |||
int *x, int *y, int *width, int *height); | |||
// These hide in xvnc.c or vncModule.c | |||
void vncClientGone(int fd); | |||
int vncRandRCreateOutputs(int scrIdx, int extraOutputs); | |||
void *vncRandRCreatePreferredMode(void *output, int width, int height); | |||
#ifdef __cplusplus | |||
} |
@@ -185,68 +185,14 @@ void XserverDesktop::setFramebuffer(int w, int h, void* fbptr, int stride_) | |||
data = (rdr::U8*)fbptr; | |||
stride = stride_; | |||
layout = computeScreenLayout(); | |||
layout = ::computeScreenLayout(screenIndex, &outputIdMap); | |||
server->setPixelBuffer(this, layout); | |||
} | |||
void XserverDesktop::refreshScreenLayout() | |||
{ | |||
server->setScreenLayout(computeScreenLayout()); | |||
} | |||
ScreenSet XserverDesktop::computeScreenLayout() | |||
{ | |||
ScreenSet layout; | |||
OutputIdMap newIdMap; | |||
for (int i = 0;i < vncRandRGetOutputCount(screenIndex);i++) { | |||
unsigned int outputId; | |||
int x, y, width, height; | |||
/* Disabled? */ | |||
if (!vncRandRIsOutputEnabled(screenIndex, i)) | |||
continue; | |||
outputId = vncRandRGetOutputId(screenIndex, i); | |||
/* Known output? */ | |||
if (outputIdMap.count(outputId) == 1) | |||
newIdMap[outputId] = outputIdMap[outputId]; | |||
else { | |||
rdr::U32 id; | |||
OutputIdMap::const_iterator iter; | |||
while (true) { | |||
id = rand(); | |||
for (iter = outputIdMap.begin();iter != outputIdMap.end();++iter) { | |||
if (iter->second == id) | |||
break; | |||
} | |||
if (iter == outputIdMap.end()) | |||
break; | |||
} | |||
newIdMap[outputId] = id; | |||
} | |||
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; | |||
/* | |||
* 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, vncGetScreenWidth(screenIndex), | |||
vncGetScreenHeight(screenIndex), 0)); | |||
return layout; | |||
server->setScreenLayout(::computeScreenLayout(screenIndex, &outputIdMap)); | |||
} | |||
char* XserverDesktop::substitute(const char* varName) | |||
@@ -605,170 +551,13 @@ void XserverDesktop::clientCutText(const char* str, int len) | |||
unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height, | |||
const rfb::ScreenSet& layout) | |||
{ | |||
int ret; | |||
int availableOutputs; | |||
// RandR support? | |||
if (vncRandRGetOutputCount(screenIndex) == 0) | |||
return rfb::resultProhibited; | |||
char buffer[2048]; | |||
vlog.debug("Got request for framebuffer resize to %dx%d", | |||
fb_width, fb_height); | |||
layout.print(buffer, sizeof(buffer)); | |||
vlog.debug("%s", buffer); | |||
/* | |||
* First check that we don't have any active clone modes. That's just | |||
* too messy to deal with. | |||
*/ | |||
if (vncRandRHasOutputClones(screenIndex)) { | |||
vlog.error("Clone mode active. Refusing to touch screen layout."); | |||
return rfb::resultInvalid; | |||
} | |||
/* 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) { | |||
vlog.debug("Insufficient screens. Need to create %d more.", | |||
layout.num_screens() - availableOutputs); | |||
ret = vncRandRCreateOutputs(screenIndex, | |||
layout.num_screens() - availableOutputs); | |||
if (ret < 0) { | |||
vlog.error("Unable to create more screens, as needed by the new client layout."); | |||
return rfb::resultInvalid; | |||
} | |||
} | |||
/* First we might need to resize the screen */ | |||
if ((fb_width != vncGetScreenWidth(screenIndex)) || | |||
(fb_height != vncGetScreenHeight(screenIndex))) { | |||
ret = vncRandRResizeScreen(screenIndex, fb_width, fb_height); | |||
if (!ret) { | |||
vlog.error("Failed to resize screen to %dx%d", fb_width, fb_height); | |||
return rfb::resultInvalid; | |||
} | |||
} | |||
/* Next, reconfigure all known outputs, and turn off the other ones */ | |||
for (int i = 0;i < vncRandRGetOutputCount(screenIndex);i++) { | |||
unsigned int output; | |||
ScreenSet::const_iterator iter; | |||
output = vncRandRGetOutputId(screenIndex, i); | |||
/* Known? */ | |||
if (outputIdMap.count(output) == 0) | |||
continue; | |||
/* Find the corresponding screen... */ | |||
for (iter = layout.begin();iter != layout.end();++iter) { | |||
if (iter->id == outputIdMap[output]) | |||
break; | |||
} | |||
/* Missing? */ | |||
if (iter == layout.end()) { | |||
/* Disable and move on... */ | |||
ret = vncRandRDisableOutput(screenIndex, i); | |||
if (!ret) { | |||
char *name = vncRandRGetOutputName(screenIndex, i); | |||
vlog.error("Failed to disable unused output '%s'", | |||
name); | |||
free(name); | |||
return rfb::resultInvalid; | |||
} | |||
outputIdMap.erase(output); | |||
continue; | |||
} | |||
/* Reconfigure new mode and position */ | |||
ret = vncRandRReconfigureOutput(screenIndex, i, | |||
iter->dimensions.tl.x, | |||
iter->dimensions.tl.y, | |||
iter->dimensions.width(), | |||
iter->dimensions.height()); | |||
if (!ret) { | |||
char *name = vncRandRGetOutputName(screenIndex, i); | |||
vlog.error("Failed to reconfigure output '%s' to %dx%d+%d+%d", | |||
name, | |||
iter->dimensions.width(), iter->dimensions.height(), | |||
iter->dimensions.tl.x, iter->dimensions.tl.y); | |||
free(name); | |||
return rfb::resultInvalid; | |||
} | |||
} | |||
/* Finally, allocate new outputs for new screens */ | |||
ScreenSet::const_iterator iter; | |||
for (iter = layout.begin();iter != layout.end();++iter) { | |||
OutputIdMap::const_iterator oi; | |||
unsigned int output; | |||
int i; | |||
/* Does this screen have an output already? */ | |||
for (oi = outputIdMap.begin();oi != outputIdMap.end();++oi) { | |||
if (oi->second == iter->id) | |||
break; | |||
} | |||
if (oi != outputIdMap.end()) | |||
continue; | |||
/* Find an unused output */ | |||
for (i = 0;i < vncRandRGetOutputCount(screenIndex);i++) { | |||
output = vncRandRGetOutputId(screenIndex, i); | |||
/* In use? */ | |||
if (outputIdMap.count(output) == 1) | |||
continue; | |||
/* Can it be used? */ | |||
if (!vncRandRIsOutputUsable(screenIndex, i)) | |||
continue; | |||
break; | |||
} | |||
/* Shouldn't happen */ | |||
if (i == vncRandRGetOutputCount(screenIndex)) | |||
return rfb::resultInvalid; | |||
/* | |||
* Make sure we already have an entry for this, or | |||
* computeScreenLayout() will think it is a brand new output and | |||
* assign it a random id. | |||
*/ | |||
outputIdMap[output] = iter->id; | |||
/* Reconfigure new mode and position */ | |||
ret = vncRandRReconfigureOutput(screenIndex, i, | |||
iter->dimensions.tl.x, | |||
iter->dimensions.tl.y, | |||
iter->dimensions.width(), | |||
iter->dimensions.height()); | |||
if (!ret) { | |||
char *name = vncRandRGetOutputName(screenIndex, i); | |||
vlog.error("Failed to reconfigure output '%s' to %dx%d+%d+%d", | |||
name, | |||
iter->dimensions.width(), iter->dimensions.height(), | |||
iter->dimensions.tl.x, iter->dimensions.tl.y); | |||
free(name); | |||
return rfb::resultInvalid; | |||
} | |||
} | |||
/* | |||
* Update timestamp for when screen layout was last changed. | |||
* This is normally done in the X11 request handlers, which is | |||
* why we have to deal with it manually here. | |||
*/ | |||
vncRandRUpdateSetTime(screenIndex); | |||
return rfb::resultSuccess; | |||
return ::setScreenLayout(screenIndex, fb_width, fb_height, layout, &outputIdMap); | |||
} | |||
void XserverDesktop::grabRegion(const rfb::Region& region) |
@@ -37,6 +37,7 @@ | |||
#include <rfb/Configuration.h> | |||
#include <rfb/VNCServerST.h> | |||
#include <rdr/SubstitutingInStream.h> | |||
#include <unixcommon.h> | |||
#include "Input.h" | |||
namespace rfb { | |||
@@ -117,7 +118,6 @@ protected: | |||
virtual bool handleTimeout(rfb::Timer* t); | |||
private: | |||
rfb::ScreenSet computeScreenLayout(); | |||
int screenIndex; | |||
rfb::VNCServerST* server; | |||
@@ -133,7 +133,6 @@ private: | |||
rfb::Timer queryConnectTimer; | |||
#ifdef RANDR | |||
typedef std::map<unsigned int, rdr::U32> OutputIdMap; | |||
OutputIdMap outputIdMap; | |||
#endif | |||
@@ -41,6 +41,7 @@ | |||
#include "vncBlockHandler.h" | |||
#include "vncSelection.h" | |||
#include "XorgGlue.h" | |||
#include "RandrGlue.h" | |||
#include "xorg-version.h" | |||
using namespace rfb; |
@@ -39,6 +39,7 @@ typedef pointer XF86OptionPtr; | |||
#include "vncExtInit.h" | |||
#include "RFBGlue.h" | |||
#include "XorgGlue.h" | |||
#include "RandrGlue.h" | |||
static void vncModuleInit(INITARGS); | |||
@@ -35,6 +35,7 @@ from the X Consortium. | |||
#include "vncExtInit.h" | |||
#include "RFBGlue.h" | |||
#include "XorgGlue.h" | |||
#include "RandrGlue.h" | |||
#include "xorg-version.h" | |||
#ifdef WIN32 |