From 3cf8fa7d31a3ebf1d051ba0e1bd3df9957bdb112 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 23 Sep 2011 16:51:48 +0200 Subject: 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 --- configure.ac | 2 +- src/vdagent-x11.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++--- src/vdagentd-uinput.c | 28 ++++++++++++++++++---- src/vdagentd-uinput.h | 9 +++++-- src/vdagentd.c | 28 ++++++++++++++++++---- 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 #include #include +#include #include #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 +#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; } -- cgit v1.2.3