summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPierre Ossman <ossman@cendio.se>2018-04-10 08:11:46 +0200
committerPierre Ossman <ossman@cendio.se>2018-04-10 08:11:46 +0200
commit382d3735f0b32792a2cc17be3bb9845dab953ab7 (patch)
treea9c1b88bd5313b57bce50998770594e86aa81433
parent4ae358d561463f1a2dc763fec885be5e4932f394 (diff)
parent242c5b2c8af6d89a34ff83089e9e724e32dcb279 (diff)
downloadtigervnc-382d3735f0b32792a2cc17be3bb9845dab953ab7.tar.gz
tigervnc-382d3735f0b32792a2cc17be3bb9845dab953ab7.zip
Merge branch 'x0vncserver-randr' of https://github.com/x11clone/x11clone
-rw-r--r--cmake/StaticBuild.cmake3
-rw-r--r--unix/CMakeLists.txt2
-rw-r--r--unix/common/CMakeLists.txt14
-rw-r--r--unix/common/RandrGlue.h68
-rw-r--r--unix/common/randr.cxx439
-rw-r--r--unix/common/unixcommon.h48
-rw-r--r--unix/x0vncserver/CMakeLists.txt11
-rw-r--r--unix/x0vncserver/Geometry.cxx12
-rw-r--r--unix/x0vncserver/Geometry.h1
-rw-r--r--unix/x0vncserver/RandrGlue.c511
-rw-r--r--unix/x0vncserver/XDesktop.cxx289
-rw-r--r--unix/x0vncserver/XDesktop.h10
-rw-r--r--unix/xserver/hw/vnc/Makefile.am10
-rw-r--r--unix/xserver/hw/vnc/RandrGlue.c360
-rw-r--r--unix/xserver/hw/vnc/XorgGlue.c250
-rw-r--r--unix/xserver/hw/vnc/XorgGlue.h30
-rw-r--r--unix/xserver/hw/vnc/XserverDesktop.cc218
-rw-r--r--unix/xserver/hw/vnc/XserverDesktop.h5
-rw-r--r--unix/xserver/hw/vnc/vncExtInit.cc10
-rw-r--r--unix/xserver/hw/vnc/vncHooks.c18
-rw-r--r--unix/xserver/hw/vnc/vncModule.c41
-rw-r--r--unix/xserver/hw/vnc/xvnc.c78
22 files changed, 1872 insertions, 556 deletions
diff --git a/cmake/StaticBuild.cmake b/cmake/StaticBuild.cmake
index 06883c6f..4b58b1de 100644
--- a/cmake/StaticBuild.cmake
+++ b/cmake/StaticBuild.cmake
@@ -109,6 +109,9 @@ if(BUILD_STATIC)
if(X11_Xdamage_LIB)
set(X11_Xdamage_LIB "-Wl,-Bstatic -lXdamage -Wl,-Bdynamic")
endif()
+ if(X11_Xrandr_LIB)
+ set(X11_Xrandr_LIB "-Wl,-Bstatic -lXrandr -lXrender -Wl,-Bdynamic")
+ endif()
endif()
endif()
diff --git a/unix/CMakeLists.txt b/unix/CMakeLists.txt
index 8b2c70eb..7a1457df 100644
--- a/unix/CMakeLists.txt
+++ b/unix/CMakeLists.txt
@@ -1,5 +1,5 @@
add_subdirectory(tx)
-
+add_subdirectory(common)
add_subdirectory(vncconfig)
add_subdirectory(vncpasswd)
add_subdirectory(x0vncserver)
diff --git a/unix/common/CMakeLists.txt b/unix/common/CMakeLists.txt
new file mode 100644
index 00000000..611e1956
--- /dev/null
+++ b/unix/common/CMakeLists.txt
@@ -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()
diff --git a/unix/common/RandrGlue.h b/unix/common/RandrGlue.h
new file mode 100644
index 00000000..5cc57003
--- /dev/null
+++ b/unix/common/RandrGlue.h
@@ -0,0 +1,68 @@
+/* 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(void);
+int vncGetScreenHeight(void);
+
+int vncRandRIsValidScreenSize(int width, int height);
+int vncRandRResizeScreen(int width, int height);
+void vncRandRUpdateSetTime(void);
+
+int vncRandRHasOutputClones(void);
+
+int vncRandRGetOutputCount(void);
+int vncRandRGetAvailableOutputs(void);
+
+char *vncRandRGetOutputName(int outputIdx);
+
+int vncRandRIsOutputEnabled(int outputIdx);
+int vncRandRIsOutputUsable(int outputIdx);
+int vncRandRIsOutputConnected(int outputIdx);
+
+int vncRandRCheckOutputMode(int outputIdx, int width, int height);
+
+int vncRandRDisableOutput(int outputIdx);
+int vncRandRReconfigureOutput(int outputIdx, int x, int y,
+ int width, int height);
+
+unsigned int vncRandRGetOutputId(int outputIdx);
+int vncRandRGetOutputDimensions(int outputIdx,
+ int *x, int *y, int *width, int *height);
+
+int vncRandRCanCreateOutputs(int extraOutputs);
+int vncRandRCreateOutputs(int extraOutputs);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/unix/common/randr.cxx b/unix/common/randr.cxx
new file mode 100644
index 00000000..95c1f332
--- /dev/null
+++ b/unix/common/randr.cxx
@@ -0,0 +1,439 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2009-2017 Pierre Ossman for Cendio AB
+ * Copyright 2018 Peter Astrand <astrand@cendio.se> 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");
+
+static int ResizeScreen(bool dryrun, int fb_width, int fb_height,
+ std::set<unsigned int>* disabledOutputs)
+{
+ vlog.debug("Resizing screen framebuffer to %dx%d", fb_width, fb_height);
+
+ /*
+ * Disable outputs which are larger than the target size
+ */
+ for (int i = 0;i < vncRandRGetOutputCount();i++) {
+ int x, y, width, height;
+ if (vncRandRGetOutputDimensions(i, &x, &y, &width, &height) == 0) {
+ if (x + width > fb_width || y + height > fb_height) {
+ char *name = vncRandRGetOutputName(i);
+ vlog.debug("Temporarily disabling output '%s'", name);
+ free(name);
+ if (!dryrun) {
+ /* Currently ignoring errors */
+ /* FIXME: Save output rotation and restore when configuring output */
+ vncRandRDisableOutput(i);
+ disabledOutputs->insert(vncRandRGetOutputId(i));
+ }
+ }
+ }
+ }
+
+ if (!vncRandRIsValidScreenSize(fb_width, fb_height))
+ return 0;
+
+ if (dryrun)
+ return 1;
+
+ return vncRandRResizeScreen(fb_width, fb_height);
+}
+
+
+/* Return output index of preferred output, -1 on failure */
+int getPreferredScreenOutput(OutputIdMap *outputIdMap,
+ const std::set<unsigned int>& disabledOutputs)
+{
+ int firstDisabled = -1;
+ int firstEnabled = -1;
+ int firstConnected = -1;
+ int firstUsable = -1;
+
+ for (int i = 0;i < vncRandRGetOutputCount();i++) {
+ unsigned int output = vncRandRGetOutputId(i);
+
+ /* In use? */
+ if (outputIdMap->count(output) == 1) {
+ continue;
+ }
+
+ /* Can it be used? */
+ if (!vncRandRIsOutputUsable(i)) {
+ continue;
+ }
+
+ /* Temporarily disabled? */
+ if (disabledOutputs.count(output)) {
+ if (firstDisabled == -1) firstDisabled = i;
+ }
+
+ /* Enabled? */
+ if (vncRandRIsOutputEnabled(i)) {
+ if (firstEnabled == -1) firstEnabled = i;
+ }
+
+ /* Connected? */
+ if (vncRandRIsOutputConnected(i)) {
+ if (firstConnected == -1) firstConnected = i;
+ }
+
+ if (firstUsable == -1) firstUsable = i;
+ }
+
+ if (firstEnabled != -1) {
+ return firstEnabled;
+ } else if (firstDisabled != -1) {
+ return firstDisabled;
+ } else if (firstConnected != -1) {
+ return firstConnected;
+ } else {
+ return firstUsable; /* Possibly -1 */
+ }
+}
+
+
+rfb::ScreenSet computeScreenLayout(OutputIdMap *outputIdMap)
+{
+ rfb::ScreenSet layout;
+ OutputIdMap newIdMap;
+
+ for (int i = 0;i < vncRandRGetOutputCount();i++) {
+ unsigned int outputId;
+ int x, y, width, height;
+
+ /* Disabled? */
+ if (!vncRandRIsOutputEnabled(i))
+ continue;
+
+ outputId = vncRandRGetOutputId(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;
+ }
+
+ if (vncRandRGetOutputDimensions(i, &x, &y, &width, &height) == 0) {
+ 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(),
+ vncGetScreenHeight(), 0));
+
+ return layout;
+}
+
+static unsigned int _setScreenLayout(bool dryrun,
+ int fb_width, int fb_height, const rfb::ScreenSet& layout,
+ OutputIdMap *outputIdMap)
+{
+ int ret;
+ int availableOutputs;
+ std::set<unsigned int> disabledOutputs;
+ /* Printing errors in the dryrun pass might be confusing */
+ const bool logErrors = !dryrun || vlog.getLevel() >= vlog.LEVEL_DEBUG;
+
+ // RandR support?
+ if (vncRandRGetOutputCount() == 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()) {
+ if (logErrors) {
+ vlog.error("Clone mode active. Refusing to touch screen layout.");
+ }
+ return rfb::resultInvalid;
+ }
+
+ /* Next count how many useful outputs we have... */
+ availableOutputs = vncRandRGetAvailableOutputs();
+
+ /* 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);
+
+ if (!vncRandRCanCreateOutputs(layout.num_screens() - availableOutputs)) {
+ if (logErrors)
+ vlog.error("Unable to create more screens, as needed by the new client layout.");
+ return rfb::resultInvalid;
+ }
+
+ if (!dryrun) {
+ ret = vncRandRCreateOutputs(layout.num_screens() - availableOutputs);
+ if (!ret) {
+ if (logErrors)
+ 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()) ||
+ (fb_height != vncGetScreenHeight())) {
+ ret = ResizeScreen(dryrun, fb_width, fb_height, &disabledOutputs);
+ if (!ret) {
+ if (logErrors) {
+ vlog.error("Failed to resize screen to %dx%d", fb_width, fb_height);
+ }
+ return rfb::resultInvalid;
+ }
+ }
+
+ /* Next, reconfigure all known outputs */
+ for (int i = 0;i < vncRandRGetOutputCount();i++) {
+ unsigned int output;
+
+ rfb::ScreenSet::const_iterator iter;
+
+ output = vncRandRGetOutputId(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()) {
+ outputIdMap->erase(output);
+ continue;
+ }
+
+ /* Probably not needed, but let's be safe */
+ if (!vncRandRIsOutputUsable(i)) {
+ if (logErrors) {
+ char *name = vncRandRGetOutputName(i);
+ vlog.error("Required output '%s' cannot be used", name);
+ free(name);
+ }
+ return rfb::resultInvalid;
+ }
+
+ /* Possible mode? */
+ if (!vncRandRCheckOutputMode(i, iter->dimensions.width(),
+ iter->dimensions.height())) {
+ if (logErrors) {
+ char *name = vncRandRGetOutputName(i);
+ vlog.error("Output '%s' does not support required mode %dx%d", name,
+ iter->dimensions.width(), iter->dimensions.height());
+ free(name);
+ }
+ return rfb::resultInvalid;
+ }
+
+ char *name = vncRandRGetOutputName(i);
+ vlog.debug("Reconfiguring output '%s' to %dx%d+%d+%d", name,
+ iter->dimensions.width(), iter->dimensions.height(),
+ iter->dimensions.tl.x, iter->dimensions.tl.y);
+ free(name);
+
+ if (dryrun)
+ continue;
+
+ /* Reconfigure new mode and position */
+ ret = vncRandRReconfigureOutput(i,
+ iter->dimensions.tl.x,
+ iter->dimensions.tl.y,
+ iter->dimensions.width(),
+ iter->dimensions.height());
+ if (!ret) {
+ if (logErrors) {
+ char *name = vncRandRGetOutputName(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;
+ }
+ }
+
+ /* 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 */
+ i = getPreferredScreenOutput(outputIdMap, disabledOutputs);
+
+ /* Shouldn't happen */
+ if (i == -1)
+ return rfb::resultInvalid;
+ output = vncRandRGetOutputId(i);
+
+ /*
+ * 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;
+
+ /* Probably not needed, but let's be safe */
+ if (!vncRandRIsOutputUsable(i)) {
+ if (logErrors) {
+ char *name = vncRandRGetOutputName(i);
+ vlog.error("Required new output '%s' cannot be used", name);
+ free(name);
+ }
+ return rfb::resultInvalid;
+ }
+
+ /* Possible mode? */
+ if (!vncRandRCheckOutputMode(i, iter->dimensions.width(),
+ iter->dimensions.height())) {
+ if (logErrors) {
+ char *name = vncRandRGetOutputName(i);
+ vlog.error("New output '%s' does not support required mode %dx%d", name,
+ iter->dimensions.width(), iter->dimensions.height());
+ free(name);
+ }
+ return rfb::resultInvalid;
+ }
+
+ char *name = vncRandRGetOutputName(i);
+ vlog.debug("Reconfiguring new output '%s' to %dx%d+%d+%d", name,
+ iter->dimensions.width(), iter->dimensions.height(),
+ iter->dimensions.tl.x, iter->dimensions.tl.y);
+ free(name);
+
+ if (dryrun)
+ continue;
+
+ /* Reconfigure new mode and position */
+ ret = vncRandRReconfigureOutput(i,
+ iter->dimensions.tl.x,
+ iter->dimensions.tl.y,
+ iter->dimensions.width(),
+ iter->dimensions.height());
+ if (!ret) {
+ if (logErrors) {
+ char *name = vncRandRGetOutputName(i);
+ vlog.error("Failed to reconfigure new 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;
+ }
+ }
+
+ /* Turn off unused outputs */
+ for (int i = 0;i < vncRandRGetOutputCount();i++) {
+ unsigned int output = vncRandRGetOutputId(i);
+
+ /* Known? */
+ if (outputIdMap->count(output) == 1)
+ continue;
+
+ /* Enabled? */
+ if (!vncRandRIsOutputEnabled(i))
+ continue;
+
+ /* Disable and move on... */
+ ret = vncRandRDisableOutput(i);
+ char *name = vncRandRGetOutputName(i);
+ if (ret) {
+ vlog.debug("Disabled unused output '%s'", name);
+ } else {
+ if (logErrors) {
+ vlog.error("Failed to disable unused output '%s'", name);
+ }
+ free(name);
+ return rfb::resultInvalid;
+ }
+ free(name);
+ }
+
+ /*
+ * 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();
+
+ return rfb::resultSuccess;
+}
+
+
+unsigned int setScreenLayout(int fb_width, int fb_height, const rfb::ScreenSet& layout,
+ OutputIdMap *outputIdMap)
+{
+ return _setScreenLayout(false, fb_width, fb_height, layout, outputIdMap);
+}
+
+
+unsigned int tryScreenLayout(int fb_width, int fb_height, const rfb::ScreenSet& layout,
+ OutputIdMap *outputIdMap)
+{
+ OutputIdMap dryrunIdMap = *outputIdMap;
+ return _setScreenLayout(true, fb_width, fb_height, layout, &dryrunIdMap);
+}
diff --git a/unix/common/unixcommon.h b/unix/common/unixcommon.h
new file mode 100644
index 00000000..43191fb6
--- /dev/null
+++ b/unix/common/unixcommon.h
@@ -0,0 +1,48 @@
+/* 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(OutputIdMap *outputIdMap);
+
+unsigned int setScreenLayout(int fb_width, int fb_height, const rfb::ScreenSet& layout,
+ OutputIdMap *outputIdMap);
+
+unsigned int tryScreenLayout(int fb_width, int fb_height, const rfb::ScreenSet& layout,
+ OutputIdMap *outputIdMap);
+
+/*
+ * FIXME: This is only exposed because we still have logic in XDesktop
+ * that we haven't integrated in setScreenLayout()
+ */
+int getPreferredScreenOutput(OutputIdMap *outputIdMap,
+ const std::set<unsigned int>& disabledOutputs);
+
+#endif /* UNIXCOMMON_H */
diff --git a/unix/x0vncserver/CMakeLists.txt b/unix/x0vncserver/CMakeLists.txt
index 5930e32a..8beade7e 100644
--- a/unix/x0vncserver/CMakeLists.txt
+++ b/unix/x0vncserver/CMakeLists.txt
@@ -1,4 +1,5 @@
include_directories(${X11_INCLUDE_DIR})
+include_directories(${CMAKE_SOURCE_DIR}/unix/common)
include_directories(${CMAKE_SOURCE_DIR}/unix/tx)
include_directories(${CMAKE_SOURCE_DIR}/unix)
include_directories(${CMAKE_SOURCE_DIR}/common)
@@ -15,10 +16,11 @@ add_executable(x0vncserver
x0vncserver.cxx
XPixelBuffer.cxx
XDesktop.cxx
+ RandrGlue.c
../vncconfig/QueryConnectDialog.cxx
)
-target_link_libraries(x0vncserver tx rfb network rdr)
+target_link_libraries(x0vncserver tx rfb network rdr unixcommon)
if(X11_FOUND AND X11_XTest_LIB)
add_definitions(-DHAVE_XTEST)
@@ -41,6 +43,13 @@ else()
message(WARNING "No XFIXES extension. x0vncserver will not be able to show cursors.")
endif()
+if(X11_FOUND AND X11_Xrandr_LIB)
+ add_definitions(-DHAVE_XRANDR)
+ target_link_libraries(x0vncserver ${X11_Xrandr_LIB})
+else()
+ message(WARNING "No Xrandr extension. x0vncserver will not be able to resize session.")
+endif()
+
target_link_libraries(x0vncserver ${X11_LIBRARIES})
install(TARGETS x0vncserver DESTINATION ${BIN_DIR})
diff --git a/unix/x0vncserver/Geometry.cxx b/unix/x0vncserver/Geometry.cxx
index 48c18426..d9114713 100644
--- a/unix/x0vncserver/Geometry.cxx
+++ b/unix/x0vncserver/Geometry.cxx
@@ -35,10 +35,16 @@ StringParameter Geometry::m_geometryParam("Geometry",
"");
Geometry::Geometry(int fullWidth, int fullHeight)
- : m_fullWidth(fullWidth),
- m_fullHeight(fullHeight),
- m_rect(0, 0, fullWidth, fullHeight)
{
+ recalc(fullWidth, fullHeight);
+}
+
+void Geometry::recalc(int fullWidth, int fullHeight)
+{
+ m_fullWidth = fullWidth;
+ m_fullHeight = fullHeight;
+ m_rect.setXYWH(0, 0, fullWidth, fullHeight);
+
// Parse geometry specification and save the result in m_rect.
const char *param = m_geometryParam.getData();
bool geometrySpecified = (strlen(param) > 0);
diff --git a/unix/x0vncserver/Geometry.h b/unix/x0vncserver/Geometry.h
index 98bafb24..d938d63f 100644
--- a/unix/x0vncserver/Geometry.h
+++ b/unix/x0vncserver/Geometry.h
@@ -30,6 +30,7 @@ class Geometry
{
public:
Geometry(int fullWidth, int fullHeight);
+ void recalc(int fullWidth, int fullHeight);
// Return coordinates and dimensions that specify a rectangular part
// of the desktop that would be shown to RFB clients. This
diff --git a/unix/x0vncserver/RandrGlue.c b/unix/x0vncserver/RandrGlue.c
new file mode 100644
index 00000000..2e477630
--- /dev/null
+++ b/unix/x0vncserver/RandrGlue.c
@@ -0,0 +1,511 @@
+/* Copyright 2018 Peter Astrand <astrand@cendio.se> 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_XRANDR
+#include <X11/Xlib.h>
+#include <X11/extensions/Xrandr.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "RandrGlue.h"
+
+typedef struct _vncGlueContext {
+ Display *dpy;
+ XRRScreenResources *res;
+} vncGlueContext;
+
+static vncGlueContext randrGlueContext;
+
+void vncSetGlueContext(Display *dpy, void *res)
+{
+ randrGlueContext.dpy = dpy;
+ randrGlueContext.res = (XRRScreenResources *)res;
+}
+
+static RRMode vncRandRGetMatchingMode(XRROutputInfo *output,
+ unsigned int width, unsigned int height)
+{
+ vncGlueContext *ctx = &randrGlueContext;
+
+ /*
+ * We're not going to change which modes are preferred, but let's
+ * see if we can at least find a mode with matching dimensions.
+ */
+
+ if (output->crtc) {
+ XRRCrtcInfo *crtc;
+ unsigned int swap;
+
+ crtc = XRRGetCrtcInfo(ctx->dpy, ctx->res, output->crtc);
+ if (!crtc)
+ return None;
+
+ switch (crtc->rotation) {
+ case RR_Rotate_90:
+ case RR_Rotate_270:
+ swap = width;
+ width = height;
+ height = swap;
+ break;
+ }
+
+ XRRFreeCrtcInfo(crtc);
+ }
+
+ for (int i = 0; i < ctx->res->nmode; i++) {
+ for (int j = 0; j < output->nmode; j++) {
+ if ((output->modes[j] == ctx->res->modes[i].id) &&
+ (ctx->res->modes[i].width == width) &&
+ (ctx->res->modes[i].height == height)) {
+ return ctx->res->modes[i].id;
+ }
+ }
+ }
+
+ return None;
+}
+
+int vncGetScreenWidth(void)
+{
+ vncGlueContext *ctx = &randrGlueContext;
+ return DisplayWidth(ctx->dpy, DefaultScreen(ctx->dpy));
+}
+
+int vncGetScreenHeight(void)
+{
+ vncGlueContext *ctx = &randrGlueContext;
+ return DisplayHeight(ctx->dpy, DefaultScreen(ctx->dpy));
+}
+
+int vncRandRIsValidScreenSize(int width, int height)
+{
+ vncGlueContext *ctx = &randrGlueContext;
+ /* Assert size ranges */
+ int minwidth, minheight, maxwidth, maxheight;
+ int ret = XRRGetScreenSizeRange(ctx->dpy, DefaultRootWindow(ctx->dpy),
+ &minwidth, &minheight,
+ &maxwidth, &maxheight);
+ if (!ret) {
+ return 0;
+ }
+ if (width < minwidth || maxwidth < width) {
+ return 0;
+ }
+ if (height < minheight || maxheight < height) {
+ return 0;
+ }
+
+ return 1;
+}
+
+int vncRandRResizeScreen(int width, int height)
+{
+ vncGlueContext *ctx = &randrGlueContext;
+
+ int xwidth = DisplayWidth(ctx->dpy, DefaultScreen(ctx->dpy));
+ int xheight = DisplayHeight(ctx->dpy, DefaultScreen(ctx->dpy));
+ int xwidthmm = DisplayWidthMM(ctx->dpy, DefaultScreen(ctx->dpy));
+ int xheightmm = DisplayHeightMM(ctx->dpy, DefaultScreen(ctx->dpy));
+
+ /* Try to retain DPI when we resize */
+ XRRSetScreenSize(ctx->dpy, DefaultRootWindow(ctx->dpy), width, height,
+ xwidthmm * width / xwidth,
+ xheightmm * height / xheight);
+
+ return 1;
+}
+
+void vncRandRUpdateSetTime(void)
+{
+
+}
+
+int vncRandRHasOutputClones(void)
+{
+ vncGlueContext *ctx = &randrGlueContext;
+ for (int i = 0; i < ctx->res->ncrtc; i++) {
+ XRRCrtcInfo *crtc = XRRGetCrtcInfo(ctx->dpy, ctx->res, ctx->res->crtcs[i]);
+ if (!crtc) {
+ return 0;
+ }
+ if (crtc->noutput > 1) {
+ XRRFreeCrtcInfo (crtc);
+ return 1;
+ }
+ XRRFreeCrtcInfo (crtc);
+ }
+ return 0;
+}
+
+int vncRandRGetOutputCount(void)
+{
+ vncGlueContext *ctx = &randrGlueContext;
+ return ctx->res->noutput;
+}
+
+int vncRandRGetAvailableOutputs(void)
+{
+ vncGlueContext *ctx = &randrGlueContext;
+
+ int availableOutputs;
+ RRCrtc *usedCrtcs;
+ int numUsed;
+
+ int i, j, k;
+
+ usedCrtcs = (RRCrtc*)malloc(sizeof(RRCrtc) * ctx->res->ncrtc);
+ 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 < ctx->res->noutput; i++) {
+ XRROutputInfo *output;
+
+ output = XRRGetOutputInfo(ctx->dpy, ctx->res, ctx->res->outputs[i]);
+ if (!output) {
+ continue;
+ }
+
+ if (output->crtc != None)
+ availableOutputs++;
+ else {
+ for (j = 0;j < output->ncrtc;j++) {
+ XRRCrtcInfo *crtc = XRRGetCrtcInfo(ctx->dpy, ctx->res, output->crtcs[j]);
+ if (!crtc) {
+ continue;
+ }
+ if (crtc->noutput != 0) {
+ XRRFreeCrtcInfo(crtc);
+ continue;
+ }
+ XRRFreeCrtcInfo(crtc);
+
+ 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;
+ }
+ }
+ XRRFreeOutputInfo(output);
+ }
+
+ free(usedCrtcs);
+
+ return availableOutputs;
+}
+
+char *vncRandRGetOutputName(int outputIdx)
+{
+ vncGlueContext *ctx = &randrGlueContext;
+ XRROutputInfo *output = XRRGetOutputInfo(ctx->dpy, ctx->res, ctx->res->outputs[outputIdx]);
+ if (!output) {
+ return strdup("");
+ }
+ char *ret = strdup(output->name);
+ XRRFreeOutputInfo(output);
+ return ret;
+}
+
+int vncRandRIsOutputEnabled(int outputIdx)
+{
+ vncGlueContext *ctx = &randrGlueContext;
+ XRROutputInfo *output = XRRGetOutputInfo(ctx->dpy, ctx->res, ctx->res->outputs[outputIdx]);
+ if (!output) {
+ return 0;
+ }
+
+ if (output->crtc == None) {
+ XRRFreeOutputInfo(output);
+ return 0;
+ }
+ XRRCrtcInfo *crtc = XRRGetCrtcInfo(ctx->dpy, ctx->res, output->crtc);
+ XRRFreeOutputInfo(output);
+ if (!crtc) {
+ return 0;
+ }
+ if (crtc->mode == None) {
+ XRRFreeCrtcInfo(crtc);
+ return 0;
+ }
+ XRRFreeCrtcInfo(crtc);
+ return 1;
+}
+
+int vncRandRIsOutputUsable(int outputIdx)
+{
+ vncGlueContext *ctx = &randrGlueContext;
+
+ XRROutputInfo *output;
+ int i;
+
+ output = XRRGetOutputInfo(ctx->dpy, ctx->res, ctx->res->outputs[outputIdx]);
+ if (!output) {
+ return 0;
+ }
+
+ if (output->crtc != None) {
+ XRRFreeOutputInfo(output);
+ return 1;
+ }
+
+ /* Any unused CRTCs? */
+ for (i = 0;i < output->ncrtc;i++) {
+ XRRCrtcInfo *crtc = XRRGetCrtcInfo(ctx->dpy, ctx->res, output->crtcs[i]);
+ if (crtc->noutput == 0) {
+ XRRFreeOutputInfo(output);
+ XRRFreeCrtcInfo(crtc);
+ return 1;
+ }
+ XRRFreeCrtcInfo(crtc);
+ }
+
+ XRRFreeOutputInfo(output);
+ return 0;
+}
+
+int vncRandRIsOutputConnected(int outputIdx)
+{
+ vncGlueContext *ctx = &randrGlueContext;
+ XRROutputInfo *output;
+
+ output = XRRGetOutputInfo(ctx->dpy, ctx->res, ctx->res->outputs[outputIdx]);
+ if (!output) {
+ return 0;
+ }
+
+ int ret = (output->connection == RR_Connected);
+ XRRFreeOutputInfo(output);
+ return ret;
+}
+
+int vncRandRCheckOutputMode(int outputIdx, int width, int height)
+{
+ vncGlueContext *ctx = &randrGlueContext;
+ XRROutputInfo *output;
+ RRMode mode;
+
+ output = XRRGetOutputInfo(ctx->dpy, ctx->res, ctx->res->outputs[outputIdx]);
+ if (!output)
+ return 0;
+
+ /* Make sure we have the mode we want */
+ mode = vncRandRGetMatchingMode(output, width, height);
+ XRRFreeOutputInfo(output);
+
+ if (mode == None)
+ return 0;
+
+ return 1;
+}
+
+int vncRandRDisableOutput(int outputIdx)
+{
+ vncGlueContext *ctx = &randrGlueContext;
+ RRCrtc crtcid;
+ int i;
+ int move = 0;
+
+ XRROutputInfo *output = XRRGetOutputInfo(ctx->dpy, ctx->res, ctx->res->outputs[outputIdx]);
+ if (!output) {
+ return 0;
+ }
+
+ crtcid = output->crtc;
+ if (crtcid == 0) {
+ XRRFreeOutputInfo(output);
+ return 1;
+ }
+
+ XRRCrtcInfo *crtc = XRRGetCrtcInfo(ctx->dpy, ctx->res, output->crtc);
+ XRRFreeOutputInfo(output);
+ if (!crtc) {
+ return 0;
+ }
+
+ /* Remove this output from the CRTC configuration */
+ for (i = 0; i < crtc->noutput; i++) {
+ if (ctx->res->outputs[outputIdx] == crtc->outputs[i]) {
+ crtc->noutput -= 1;
+ move = 1;
+ }
+ if (move && i < crtc->noutput) {
+ crtc->outputs[i] = crtc->outputs[i+1];
+ }
+ }
+ if (crtc->noutput == 0) {
+ crtc->mode = None;
+ crtc->outputs = NULL;
+ }
+
+ int ret = XRRSetCrtcConfig(ctx->dpy,
+ ctx->res,
+ crtcid,
+ CurrentTime,
+ crtc->x, crtc->y,
+ crtc->mode, crtc->rotation,
+ crtc->outputs, crtc->noutput);
+
+ XRRFreeCrtcInfo(crtc);
+
+ return (ret == RRSetConfigSuccess);
+}
+
+unsigned int vncRandRGetOutputId(int outputIdx)
+{
+ vncGlueContext *ctx = &randrGlueContext;
+ return ctx->res->outputs[outputIdx];
+}
+
+int vncRandRGetOutputDimensions(int outputIdx,
+ int *x, int *y, int *width, int *height)
+{
+ vncGlueContext *ctx = &randrGlueContext;
+ int swap;
+ *x = *y = *width = *height = 0;
+
+ XRROutputInfo *output = XRRGetOutputInfo(ctx->dpy, ctx->res, ctx->res->outputs[outputIdx]);
+ if (!output) {
+ return 1;
+ }
+
+ if (!output->crtc) {
+ XRRFreeOutputInfo(output);
+ return 1;
+ }
+
+ XRRCrtcInfo *crtc = XRRGetCrtcInfo(ctx->dpy, ctx->res, output->crtc);
+ XRRFreeOutputInfo(output);
+ if (!crtc) {
+ return 1;
+ }
+ if (crtc->mode == None) {
+ XRRFreeCrtcInfo(crtc);
+ return 1;
+ }
+
+ *x = crtc->x;
+ *y = crtc->y;
+ for (int m = 0; m < ctx->res->nmode; m++) {
+ if (crtc->mode == ctx->res->modes[m].id) {
+ *width = ctx->res->modes[m].width;
+ *height = ctx->res->modes[m].height;
+ }
+ }
+
+ switch (crtc->rotation) {
+ case RR_Rotate_90:
+ case RR_Rotate_270:
+ swap = *width;
+ *width = *height;
+ *height = swap;
+ break;
+ }
+
+ XRRFreeCrtcInfo(crtc);
+ return 0;
+}
+
+int vncRandRReconfigureOutput(int outputIdx, int x, int y,
+ int width, int height)
+{
+ vncGlueContext *ctx = &randrGlueContext;
+
+ XRROutputInfo *output;
+ RRCrtc crtcid;
+ RRMode mode;
+ XRRCrtcInfo *crtc = NULL;
+
+ int i, ret;
+
+ output = XRRGetOutputInfo(ctx->dpy, ctx->res, ctx->res->outputs[outputIdx]);
+ if (!output) {
+ return 0;
+ }
+
+ crtcid = output->crtc;
+
+ /* Need a CRTC? */
+ if (crtcid == None) {
+ for (i = 0;i < output->ncrtc;i++) {
+ crtc = XRRGetCrtcInfo(ctx->dpy, ctx->res, output->crtcs[i]);
+ if (!crtc) {
+ continue;
+ }
+
+ if (crtc->noutput != 0) {
+ XRRFreeCrtcInfo(crtc);
+ continue;
+ }
+
+ crtcid = output->crtcs[i];
+ break;
+ }
+ } else {
+ crtc = XRRGetCrtcInfo(ctx->dpy, ctx->res, crtcid);
+ }
+
+ /* Couldn't find one... */
+ if (crtc == NULL) {
+ XRRFreeOutputInfo(output);
+ return 0;
+ }
+
+ /* Make sure we have the mode we want */
+ mode = vncRandRGetMatchingMode(output, width, height);
+ if (mode == None) {
+ XRRFreeCrtcInfo(crtc);
+ XRRFreeOutputInfo(output);
+ return 0;
+ }
+
+ /* Reconfigure new mode and position */
+ ret = XRRSetCrtcConfig (ctx->dpy, ctx->res, crtcid, CurrentTime, x, y,
+ mode, crtc->rotation, ctx->res->outputs+outputIdx, 1);
+
+ XRRFreeCrtcInfo(crtc);
+ XRRFreeOutputInfo(output);
+
+ return (ret == RRSetConfigSuccess);
+}
+
+int vncRandRCanCreateOutputs(int extraOutputs)
+{
+ return 0;
+}
+
+int vncRandRCreateOutputs(int extraOutputs)
+{
+ return 0;
+}
+
+#endif /* HAVE_XRANDR */
diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx
index 748796be..59e25323 100644
--- a/unix/x0vncserver/XDesktop.cxx
+++ b/unix/x0vncserver/XDesktop.cxx
@@ -30,7 +30,13 @@
#ifdef HAVE_XFIXES
#include <X11/extensions/Xfixes.h>
#endif
-
+#ifdef HAVE_XRANDR
+#include <X11/extensions/Xrandr.h>
+#include <RandrGlue.h>
+extern "C" {
+void vncSetGlueContext(Display *dpy, void *res);
+}
+#endif
#include <x0vncserver/Geometry.h>
#include <x0vncserver/XPixelBuffer.h>
@@ -162,6 +168,24 @@ XDesktop::XDesktop(Display* dpy_, Geometry *geometry_)
}
#endif
+#ifdef HAVE_XRANDR
+ int xrandrErrorBase;
+
+ randrSyncSerial = 0;
+ if (XRRQueryExtension(dpy, &xrandrEventBase, &xrandrErrorBase)) {
+ XRRSelectInput(dpy, DefaultRootWindow(dpy),
+ RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask);
+ /* Override TXWindow::init input mask */
+ XSelectInput(dpy, DefaultRootWindow(dpy),
+ PropertyChangeMask | StructureNotifyMask | ExposureMask);
+ } else {
+#endif
+ vlog.info("RANDR extension not present");
+ vlog.info("Will not be able to handle session resize");
+#ifdef HAVE_XRANDR
+ }
+#endif
+
TXWindow::setGlobalEventHandler(this);
}
@@ -202,7 +226,7 @@ void XDesktop::start(VNCServer* vs) {
vlog.info("Allocated %s", pb->getImage()->classDesc());
server = (VNCServerST *)vs;
- server->setPixelBuffer(pb);
+ server->setPixelBuffer(pb, computeScreenLayout());
#ifdef HAVE_XDAMAGE
if (haveDamage) {
@@ -331,6 +355,217 @@ void XDesktop::keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down) {
void XDesktop::clientCutText(const char* str, int len) {
}
+ScreenSet XDesktop::computeScreenLayout()
+{
+ ScreenSet layout;
+
+#ifdef HAVE_XRANDR
+ XRRScreenResources *res = XRRGetScreenResources(dpy, DefaultRootWindow(dpy));
+ if (!res) {
+ vlog.error("XRRGetScreenResources failed");
+ return layout;
+ }
+ vncSetGlueContext(dpy, res);
+
+ layout = ::computeScreenLayout(&outputIdMap);
+ XRRFreeScreenResources(res);
+#endif
+
+ return layout;
+}
+
+#ifdef HAVE_XRANDR
+/* Get the biggest mode which is equal or smaller to requested
+ size. If no such mode exists, return the smallest. */
+static void GetSmallerMode(XRRScreenResources *res,
+ XRROutputInfo *output,
+ unsigned int *width, unsigned int *height)
+{
+ XRRModeInfo best = {};
+ XRRModeInfo smallest = {};
+ smallest.width = -1;
+ smallest.height = -1;
+
+ for (int i = 0; i < res->nmode; i++) {
+ for (int j = 0; j < output->nmode; j++) {
+ if (output->modes[j] == res->modes[i].id) {
+ if ((res->modes[i].width > best.width && res->modes[i].width <= *width) &&
+ (res->modes[i].height > best.height && res->modes[i].height <= *height)) {
+ best = res->modes[i];
+ }
+ if ((res->modes[i].width < smallest.width) && res->modes[i].height < smallest.height) {
+ smallest = res->modes[i];
+ }
+ }
+ }
+ }
+
+ if (best.id == 0 && smallest.id != 0) {
+ best = smallest;
+ }
+
+ *width = best.width;
+ *height = best.height;
+}
+#endif /* HAVE_XRANDR */
+
+unsigned int XDesktop::setScreenLayout(int fb_width, int fb_height,
+ const rfb::ScreenSet& layout)
+{
+#ifdef HAVE_XRANDR
+ 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);
+
+ XRRScreenResources *res = XRRGetScreenResources(dpy, DefaultRootWindow(dpy));
+ if (!res) {
+ vlog.error("XRRGetScreenResources failed");
+ return rfb::resultProhibited;
+ }
+ vncSetGlueContext(dpy, res);
+
+ /* The client may request a screen layout which is not supported by
+ the Xserver. This happens, for example, when adjusting the size
+ of a non-fullscreen vncviewer window. To handle this and other
+ cases, we first call tryScreenLayout. If this fails, we try to
+ adjust the request to one screen with a smaller mode. */
+ vlog.debug("Testing screen layout");
+ unsigned int tryresult = ::tryScreenLayout(fb_width, fb_height, layout, &outputIdMap);
+ rfb::ScreenSet adjustedLayout;
+ if (tryresult == rfb::resultSuccess) {
+ adjustedLayout = layout;
+ } else {
+ vlog.debug("Impossible layout - trying to adjust");
+
+ ScreenSet::const_iterator firstscreen = layout.begin();
+ adjustedLayout.add_screen(*firstscreen);
+ ScreenSet::iterator iter = adjustedLayout.begin();
+ RROutput outputId = None;
+
+ for (int i = 0;i < vncRandRGetOutputCount();i++) {
+ unsigned int oi = vncRandRGetOutputId(i);
+
+ /* Known? */
+ if (outputIdMap.count(oi) == 0)
+ continue;
+
+ /* Find the corresponding screen... */
+ if (iter->id == outputIdMap[oi]) {
+ outputId = oi;
+ } else {
+ outputIdMap.erase(oi);
+ }
+ }
+
+ /* New screen */
+ if (outputId == None) {
+ int i = getPreferredScreenOutput(&outputIdMap, std::set<unsigned int>());
+ if (i != -1) {
+ outputId = vncRandRGetOutputId(i);
+ }
+ }
+ if (outputId == None) {
+ vlog.debug("Resize adjust: Could not find corresponding screen");
+ XRRFreeScreenResources(res);
+ return rfb::resultInvalid;
+ }
+ XRROutputInfo *output = XRRGetOutputInfo(dpy, res, outputId);
+ if (!output) {
+ vlog.debug("Resize adjust: XRRGetOutputInfo failed");
+ XRRFreeScreenResources(res);
+ return rfb::resultInvalid;
+ }
+ if (!output->crtc) {
+ vlog.debug("Resize adjust: Selected output has no CRTC");
+ XRRFreeScreenResources(res);
+ XRRFreeOutputInfo(output);
+ return rfb::resultInvalid;
+ }
+ XRRCrtcInfo *crtc = XRRGetCrtcInfo(dpy, res, output->crtc);
+ if (!crtc) {
+ vlog.debug("Resize adjust: XRRGetCrtcInfo failed");
+ XRRFreeScreenResources(res);
+ XRRFreeOutputInfo(output);
+ return rfb::resultInvalid;
+ }
+
+ unsigned int swidth = iter->dimensions.width();
+ unsigned int sheight = iter->dimensions.height();
+
+ switch (crtc->rotation) {
+ case RR_Rotate_90:
+ case RR_Rotate_270:
+ unsigned int swap = swidth;
+ swidth = sheight;
+ sheight = swap;
+ break;
+ }
+
+ GetSmallerMode(res, output, &swidth, &sheight);
+ XRRFreeOutputInfo(output);
+
+ switch (crtc->rotation) {
+ case RR_Rotate_90:
+ case RR_Rotate_270:
+ unsigned int swap = swidth;
+ swidth = sheight;
+ sheight = swap;
+ break;
+ }
+
+ XRRFreeCrtcInfo(crtc);
+
+ if (sheight != 0 && swidth != 0) {
+ vlog.debug("Adjusted resize request to %dx%d", swidth, sheight);
+ iter->dimensions.setXYWH(0, 0, swidth, sheight);
+ fb_width = swidth;
+ fb_height = sheight;
+ } else {
+ vlog.error("Failed to find smaller or equal screen size");
+ XRRFreeScreenResources(res);
+ return rfb::resultInvalid;
+ }
+ }
+
+ vlog.debug("Changing screen layout");
+ unsigned int ret = ::setScreenLayout(fb_width, fb_height, adjustedLayout, &outputIdMap);
+ XRRFreeScreenResources(res);
+
+ /* Send a dummy event to the root window. When this event is seen,
+ earlier change events (ConfigureNotify and/or CrtcChange) have
+ been processed. An Expose event is used for simplicity; does not
+ require any Atoms, and will not affect other applications. */
+ unsigned long serial = XNextRequest(dpy);
+ XExposeEvent ev = {}; /* zero x, y, width, height, count */
+ ev.type = Expose;
+ ev.display = dpy;
+ ev.window = DefaultRootWindow(dpy);
+ if (XSendEvent(dpy, DefaultRootWindow(dpy), False, ExposureMask, (XEvent*)&ev)) {
+ while (randrSyncSerial < serial) {
+ TXWindow::handleXEvents(dpy);
+ }
+ } else {
+ vlog.error("XSendEvent failed");
+ }
+
+ /* The protocol requires that an error is returned if the requested
+ layout could not be set. This is checked by
+ VNCSConnectionST::setDesktopSize. Another ExtendedDesktopSize
+ with reason=0 will be sent in response to the changes seen by the
+ event handler. */
+ if (adjustedLayout != layout) {
+ return rfb::resultInvalid;
+ } else {
+ return ret;
+ }
+
+#else
+ return rfb::resultProhibited;
+#endif /* HAVE_XRANDR */
+}
+
bool XDesktop::handleGlobalEvent(XEvent* ev) {
if (ev->type == xkbEventBase + XkbEventCode) {
@@ -379,6 +614,56 @@ bool XDesktop::handleGlobalEvent(XEvent* ev) {
return setCursor();
#endif
+#ifdef HAVE_XRANDR
+ } else if (ev->type == Expose) {
+ XExposeEvent* eev = (XExposeEvent*)ev;
+ randrSyncSerial = eev->serial;
+
+ return false;
+
+ } else if (ev->type == ConfigureNotify) {
+ XConfigureEvent* cev = (XConfigureEvent*)ev;
+
+ if (cev->window != DefaultRootWindow(dpy)) {
+ return false;
+ }
+
+ XRRUpdateConfiguration(ev);
+ geometry->recalc(cev->width, cev->height);
+
+ if (!running) {
+ return false;
+ }
+
+ if ((cev->width != pb->width() || (cev->height != pb->height()))) {
+ // Recreate pixel buffer
+ ImageFactory factory((bool)useShm);
+ delete pb;
+ pb = new XPixelBuffer(dpy, factory, geometry->getRect());
+ server->setPixelBuffer(pb, computeScreenLayout());
+
+ // Mark entire screen as changed
+ server->add_changed(rfb::Region(Rect(0, 0, cev->width, cev->height)));
+ }
+
+ return true;
+
+ } else if (ev->type == xrandrEventBase + RRNotify) {
+ XRRNotifyEvent* rev = (XRRNotifyEvent*)ev;
+
+ if (rev->window != DefaultRootWindow(dpy)) {
+ return false;
+ }
+
+ if (!running)
+ return false;
+
+ if (rev->subtype == RRNotify_CrtcChange) {
+ server->setScreenLayout(computeScreenLayout());
+ }
+
+ return true;
+#endif
}
return false;
diff --git a/unix/x0vncserver/XDesktop.h b/unix/x0vncserver/XDesktop.h
index c9106f8b..ff52c014 100644
--- a/unix/x0vncserver/XDesktop.h
+++ b/unix/x0vncserver/XDesktop.h
@@ -23,6 +23,7 @@
#include <rfb/VNCServerST.h>
#include <tx/TXWindow.h>
+#include <unixcommon.h>
#include <X11/XKBlib.h>
#ifdef HAVE_XDAMAGE
@@ -49,6 +50,9 @@ public:
KeyCode XkbKeysymToKeycode(Display* dpy, KeySym keysym);
virtual void keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down);
virtual void clientCutText(const char* str, int len);
+ virtual unsigned int setScreenLayout(int fb_width, int fb_height,
+ const rfb::ScreenSet& layout);
+
// -=- TXGlobalEventHandler interface
virtual bool handleGlobalEvent(XEvent* ev);
@@ -71,11 +75,17 @@ protected:
#ifdef HAVE_XFIXES
int xfixesEventBase;
#endif
+#ifdef HAVE_XRANDR
+ int xrandrEventBase;
+ OutputIdMap outputIdMap;
+ unsigned long randrSyncSerial;
+#endif
int ledMasks[XDESKTOP_N_LEDS];
unsigned ledState;
const unsigned short *codeMap;
unsigned codeMapLen;
bool setCursor();
+ rfb::ScreenSet computeScreenLayout();
};
#endif // __XDESKTOP_H__
diff --git a/unix/xserver/hw/vnc/Makefile.am b/unix/xserver/hw/vnc/Makefile.am
index 24a40b3d..e8fa38e8 100644
--- a/unix/xserver/hw/vnc/Makefile.am
+++ b/unix/xserver/hw/vnc/Makefile.am
@@ -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 \
diff --git a/unix/xserver/hw/vnc/RandrGlue.c b/unix/xserver/hw/vnc/RandrGlue.c
new file mode 100644
index 00000000..82e85524
--- /dev/null
+++ b/unix/xserver/hw/vnc/RandrGlue.c
@@ -0,0 +1,360 @@
+/* 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"
+#include "randrstr.h"
+
+#include "RandrGlue.h"
+#include "XorgGlue.h"
+
+static int scrIdx;
+
+void vncSetGlueContext(int screenIndex);
+
+void vncSetGlueContext(int screenIndex)
+{
+ scrIdx = screenIndex;
+}
+
+int vncGetScreenWidth(void)
+{
+ return screenInfo.screens[scrIdx]->width;
+}
+
+int vncGetScreenHeight(void)
+{
+ return screenInfo.screens[scrIdx]->height;
+}
+
+int vncRandRIsValidScreenSize(int width, int height)
+{
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+
+ if (width < rp->minWidth || rp->maxWidth < width)
+ return 0;
+ if (height < rp->minHeight || rp->maxHeight < height)
+ return 0;
+
+ return 1;
+}
+
+int vncRandRResizeScreen(int width, int height)
+{
+ 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);
+}
+
+void vncRandRUpdateSetTime(void)
+{
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+ rp->lastSetTime = currentTime;
+}
+
+int vncRandRHasOutputClones(void)
+{
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+ for (int i = 0;i < rp->numCrtcs;i++) {
+ if (rp->crtcs[i]->numOutputs > 1)
+ return 1;
+ }
+ return 0;
+}
+
+int vncRandRGetOutputCount(void)
+{
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+ return rp->numOutputs;
+}
+
+int vncRandRGetAvailableOutputs(void)
+{
+ 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;
+}
+
+char *vncRandRGetOutputName(int outputIdx)
+{
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+ return strdup(rp->outputs[outputIdx]->name);
+}
+
+int vncRandRIsOutputEnabled(int outputIdx)
+{
+ 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;
+}
+
+int vncRandRIsOutputUsable(int outputIdx)
+{
+ 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;
+ }
+
+ return 0;
+}
+
+int vncRandRIsOutputConnected(int outputIdx)
+{
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+
+ RROutputPtr output;
+
+ output = rp->outputs[outputIdx];
+ return (output->connection == RR_Connected);
+}
+
+static RRModePtr vncRandRGetMatchingMode(int outputIdx, int width, int height)
+{
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+
+ RROutputPtr output;
+
+ output = rp->outputs[outputIdx];
+
+ if (output->crtc != NULL) {
+ unsigned int swap;
+ switch (output->crtc->rotation) {
+ case RR_Rotate_90:
+ case RR_Rotate_270:
+ swap = width;
+ width = height;
+ height = swap;
+ break;
+ }
+ }
+
+ for (int i = 0; i < output->numModes; i++) {
+ if ((output->modes[i]->mode.width == width) &&
+ (output->modes[i]->mode.height == height))
+ return output->modes[i];
+ }
+
+ return NULL;
+}
+
+int vncRandRCheckOutputMode(int outputIdx, int width, int height)
+{
+ if (vncRandRGetMatchingMode(outputIdx, width, height) != NULL)
+ return 1;
+ if (vncRandRCanCreateModes())
+ return 1;
+ return 0;
+}
+
+int vncRandRDisableOutput(int outputIdx)
+{
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+ RRCrtcPtr crtc;
+ int i;
+ RROutputPtr *outputs;
+ int numOutputs = 0;
+ RRModePtr mode;
+ int ret;
+
+ crtc = rp->outputs[outputIdx]->crtc;
+ if (crtc == NULL)
+ return 1;
+
+ /* Remove this output from the CRTC configuration */
+ outputs = malloc(crtc->numOutputs * sizeof(RROutputPtr));
+ if (!outputs) {
+ return 0;
+ }
+
+ for (i = 0; i < crtc->numOutputs; i++) {
+ if (rp->outputs[outputIdx] != crtc->outputs[i]) {
+ outputs[numOutputs++] = crtc->outputs[i];
+ }
+ }
+
+ if (numOutputs == 0) {
+ mode = NULL;
+ } else {
+ mode = crtc->mode;
+ }
+
+ ret = RRCrtcSet(crtc, mode, crtc->x, crtc->y, crtc->rotation, numOutputs, outputs);
+ free(outputs);
+ return ret;
+}
+
+unsigned int vncRandRGetOutputId(int outputIdx)
+{
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+ return rp->outputs[outputIdx]->id;
+}
+
+int vncRandRGetOutputDimensions(int outputIdx,
+ int *x, int *y, int *width, int *height)
+{
+ rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+ RRCrtcPtr crtc;
+ int swap;
+ *x = *y = *width = *height = 0;
+
+ crtc = rp->outputs[outputIdx]->crtc;
+ if (crtc == NULL || !crtc->mode)
+ return 1;
+
+ *x = crtc->x;
+ *y = crtc->y;
+ *width = crtc->mode->mode.width;
+ *height = crtc->mode->mode.height;
+
+ switch (crtc->rotation & 0xf) {
+ case RR_Rotate_90:
+ case RR_Rotate_270:
+ swap = *width;
+ *width = *height;
+ *height = swap;
+ break;
+ }
+ return 0;
+}
+
+int vncRandRReconfigureOutput(int outputIdx, int x, int y,
+ int width, int height)
+{
+ 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 0;
+ }
+
+ /* Make sure we have the mode we want */
+ mode = vncRandRGetMatchingMode(outputIdx, width, height);
+ if (mode == NULL) {
+ mode = vncRandRCreateMode(output, width, height);
+ if (mode == NULL)
+ return 0;
+ }
+ mode = vncRandRSetPreferredMode(output, mode);
+ if (mode == NULL)
+ return 0;
+
+ /* Reconfigure new mode and position */
+ return RRCrtcSet(crtc, mode, x, y, crtc->rotation, 1, &output);
+}
+
+int vncRandRCanCreateOutputs(int extraOutputs)
+{
+ return vncRandRCanCreateScreenOutputs(scrIdx, extraOutputs);
+}
+
+int vncRandRCreateOutputs(int extraOutputs)
+{
+ return vncRandRCreateScreenOutputs(scrIdx, extraOutputs);
+}
diff --git a/unix/xserver/hw/vnc/XorgGlue.c b/unix/xserver/hw/vnc/XorgGlue.c
index 141023a8..10ba98d6 100644
--- a/unix/xserver/hw/vnc/XorgGlue.c
+++ b/unix/xserver/hw/vnc/XorgGlue.c
@@ -114,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
-}
-
-const char *vncRandRGetOutputName(int scrIdx, int outputIdx)
-{
-#ifdef RANDR
- rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
- return rp->outputs[outputIdx]->name;
-#else
- return "";
-#endif
-}
-
-int vncRandRIsOutputEnabled(int scrIdx, int outputIdx)
-{
-#ifdef RANDR
- rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
-
- if (rp->outputs[outputIdx]->crtc == NULL)
- return 0;
- if (rp->outputs[outputIdx]->crtc->mode == NULL)
- return 0;
-
- return 1;
-#else
- return 0;
-#endif
-}
-
-int vncRandRIsOutputUsable(int scrIdx, int outputIdx)
-{
-#ifdef RANDR
- rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
-
- RROutputPtr output;
- int i;
-
- output = rp->outputs[outputIdx];
- if (output->crtc != NULL)
- return 1;
-
- /* Any unused CRTCs? */
- for (i = 0;i < output->numCrtcs;i++) {
- if (output->crtcs[i]->numOutputs == 0)
- return 1;
- }
-#endif
-
- return 0;
-}
-
-int vncRandRDisableOutput(int scrIdx, int outputIdx)
-{
-#ifdef RANDR
- rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
- RRCrtcPtr crtc;
-
- crtc = rp->outputs[outputIdx]->crtc;
- if (crtc == NULL)
- return 0;
-
- return RRCrtcSet(crtc, NULL, crtc->x, crtc->y, crtc->rotation, 0, NULL);
-#else
- return -1;
-#endif
-}
-
-intptr_t vncRandRGetOutputId(int scrIdx, int outputIdx)
-{
-#ifdef RANDR
- rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
- return (intptr_t)rp->outputs[outputIdx];
-#else
- return 0;
-#endif
-}
-
-void vncRandRGetOutputDimensions(int scrIdx, int outputIdx,
- int *x, int *y, int *width, int *height)
-{
-#ifdef RANDR
- rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
- 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
-}
diff --git a/unix/xserver/hw/vnc/XorgGlue.h b/unix/xserver/hw/vnc/XorgGlue.h
index 63227ac3..5d019493 100644
--- a/unix/xserver/hw/vnc/XorgGlue.h
+++ b/unix/xserver/hw/vnc/XorgGlue.h
@@ -45,34 +45,14 @@ 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);
-
-const char *vncRandRGetOutputName(int scrIdx, int outputIdx);
-
-int vncRandRIsOutputEnabled(int scrIdx, int outputIdx);
-int vncRandRIsOutputUsable(int scrIdx, int outputIdx);
-
-int vncRandRDisableOutput(int scrIdx, int outputIdx);
-int vncRandRReconfigureOutput(int scrIdx, int outputIdx, int x, int y,
- int width, int height);
-
-intptr_t vncRandRGetOutputId(int scrIdx, int outputIdx);
-void vncRandRGetOutputDimensions(int scrIdx, int outputIdx,
- int *x, int *y, int *width, int *height);
// 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);
+int vncRandRCanCreateScreenOutputs(int scrIdx, int extraOutputs);
+int vncRandRCreateScreenOutputs(int scrIdx, int extraOutputs);
+int vncRandRCanCreateModes(void);
+void* vncRandRCreateMode(void* output, int width, int height);
+void* vncRandRSetPreferredMode(void* output, void* mode);
#ifdef __cplusplus
}
diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc
index c68a0775..080943d0 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.cc
+++ b/unix/xserver/hw/vnc/XserverDesktop.cc
@@ -48,6 +48,10 @@
#include "XorgGlue.h"
#include "Input.h"
+extern "C" {
+void vncSetGlueContext(int screenIndex);
+}
+
using namespace rfb;
using namespace network;
@@ -185,68 +189,16 @@ void XserverDesktop::setFramebuffer(int w, int h, void* fbptr, int stride_)
data = (rdr::U8*)fbptr;
stride = stride_;
- layout = computeScreenLayout();
+ vncSetGlueContext(screenIndex);
+ layout = ::computeScreenLayout(&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++) {
- intptr_t 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;
+ vncSetGlueContext(screenIndex);
+ server->setScreenLayout(::computeScreenLayout(&outputIdMap));
}
char* XserverDesktop::substitute(const char* varName)
@@ -605,164 +557,14 @@ 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++) {
- intptr_t 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) {
- vlog.error("Failed to disable unused output '%s'",
- vncRandRGetOutputName(screenIndex, i));
- 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) {
- vlog.error("Failed to reconfigure output '%s' to %dx%d+%d+%d",
- vncRandRGetOutputName(screenIndex, i),
- iter->dimensions.width(), iter->dimensions.height(),
- iter->dimensions.tl.x, iter->dimensions.tl.y);
- 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;
- intptr_t 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) {
- vlog.error("Failed to reconfigure output '%s' to %dx%d+%d+%d",
- vncRandRGetOutputName(screenIndex, i),
- iter->dimensions.width(), iter->dimensions.height(),
- iter->dimensions.tl.x, iter->dimensions.tl.y);
- 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;
+ vncSetGlueContext(screenIndex);
+ return ::setScreenLayout(fb_width, fb_height, layout, &outputIdMap);
}
void XserverDesktop::grabRegion(const rfb::Region& region)
diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h
index 2a378ea1..f1c3e3e7 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.h
+++ b/unix/xserver/hw/vnc/XserverDesktop.h
@@ -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;
@@ -132,10 +132,7 @@ private:
rfb::CharArray queryConnectUsername;
rfb::Timer queryConnectTimer;
-#ifdef RANDR
- typedef std::map<intptr_t, rdr::U32> OutputIdMap;
OutputIdMap outputIdMap;
-#endif
rfb::Point oldCursorPos;
};
diff --git a/unix/xserver/hw/vnc/vncExtInit.cc b/unix/xserver/hw/vnc/vncExtInit.cc
index c47dfa72..54cca953 100644
--- a/unix/xserver/hw/vnc/vncExtInit.cc
+++ b/unix/xserver/hw/vnc/vncExtInit.cc
@@ -41,8 +41,13 @@
#include "vncBlockHandler.h"
#include "vncSelection.h"
#include "XorgGlue.h"
+#include "RandrGlue.h"
#include "xorg-version.h"
+extern "C" {
+void vncSetGlueContext(int screenIndex);
+}
+
using namespace rfb;
static rfb::LogWriter vlog("vncext");
@@ -211,13 +216,14 @@ void vncExtensionInit(void)
CharArray desktopNameStr(desktopName.getData());
PixelFormat pf = vncGetPixelFormat(scr);
+ vncSetGlueContext(scr);
desktop[scr] = new XserverDesktop(scr,
listeners,
httpListeners,
desktopNameStr.buf,
pf,
- vncGetScreenWidth(scr),
- vncGetScreenHeight(scr),
+ vncGetScreenWidth(),
+ vncGetScreenHeight(),
vncFbptr[scr],
vncFbstride[scr]);
vlog.info("created VNC server for screen %d", scr);
diff --git a/unix/xserver/hw/vnc/vncHooks.c b/unix/xserver/hw/vnc/vncHooks.c
index c0d9f7c6..f3c2520a 100644
--- a/unix/xserver/hw/vnc/vncHooks.c
+++ b/unix/xserver/hw/vnc/vncHooks.c
@@ -38,9 +38,7 @@
#ifdef RENDER
#include "picturestr.h"
#endif
-#ifdef RANDR
#include "randrstr.h"
-#endif
#define DBGPRINT(x) //(fprintf x)
@@ -79,11 +77,9 @@ typedef struct _vncHooksScreenRec {
TriFanProcPtr TriFan;
#endif
#endif
-#ifdef RANDR
RRSetConfigProcPtr rrSetConfig;
RRScreenSetSizeProcPtr rrScreenSetSize;
RRCrtcSetProcPtr rrCrtcSet;
-#endif
} vncHooksScreenRec, *vncHooksScreenPtr;
typedef struct _vncHooksGCRec {
@@ -174,7 +170,6 @@ static void vncHooksTriFan(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
int npoint, xPointFixed * points);
#endif
#endif
-#ifdef RANDR
static Bool vncHooksRandRSetConfig(ScreenPtr pScreen, Rotation rotation,
int rate, RRScreenSizePtr pSize);
static Bool vncHooksRandRScreenSetSize(ScreenPtr pScreen,
@@ -184,7 +179,6 @@ static Bool vncHooksRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc,
RRModePtr mode, int x, int y,
Rotation rotation, int numOutputs,
RROutputPtr *outputs);
-#endif
// GC "funcs"
@@ -277,9 +271,7 @@ int vncHooksInit(int scrIdx)
#ifdef RENDER
PictureScreenPtr ps;
#endif
-#ifdef RANDR
rrScrPrivPtr rp;
-#endif
pScreen = screenInfo.screens[scrIdx];
@@ -339,7 +331,6 @@ int vncHooksInit(int scrIdx)
#endif
}
#endif
-#ifdef RANDR
rp = rrGetScrPriv(pScreen);
if (rp) {
/* Some RandR callbacks are optional */
@@ -350,7 +341,6 @@ int vncHooksInit(int scrIdx)
if (rp->rrCrtcSet)
wrap(vncHooksScreen, rp, rrCrtcSet, vncHooksRandRCrtcSet);
}
-#endif
return TRUE;
}
@@ -473,9 +463,7 @@ static Bool vncHooksCloseScreen(ScreenPtr pScreen_)
#ifdef RENDER
PictureScreenPtr ps;
#endif
-#ifdef RANDR
rrScrPrivPtr rp;
-#endif
SCREEN_PROLOGUE(pScreen_, CloseScreen);
@@ -501,14 +489,12 @@ static Bool vncHooksCloseScreen(ScreenPtr pScreen_)
#endif
}
#endif
-#ifdef RANDR
rp = rrGetScrPriv(pScreen);
if (rp) {
unwrap(vncHooksScreen, rp, rrSetConfig);
unwrap(vncHooksScreen, rp, rrScreenSetSize);
unwrap(vncHooksScreen, rp, rrCrtcSet);
}
-#endif
DBGPRINT((stderr,"vncHooksCloseScreen: unwrapped screen functions\n"));
@@ -1199,8 +1185,6 @@ static void vncHooksTriFan(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
#endif /* RENDER */
-#ifdef RANDR
-
// Unwrap and rewrap helpers
#define RANDR_PROLOGUE(field) \
@@ -1275,8 +1259,6 @@ static Bool vncHooksRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc,
return TRUE;
}
-#endif /* RANDR */
-
/////////////////////////////////////////////////////////////////////////////
//
// GC "funcs"
diff --git a/unix/xserver/hw/vnc/vncModule.c b/unix/xserver/hw/vnc/vncModule.c
index 5b4db968..451f527a 100644
--- a/unix/xserver/hw/vnc/vncModule.c
+++ b/unix/xserver/hw/vnc/vncModule.c
@@ -24,9 +24,7 @@
#endif
#include "opaque.h"
-#ifdef RANDR
#include "randrstr.h"
-#endif
#include "xorg-version.h"
#if XORG <= 111
@@ -39,6 +37,7 @@ typedef pointer XF86OptionPtr;
#include "vncExtInit.h"
#include "RFBGlue.h"
#include "XorgGlue.h"
+#include "RandrGlue.h"
static void vncModuleInit(INITARGS);
@@ -111,29 +110,31 @@ void vncClientGone(int fd)
{
}
-#ifdef RANDR
-int vncRandRCreateOutputs(int scrIdx, int extraOutputs)
+int vncRandRCanCreateScreenOutputs(int scrIdx, int extraOutputs)
{
- return -1;
+ return 0;
}
-void *vncRandRCreatePreferredMode(void *out, int width, int height)
+int vncRandRCreateScreenOutputs(int scrIdx, int extraOutputs)
{
- RROutputPtr output;
-
- /*
- * We're not going to change which modes are preferred, but let's
- * see if we can at least find a mode with matching dimensions.
- */
+ return 0;
+}
- output = out;
+int vncRandRCanCreateModes(void)
+{
+ return 0;
+}
- for (int i = 0;i < output->numModes;i++) {
- if ((output->modes[i]->mode.width == width) &&
- (output->modes[i]->mode.height == height))
- return output->modes[i];
- }
+void* vncRandRCreateMode(void* output, int width, int height)
+{
+ return 0;
+}
- return NULL;
+void* vncRandRSetPreferredMode(void* output, void* mode)
+{
+ /*
+ * We're not going to change which modes are preferred,
+ * so just return the incoming mode.
+ */
+ return mode;
}
-#endif
diff --git a/unix/xserver/hw/vnc/xvnc.c b/unix/xserver/hw/vnc/xvnc.c
index 6924f65f..57152cd5 100644
--- a/unix/xserver/hw/vnc/xvnc.c
+++ b/unix/xserver/hw/vnc/xvnc.c
@@ -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
@@ -72,9 +73,7 @@ from the X Consortium.
#include "os.h"
#include "miline.h"
#include "inputstr.h"
-#ifdef RANDR
#include "randrstr.h"
-#endif /* RANDR */
#ifdef DPMSExtension
#include "dpmsproc.h"
#endif
@@ -952,7 +951,6 @@ static miPointerScreenFuncRec vfbPointerCursorFuncs = {
miPointerWarpCursor
};
-#ifdef RANDR
static Bool vncRandRGetInfo (ScreenPtr pScreen, Rotation *rotations)
{
@@ -1379,41 +1377,87 @@ static RRCrtcPtr vncRandRCrtcCreate(ScreenPtr pScreen)
}
/* Used from XserverDesktop when it needs more outputs... */
-int vncRandRCreateOutputs(int scrIdx, int extraOutputs)
+
+int vncRandRCanCreateScreenOutputs(int scrIdx, int extraOutputs)
+{
+ return 1;
+}
+
+int vncRandRCreateScreenOutputs(int scrIdx, int extraOutputs)
{
RRCrtcPtr crtc;
while (extraOutputs > 0) {
crtc = vncRandRCrtcCreate(screenInfo.screens[scrIdx]);
if (crtc == NULL)
- return -1;
+ return 0;
extraOutputs--;
}
- return 0;
+ return 1;
+}
+
+/* Creating and modifying modes, used by XserverDesktop and init here */
+
+int vncRandRCanCreateModes()
+{
+ return 1;
}
-/* Used to create a preferred mode from various places */
-void *vncRandRCreatePreferredMode(void *out, int width, int height)
+void* vncRandRCreateMode(void* out, int width, int height)
{
RROutputPtr output;
output = out;
+ /* Do we already have the mode? */
+ for (int i = 0; i < output->numModes; i++) {
+ if ((output->modes[i]->mode.width == width) &&
+ (output->modes[i]->mode.height == height))
+ return output->modes[i];
+ }
+
+ /* Just recreate the entire list */
+ vncRandRSetModes(output, width, height);
+
+ /* Find the new mode */
+ for (int i = 0; i < output->numModes; i++) {
+ if ((output->modes[i]->mode.width == width) &&
+ (output->modes[i]->mode.height == height))
+ return output->modes[i];
+ }
+
+ /* Something went horribly wrong */
+ return NULL;
+}
+
+void* vncRandRSetPreferredMode(void* out, void* m)
+{
+ RRModePtr mode;
+ RROutputPtr output;
+ int width, height;
+
+ mode = m;
+ output = out;
+
+ width = mode->mode.width;
+ height = mode->mode.height;
+
/* Already the preferred mode? */
if ((output->numModes >= 1) && (output->numPreferred == 1) &&
- (output->modes[0]->mode.width == width) &&
- (output->modes[0]->mode.height == height))
- return output->modes[0];
+ (output->modes[0] == mode))
+ return mode;
/* Recreate the list, with the mode we want as preferred */
vncRandRSetModes(output, width, height);
+ /* Sanity check */
if ((output->numModes >= 1) && (output->numPreferred == 1) &&
(output->modes[0]->mode.width == width) &&
(output->modes[0]->mode.height == height))
return output->modes[0];
+ /* Something went horribly wrong */
return NULL;
}
@@ -1436,8 +1480,11 @@ static Bool vncRandRInit(ScreenPtr pScreen)
crtc = vncRandRCrtcCreate(pScreen);
/* Make sure the current screen size is the active mode */
- mode = vncRandRCreatePreferredMode(crtc->outputs[0],
- pScreen->width, pScreen->height);
+ mode = vncRandRCreateMode(crtc->outputs[0],
+ pScreen->width, pScreen->height);
+ if (mode == NULL)
+ return FALSE;
+ mode = vncRandRSetPreferredMode(crtc->outputs[0], mode);
if (mode == NULL)
return FALSE;
@@ -1449,7 +1496,6 @@ static Bool vncRandRInit(ScreenPtr pScreen)
return TRUE;
}
-#endif
static Bool
#if XORG < 113
@@ -1506,9 +1552,7 @@ vfbScreenInit(ScreenPtr pScreen, int argc, char **argv)
int ret;
void *pbits;
-#ifdef RANDR
rrScrPrivPtr rp;
-#endif
#if XORG >= 113
if (!dixRegisterPrivateKey(&cmapScrPrivateKeyRec, PRIVATE_SCREEN, 0))
@@ -1644,7 +1688,6 @@ vfbScreenInit(ScreenPtr pScreen, int argc, char **argv)
pvfb->closeScreen = pScreen->CloseScreen;
pScreen->CloseScreen = vfbCloseScreen;
-#ifdef RANDR
ret = RRScreenInit(pScreen);
if (!ret) return FALSE;
@@ -1659,7 +1702,6 @@ vfbScreenInit(ScreenPtr pScreen, int argc, char **argv)
ret = vncRandRInit(pScreen);
if (!ret) return FALSE;
-#endif
return TRUE;