Commit 5ad18905 authored by Jonathon Jongsma's avatar Jonathon Jongsma

Send display_id down to the vdagentd daemon

Add a display_id field to the structure that we use to send down the
list of guest display resolutions to the vdagentd daemon. This allows us
to map the spice display id to the proper X display for determining
mouse locations, etc.

In the case where we have an mjpeg plugin running in the streaming
agent, we have two spice displays representing the same guest display.
In that scenario, the session agent may maintain the following guest
output mapping:
 spice channel 0 (QXL) => X output 0
 spice channel 1 (streaming-agent) => X output 0

While this is not necessarily a supported scenario, it would be nice if
the cursor input worked properly in this case. The root problem is that
when the session agent sends down the guest xorg resolutions to the
system daemon, it simply loops through the list of xorg displays, and
for each X display it looks up the first spice display ID associated
with it and sends that down to the daemon. In the scenario mentioned
above, since there is only a single X display configured (albeit
represented by two different spice displays), we would send down a
single display resolution to the system daemon:
 - { width=1280, height=1024, x=0, y=0, display_id=0 }

Notice that there is no entry for display_id=1. When the agent receives
a cursor input message for display channel 1, that message will get
passed to the systemn daemon, which will attempt to look up display_id 1
in order to convert the event coordinates to global coordinates. Finding
no entry for display_id=1, the mouse events do not work.

In this patch, when we want to send the guest resolutions down to the
system daemon, we still loop through the list of X outputs, but for each
output we also loop through the guest output mapping table and send a
resolution structure down to the daemon for each registered output
mapping.  This means that in the previously mentioned scenario, we would
send down the following information:
 - { width=1280, height=1024, x=0, y=0, display_id=0 }
 - { width=1280, height=1024, x=0, y=0, display_id=1 }

 This means that when the client sends a mouse event for display_id=1,
 the system daemon knows the coordinates of the guest display associated
 with that ID and can process the mouse event properly.
