summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2011-09-26 13:01:56 +0200
committerHans de Goede <hdegoede@redhat.com>2011-09-26 14:24:00 +0200
commit571948ffb78eddd3015c456d084e0ca941f3e45d (patch)
tree2816ac6dea9ee2c7a58323bb6851fc1a0e574deb
parent3cf8fa7d31a3ebf1d051ba0e1bd3df9957bdb112 (diff)
vdagentd: Autogenerate a Xinerama xorg.conf for multi monitor setups
The autogenerated file will get written as /etc/X11/xorg.conf.spice Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r--Makefile.am6
-rw-r--r--configure.ac12
-rw-r--r--src/vdagentd-xorg-conf.c171
-rw-r--r--src/vdagentd.c12
4 files changed, 198 insertions, 3 deletions
diff --git a/Makefile.am b/Makefile.am
index c3881ef..1102c02 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -7,10 +7,11 @@ src_spice_vdagent_CFLAGS = $(X_CFLAGS) $(SPICE_CFLAGS)
src_spice_vdagent_LDADD = $(X_LIBS) $(SPICE_LIBS)
src_spice_vdagent_SOURCES = src/vdagent.c src/vdagent-x11.c src/udscs.c
-src_spice_vdagentd_CFLAGS = $(DBUS_CFLAGS) $(SPICE_CFLAGS)
-src_spice_vdagentd_LDADD = $(DBUS_LIBS) $(SPICE_LIBS)
+src_spice_vdagentd_CFLAGS = $(DBUS_CFLAGS) $(PCIACCESS_CFLAGS) $(SPICE_CFLAGS)
+src_spice_vdagentd_LDADD = $(DBUS_LIBS) $(PCIACCESS_LIBS) $(SPICE_LIBS)
src_spice_vdagentd_SOURCES = src/vdagentd.c \
src/vdagentd-uinput.c \
+ src/vdagentd-xorg-conf.c \
src/vdagent-virtio-port.c \
src/udscs.c
if HAVE_CONSOLE_KIT
@@ -22,6 +23,7 @@ noinst_HEADERS = src/console-kit.h \
src/vdagent-x11.h \
src/udscs.h \
src/vdagentd-uinput.h \
+ src/vdagentd-xorg-conf.h \
src/vdagentd-proto.h \
src/vdagent-virtio-port.h
diff --git a/configure.ac b/configure.ac
index 6c9c156..c4659f8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -18,14 +18,24 @@ AC_ARG_ENABLE([console-kit],
[enable_console_kit="$enableval"],
[enable_console_kit="yes"])
+AC_ARG_ENABLE([pciaccess],
+ [AS_HELP_STRING([--enable-pciaccess], [Enable libpciaccess use for auto generation of Xinerama xorg.conf (default: yes)])],
+ [enable_pciaccess="$enableval"],
+ [enable_pciaccess="yes"])
+
PKG_PROG_PKG_CONFIG
PKG_CHECK_MODULES(X, [xfixes xrandr xinerama x11])
+PKG_CHECK_MODULES(SPICE, [spice-protocol >= 0.8.0])
if test x"$enable_console_kit" = "xyes" ; then
PKG_CHECK_MODULES(DBUS, [dbus-1])
AC_DEFINE([HAVE_CONSOLE_KIT], [1], [If defined, vdagentd will be compiled with ConsoleKit support] )
fi
AM_CONDITIONAL(HAVE_CONSOLE_KIT, test x"$enable_console_kit" = "xyes")
-PKG_CHECK_MODULES(SPICE, [spice-protocol >= 0.8.0])
+if test x"$enable_pciaccess" = "xyes" ; then
+ PKG_CHECK_MODULES(PCIACCESS, [pciaccess >= 0.10])
+ AC_DEFINE([HAVE_PCIACCESS], [1], [If defined, vdagentd will be compiled with pciaccess support] )
+fi
+AM_CONDITIONAL(HAVE_PCIACCESS, test x"$enable_pciaccess" = "xyes")
AC_CONFIG_FILES([
Makefile
diff --git a/src/vdagentd-xorg-conf.c b/src/vdagentd-xorg-conf.c
new file mode 100644
index 0000000..5610837
--- /dev/null
+++ b/src/vdagentd-xorg-conf.c
@@ -0,0 +1,171 @@
+/* vdagentd.c vdagentd xorg.conf writing code
+
+ Copyright 2011 Red Hat, Inc.
+
+ Red Hat Authors:
+ Hans de Goede <hdegoede@redhat.com>
+
+ This program 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 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_PCIACCESS
+#include <pciaccess.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "vdagentd-xorg-conf.h"
+
+#define FPRINTF(...) \
+ do { \
+ r = fprintf(f, __VA_ARGS__); \
+ if (r < 0) { \
+ fprintf(logfile, "Error writing to %s: %s\n", \
+ xorg_conf, strerror(errno)); \
+ fclose(f); \
+ pci_system_cleanup(); \
+ return; \
+ } \
+ } while(0)
+
+void vdagentd_write_xorg_conf(VDAgentMonitorsConfig *monitor_conf,
+ FILE *logfile)
+{
+#ifdef HAVE_PCIACCESS
+ int i, r, count, min_x = INT_MAX, min_y = INT_MAX;
+ FILE *f;
+ struct pci_device_iterator *it;
+ struct pci_device *dev;
+ const struct pci_id_match qxl_id_match = {
+ .vendor_id = 0x1b36,
+ .device_id = 0x0100,
+ .subvendor_id = PCI_MATCH_ANY,
+ .subdevice_id = PCI_MATCH_ANY,
+ };
+ const char *xorg_conf = "/var/run/spice-vdagentd/xorg.conf.spice";
+ const char *xorg_conf_old = "/var/run/spice-vdagentd/xorg.conf.spice.old";
+
+ r = rename(xorg_conf, xorg_conf_old);
+ if (r && errno != ENOENT) {
+ fprintf(logfile,
+ "Error renaming %s to %s: %s, not generating xorg.conf\n",
+ xorg_conf, xorg_conf_old, strerror(errno));
+ return;
+ }
+
+ r = pci_system_init();
+ if (r) {
+ fprintf(logfile, "Error initializing libpciaccess: %d, not generating xorg.conf\n", r);
+ return;
+ }
+
+ it = pci_id_match_iterator_create(&qxl_id_match);
+ if (!it) {
+ fprintf(logfile, "Error could not create pci id iterator for QXL devices, not generating xorg.conf\n");
+ pci_system_cleanup();
+ return;
+ }
+
+ dev = pci_device_next(it);
+ if (!dev) {
+ fprintf(logfile, "No QXL devices found, not generating xorg.conf\n");
+ pci_system_cleanup();
+ return;
+ }
+
+ f = fopen(xorg_conf, "w");
+ if (!f) {
+ fprintf(logfile, "Error opening %s for writing: %s\n",
+ xorg_conf, strerror(errno));
+ pci_system_cleanup();
+ return;
+ }
+
+ FPRINTF("# xorg.conf generated by spice-vdagentd\n");
+ FPRINTF("# generated from monitor info provided by the client\n\n");
+
+ if (monitor_conf->num_of_monitors == 1) {
+ FPRINTF("# Client has only 1 monitor\n");
+ FPRINTF("# This works best with no xorg.conf, leaving xorg.conf empty\n");
+ fclose(f);
+ pci_system_cleanup();
+ return;
+ }
+
+ FPRINTF("Section \"ServerFlags\"\n");
+ FPRINTF("\tOption\t\t\"Xinerama\"\t\"true\"\n");
+ FPRINTF("EndSection\n\n");
+
+ i = 0;
+ do {
+ FPRINTF("Section \"Device\"\n");
+ FPRINTF("\tIdentifier\t\"qxl%d\"\n", i++);
+ FPRINTF("\tDriver\t\t\"qxl\"\n");
+ FPRINTF("\tBusID\t\t\"PCI:%02d:%02d:%d\"\n",
+ dev->bus, dev->dev, dev->func);
+ FPRINTF("EndSection\n\n");
+ } while ((dev = pci_device_next(it)));
+
+ if (i < monitor_conf->num_of_monitors) {
+ fprintf(logfile, "Client has %d monitors, but only %d qxl devices found\n",
+ monitor_conf->num_of_monitors, i);
+ FPRINTF("# Client has %d monitors, but only %d qxl devices found\n",
+ monitor_conf->num_of_monitors, i);
+ FPRINTF("# Only generation %d \"Screen\" sections\n\n", i);
+ count = i;
+ } else {
+ count = monitor_conf->num_of_monitors;
+ }
+
+ for (i = 0; i < count; i++) {
+ FPRINTF("Section \"Screen\"\n");
+ FPRINTF("\tIdentifier\t\"Screen%d\"\n", i);
+ FPRINTF("\tDevice\t\t\"qxl%d\"\n", i);
+ FPRINTF("\tDefaultDepth\t24\n");
+ FPRINTF("\tSubSection \"Display\"\n");
+ FPRINTF("\t\tViewport\t0 0\n");
+ FPRINTF("\t\tDepth\t\t24\n");
+ FPRINTF("\t\tModes\t\t\"%dx%d\"\n", monitor_conf->monitors[i].width,
+ monitor_conf->monitors[i].height);
+ FPRINTF("\tEndSubSection\n");
+ FPRINTF("EndSection\n\n");
+ }
+
+ /* monitor_conf may contain negative values, convert these to 0 - # */
+ for (i = 0; i < count; i++) {
+ if (monitor_conf->monitors[i].x < min_x) {
+ min_x = monitor_conf->monitors[i].x;
+ }
+ if (monitor_conf->monitors[i].y < min_y) {
+ min_y = monitor_conf->monitors[i].y;
+ }
+ }
+
+ FPRINTF("Section \"ServerLayout\"\n");
+ FPRINTF("\tIdentifier\t\"layout\"\n");
+ for (i = 0; i < count; i++) {
+ FPRINTF("\tScreen\t\t\"Screen%d\" %d %d\n", i,
+ monitor_conf->monitors[i].x - min_x,
+ monitor_conf->monitors[i].y - min_y);
+ }
+ FPRINTF("EndSection\n");
+
+ fclose(f);
+ pci_system_cleanup();
+#endif
+}
diff --git a/src/vdagentd.c b/src/vdagentd.c
index cee779b..939d36a 100644
--- a/src/vdagentd.c
+++ b/src/vdagentd.c
@@ -38,6 +38,7 @@
#include "vdagentd-proto.h"
#include "vdagentd-proto-strings.h"
#include "vdagentd-uinput.h"
+#include "vdagentd-xorg-conf.h"
#include "vdagent-virtio-port.h"
#include "console-kit.h"
@@ -118,6 +119,16 @@ static void do_client_monitors(struct vdagent_virtio_port *vport, int port_nr,
return;
}
+ vdagentd_write_xorg_conf(new_monitors, logfile);
+
+ if (new_monitors->num_of_monitors != 1) {
+ /* No use in sending this to the session agent it cannot handle it
+ anyways */
+ free(mon_config);
+ mon_config = NULL;
+ goto ack;
+ }
+
if (!mon_config ||
mon_config->num_of_monitors != new_monitors->num_of_monitors) {
free(mon_config);
@@ -133,6 +144,7 @@ static void do_client_monitors(struct vdagent_virtio_port *vport, int port_nr,
udscs_server_write_all(server, VDAGENTD_MONITORS_CONFIG, 0, 0,
(uint8_t *)mon_config, size);
+ack:
/* Acknowledge reception of monitors config to spice server / client */
reply.type = VD_AGENT_MONITORS_CONFIG;
reply.error = VD_AGENT_SUCCESS;