1 /* vdagent-x11-randr.c vdagent Xrandr integration code
3 Copyright 2012 Red Hat, Inc.
6 Alon Levy <alevy@redhat.com>
7 Hans de Goede <hdegoede@redhat.com>
8 Marc-André Lureau <mlureau@redhat.com>
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
29 #include <X11/extensions/Xinerama.h>
31 #include "vdagentd-proto.h"
32 #include "vdagent-x11.h"
33 #include "vdagent-x11-priv.h"
35 static int error_handler(Display *display, XErrorEvent *error)
37 vdagent_x11_caught_error = 1;
41 static XRRModeInfo *mode_from_id(struct vdagent_x11 *x11, int id)
45 for (i = 0 ; i < x11->randr.res->nmode ; ++i) {
46 if (id == x11->randr.res->modes[i].id) {
47 return &x11->randr.res->modes[i];
53 static XRRCrtcInfo *crtc_from_id(struct vdagent_x11 *x11, int id)
57 for (i = 0 ; i < x11->randr.res->ncrtc ; ++i) {
58 if (id == x11->randr.res->crtcs[i]) {
59 return x11->randr.crtcs[i];
65 static void free_randr_resources(struct vdagent_x11 *x11)
69 if (!x11->randr.res) {
72 if (x11->randr.outputs != NULL) {
73 for (i = 0 ; i < x11->randr.res->noutput; ++i) {
74 XRRFreeOutputInfo(x11->randr.outputs[i]);
76 free(x11->randr.outputs);
78 if (x11->randr.crtcs != NULL) {
79 for (i = 0 ; i < x11->randr.res->ncrtc; ++i) {
80 XRRFreeCrtcInfo(x11->randr.crtcs[i]);
82 free(x11->randr.crtcs);
84 XRRFreeScreenResources(x11->randr.res);
85 x11->randr.res = NULL;
86 x11->randr.outputs = NULL;
87 x11->randr.crtcs = NULL;
88 x11->randr.num_monitors = 0;
91 static void update_randr_res(struct vdagent_x11 *x11, int poll)
95 free_randr_resources(x11);
97 x11->randr.res = XRRGetScreenResources(x11->display, x11->root_window[0]);
99 x11->randr.res = XRRGetScreenResourcesCurrent(x11->display, x11->root_window[0]);
100 x11->randr.outputs = malloc(x11->randr.res->noutput * sizeof(*x11->randr.outputs));
101 x11->randr.crtcs = malloc(x11->randr.res->ncrtc * sizeof(*x11->randr.crtcs));
102 for (i = 0 ; i < x11->randr.res->noutput; ++i) {
103 x11->randr.outputs[i] = XRRGetOutputInfo(x11->display, x11->randr.res,
104 x11->randr.res->outputs[i]);
105 if (x11->randr.outputs[i]->connection == RR_Connected)
106 x11->randr.num_monitors++;
108 for (i = 0 ; i < x11->randr.res->ncrtc; ++i) {
109 x11->randr.crtcs[i] = XRRGetCrtcInfo(x11->display, x11->randr.res,
110 x11->randr.res->crtcs[i]);
112 /* XXX is this dynamic? should it be cached? */
113 if (XRRGetScreenSizeRange(x11->display, x11->root_window[0],
114 &x11->randr.min_width,
115 &x11->randr.min_height,
116 &x11->randr.max_width,
117 &x11->randr.max_height) != 1) {
118 syslog(LOG_ERR, "update_randr_res: RRGetScreenSizeRange failed");
122 void vdagent_x11_randr_init(struct vdagent_x11 *x11)
126 if (x11->screen_count > 1) {
127 syslog(LOG_WARNING, "X-server has more then 1 screen, "
128 "disabling client -> guest resolution syncing");
132 if (XRRQueryExtension(x11->display, &i, &i)) {
133 XRRQueryVersion(x11->display, &x11->xrandr_major, &x11->xrandr_minor);
134 if (x11->xrandr_major == 1 && x11->xrandr_minor >= 3)
138 if (x11->has_xrandr) {
139 update_randr_res(x11, 0);
141 x11->randr.res = NULL;
144 if (XineramaQueryExtension(x11->display, &i, &i))
145 x11->has_xinerama = 1;
147 switch (x11->has_xrandr << 4 | x11->has_xinerama) {
149 syslog(LOG_ERR, "Neither Xrandr nor Xinerama found, assuming single monitor setup");
153 syslog(LOG_DEBUG, "Found Xinerama extension without Xrandr, assuming Xinerama multi monitor setup");
156 syslog(LOG_ERR, "Found Xrandr but no Xinerama, weird!");
159 /* Standard xrandr setup, nothing to see here */
165 find_mode_by_name (struct vdagent_x11 *x11, char *name)
168 XRRModeInfo *ret = NULL;
170 for (m = 0; m < x11->randr.res->nmode; m++) {
171 XRRModeInfo *mode = &x11->randr.res->modes[m];
172 if (!strcmp (name, mode->name)) {
181 find_mode_by_size (struct vdagent_x11 *x11, int output, int width, int height)
184 XRRModeInfo *ret = NULL;
186 for (m = 0; m < x11->randr.outputs[output]->nmode; m++) {
187 XRRModeInfo *mode = mode_from_id(x11,
188 x11->randr.outputs[output]->modes[m]);
189 if (mode && mode->width == width && mode->height == height) {
197 static void delete_mode(struct vdagent_x11 *x11, int output_index,
198 int width, int height)
202 XRROutputInfo *output_info;
205 if (width == 0 || height == 0)
208 snprintf(name, sizeof(name), "%dx%d-%d", width, height, output_index);
210 syslog(LOG_DEBUG, "Deleting mode %s", name);
212 output_info = x11->randr.outputs[output_index];
213 if (output_info->ncrtc != 1) {
214 syslog(LOG_ERR, "output has %d crtcs, expected exactly 1, "
215 "failed to delete mode", output_info->ncrtc);
218 for (m = 0 ; m < x11->randr.res->nmode; ++m) {
219 mode = &x11->randr.res->modes[m];
220 if (strcmp(mode->name, name) == 0)
223 if (m < x11->randr.res->nmode) {
224 vdagent_x11_set_error_handler(x11, error_handler);
225 XRRDeleteOutputMode (x11->display, x11->randr.res->outputs[output_index],
227 XRRDestroyMode (x11->display, mode->id);
228 // ignore race error, if mode is created by others
229 vdagent_x11_restore_error_handler(x11);
232 /* silly to update everytime for more then one monitor */
233 update_randr_res(x11, 0);
236 static void set_reduced_cvt_mode(XRRModeInfo *mode, int width, int height)
238 /* Code taken from hw/xfree86/modes/xf86cvt.c
239 * See that file for lineage. Originated in public domain code
240 * Would be nice if xorg exported this in a library */
242 /* 1) top/bottom margin size (% of height) - default: 1.8 */
243 #define CVT_MARGIN_PERCENTAGE 1.8
245 /* 2) character cell horizontal granularity (pixels) - default 8 */
246 #define CVT_H_GRANULARITY 8
248 /* 4) Minimum vertical porch (lines) - default 3 */
249 #define CVT_MIN_V_PORCH 3
251 /* 4) Minimum number of vertical back porch lines - default 6 */
252 #define CVT_MIN_V_BPORCH 6
254 /* Pixel Clock step (kHz) */
255 #define CVT_CLOCK_STEP 250
257 /* Minimum vertical blanking interval time (µs) - default 460 */
258 #define CVT_RB_MIN_VBLANK 460.0
260 /* Fixed number of clocks for horizontal sync */
261 #define CVT_RB_H_SYNC 32.0
263 /* Fixed number of clocks for horizontal blanking */
264 #define CVT_RB_H_BLANK 160.0
266 /* Fixed number of lines for vertical front porch - default 3 */
267 #define CVT_RB_VFPORCH 3
270 float VFieldRate = 60.0;
274 /* 2. Horizontal pixels */
275 width = width - (width % CVT_H_GRANULARITY);
278 mode->height = height;
281 /* 8. Estimate Horizontal period. */
282 HPeriod = ((float) (1000000.0 / VFieldRate - CVT_RB_MIN_VBLANK)) / height;
284 /* 9. Find number of lines in vertical blanking */
285 VBILines = ((float) CVT_RB_MIN_VBLANK) / HPeriod + 1;
287 /* 10. Check if vertical blanking is sufficient */
288 if (VBILines < (CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH))
289 VBILines = CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH;
291 /* 11. Find total number of lines in vertical field */
292 mode->vTotal = height + VBILines;
294 /* 12. Find total number of pixels in a line */
295 mode->hTotal = mode->width + CVT_RB_H_BLANK;
297 /* Fill in HSync values */
298 mode->hSyncEnd = mode->width + CVT_RB_H_BLANK / 2;
299 mode->hSyncStart = mode->hSyncEnd - CVT_RB_H_SYNC;
301 /* Fill in VSync values */
302 mode->vSyncStart = mode->height + CVT_RB_VFPORCH;
303 mode->vSyncEnd = mode->vSyncStart + VSync;
305 /* 15/13. Find pixel clock frequency (kHz for xf86) */
306 mode->dotClock = mode->hTotal * 1000.0 / HPeriod;
307 mode->dotClock -= mode->dotClock % CVT_CLOCK_STEP;
311 static XRRModeInfo *create_new_mode(struct vdagent_x11 *x11, int output_index,
312 int width, int height)
317 snprintf(modename, sizeof(modename), "%dx%d-%d", width, height, output_index);
319 mode.name = modename;
320 mode.nameLength = strlen(mode.name);
321 set_reduced_cvt_mode(&mode, width, height);
324 vdagent_x11_set_error_handler(x11, error_handler);
325 XRRCreateMode (x11->display, x11->root_window[0], &mode);
326 // ignore race error, if mode is created by others
327 vdagent_x11_restore_error_handler(x11);
329 /* silly to update everytime for more then one monitor */
330 update_randr_res(x11, 0);
332 return find_mode_by_name(x11, modename);
335 static int xrandr_add_and_set(struct vdagent_x11 *x11, int output, int x, int y,
336 int width, int height)
342 int old_width = x11->randr.monitor_sizes[output].width;
343 int old_height = x11->randr.monitor_sizes[output].height;
345 if (!x11->randr.res || output >= x11->randr.res->noutput || output < 0) {
346 syslog(LOG_ERR, "%s: program error: missing RANDR or bad output",
350 if (x11->set_crtc_config_not_functional) {
351 /* fail, set_best_mode will find something close. */
354 xid = x11->randr.res->outputs[output];
355 mode = find_mode_by_size(x11, output, width, height);
357 mode = create_new_mode(x11, output, width, height);
360 syslog(LOG_ERR, "failed to add a new mode");
363 XRRAddOutputMode(x11->display, xid, mode->id);
364 x11->randr.monitor_sizes[output].width = width;
365 x11->randr.monitor_sizes[output].height = height;
367 s = XRRSetCrtcConfig(x11->display, x11->randr.res, x11->randr.res->crtcs[output],
368 CurrentTime, x, y, mode->id, RR_Rotate_0, outputs,
371 if (s != RRSetConfigSuccess) {
372 syslog(LOG_ERR, "failed to XRRSetCrtcConfig");
373 x11->set_crtc_config_not_functional = 1;
377 /* clean the previous name, if any */
378 if (width != old_width || height != old_height)
379 delete_mode(x11, output, old_width, old_height);
384 static void xrandr_disable_output(struct vdagent_x11 *x11, int output)
388 if (!x11->randr.res || output >= x11->randr.res->noutput || output < 0) {
389 syslog(LOG_ERR, "%s: program error: missing RANDR or bad output",
394 s = XRRSetCrtcConfig(x11->display, x11->randr.res,
395 x11->randr.res->crtcs[output],
396 CurrentTime, 0, 0, None, RR_Rotate_0,
399 if (s != RRSetConfigSuccess)
400 syslog(LOG_ERR, "failed to disable monitor");
402 delete_mode(x11, output, x11->randr.monitor_sizes[output].width,
403 x11->randr.monitor_sizes[output].height);
404 x11->randr.monitor_sizes[output].width = 0;
405 x11->randr.monitor_sizes[output].height = 0;
408 static int set_screen_to_best_size(struct vdagent_x11 *x11, int width, int height,
409 int *out_width, int *out_height){
410 int i, num_sizes = 0;
412 unsigned int closest_diff = -1;
413 XRRScreenSize *sizes;
414 XRRScreenConfiguration *config;
417 sizes = XRRSizes(x11->display, 0, &num_sizes);
418 if (!sizes || !num_sizes) {
419 syslog(LOG_ERR, "XRRSizes failed");
423 syslog(LOG_DEBUG, "set_screen_to_best_size found %d modes\n", num_sizes);
425 /* Find the closest size which will fit within the monitor */
426 for (i = 0; i < num_sizes; i++) {
427 if (sizes[i].width > width ||
428 sizes[i].height > height)
429 continue; /* Too large for the monitor */
431 unsigned int wdiff = width - sizes[i].width;
432 unsigned int hdiff = height - sizes[i].height;
433 unsigned int diff = wdiff * wdiff + hdiff * hdiff;
434 if (diff < closest_diff) {
441 syslog(LOG_ERR, "no suitable resolution found for monitor");
445 config = XRRGetScreenInfo(x11->display, x11->root_window[0]);
447 syslog(LOG_ERR, "get screen info failed");
450 XRRConfigCurrentConfiguration(config, &rotation);
451 XRRSetScreenConfig(x11->display, config, x11->root_window[0], best,
452 rotation, CurrentTime);
453 XRRFreeScreenConfigInfo(config);
456 syslog(LOG_DEBUG, "set_screen_to_best_size set size to: %dx%d\n",
457 sizes[best].width, sizes[best].height);
458 *out_width = sizes[best].width;
459 *out_height = sizes[best].height;
463 void vdagent_x11_randr_handle_root_size_change(struct vdagent_x11 *x11,
464 int screen, int width, int height)
466 if (width == x11->width[screen] && height == x11->height[screen]) {
471 syslog(LOG_DEBUG, "Root size of screen %d changed to %dx%d send %d",
472 screen, width, height, !x11->dont_send_guest_xorg_res);
474 x11->width[screen] = width;
475 x11->height[screen] = height;
476 if (!x11->dont_send_guest_xorg_res) {
477 vdagent_x11_send_daemon_guest_xorg_res(x11, 1);
481 static int min_int(int x, int y)
483 return x > y ? y : x;
486 static int max_int(int x, int y)
488 return x > y ? x : y;
491 static int constrain_to_range(int low, int *val, int high)
493 if (low <= *val && *val <= high) {
505 static void constrain_to_screen(struct vdagent_x11 *x11, int *w, int *h)
511 lx = x11->randr.min_width;
512 hx = x11->randr.max_width;
513 ly = x11->randr.min_height;
514 hy = x11->randr.max_height;
515 if (constrain_to_range(lx, w, hx)) {
516 syslog(LOG_ERR, "width not in driver range: ! %d < %d < %d",
519 if (constrain_to_range(ly, h, hy)) {
520 syslog(LOG_ERR, "height not in driver range: ! %d < %d < %d",
525 static int monitor_enabled(VDAgentMonConfig *mon)
527 return mon->width != 0 && mon->height != 0;
531 * The agent config doesn't contain a primary size, just the monitors, but
532 * we need to total size as well, to make sure we have enough memory and
533 * because X needs it.
535 * At the same pass constrain any provided size to what the server accepts.
538 * x >= 0, y >= 0 for all x, y in mon_config
539 * max_width >= width >= min_width,
540 * max_height >= height >= min_height for all monitors in mon_config
542 static void zero_base_monitors(struct vdagent_x11 *x11,
543 VDAgentMonitorsConfig *mon_config,
544 int *width, int *height)
546 int i, min_x = INT_MAX, min_y = INT_MAX, max_x = INT_MIN, max_y = INT_MIN;
547 int *mon_height, *mon_width;
549 for (i = 0; i < mon_config->num_of_monitors; i++) {
550 if (!monitor_enabled(&mon_config->monitors[i]))
552 mon_config->monitors[i].x &= ~7;
553 mon_config->monitors[i].width &= ~7;
554 mon_width = (int *)&mon_config->monitors[i].width;
555 mon_height = (int *)&mon_config->monitors[i].height;
556 constrain_to_screen(x11, mon_width, mon_height);
557 min_x = min_int(mon_config->monitors[i].x, min_x);
558 min_y = min_int(mon_config->monitors[i].y, min_y);
559 max_x = max_int(mon_config->monitors[i].x + *mon_width, max_x);
560 max_y = max_int(mon_config->monitors[i].y + *mon_height, max_y);
562 if (min_x != 0 || min_y != 0) {
563 syslog(LOG_ERR, "%s: agent config %d,%d rooted, adjusting to 0,0.",
564 __FUNCTION__, min_x, min_y);
565 for (i = 0 ; i < mon_config->num_of_monitors; ++i) {
566 if (!monitor_enabled(&mon_config->monitors[i]))
568 mon_config->monitors[i].x -= min_x;
569 mon_config->monitors[i].y -= min_y;
578 static int enabled_monitors(VDAgentMonitorsConfig *mon)
582 for (i = 0; i < mon->num_of_monitors; i++) {
583 if (monitor_enabled(&mon->monitors[i]))
589 static int same_monitor_configs(VDAgentMonitorsConfig *conf1,
590 VDAgentMonitorsConfig *conf2)
594 if (conf1 == NULL || conf2 == NULL ||
595 conf1->num_of_monitors != conf2->num_of_monitors)
598 for (i = 0; i < conf1->num_of_monitors; i++) {
599 VDAgentMonConfig *mon1 = &conf1->monitors[i];
600 VDAgentMonConfig *mon2 = &conf2->monitors[i];
601 /* NOTE: we don't compare depth. */
602 if (mon1->x != mon2->x || mon1->y != mon2->y ||
603 mon1->width != mon2->width || mon1->height != mon2->height)
609 static int config_size(int num_of_monitors)
611 return sizeof(VDAgentMonitorsConfig) +
612 num_of_monitors * sizeof(VDAgentMonConfig);
615 static VDAgentMonitorsConfig *get_current_mon_config(struct vdagent_x11 *x11)
617 int i, num_of_monitors = 0;
620 XRRScreenResources *res = x11->randr.res;
621 VDAgentMonitorsConfig *mon_config;
623 mon_config = calloc(1, config_size(res->noutput));
625 syslog(LOG_ERR, "out of memory allocating current monitor config");
629 for (i = 0 ; i < res->noutput; i++) {
630 if (x11->randr.outputs[i]->ncrtc == 0)
631 continue; /* Monitor disabled, already zero-ed by calloc */
632 if (x11->randr.outputs[i]->ncrtc != 1)
635 crtc = crtc_from_id(x11, x11->randr.outputs[i]->crtcs[0]);
639 mode = mode_from_id(x11, crtc->mode);
641 continue; /* Monitor disabled, already zero-ed by calloc */
643 mon_config->monitors[i].x = crtc->x;
644 mon_config->monitors[i].y = crtc->y;
645 mon_config->monitors[i].width = mode->width;
646 mon_config->monitors[i].height = mode->height;
647 num_of_monitors = i + 1;
649 mon_config->num_of_monitors = num_of_monitors;
650 mon_config->flags = VD_AGENT_CONFIG_MONITORS_FLAG_USE_POS;
654 syslog(LOG_ERR, "error: inconsistent or stale data from X");
659 static void dump_monitors_config(struct vdagent_x11 *x11,
660 VDAgentMonitorsConfig *mon_config,
666 syslog(LOG_DEBUG, "%s: %d, %x", prefix, mon_config->num_of_monitors,
668 for (i = 0 ; i < mon_config->num_of_monitors; ++i) {
669 m = &mon_config->monitors[i];
670 if (!monitor_enabled(m))
672 syslog(LOG_DEBUG, "received monitor %d config %dx%d+%d+%d", i,
673 m->width, m->height, m->x, m->y);
678 * Set monitor configuration according to client request.
680 * On exit send current configuration to client, regardless of error.
683 * screen size too large for driver to handle. (we set the largest/smallest possible)
684 * no randr support in X server.
685 * invalid configuration request from client.
687 void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11,
688 VDAgentMonitorsConfig *mon_config,
693 int primary_w, primary_h;
694 int i, real_num_of_monitors = 0;
695 VDAgentMonitorsConfig *curr = NULL;
697 if (!x11->has_xrandr)
700 if (enabled_monitors(mon_config) < 1) {
701 syslog(LOG_ERR, "client sent config with all monitors disabled");
706 dump_monitors_config(x11, mon_config, "from guest");
709 for (i = 0; i < mon_config->num_of_monitors; i++) {
710 if (monitor_enabled(&mon_config->monitors[i]))
711 real_num_of_monitors = i + 1;
713 mon_config->num_of_monitors = real_num_of_monitors;
715 update_randr_res(x11, 0);
716 if (mon_config->num_of_monitors > x11->randr.res->noutput) {
718 "warning unexpected client request: #mon %d > driver output %d",
719 mon_config->num_of_monitors, x11->randr.res->noutput);
720 mon_config->num_of_monitors = x11->randr.res->noutput;
723 if (mon_config->num_of_monitors > MONITOR_SIZE_COUNT) {
724 syslog(LOG_WARNING, "warning: client send %d monitors, capping at %d",
725 mon_config->num_of_monitors, MONITOR_SIZE_COUNT);
726 mon_config->num_of_monitors = MONITOR_SIZE_COUNT;
729 zero_base_monitors(x11, mon_config, &primary_w, &primary_h);
731 constrain_to_screen(x11, &primary_w, &primary_h);
734 dump_monitors_config(x11, mon_config, "after zeroing");
737 curr = get_current_mon_config(x11);
738 if (same_monitor_configs(mon_config, curr) &&
739 x11->width[0] == primary_w && x11->height[0] == primary_h) {
743 if (same_monitor_configs(mon_config, x11->randr.failed_conf)) {
744 syslog(LOG_WARNING, "Ignoring previous failed client monitor config");
748 for (i = mon_config->num_of_monitors; i < x11->randr.res->noutput; i++)
749 xrandr_disable_output(x11, i);
751 for (i = 0; i < mon_config->num_of_monitors; ++i) {
752 if (!monitor_enabled(&mon_config->monitors[i])) {
753 xrandr_disable_output(x11, i);
756 /* Try to create the requested resolution */
757 width = mon_config->monitors[i].width;
758 height = mon_config->monitors[i].height;
759 x = mon_config->monitors[i].x;
760 y = mon_config->monitors[i].y;
761 if (!xrandr_add_and_set(x11, i, x, y, width, height) &&
762 enabled_monitors(mon_config) == 1) {
763 set_screen_to_best_size(x11, width, height,
764 &primary_w, &primary_h);
769 if (primary_w != x11->width[0] || primary_h != x11->height[0]) {
771 syslog(LOG_DEBUG, "Changing screen size to %dx%d",
772 primary_w, primary_h);
773 vdagent_x11_set_error_handler(x11, error_handler);
774 XRRSetScreenSize(x11->display, x11->root_window[0], primary_w, primary_h,
775 DisplayWidthMM(x11->display, 0),
776 DisplayHeightMM(x11->display, 0));
777 if (vdagent_x11_restore_error_handler(x11)) {
778 syslog(LOG_ERR, "XRRSetScreenSize failed, not enough mem?");
779 if (!fallback && curr) {
780 syslog(LOG_WARNING, "Restoring previous config");
781 vdagent_x11_set_monitor_config(x11, curr, 1);
783 /* Remember this config failed, if the client is maximized or
784 fullscreen it will keep sending the failing config. */
785 free(x11->randr.failed_conf);
786 x11->randr.failed_conf =
787 malloc(config_size(mon_config->num_of_monitors));
788 if (x11->randr.failed_conf)
789 memcpy(x11->randr.failed_conf, mon_config,
790 config_size(mon_config->num_of_monitors));
797 update_randr_res(x11,
798 x11->randr.num_monitors != enabled_monitors(mon_config));
799 x11->width[0] = primary_w;
800 x11->height[0] = primary_h;
802 /* Flush output buffers and consume any pending events (ConfigureNotify) */
803 x11->dont_send_guest_xorg_res = 1;
804 vdagent_x11_do_read(x11);
805 x11->dont_send_guest_xorg_res = 0;
808 vdagent_x11_send_daemon_guest_xorg_res(x11, 0);
810 /* Flush output buffers and consume any pending events */
811 vdagent_x11_do_read(x11);
815 void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11, int update)
817 struct vdagentd_guest_xorg_resolution *res = NULL;
818 int i, width = 0, height = 0, screen_count = 0;
820 if (x11->has_xrandr) {
821 VDAgentMonitorsConfig *curr;
824 update_randr_res(x11, 0);
826 curr = get_current_mon_config(x11);
830 screen_count = curr->num_of_monitors;
831 res = malloc(screen_count * sizeof(*res));
837 for (i = 0; i < screen_count; i++) {
838 res[i].width = curr->monitors[i].width;
839 res[i].height = curr->monitors[i].height;
840 res[i].x = curr->monitors[i].x;
841 res[i].y = curr->monitors[i].y;
844 width = x11->width[0];
845 height = x11->height[0];
846 } else if (x11->has_xinerama) {
847 XineramaScreenInfo *screen_info = NULL;
849 screen_info = XineramaQueryScreens(x11->display, &screen_count);
852 res = malloc(screen_count * sizeof(*res));
857 for (i = 0; i < screen_count; i++) {
858 if (screen_info[i].screen_number >= screen_count) {
859 syslog(LOG_ERR, "Invalid screen number in xinerama screen info (%d >= %d)",
860 screen_info[i].screen_number, screen_count);
865 res[screen_info[i].screen_number].width = screen_info[i].width;
866 res[screen_info[i].screen_number].height = screen_info[i].height;
867 res[screen_info[i].screen_number].x = screen_info[i].x_org;
868 res[screen_info[i].screen_number].y = screen_info[i].y_org;
871 width = x11->width[0];
872 height = x11->height[0];
875 screen_count = x11->screen_count;
876 res = malloc(screen_count * sizeof(*res));
879 for (i = 0; i < screen_count; i++) {
880 res[i].width = x11->width[i];
881 res[i].height = x11->height[i];
882 /* No way to get screen coordinates, assume rtl order */
885 width += x11->width[i];
886 if (x11->height[i] > height)
887 height = x11->height[i];
892 for (i = 0; i < screen_count; i++)
893 syslog(LOG_DEBUG, "Screen %d %dx%d%+d%+d", i, res[i].width,
894 res[i].height, res[i].x, res[i].y);
897 udscs_write(x11->vdagentd, VDAGENTD_GUEST_XORG_RESOLUTION, width, height,
898 (uint8_t *)res, screen_count * sizeof(*res));
902 syslog(LOG_ERR, "out of memory while trying to send resolutions, not sending resolutions.");