summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2011-09-23 16:51:48 +0200
committerHans de Goede <hdegoede@redhat.com>2011-09-23 16:51:48 +0200
commit3cf8fa7d31a3ebf1d051ba0e1bd3df9957bdb112 (patch)
treeefa7339be8eb0b4e8714a283bcff176cb113b505
parent3e7f2a287d21b57b167d3d49fa3d8640ffcf2d60 (diff)
Make mouse handling multiple monitor aware.
Actually send monitor info from the session agent to the system agent daemon, and use this information in vdagentd-uinput to properly generate events for events originating from different monitors on the client. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-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;
}