diff options
author | Hans de Goede <hans@localhost.localdomain> | 2013-04-10 17:41:14 +0200 |
---|---|---|
committer | Hans de Goede <hdegoede@redhat.com> | 2013-04-10 17:48:54 +0200 |
commit | a322d13b7ee7ced191d50e44ad8a79bdd6839779 (patch) | |
tree | 00ee7ca5c06621d1222c81cd6a3fd9416a568bb3 | |
parent | cc6f3d5a72d01a87a3630acb3f79e860ddf79901 (diff) |
vdagent-x11: Add support for setups with multiple screens
Some users have a need for old-fashioned setups with multiple X11 Screens
rather then one large virtual Screen as modern X usually has. This can be
accomplished by using multiple qxl devices + a xorg.conf file assigning
one Screen per qxl device.
Limitations:
-Max one monitor per Screen / qxl device
-All monitors / Screens must have the same resolution
-No client -> guest resolution syncing
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r-- | src/vdagent-x11-priv.h | 3 | ||||
-rw-r--r-- | src/vdagent-x11-randr.c | 44 | ||||
-rw-r--r-- | src/vdagent-x11.c | 35 |
3 files changed, 57 insertions, 25 deletions
diff --git a/src/vdagent-x11-priv.h b/src/vdagent-x11-priv.h index 71c26b9..c607850 100644 --- a/src/vdagent-x11-priv.h +++ b/src/vdagent-x11-priv.h @@ -89,6 +89,7 @@ struct vdagent_x11 { char *net_wm_name; int debug; int fd; + int screen_count; int width[MAX_SCREENS]; int height[MAX_SCREENS]; int has_xfixes; @@ -142,7 +143,7 @@ void vdagent_x11_randr_init(struct vdagent_x11 *x11); void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11, int update); void vdagent_x11_randr_handle_root_size_change(struct vdagent_x11 *x11, - int width, int height); + int screen, int width, int height); void vdagent_x11_set_error_handler(struct vdagent_x11 *x11, int (*handler)(Display *, XErrorEvent *)); diff --git a/src/vdagent-x11-randr.c b/src/vdagent-x11-randr.c index 1d609bd..5223f88 100644 --- a/src/vdagent-x11-randr.c +++ b/src/vdagent-x11-randr.c @@ -123,6 +123,12 @@ void vdagent_x11_randr_init(struct vdagent_x11 *x11) { int i; + if (x11->screen_count > 1) { + syslog(LOG_WARNING, "X-server has more then 1 screen, " + "disabling client -> guest resolution syncing"); + return; + } + if (XRRQueryExtension(x11->display, &i, &i)) { XRRQueryVersion(x11->display, &x11->xrandr_major, &x11->xrandr_minor); if (x11->xrandr_major == 1 && x11->xrandr_minor >= 3) @@ -455,18 +461,18 @@ static int set_screen_to_best_size(struct vdagent_x11 *x11, int width, int heigh } void vdagent_x11_randr_handle_root_size_change(struct vdagent_x11 *x11, - int width, int height) + int screen, int width, int height) { - if (width == x11->width[0] && height == x11->height[0]) { + if (width == x11->width[screen] && height == x11->height[screen]) { return; } if (x11->debug) - syslog(LOG_DEBUG, "Root size changed to %dx%d send %d", - width, height, !x11->dont_send_guest_xorg_res); + syslog(LOG_DEBUG, "Root size of screen %d changed to %dx%d send %d", + screen, width, height, !x11->dont_send_guest_xorg_res); - x11->width[0] = width; - x11->height[0] = height; + x11->width[screen] = width; + x11->height[screen] = height; if (!x11->dont_send_guest_xorg_res) { vdagent_x11_send_daemon_guest_xorg_res(x11, 1); } @@ -809,7 +815,7 @@ exit: void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11, int update) { struct vdagentd_guest_xorg_resolution *res = NULL; - int i, screen_count = 0; + int i, width = 0, height = 0, screen_count = 0; if (x11->has_xrandr) { VDAgentMonitorsConfig *curr; @@ -835,6 +841,8 @@ void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11, int update) res[i].y = curr->monitors[i].y; } free(curr); + width = x11->width[0]; + height = x11->height[0]; } else if (x11->has_xinerama) { XineramaScreenInfo *screen_info = NULL; @@ -860,16 +868,24 @@ void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11, int update) res[screen_info[i].screen_number].y = screen_info[i].y_org; } XFree(screen_info); + width = x11->width[0]; + height = x11->height[0]; } else { no_info: - screen_count = 1; + screen_count = x11->screen_count; res = malloc(screen_count * sizeof(*res)); if (!res) goto no_mem; - res[0].width = x11->width[0]; - res[0].height = x11->height[0]; - res[0].x = 0; - res[0].y = 0; + for (i = 0; i < screen_count; i++) { + res[i].width = x11->width[i]; + res[i].height = x11->height[i]; + /* No way to get screen coordinates, assume rtl order */ + res[i].x = width; + res[i].y = 0; + width += x11->width[i]; + if (x11->height[i] > height) + height = x11->height[i]; + } } if (x11->debug) { @@ -878,8 +894,8 @@ no_info: res[i].height, res[i].x, res[i].y); } - udscs_write(x11->vdagentd, VDAGENTD_GUEST_XORG_RESOLUTION, x11->width[0], - x11->height[0], (uint8_t *)res, screen_count * sizeof(*res)); + udscs_write(x11->vdagentd, VDAGENTD_GUEST_XORG_RESOLUTION, width, height, + (uint8_t *)res, screen_count * sizeof(*res)); free(res); return; no_mem: diff --git a/src/vdagent-x11.c b/src/vdagent-x11.c index 51f9315..6a58532 100644 --- a/src/vdagent-x11.c +++ b/src/vdagent-x11.c @@ -196,12 +196,22 @@ struct vdagent_x11 *vdagent_x11_create(struct udscs_connection *vdagentd, return NULL; } + x11->screen_count = ScreenCount(x11->display); + if (x11->screen_count > MAX_SCREENS) { + syslog(LOG_ERR, "Error too much screens: %d > %d", + x11->screen_count, MAX_SCREENS); + XCloseDisplay(x11->display); + free(x11); + return NULL; + } + if (sync) { XSetErrorHandler(vdagent_x11_debug_error_handler); XSynchronize(x11->display, True); } - x11->root_window[0] = RootWindow(x11->display, 0); + for (i = 0; i < x11->screen_count; i++) + x11->root_window[i] = RootWindow(x11->display, i); x11->fd = ConnectionNumber(x11->display); x11->clipboard_atom = XInternAtom(x11->display, "CLIPBOARD", False); x11->clipboard_primary_atom = XInternAtom(x11->display, "PRIMARY", False); @@ -253,13 +263,15 @@ struct vdagent_x11 *vdagent_x11_create(struct udscs_connection *vdagentd, if (x11->max_prop_size > 262144) x11->max_prop_size = 262144; - /* Catch resolution changes */ - XSelectInput(x11->display, x11->root_window[0], StructureNotifyMask); + for (i = 0; i < x11->screen_count; i++) { + /* Catch resolution changes */ + XSelectInput(x11->display, x11->root_window[i], StructureNotifyMask); - /* Get the current resolution */ - XGetWindowAttributes(x11->display, x11->root_window[0], &attrib); - x11->width[0] = attrib.width; - x11->height[0] = attrib.height; + /* Get the current resolution */ + XGetWindowAttributes(x11->display, x11->root_window[i], &attrib); + x11->width[i] = attrib.width; + x11->height[i] = attrib.height; + } vdagent_x11_send_daemon_guest_xorg_res(x11, 1); /* Get net_wm_name, since we are started at the same time as the wm, @@ -443,7 +455,7 @@ static int vdagent_x11_get_clipboard_selection(struct vdagent_x11 *x11, static void vdagent_x11_handle_event(struct vdagent_x11 *x11, XEvent event) { - int handled = 0; + int i, handled = 0; uint8_t selection; if (event.type == x11->xfixes_event_base) { @@ -493,11 +505,14 @@ static void vdagent_x11_handle_event(struct vdagent_x11 *x11, XEvent event) switch (event.type) { case ConfigureNotify: // TODO: handle CrtcConfigureNotify, OutputConfigureNotify can be ignored. - if (event.xconfigure.window != x11->root_window[0]) + for (i = 0; i < x11->screen_count; i++) + if (event.xconfigure.window == x11->root_window[i]) + break; + if (i == x11->screen_count) break; handled = 1; - vdagent_x11_randr_handle_root_size_change(x11, + vdagent_x11_randr_handle_root_size_change(x11, i, event.xconfigure.width, event.xconfigure.height); break; case MappingNotify: |