Browse Source

Move computeScreenLayout/setScreenLayout to unixcommon lib

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
Peter Åstrand (astrand) 6 years ago
parent
commit
1173637739

+ 1
- 1
unix/CMakeLists.txt View File

@@ -1,5 +1,5 @@
add_subdirectory(tx)
add_subdirectory(common)
add_subdirectory(vncconfig)
add_subdirectory(vncpasswd)
add_subdirectory(x0vncserver)

+ 14
- 0
unix/common/CMakeLists.txt View File

@@ -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()

+ 64
- 0
unix/common/RandrGlue.h View File

@@ -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

+ 249
- 0
unix/common/randr.cxx View File

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

+ 40
- 0
unix/common/unixcommon.h View File

@@ -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
- 4
unix/xserver/hw/vnc/Makefile.am View File

@@ -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 \

+ 283
- 0
unix/xserver/hw/vnc/RandrGlue.c View File

@@ -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
}

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

@@ -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
}

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

@@ -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
}

+ 3
- 214
unix/xserver/hw/vnc/XserverDesktop.cc View File

@@ -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)

+ 1
- 2
unix/xserver/hw/vnc/XserverDesktop.h View File

@@ -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


+ 1
- 0
unix/xserver/hw/vnc/vncExtInit.cc View File

@@ -41,6 +41,7 @@
#include "vncBlockHandler.h"
#include "vncSelection.h"
#include "XorgGlue.h"
#include "RandrGlue.h"
#include "xorg-version.h"

using namespace rfb;

+ 1
- 0
unix/xserver/hw/vnc/vncModule.c View File

@@ -39,6 +39,7 @@ typedef pointer XF86OptionPtr;
#include "vncExtInit.h"
#include "RFBGlue.h"
#include "XorgGlue.h"
#include "RandrGlue.h"

static void vncModuleInit(INITARGS);


+ 1
- 0
unix/xserver/hw/vnc/xvnc.c View File

@@ -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

Loading…
Cancel
Save