randr: do not set crtc mode to NULL when changing resolution
[vd_agent.git] / src / vdagent-x11-randr.c
blob2c1819a982595bf2d06d8ed75926c3acc68da52d
1 /* vdagent-x11-randr.c vdagent Xrandr integration code
3 Copyright 2012 Red Hat, Inc.
5 Red Hat Authors:
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/>.
24 #include <string.h>
25 #include <syslog.h>
26 #include <stdlib.h>
28 #include <X11/extensions/Xinerama.h>
30 #include "vdagentd-proto.h"
31 #include "vdagent-x11.h"
32 #include "vdagent-x11-priv.h"
34 static int caught_error;
35 static int (*old_error_handler)(Display *, XErrorEvent *);
37 static int error_handler(Display *display, XErrorEvent *error)
39 caught_error = 1;
40 return 0;
43 static void arm_error_handler(struct vdagent_x11 *x11)
45 caught_error = 0;
46 XSync(x11->display, False);
47 old_error_handler = XSetErrorHandler(error_handler);
50 static int check_error_handler(struct vdagent_x11 *x11)
52 int error;
54 XSync(x11->display, False);
55 XSetErrorHandler(old_error_handler);
56 error = caught_error;
57 caught_error = 0;
59 return error;
62 static XRRModeInfo *mode_from_id(struct vdagent_x11 *x11, int id)
64 int i;
66 for (i = 0 ; i < x11->randr.res->nmode ; ++i) {
67 if (id == x11->randr.res->modes[i].id) {
68 return &x11->randr.res->modes[i];
71 return NULL;
74 static XRRCrtcInfo *crtc_from_id(struct vdagent_x11 *x11, int id)
76 int i;
78 for (i = 0 ; i < x11->randr.res->ncrtc ; ++i) {
79 if (id == x11->randr.res->crtcs[i]) {
80 return x11->randr.crtcs[i];
83 return NULL;
86 static void free_randr_resources(struct vdagent_x11 *x11)
88 int i;
90 if (!x11->randr.res) {
91 return;
93 if (x11->randr.outputs != NULL) {
94 for (i = 0 ; i < x11->randr.res->noutput; ++i) {
95 XRRFreeOutputInfo(x11->randr.outputs[i]);
97 free(x11->randr.outputs);
99 if (x11->randr.crtcs != NULL) {
100 for (i = 0 ; i < x11->randr.res->ncrtc; ++i) {
101 XRRFreeCrtcInfo(x11->randr.crtcs[i]);
103 free(x11->randr.crtcs);
105 XRRFreeScreenResources(x11->randr.res);
106 x11->randr.res = NULL;
107 x11->randr.outputs = NULL;
108 x11->randr.crtcs = NULL;
111 static void update_randr_res(struct vdagent_x11 *x11)
113 int i;
115 free_randr_resources(x11);
116 /* Note: we don't need XRRGetScreenResourcesCurrent since we cache the changes */
117 x11->randr.res = XRRGetScreenResources(x11->display, x11->root_window);
118 x11->randr.outputs = malloc(x11->randr.res->noutput * sizeof(*x11->randr.outputs));
119 x11->randr.crtcs = malloc(x11->randr.res->ncrtc * sizeof(*x11->randr.crtcs));
120 for (i = 0 ; i < x11->randr.res->noutput; ++i) {
121 x11->randr.outputs[i] = XRRGetOutputInfo(x11->display, x11->randr.res,
122 x11->randr.res->outputs[i]);
124 for (i = 0 ; i < x11->randr.res->ncrtc; ++i) {
125 x11->randr.crtcs[i] = XRRGetCrtcInfo(x11->display, x11->randr.res,
126 x11->randr.res->crtcs[i]);
128 /* XXX is this dynamic? should it be cached? */
129 if (XRRGetScreenSizeRange(x11->display, x11->root_window,
130 &x11->randr.min_width,
131 &x11->randr.min_height,
132 &x11->randr.max_width,
133 &x11->randr.max_height) != 1) {
134 syslog(LOG_ERR, "update_randr_res: RRGetScreenSizeRange failed");
138 void vdagent_x11_randr_init(struct vdagent_x11 *x11)
140 int i;
142 if (XRRQueryExtension(x11->display, &i, &i)) {
143 x11->has_xrandr = 1;
144 update_randr_res(x11);
145 XRRQueryVersion(x11->display, &x11->xrandr_major, &x11->xrandr_minor);
146 } else {
147 x11->randr.res = NULL;
150 if (XineramaQueryExtension(x11->display, &i, &i))
151 x11->has_xinerama = 1;
153 switch (x11->has_xrandr << 4 | x11->has_xinerama) {
154 case 0x00:
155 syslog(LOG_ERR, "Neither Xrandr nor Xinerama found, assuming single monitor setup");
156 break;
157 case 0x01:
158 if (x11->debug)
159 syslog(LOG_DEBUG, "Found Xinerama extension without Xrandr, assuming Xinerama multi monitor setup");
160 break;
161 case 0x10:
162 syslog(LOG_ERR, "Found Xrandr but no Xinerama, weird!");
163 break;
164 case 0x11:
165 /* Standard xrandr setup, nothing to see here */
166 break;
170 static XRRModeInfo *
171 find_mode_by_name (struct vdagent_x11 *x11, char *name)
173 int m;
174 XRRModeInfo *ret = NULL;
176 for (m = 0; m < x11->randr.res->nmode; m++) {
177 XRRModeInfo *mode = &x11->randr.res->modes[m];
178 if (!strcmp (name, mode->name)) {
179 ret = mode;
180 break;
183 return ret;
186 static XRRModeInfo *
187 find_mode_by_size (struct vdagent_x11 *x11, int width, int height)
189 int m;
190 XRRModeInfo *ret = NULL;
192 for (m = 0; m < x11->randr.res->nmode; m++) {
193 XRRModeInfo *mode = &x11->randr.res->modes[m];
194 if (mode->width == width && mode->height == height) {
195 ret = mode;
196 break;
199 return ret;
202 static void delete_mode(struct vdagent_x11 *x11, int output_index, const char* name)
204 int m;
205 XRRModeInfo *mode;
206 XRROutputInfo *output_info;
207 XRRCrtcInfo *crtc_info;
208 RRCrtc crtc;
209 int current_mode = -1;
211 output_info = x11->randr.outputs[output_index];
212 if (output_info->ncrtc != 1) {
213 syslog(LOG_ERR, "output has %d crtcs, expected exactly 1, "
214 "failed to delete mode", output_info->ncrtc);
215 return;
217 crtc_info = crtc_from_id(x11, output_info->crtcs[0]);
218 current_mode = crtc_info->mode;
219 crtc = output_info->crtc;
220 for (m = 0 ; m < x11->randr.res->nmode; ++m) {
221 mode = &x11->randr.res->modes[m];
222 if (strcmp(mode->name, name) == 0)
223 break;
225 if (m < x11->randr.res->nmode) {
226 arm_error_handler(x11);
227 XRRDeleteOutputMode (x11->display, x11->randr.res->outputs[output_index],
228 mode->id);
229 XRRDestroyMode (x11->display, mode->id);
230 // ignore race error, if mode is created by others
231 check_error_handler(x11);
234 /* silly to update everytime for more then one monitor */
235 update_randr_res(x11);
238 static void set_reduced_cvt_mode(XRRModeInfo *mode, int width, int height)
240 /* Code taken from hw/xfree86/modes/xf86cvt.c
241 * See that file for lineage. Originated in public domain code
242 * Would be nice if xorg exported this in a library */
244 /* 1) top/bottom margin size (% of height) - default: 1.8 */
245 #define CVT_MARGIN_PERCENTAGE 1.8
247 /* 2) character cell horizontal granularity (pixels) - default 8 */
248 #define CVT_H_GRANULARITY 8
250 /* 4) Minimum vertical porch (lines) - default 3 */
251 #define CVT_MIN_V_PORCH 3
253 /* 4) Minimum number of vertical back porch lines - default 6 */
254 #define CVT_MIN_V_BPORCH 6
256 /* Pixel Clock step (kHz) */
257 #define CVT_CLOCK_STEP 250
259 /* Minimum vertical blanking interval time (µs) - default 460 */
260 #define CVT_RB_MIN_VBLANK 460.0
262 /* Fixed number of clocks for horizontal sync */
263 #define CVT_RB_H_SYNC 32.0
265 /* Fixed number of clocks for horizontal blanking */
266 #define CVT_RB_H_BLANK 160.0
268 /* Fixed number of lines for vertical front porch - default 3 */
269 #define CVT_RB_VFPORCH 3
271 int VBILines;
272 float VFieldRate = 60.0;
273 int VSync;
274 float HPeriod;
276 /* 2. Horizontal pixels */
277 width = width - (width % CVT_H_GRANULARITY);
279 mode->width = width;
280 mode->height = height;
281 VSync = 10;
283 /* 8. Estimate Horizontal period. */
284 HPeriod = ((float) (1000000.0 / VFieldRate - CVT_RB_MIN_VBLANK)) / height;
286 /* 9. Find number of lines in vertical blanking */
287 VBILines = ((float) CVT_RB_MIN_VBLANK) / HPeriod + 1;
289 /* 10. Check if vertical blanking is sufficient */
290 if (VBILines < (CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH))
291 VBILines = CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH;
293 /* 11. Find total number of lines in vertical field */
294 mode->vTotal = height + VBILines;
296 /* 12. Find total number of pixels in a line */
297 mode->hTotal = mode->width + CVT_RB_H_BLANK;
299 /* Fill in HSync values */
300 mode->hSyncEnd = mode->width + CVT_RB_H_BLANK / 2;
301 mode->hSyncStart = mode->hSyncEnd - CVT_RB_H_SYNC;
303 /* Fill in VSync values */
304 mode->vSyncStart = mode->height + CVT_RB_VFPORCH;
305 mode->vSyncEnd = mode->vSyncStart + VSync;
307 /* 15/13. Find pixel clock frequency (kHz for xf86) */
308 mode->dotClock = mode->hTotal * 1000.0 / HPeriod;
309 mode->dotClock -= mode->dotClock % CVT_CLOCK_STEP;
313 static XRRModeInfo *create_new_mode(struct vdagent_x11 *x11, int output_index,
314 int width, int height)
316 char modename[20];
317 XRRModeInfo mode;
319 snprintf(modename, sizeof(modename), "%dx%d-%d", width, height, output_index);
320 mode.hSkew = 0;
321 mode.name = modename;
322 mode.nameLength = strlen(mode.name);
323 set_reduced_cvt_mode(&mode, width, height);
324 mode.modeFlags = 0;
325 mode.id = 0;
326 arm_error_handler(x11);
327 XRRCreateMode (x11->display, x11->root_window, &mode);
328 // ignore race error, if mode is created by others
329 check_error_handler(x11);
331 /* silly to update everytime for more then one monitor */
332 update_randr_res(x11);
334 return find_mode_by_name(x11, modename);
337 static int xrandr_add_and_set(struct vdagent_x11 *x11, int output, int x, int y,
338 int width, int height)
340 XRRModeInfo *mode;
341 int xid;
342 Status s;
343 RROutput outputs[1];
344 char modename[20];
346 if (!x11->randr.res || output >= x11->randr.res->noutput || output < 0) {
347 syslog(LOG_ERR, "%s: program error: missing RANDR or bad output",
348 __FUNCTION__);
349 return 0;
351 if (x11->set_crtc_config_not_functional) {
352 /* fail, set_best_mode will find something close. */
353 return 0;
355 xid = x11->randr.res->outputs[output];
356 mode = find_mode_by_size(x11, width, height);
357 if (!mode) {
358 mode = create_new_mode(x11, output, width, height);
360 if (!mode) {
361 syslog(LOG_ERR, "failed to add a new mode");
362 return 0;
364 XRRAddOutputMode(x11->display, xid, mode->id);
365 outputs[0] = xid;
366 s = XRRSetCrtcConfig(x11->display, x11->randr.res, x11->randr.res->crtcs[output],
367 CurrentTime, x, y, mode->id, RR_Rotate_0, outputs,
370 if (s != RRSetConfigSuccess) {
371 syslog(LOG_ERR, "failed to XRRSetCrtcConfig");
372 x11->set_crtc_config_not_functional = 1;
373 return 0;
376 /* clean the previous name, if any */
377 snprintf(modename, sizeof(modename), "%dx%d-%d", x11->width, x11->height, output);
378 delete_mode(x11, output, modename);
380 return 1;
383 static void xrandr_disable_output(struct vdagent_x11 *x11, int output)
385 Status s;
387 if (!x11->randr.res || output >= x11->randr.res->noutput || output < 0) {
388 syslog(LOG_ERR, "%s: program error: missing RANDR or bad output",
389 __FUNCTION__);
390 return;
393 s = XRRSetCrtcConfig(x11->display, x11->randr.res,
394 x11->randr.res->crtcs[output],
395 CurrentTime, 0, 0, None, RR_Rotate_0,
396 NULL, 0);
398 if (s != RRSetConfigSuccess)
399 syslog(LOG_ERR, "failed to disable monitor");
402 static int set_screen_to_best_size(struct vdagent_x11 *x11, int width, int height,
403 int *out_width, int *out_height){
404 int i, num_sizes = 0;
405 int best = -1;
406 unsigned int closest_diff = -1;
407 XRRScreenSize *sizes;
408 XRRScreenConfiguration *config;
409 Rotation rotation;
411 sizes = XRRSizes(x11->display, x11->screen, &num_sizes);
412 if (!sizes || !num_sizes) {
413 syslog(LOG_ERR, "XRRSizes failed");
414 return 0;
416 if (x11->debug)
417 syslog(LOG_DEBUG, "set_screen_to_best_size found %d modes\n", num_sizes);
419 /* Find the closest size which will fit within the monitor */
420 for (i = 0; i < num_sizes; i++) {
421 if (sizes[i].width > width ||
422 sizes[i].height > height)
423 continue; /* Too large for the monitor */
425 unsigned int wdiff = width - sizes[i].width;
426 unsigned int hdiff = height - sizes[i].height;
427 unsigned int diff = wdiff * wdiff + hdiff * hdiff;
428 if (diff < closest_diff) {
429 closest_diff = diff;
430 best = i;
434 if (best == -1) {
435 syslog(LOG_ERR, "no suitable resolution found for monitor");
436 return 0;
439 config = XRRGetScreenInfo(x11->display, x11->root_window);
440 if(!config) {
441 syslog(LOG_ERR, "get screen info failed");
442 return 0;
444 XRRConfigCurrentConfiguration(config, &rotation);
445 XRRSetScreenConfig(x11->display, config, x11->root_window, best,
446 rotation, CurrentTime);
447 XRRFreeScreenConfigInfo(config);
449 if (x11->debug)
450 syslog(LOG_DEBUG, "set_screen_to_best_size set size to: %dx%d\n",
451 sizes[best].width, sizes[best].height);
452 *out_width = sizes[best].width;
453 *out_height = sizes[best].height;
454 return 1;
457 void vdagent_x11_randr_handle_root_size_change(struct vdagent_x11 *x11,
458 int width, int height)
460 if (width == x11->width && height == x11->height) {
461 return;
464 x11->width = width;
465 x11->height = height;
466 if (!x11->dont_send_guest_xorg_res) {
467 vdagent_x11_send_daemon_guest_xorg_res(x11);
471 static uint32_t min_int(uint32_t x, uint32_t y)
473 return x > y ? y : x;
476 static uint32_t max_int(uint32_t x, uint32_t y)
478 return x > y ? x : y;
481 static int constrain_to_range(uint32_t low, uint32_t *val, uint32_t high)
483 if (low <= *val && *val <= high) {
484 return 0;
486 if (low > *val) {
487 *val = low;
489 if (*val > high) {
490 *val = high;
492 return 1;
495 static void constrain_to_screen(struct vdagent_x11 *x11, uint32_t *w, uint32_t *h)
497 uint32_t lx, ly, hx, hy;
498 uint32_t orig_h = *h;
499 uint32_t orig_w = *w;
501 lx = x11->randr.min_width;
502 hx = x11->randr.max_width;
503 ly = x11->randr.min_height;
504 hy = x11->randr.max_height;
505 if (constrain_to_range(lx, w, hx)) {
506 syslog(LOG_ERR, "width not in driver range: ! %d < %d < %d",
507 lx, orig_w, hx);
509 if (constrain_to_range(ly, h, hy)) {
510 syslog(LOG_ERR, "height not in driver range: ! %d < %d < %d",
511 ly, orig_h, hy);
516 * The agent config doesn't contain a primary size, just the monitors, but
517 * we need to total size as well, to make sure we have enough memory and
518 * because X needs it.
520 * At the same pass constrain any provided size to what the server accepts.
522 * Exit axioms:
523 * x >= 0, y >= 0 for all x, y in mon_config
524 * max_width >= width >= min_width,
525 * max_height >= height >= min_height for all monitors in mon_config
527 static void zero_base_monitors(struct vdagent_x11 *x11,
528 VDAgentMonitorsConfig *mon_config,
529 uint32_t *width, uint32_t *height)
531 int i = 0;
532 uint32_t min_x, min_y, max_x, max_y;
533 uint32_t *mon_height, *mon_width;
535 mon_width = &mon_config->monitors[i].width;
536 mon_height = &mon_config->monitors[i].height;
537 constrain_to_screen(x11, mon_width, mon_height);
538 min_x = mon_config->monitors[0].x;
539 min_y = mon_config->monitors[0].y;
540 max_x = mon_config->monitors[0].width + min_x;
541 max_y = mon_config->monitors[0].height + min_y;
542 for (++i ; i < mon_config->num_of_monitors; ++i) {
543 mon_width = &mon_config->monitors[i].width;
544 mon_height = &mon_config->monitors[i].height;
545 constrain_to_screen(x11, mon_width, mon_height);
546 min_x = min_int(mon_config->monitors[i].x, min_x);
547 min_y = min_int(mon_config->monitors[i].y, min_y);
548 max_x = max_int(mon_config->monitors[i].x + *mon_width, max_x);
549 max_y = max_int(mon_config->monitors[i].y + *mon_height, max_y);
551 if (min_x != 0 || min_y != 0) {
552 syslog(LOG_ERR, "%s: agent config %d,%d rooted, adjusting to 0,0.",
553 __FUNCTION__, min_x, min_y);
554 for (i = 0 ; i < mon_config->num_of_monitors; ++i) {
555 mon_config->monitors[i].x -= min_x;
556 mon_config->monitors[i].y -= min_y;
559 max_x -= min_x;
560 max_y -= min_y;
561 *width = max_x;
562 *height = max_y;
565 static int same_monitor_configs(struct vdagent_x11 *x11, VDAgentMonitorsConfig *mon)
567 int i;
568 XRRModeInfo *mode;
569 XRRCrtcInfo *crtc;
570 VDAgentMonConfig *client_mode;
571 XRRScreenResources *res = x11->randr.res;
573 if (res->noutput > res->ncrtc) {
574 syslog(LOG_ERR, "error: unexpected noutput > ncrtc in driver");
575 return 0;
578 if (mon->num_of_monitors > res->noutput) {
579 for (i = res->noutput; i < mon->num_of_monitors; i++) {
580 if (mon->monitors[i].width || mon->monitors[i].height) {
581 syslog(LOG_WARNING,
582 "warning: unexpected client request: #mon %d > driver output %d",
583 mon->num_of_monitors, res->noutput);
584 break;
587 mon->num_of_monitors = res->noutput;
590 for (i = 0 ; i < mon->num_of_monitors; ++i) {
591 if (x11->randr.outputs[i]->ncrtc == 0) {
592 return 0;
594 if (x11->randr.outputs[i]->ncrtc != 1) {
595 syslog(LOG_ERR, "error: unexpected driver config, ncrtc %d != 1",
596 x11->randr.outputs[i]->ncrtc);
597 return 0;
599 crtc = crtc_from_id(x11, x11->randr.outputs[i]->crtcs[0]);
600 if (!crtc) {
601 syslog(LOG_ERR, "error: inconsistent or stale data from X");
602 return 0;
604 client_mode = &mon->monitors[i];
605 mode = mode_from_id(x11, crtc->mode);
606 if (!mode) {
607 return 0;
609 /* NOTE: we don't compare depth. */
610 /* NOTE 2: width set by X is a multiple of 8, so ignore lower 3 bits */
611 if ((mode->width & ~7) != (client_mode->width & ~7) ||
612 mode->height != client_mode->height ||
613 (crtc->x & ~7) != (client_mode->x & ~7) ||
614 crtc->y != client_mode->y) {
615 return 0;
618 return 1;
621 static void dump_monitors_config(struct vdagent_x11 *x11,
622 VDAgentMonitorsConfig *mon_config,
623 const char *prefix)
625 int i;
626 VDAgentMonConfig *m;
628 syslog(LOG_DEBUG, "%s: %d, %x", prefix, mon_config->num_of_monitors,
629 mon_config->flags);
630 for (i = 0 ; i < mon_config->num_of_monitors; ++i) {
631 m = &mon_config->monitors[i];
632 syslog(LOG_DEBUG, "received monitor %d config %dx%d+%d+%d", i,
633 m->width, m->height, m->x, m->y);
638 * Set monitor configuration according to client request.
640 * On exit send current configuration to client, regardless of error.
642 * Errors:
643 * screen size too large for driver to handle. (we set the largest/smallest possible)
644 * no randr support in X server.
645 * invalid configuration request from client.
647 void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11,
648 VDAgentMonitorsConfig *mon_config)
650 int i;
651 int width, height;
652 int x, y;
653 uint32_t primary_w, primary_h;
655 if (!x11->has_xrandr)
656 goto exit;
658 if (mon_config->num_of_monitors < 1) {
659 syslog(LOG_ERR, "client sent invalid monitor config number %d",
660 mon_config->num_of_monitors);
661 goto exit;
664 if (same_monitor_configs(x11, mon_config)) {
665 goto exit;
668 if (x11->debug) {
669 dump_monitors_config(x11, mon_config, "from guest");
672 zero_base_monitors(x11, mon_config, &primary_w, &primary_h);
674 constrain_to_screen(x11, &primary_w, &primary_h);
676 if (x11->debug) {
677 dump_monitors_config(x11, mon_config, "after zeroing");
680 for (i = mon_config->num_of_monitors; i < x11->randr.res->noutput; i++)
681 xrandr_disable_output(x11, i);
683 for (i = 0; i < mon_config->num_of_monitors; ++i) {
684 /* Try to create the requested resolution */
685 width = mon_config->monitors[i].width;
686 height = mon_config->monitors[i].height;
687 x = mon_config->monitors[i].x;
688 y = mon_config->monitors[i].y;
689 if (!xrandr_add_and_set(x11, i, x, y, width, height) &&
690 mon_config->num_of_monitors == 1) {
691 set_screen_to_best_size(x11, width, height,
692 &primary_w, &primary_h);
693 goto update;
697 if (primary_w != x11->width || primary_h != x11->height) {
698 arm_error_handler(x11);
699 XRRSetScreenSize(x11->display, x11->root_window, primary_w, primary_h,
700 DisplayWidthMM(x11->display, x11->screen),
701 DisplayHeightMM(x11->display, x11->screen));
703 x11->set_crtc_config_not_functional = check_error_handler(x11);
706 update:
707 update_randr_res(x11);
708 x11->width = primary_w;
709 x11->height = primary_h;
711 /* Flush output buffers and consume any pending events (ConfigureNotify) */
712 x11->dont_send_guest_xorg_res = 1;
713 vdagent_x11_do_read(x11);
714 x11->dont_send_guest_xorg_res = 0;
716 exit:
717 vdagent_x11_send_daemon_guest_xorg_res(x11);
719 /* Flush output buffers and consume any pending events */
720 vdagent_x11_do_read(x11);
723 void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11)
725 struct vdagentd_guest_xorg_resolution *res = NULL;
726 XineramaScreenInfo *screen_info = NULL;
727 int i, screen_count = 0;
729 if (x11->has_xinerama) {
730 /* Xinerama reports the same information RANDR reports, so stay
731 * with Xinerama for support of Xinerama only setups */
732 screen_info = XineramaQueryScreens(x11->display, &screen_count);
735 if (screen_count == 0)
736 screen_count = 1;
738 res = malloc(screen_count * sizeof(*res));
739 if (!res) {
740 syslog(LOG_ERR, "out of memory while trying to send resolutions, not sending resolutions.");
741 if (screen_info)
742 XFree(screen_info);
743 return;
746 if (screen_info) {
747 for (i = 0; i < screen_count; i++) {
748 if (screen_info[i].screen_number >= screen_count) {
749 syslog(LOG_ERR, "Invalid screen number in xinerama screen info (%d >= %d)",
750 screen_info[i].screen_number, screen_count);
751 XFree(screen_info);
752 free(res);
753 return;
755 res[screen_info[i].screen_number].width = screen_info[i].width;
756 res[screen_info[i].screen_number].height = screen_info[i].height;
757 res[screen_info[i].screen_number].x = screen_info[i].x_org;
758 res[screen_info[i].screen_number].y = screen_info[i].y_org;
760 XFree(screen_info);
761 } else {
762 res[0].width = x11->width;
763 res[0].height = x11->height;
764 res[0].x = 0;
765 res[0].y = 0;
768 udscs_write(x11->vdagentd, VDAGENTD_GUEST_XORG_RESOLUTION, x11->width,
769 x11->height, (uint8_t *)res, screen_count * sizeof(*res));
770 free(res);