]> source.dussan.org Git - tigervnc.git/commitdiff
Move computeScreenLayout/setScreenLayout to unixcommon lib
authorPeter Åstrand (astrand) <astrand@cendio.se>
Wed, 7 Mar 2018 08:29:00 +0000 (09:29 +0100)
committerPeter Åstrand (astrand) <astrand@cendio.se>
Mon, 9 Apr 2018 08:26:21 +0000 (10:26 +0200)
These two code blocks are not specific to Xvnc/vnc.so, but useful for
x0vncserver as well. RandrGlue.h defines the interface on which
unixcommon depends on.

14 files changed:
unix/CMakeLists.txt
unix/common/CMakeLists.txt [new file with mode: 0644]
unix/common/RandrGlue.h [new file with mode: 0644]
unix/common/randr.cxx [new file with mode: 0644]
unix/common/unixcommon.h [new file with mode: 0644]
unix/xserver/hw/vnc/Makefile.am
unix/xserver/hw/vnc/RandrGlue.c [new file with mode: 0644]
unix/xserver/hw/vnc/XorgGlue.c
unix/xserver/hw/vnc/XorgGlue.h
unix/xserver/hw/vnc/XserverDesktop.cc
unix/xserver/hw/vnc/XserverDesktop.h
unix/xserver/hw/vnc/vncExtInit.cc
unix/xserver/hw/vnc/vncModule.c
unix/xserver/hw/vnc/xvnc.c

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