Acked-by: Lukáš Hrázký's avatarLukáš Hrázký <>
Signed-off-by: default avatarJonathon Jongsma <>
parent 5374fcc5
......@@ -689,7 +689,6 @@ static int config_size(int num_of_monitors)
num_of_monitors * sizeof(VDAgentMonConfig);
// gets monitor information about the specified output index and returns true if there was no error
static bool get_monitor_info_for_output_index(struct vdagent_x11 *x11, int output_index,
int *x, int *y, int *width, int *height)
......@@ -840,6 +839,9 @@ void vdagent_x11_handle_graphics_device_info(struct vdagent_x11 *x11, uint8_t *d
device_display_info = (VDAgentDeviceDisplayInfo*) ((char*) device_display_info +
sizeof(VDAgentDeviceDisplayInfo) + device_display_info->device_address_len);
// make sure daemon is up-to-date with (possibly updated) device IDs
vdagent_x11_send_daemon_guest_xorg_res(x11, 1);
static int get_output_index_for_display_id(struct vdagent_x11 *x11, int display_id)
......@@ -1067,7 +1069,7 @@ exit:
void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11, int update)
struct vdagentd_guest_xorg_resolution *res = NULL;
GArray *res_array = g_array_new(FALSE, FALSE, sizeof(struct vdagentd_guest_xorg_resolution));
int i, width = 0, height = 0, screen_count = 0;
if (x11->has_xrandr) {
......@@ -1075,15 +1077,38 @@ void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11, int update)
update_randr_res(x11, 0);
screen_count = x11->randr.res->noutput;
res = g_new(struct vdagentd_guest_xorg_resolution, screen_count);
for (i = 0; i < screen_count; i++) {
struct vdagentd_guest_xorg_resolution *curr = &res[i];
if (!get_monitor_info_for_output_index(x11, i, &curr->x, &curr->y,
&curr->width, &curr->height)) {
struct vdagentd_guest_xorg_resolution curr;
if (!get_monitor_info_for_output_index(x11, i, &curr.x, &curr.y,
&curr.width, &curr.height)) {
g_array_free(res_array, TRUE);
goto no_info;
if (g_hash_table_size(x11->guest_output_map) == 0) {
syslog(LOG_DEBUG, "No guest output map, using output index as display id");
curr.display_id = i;
g_array_append_val(res_array, curr);
} else {
// There may be multiple spice outputs representing a single guest output. Send them
// all down.
RROutput output_id = x11->randr.res->outputs[i];
GHashTableIter iter;
gpointer key, value;
g_hash_table_iter_init(&iter, x11->guest_output_map);
bool found = false;
while (g_hash_table_iter_next(&iter, &key, &value)) {
gint64 *other_id = value;
if (*other_id == output_id) {
curr.display_id = GPOINTER_TO_INT(key);
g_array_append_val(res_array, curr);
found = true;
if (!found) {
syslog(LOG_WARNING, "Unable to find a display id for output index %d)", i);
width = x11->width[0];
height = x11->height[0];
......@@ -1093,54 +1118,61 @@ void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11, int update)
screen_info = XineramaQueryScreens(x11->display, &screen_count);
if (!screen_info)
goto no_info;
res = g_new(struct vdagentd_guest_xorg_resolution, screen_count);
g_array_set_size(res_array, screen_count);
for (i = 0; i < screen_count; i++) {
if (screen_info[i].screen_number >= screen_count) {
syslog(LOG_ERR, "Invalid screen number in xinerama screen info (%d >= %d)",
screen_info[i].screen_number, screen_count);
g_array_free(res_array, true);
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;
struct vdagentd_guest_xorg_resolution *curr = &g_array_index(res_array,
struct vdagentd_guest_xorg_resolution,
curr->width = screen_info[i].width;
curr->height = screen_info[i].height;
curr->x = screen_info[i].x_org;
curr->y = screen_info[i].y_org;
width = x11->width[0];
height = x11->height[0];
} else {
screen_count = x11->screen_count;
res = g_new(struct vdagentd_guest_xorg_resolution, screen_count);
for (i = 0; i < screen_count; i++) {
res[i].width = x11->width[i];
res[i].height = x11->height[i];
struct vdagentd_guest_xorg_resolution res;
res.width = x11->width[i];
res.height = x11->height[i];
/* No way to get screen coordinates, assume rtl order */
res[i].x = width;
res[i].y = 0;
res.x = width;
res.y = 0;
width += x11->width[i];
if (x11->height[i] > height)
height = x11->height[i];
g_array_append_val(res_array, res);
if (screen_count == 0) {
syslog(LOG_DEBUG, "Screen count is zero, are we on wayland?");
g_array_free(res_array, TRUE);
if (x11->debug) {
syslog(LOG_DEBUG, "Sending guest screen resolutions to vdagentd:");
for (i = 0; i < screen_count; i++) {
syslog(LOG_DEBUG, " screen %d %dx%d%+d%+d", i,
res[i].width, res[i].height, res[i].x, res[i].y);
if (res_array->len > screen_count) {
syslog(LOG_DEBUG, "(NOTE: list may contain overlapping areas when multiple spice displays show the same guest output)");
for (i = 0; i < res_array->len; i++) {
struct vdagentd_guest_xorg_resolution *res = (struct vdagentd_guest_xorg_resolution*)res_array->data;
syslog(LOG_DEBUG, " screen %d %dx%d%+d%+d, display_id=%d", i,
res[i].width, res[i].height, res[i].x, res[i].y, res[i].display_id);
udscs_write(x11->vdagentd, VDAGENTD_GUEST_XORG_RESOLUTION, width, height,
(uint8_t *)res, screen_count * sizeof(*res));
(uint8_t *)res_array->data, res_array->len * sizeof(struct vdagentd_guest_xorg_resolution));
g_array_free(res_array, TRUE);
......@@ -53,6 +53,7 @@ struct vdagentd_guest_xorg_resolution {
int height;
int x;
int y;
int display_id;
......@@ -175,6 +175,18 @@ static void uinput_send_event(struct vdagentd_uinput **uinputp,
static struct vdagentd_guest_xorg_resolution* lookup_screen_info(struct vdagentd_uinput *uinput, int display_id)
int i;
for (i = 0; i < uinput->screen_count; i++) {
if (uinput->screen_info[i].display_id == display_id) {
return &uinput->screen_info[i];
syslog(LOG_WARNING, "Unable to find output index for display id %d", display_id);
return NULL;
void vdagentd_uinput_do_mouse(struct vdagentd_uinput **uinputp,
VDAgentMouseState *mouse)
......@@ -196,16 +208,17 @@ void vdagentd_uinput_do_mouse(struct vdagentd_uinput **uinputp,
int i, down;
if (*uinputp) {
if (mouse->display_id >= uinput->screen_count) {
syslog(LOG_WARNING, "mouse event for unknown monitor (%d >= %d)",
mouse->display_id, uinput->screen_count);
struct vdagentd_guest_xorg_resolution *screen_info = lookup_screen_info(uinput, mouse->display_id);
if (screen_info == NULL) {
syslog(LOG_WARNING, "mouse event for unknown monitor %d",
if (uinput->debug)
syslog(LOG_DEBUG, "mouse-event: mon %d %dx%d", mouse->display_id,
mouse->x, mouse->y);
mouse->x += uinput->screen_info[mouse->display_id].x;
mouse->y += uinput->screen_info[mouse->display_id].y;
mouse->x += screen_info->x;
mouse->y += screen_info->y;
mouse->x = mouse->x * 32767 / (uinput->width - 1);
mouse->y = mouse->y * 32767 / (uinput->height - 1);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment