summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--src/vdagent-x11.c66
-rw-r--r--src/vdagentd-uinput.c28
-rw-r--r--src/vdagentd-uinput.h9
-rw-r--r--src/vdagentd.c28
5 files changed, 118 insertions, 15 deletions
diff --git a/configure.ac b/configure.ac
index c23d7f2..6c9c156 100644
--- a/configure.ac
+++ b/configure.ac
@@ -19,7 +19,7 @@ AC_ARG_ENABLE([console-kit],
[enable_console_kit="yes"])
PKG_PROG_PKG_CONFIG
-PKG_CHECK_MODULES(X, [xfixes xrandr x11])
+PKG_CHECK_MODULES(X, [xfixes xrandr xinerama x11])
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] )
diff --git a/src/vdagent-x11.c b/src/vdagent-x11.c
index b01b5ab..c9e99ee 100644
--- a/src/vdagent-x11.c
+++ b/src/vdagent-x11.c
@@ -38,6 +38,7 @@
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>
+#include <X11/extensions/Xinerama.h>
#include <X11/extensions/Xfixes.h>
#include "vdagentd-proto.h"
#include "vdagent-x11.h"
@@ -118,6 +119,7 @@ struct vdagent_x11 {
int width;
int height;
int has_xrandr;
+ int has_xinerama;
int has_xfixes;
int xfixes_event_base;
int max_prop_size;
@@ -218,8 +220,25 @@ struct vdagent_x11 *vdagent_x11_create(struct udscs_connection *vdagentd,
if (XRRQueryExtension(x11->display, &i, &i))
x11->has_xrandr = 1;
- else
- fprintf(x11->errfile, "no xrandr\n");
+
+ if (XineramaQueryExtension(x11->display, &i, &i))
+ x11->has_xinerama = 1;
+
+ switch (x11->has_xrandr << 4 | x11->has_xinerama) {
+ case 0x00:
+ fprintf(x11->errfile, "Neither Xrandr nor Xinerama found, assuming single monitor setup\n");
+ break;
+ case 0x01:
+ if (x11->verbose)
+ fprintf(x11->errfile, "Found Xinerama extension without Xrandr, assuming a multi monitor setup\n");
+ break;
+ case 0x10:
+ fprintf(x11->errfile, "Found Xrandr but no Xinerama, weird! Assuming a single monitor setup\n");
+ break;
+ case 0x11:
+ /* Standard single monitor setup, nothing to see here */
+ break;
+ }
if (XFixesQueryExtension(x11->display, &x11->xfixes_event_base, &i) &&
XFixesQueryVersion(x11->display, &major, &minor) && major >= 1) {
@@ -564,8 +583,49 @@ void vdagent_x11_do_read(struct vdagent_x11 *x11)
static void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11)
{
+ struct vdagentd_guest_xorg_resolution *res = NULL;
+ XineramaScreenInfo *screen_info = NULL;
+ int i, screen_count = 0;
+
+ if (x11->has_xinerama)
+ screen_info = XineramaQueryScreens(x11->display, &screen_count);
+
+ if (screen_count == 0)
+ screen_count = 1;
+
+ res = malloc(screen_count * sizeof(*res));
+ if (!res) {
+ fprintf(x11->errfile, "out of memory while trying to send resolutions, not sending resolutions.\n");
+ if (screen_info)
+ XFree(screen_info);
+ return;
+ }
+
+ if (screen_info) {
+ for (i = 0; i < screen_count; i++) {
+ if (screen_info[i].screen_number >= screen_count) {
+ fprintf(x11->errfile, "Invalid screen number in xinerama screen info (%d >= %d)\n",
+ screen_info[i].screen_number, screen_count);
+ XFree(screen_info);
+ free(res);
+ return;
+ }
+ res[screen_info[i].screen_number].width = screen_info[i].width;
+ res[screen_info[i].screen_number].height = screen_info[i].height;
+ res[screen_info[i].screen_number].x = screen_info[i].x_org;
+ res[screen_info[i].screen_number].y = screen_info[i].y_org;
+ }
+ XFree(screen_info);
+ } else {
+ res[0].width = x11->width;
+ res[0].height = x11->height;
+ res[0].x = 0;
+ res[0].y = 0;
+ }
+
udscs_write(x11->vdagentd, VDAGENTD_GUEST_XORG_RESOLUTION, x11->width,
- x11->height, NULL, 0);
+ x11->height, (uint8_t *)res, screen_count * sizeof(*res));
+ free(res);
}
static const char *vdagent_x11_get_atom_name(struct vdagent_x11 *x11, Atom a)
diff --git a/src/vdagentd-uinput.c b/src/vdagentd-uinput.c
index 54cccb0..d50dfe7 100644
--- a/src/vdagentd-uinput.c
+++ b/src/vdagentd-uinput.c
@@ -33,15 +33,19 @@
struct vdagentd_uinput {
const char *devname;
int fd;
+ int verbose;
int width;
int height;
- int verbose;
+ struct vdagentd_guest_xorg_resolution *screen_info;
+ int screen_count;
FILE *errfile;
VDAgentMouseState last;
};
struct vdagentd_uinput *vdagentd_uinput_create(const char *devname,
- int width, int height, FILE *errfile, int verbose)
+ int width, int height,
+ struct vdagentd_guest_xorg_resolution *screen_info, int screen_count,
+ FILE *errfile, int verbose)
{
struct vdagentd_uinput *uinput;
@@ -54,7 +58,8 @@ struct vdagentd_uinput *vdagentd_uinput_create(const char *devname,
uinput->verbose = verbose;
uinput->errfile = errfile;
- vdagentd_uinput_update_size(&uinput, width, height);
+ vdagentd_uinput_update_size(&uinput, width, height,
+ screen_info, screen_count);
return uinput;
}
@@ -73,7 +78,9 @@ void vdagentd_uinput_destroy(struct vdagentd_uinput **uinputp)
}
void vdagentd_uinput_update_size(struct vdagentd_uinput **uinputp,
- int width, int height)
+ int width, int height,
+ struct vdagentd_guest_xorg_resolution *screen_info,
+ int screen_count)
{
struct vdagentd_uinput *uinput = *uinputp;
struct uinput_user_dev device = {
@@ -83,6 +90,9 @@ void vdagentd_uinput_update_size(struct vdagentd_uinput **uinputp,
};
int rc;
+ uinput->screen_info = screen_info;
+ uinput->screen_count = screen_count;
+
if (uinput->width == width && uinput->height == height)
return;
@@ -170,6 +180,16 @@ void vdagentd_uinput_do_mouse(struct vdagentd_uinput **uinputp,
};
int i, down;
+ if (*uinputp) {
+ if (mouse->display_id >= uinput->screen_count) {
+ fprintf(uinput->errfile, "mouse event for unknown monitor (%d >= %d)\n",
+ mouse->display_id, uinput->screen_count);
+ return;
+ }
+ mouse->x += uinput->screen_info[mouse->display_id].x;
+ mouse->y += uinput->screen_info[mouse->display_id].y;
+ }
+
if (*uinputp && uinput->last.x != mouse->x) {
if (uinput->verbose)
fprintf(uinput->errfile, "mouse: abs-x %d\n", mouse->x);
diff --git a/src/vdagentd-uinput.h b/src/vdagentd-uinput.h
index 132986b..27cd375 100644
--- a/src/vdagentd-uinput.h
+++ b/src/vdagentd-uinput.h
@@ -23,16 +23,21 @@
#define __VDAGENTD_UINPUT_H
#include <stdio.h>
+#include "vdagentd-proto.h"
struct vdagentd_uinput;
struct vdagentd_uinput *vdagentd_uinput_create(const char *devname,
- int width, int height, FILE *errfile, int verbose);
+ int width, int height,
+ struct vdagentd_guest_xorg_resolution *screen_info, int screen_count,
+ FILE *errfile, int verbose);
void vdagentd_uinput_destroy(struct vdagentd_uinput **uinputp);
void vdagentd_uinput_do_mouse(struct vdagentd_uinput **uinputp,
VDAgentMouseState *mouse);
void vdagentd_uinput_update_size(struct vdagentd_uinput **uinputp,
- int width, int height);
+ int width, int height,
+ struct vdagentd_guest_xorg_resolution *screen_info,
+ int screen_count);
#endif
diff --git a/src/vdagentd.c b/src/vdagentd.c
index 18d7950..cee779b 100644
--- a/src/vdagentd.c
+++ b/src/vdagentd.c
@@ -45,6 +45,8 @@ struct agent_data {
char *session;
int width;
int height;
+ struct vdagentd_guest_xorg_resolution *screen_info;
+ int screen_count;
};
/* variables */
@@ -238,6 +240,8 @@ int virtio_port_read_complete(
uinput = vdagentd_uinput_create(uinput_device,
agent_data->width,
agent_data->height,
+ agent_data->screen_info,
+ agent_data->screen_count,
logfile, debug > 1);
if (!uinput) {
fprintf(logfile, "Fatal uinput error\n");
@@ -394,15 +398,20 @@ static void check_xorg_resolution(void)
{
struct agent_data *agent_data = udscs_get_user_data(active_session_conn);
- if (agent_data && agent_data->width) {
+ if (agent_data && agent_data->screen_info) {
if (!uinput)
uinput = vdagentd_uinput_create(uinput_device,
agent_data->width,
agent_data->height,
+ agent_data->screen_info,
+ agent_data->screen_count,
logfile, debug > 1);
else
- vdagentd_uinput_update_size(&uinput, agent_data->width,
- agent_data->height);
+ vdagentd_uinput_update_size(&uinput,
+ agent_data->width,
+ agent_data->height,
+ agent_data->screen_info,
+ agent_data->screen_count);
if (!uinput) {
fprintf(logfile, "Fatal uinput error\n");
retval = 1;
@@ -552,8 +561,7 @@ void agent_read_complete(struct udscs_connection **connp,
switch (header->type) {
case VDAGENTD_GUEST_XORG_RESOLUTION: {
- struct vdagentd_guest_xorg_resolution *res =
- (struct vdagentd_guest_xorg_resolution *)data;
+ struct vdagentd_guest_xorg_resolution *res;
int n = header->size / sizeof(*res);
/* Detect older version session agent, but don't disconnect, as
@@ -573,8 +581,18 @@ void agent_read_complete(struct udscs_connection **connp,
return;
}
+ free(agent_data->screen_info);
+ res = malloc(n * sizeof(*res));
+ if (!res) {
+ fprintf(logfile, "out of memory allocating screen info\n");
+ n = 0;
+ }
+ memcpy(res, data, n * sizeof(*res));
agent_data->width = header->arg1;
agent_data->height = header->arg2;
+ agent_data->screen_info = res;
+ agent_data->screen_count = n;
+
check_xorg_resolution();
break;
}