add_subdirectory(tx)
-
+add_subdirectory(common)
add_subdirectory(vncconfig)
add_subdirectory(vncpasswd)
add_subdirectory(x0vncserver)
--- /dev/null
+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()
--- /dev/null
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2011-2015 Pierre Ossman for Cendio AB
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*
+ 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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2009-2015 Pierre Ossman for Cendio AB
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#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 */
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
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
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) \
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 \
--- /dev/null
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2011-2015 Pierre Ossman for Cendio AB
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <assert.h>
+#include <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
+}
#endif
#include <assert.h>
-#include <string.h>
#include "scrnintstr.h"
#ifdef RANDR
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
-}
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
}
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)
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)
#include <rfb/Configuration.h>
#include <rfb/VNCServerST.h>
#include <rdr/SubstitutingInStream.h>
+#include <unixcommon.h>
#include "Input.h"
namespace rfb {
virtual bool handleTimeout(rfb::Timer* t);
private:
- rfb::ScreenSet computeScreenLayout();
int screenIndex;
rfb::VNCServerST* server;
rfb::Timer queryConnectTimer;
#ifdef RANDR
- typedef std::map<unsigned int, rdr::U32> OutputIdMap;
OutputIdMap outputIdMap;
#endif
#include "vncBlockHandler.h"
#include "vncSelection.h"
#include "XorgGlue.h"
+#include "RandrGlue.h"
#include "xorg-version.h"
using namespace rfb;
#include "vncExtInit.h"
#include "RFBGlue.h"
#include "XorgGlue.h"
+#include "RandrGlue.h"
static void vncModuleInit(INITARGS);
#include "vncExtInit.h"
#include "RFBGlue.h"
#include "XorgGlue.h"
+#include "RandrGlue.h"
#include "xorg-version.h"
#ifdef WIN32