make a few functions static
[vd_agent.git] / src / vdagent-x11-randr.c
blob2ffd2640e779daf56295789ff1d4303a97ea3400
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 void check_error_handler(struct vdagent_x11 *x11)
52 XSync(x11->display, False);
53 XSetErrorHandler(old_error_handler);
54 if (caught_error) {
55 x11->set_crtc_config_not_functional = 1;
59 static XRRModeInfo *mode_from_id(struct vdagent_x11 *x11, int id)
61 int i;
63 for (i = 0 ; i < x11->randr.res->nmode ; ++i) {
64 if (id == x11->randr.res->modes[i].id) {
65 return &x11->randr.res->modes[i];
68 return NULL;
71 static XRRCrtcInfo *crtc_from_id(struct vdagent_x11 *x11, int id)
73 int i;
75 for (i = 0 ; i < x11->randr.res->ncrtc ; ++i) {
76 if (id == x11->randr.res->crtcs[i]) {
77 return x11->randr.crtcs[i];
80 return NULL;
83 static void free_randr_resources(struct vdagent_x11 *x11)
85 int i;
87 if (!x11->randr.res) {
88 return;
90 if (x11->randr.outputs != NULL) {
91 for (i = 0 ; i < x11->randr.res->noutput; ++i) {
92 XRRFreeOutputInfo(x11->randr.outputs[i]);
94 free(x11->randr.outputs);
96 if (x11->randr.crtcs != NULL) {
97 for (i = 0 ; i < x11->randr.res->ncrtc; ++i) {
98 XRRFreeCrtcInfo(x11->randr.crtcs[i]);
100 free(x11->randr.crtcs);
102 XRRFreeScreenResources(x11->randr.res);
103 x11->randr.res = NULL;
104 x11->randr.outputs = NULL;
105 x11->randr.crtcs = NULL;
108 static void update_randr_res(struct vdagent_x11 *x11)
110 int i;
112 free_randr_resources(x11);
113 /* Note: we don't need XRRGetScreenResourcesCurrent since we cache the changes */
114 x11->randr.res = XRRGetScreenResources(x11->display, x11->root_window);
115 x11->randr.outputs = malloc(x11->randr.res->noutput * sizeof(*x11->randr.outputs));
116 x11->randr.crtcs = malloc(x11->randr.res->ncrtc * sizeof(*x11->randr.crtcs));
117 for (i = 0 ; i < x11->randr.res->noutput; ++i) {
118 x11->randr.outputs[i] = XRRGetOutputInfo(x11->display, x11->randr.res,
119 x11->randr.res->outputs[i]);
121 for (i = 0 ; i < x11->randr.res->ncrtc; ++i) {
122 x11->randr.crtcs[i] = XRRGetCrtcInfo(x11->display, x11->randr.res,
123 x11->randr.res->crtcs[i]);
125 /* XXX is this dynamic? should it be cached? */
126 if (XRRGetScreenSizeRange(x11->display, x11->root_window,
127 &x11->randr.min_width,
128 &x11->randr.min_height,
129 &x11->randr.max_width,
130 &x11->randr.max_height) != 1) {
131 syslog(LOG_ERR, "update_randr_res: RRGetScreenSizeRange failed");
135 void vdagent_x11_randr_init(struct vdagent_x11 *x11)
137 int i;
139 if (XRRQueryExtension(x11->display, &i, &i)) {
140 x11->has_xrandr = 1;
141 update_randr_res(x11);
142 XRRQueryVersion(x11->display, &x11->xrandr_major, &x11->xrandr_minor);
143 } else {
144 x11->randr.res = NULL;
147 if (XineramaQueryExtension(x11->display, &i, &i))
148 x11->has_xinerama = 1;
150 switch (x11->has_xrandr << 4 | x11->has_xinerama) {
151 case 0x00:
152 syslog(LOG_ERR, "Neither Xrandr nor Xinerama found, assuming single monitor setup");
153 break;
154 case 0x01:
155 if (x11->debug)
156 syslog(LOG_DEBUG, "Found Xinerama extension without Xrandr, assuming Xinerama multi monitor setup");
157 break;
158 case 0x10:
159 syslog(LOG_ERR, "Found Xrandr but no Xinerama, weird!");
160 break;
161 case 0x11:
162 /* Standard xrandr setup, nothing to see here */
163 break;
167 static XRRModeInfo *
168 find_mode_by_name (struct vdagent_x11 *x11, char *name)
170 int m;
171 XRRModeInfo *ret = NULL;
173 for (m = 0; m < x11->randr.res->nmode; m++) {
174 XRRModeInfo *mode = &x11->randr.res->modes[m];
175 if (!strcmp (name, mode->name)) {
176 ret = mode;
177 break;
180 return ret;
183 static XRRModeInfo *
184 find_mode_by_size (struct vdagent_x11 *x11, int width, int height)
186 int m;
187 XRRModeInfo *ret = NULL;
189 for (m = 0; m < x11->randr.res->nmode; m++) {
190 XRRModeInfo *mode = &x11->randr.res->modes[m];
191 if (mode->width == width && mode->height == height) {
192 ret = mode;
193 break;
196 return ret;
199 static void delete_mode(struct vdagent_x11 *x11, int output_index)
201 int m;
202 XRRModeInfo *mode;
203 XRROutputInfo *output_info;
204 XRRCrtcInfo *crtc_info;
205 RRCrtc crtc;
206 int current_mode = -1;
207 char name[20];
209 output_info = x11->randr.outputs[output_index];
210 if (output_info->ncrtc != 1) {
211 syslog(LOG_ERR, "output has %d crtcs, expected exactly 1, "
212 "failed to delete mode", output_info->ncrtc);
213 return;
215 crtc_info = crtc_from_id(x11, output_info->crtcs[0]);
216 current_mode = crtc_info->mode;
217 crtc = output_info->crtc;
218 snprintf(name, sizeof(name), "vdagent-%d", output_index);
219 for (m = 0 ; m < x11->randr.res->nmode; ++m) {
220 mode = &x11->randr.res->modes[m];
221 if (strcmp(mode->name, name) == 0)
222 break;
224 if (m < x11->randr.res->nmode) {
225 if (crtc && mode->id == current_mode) {
226 syslog(LOG_DEBUG,
227 "delete_mode of in use mode, setting crtc to NULL mode");
228 XRRSetCrtcConfig(x11->display, x11->randr.res, crtc,
229 CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0);
231 XRRDeleteOutputMode (x11->display, x11->randr.res->outputs[output_index],
232 mode->id);
233 XRRDestroyMode (x11->display, mode->id);
237 static void set_reduced_cvt_mode(XRRModeInfo *mode, int width, int height)
239 /* Code taken from hw/xfree86/modes/xf86cvt.c
240 * See that file for lineage. Originated in public domain code
241 * Would be nice if xorg exported this in a library */
243 /* 1) top/bottom margin size (% of height) - default: 1.8 */
244 #define CVT_MARGIN_PERCENTAGE 1.8
246 /* 2) character cell horizontal granularity (pixels) - default 8 */
247 #define CVT_H_GRANULARITY 8
249 /* 4) Minimum vertical porch (lines) - default 3 */
250 #define CVT_MIN_V_PORCH 3
252 /* 4) Minimum number of vertical back porch lines - default 6 */
253 #define CVT_MIN_V_BPORCH 6
255 /* Pixel Clock step (kHz) */
256 #define CVT_CLOCK_STEP 250
258 /* Minimum vertical blanking interval time (µs) - default 460 */
259 #define CVT_RB_MIN_VBLANK 460.0
261 /* Fixed number of clocks for horizontal sync */
262 #define CVT_RB_H_SYNC 32.0
264 /* Fixed number of clocks for horizontal blanking */
265 #define CVT_RB_H_BLANK 160.0
267 /* Fixed number of lines for vertical front porch - default 3 */
268 #define CVT_RB_VFPORCH 3
270 int VBILines;
271 float VFieldRate = 60.0;
272 int VSync;
273 float HPeriod;
275 /* 2. Horizontal pixels */
276 width = width - (width % CVT_H_GRANULARITY);
278 mode->width = width;
279 mode->height = height;
280 VSync = 10;
282 /* 8. Estimate Horizontal period. */
283 HPeriod = ((float) (1000000.0 / VFieldRate - CVT_RB_MIN_VBLANK)) / height;
285 /* 9. Find number of lines in vertical blanking */
286 VBILines = ((float) CVT_RB_MIN_VBLANK) / HPeriod + 1;
288 /* 10. Check if vertical blanking is sufficient */
289 if (VBILines < (CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH))
290 VBILines = CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH;
292 /* 11. Find total number of lines in vertical field */
293 mode->vTotal = height + VBILines;
295 /* 12. Find total number of pixels in a line */
296 mode->hTotal = mode->width + CVT_RB_H_BLANK;
298 /* Fill in HSync values */
299 mode->hSyncEnd = mode->width + CVT_RB_H_BLANK / 2;
300 mode->hSyncStart = mode->hSyncEnd - CVT_RB_H_SYNC;
302 /* Fill in VSync values */
303 mode->vSyncStart = mode->height + CVT_RB_VFPORCH;
304 mode->vSyncEnd = mode->vSyncStart + VSync;
306 /* 15/13. Find pixel clock frequency (kHz for xf86) */
307 mode->dotClock = mode->hTotal * 1000.0 / HPeriod;
308 mode->dotClock -= mode->dotClock % CVT_CLOCK_STEP;
312 static XRRModeInfo *create_new_mode(struct vdagent_x11 *x11, int output_index,
313 int width, int height)
315 char modename[20];
316 XRRModeInfo mode;
318 /* we may be using this mode from an old invocation - check first */
319 snprintf(modename, sizeof(modename), "vdagent-%d", output_index);
320 arm_error_handler(x11);
321 delete_mode(x11, output_index);
322 check_error_handler(x11);
323 if (x11->set_crtc_config_not_functional) {
324 return NULL;
326 mode.hSkew = 0;
327 mode.name = modename;
328 mode.nameLength = strlen(mode.name);
329 set_reduced_cvt_mode(&mode, width, height);
330 mode.modeFlags = 0;
331 mode.id = 0;
333 XRRCreateMode (x11->display, x11->root_window, &mode);
334 /* silly to update everytime for more then one monitor */
335 update_randr_res(x11);
336 return find_mode_by_name(x11, modename);
339 static int xrandr_add_and_set(struct vdagent_x11 *x11, int output, int x, int y,
340 int width, int height)
342 XRRModeInfo *mode;
343 int xid;
344 Status s;
345 RROutput outputs[1];
347 if (!x11->randr.res || output >= x11->randr.res->noutput || output < 0) {
348 syslog(LOG_ERR, "%s: program error: missing RANDR or bad output",
349 __FUNCTION__);
350 return 0;
352 if (x11->set_crtc_config_not_functional) {
353 /* fail, set_best_mode will find something close. */
354 return 0;
356 xid = x11->randr.res->outputs[output];
357 mode = find_mode_by_size(x11, width, height);
358 if (!mode) {
359 mode = create_new_mode(x11, output, width, height);
361 if (!mode) {
362 syslog(LOG_ERR, "failed to add a new mode");
363 return 0;
365 XRRAddOutputMode(x11->display, xid, mode->id);
366 outputs[0] = xid;
367 s = XRRSetCrtcConfig(x11->display, x11->randr.res, x11->randr.res->crtcs[output],
368 CurrentTime, x, y, mode->id, RR_Rotate_0, outputs,
370 if (s != RRSetConfigSuccess) {
371 syslog(LOG_ERR, "failed to XRRSetCrtcConfig");
372 delete_mode(x11, output);
373 x11->set_crtc_config_not_functional = 1;
374 return 0;
376 return 1;
379 static void xrandr_disable_output(struct vdagent_x11 *x11, int output)
381 Status s;
383 if (!x11->randr.res || output >= x11->randr.res->noutput || output < 0) {
384 syslog(LOG_ERR, "%s: program error: missing RANDR or bad output",
385 __FUNCTION__);
386 return;
389 s = XRRSetCrtcConfig(x11->display, x11->randr.res,
390 x11->randr.res->crtcs[output],
391 CurrentTime, 0, 0, None, RR_Rotate_0,
392 NULL, 0);
394 if (s != RRSetConfigSuccess)
395 syslog(LOG_ERR, "failed to disable monitor");
398 static int set_screen_to_best_size(struct vdagent_x11 *x11, int width, int height,
399 int *out_width, int *out_height){
400 int i, num_sizes = 0;
401 int best = -1;
402 unsigned int closest_diff = -1;
403 XRRScreenSize *sizes;
404 XRRScreenConfiguration *config;
405 Rotation rotation;
407 sizes = XRRSizes(x11->display, x11->screen, &num_sizes);
408 if (!sizes || !num_sizes) {
409 syslog(LOG_ERR, "XRRSizes failed");
410 return 0;
412 if (x11->debug)
413 syslog(LOG_DEBUG, "set_screen_to_best_size found %d modes\n", num_sizes);
415 /* Find the closest size which will fit within the monitor */
416 for (i = 0; i < num_sizes; i++) {
417 if (sizes[i].width > width ||
418 sizes[i].height > height)
419 continue; /* Too large for the monitor */
421 unsigned int wdiff = width - sizes[i].width;
422 unsigned int hdiff = height - sizes[i].height;
423 unsigned int diff = wdiff * wdiff + hdiff * hdiff;
424 if (diff < closest_diff) {
425 closest_diff = diff;
426 best = i;
430 if (best == -1) {
431 syslog(LOG_ERR, "no suitable resolution found for monitor");
432 return 0;
435 config = XRRGetScreenInfo(x11->display, x11->root_window);
436 if(!config) {
437 syslog(LOG_ERR, "get screen info failed");
438 return 0;
440 XRRConfigCurrentConfiguration(config, &rotation);
441 XRRSetScreenConfig(x11->display, config, x11->root_window, best,
442 rotation, CurrentTime);
443 XRRFreeScreenConfigInfo(config);
445 if (x11->debug)
446 syslog(LOG_DEBUG, "set_screen_to_best_size set size to: %dx%d\n",
447 sizes[best].width, sizes[best].height);
448 *out_width = sizes[best].width;
449 *out_height = sizes[best].height;
450 return 1;
453 void vdagent_x11_randr_handle_root_size_change(struct vdagent_x11 *x11,
454 int width, int height)
456 if (width == x11->width && height == x11->height) {
457 return;
460 x11->width = width;
461 x11->height = height;
462 if (!x11->dont_send_guest_xorg_res) {
463 vdagent_x11_send_daemon_guest_xorg_res(x11);
467 static uint32_t min_int(uint32_t x, uint32_t y)
469 return x > y ? y : x;
472 static uint32_t max_int(uint32_t x, uint32_t y)
474 return x > y ? x : y;
477 static int constrain_to_range(uint32_t low, uint32_t *val, uint32_t high)
479 if (low <= *val && *val <= high) {
480 return 0;
482 if (low > *val) {
483 *val = low;
485 if (*val > high) {
486 *val = high;
488 return 1;
491 static void constrain_to_screen(struct vdagent_x11 *x11, uint32_t *w, uint32_t *h)
493 uint32_t lx, ly, hx, hy;
494 uint32_t orig_h = *h;
495 uint32_t orig_w = *w;
497 lx = x11->randr.min_width;
498 hx = x11->randr.max_width;
499 ly = x11->randr.min_height;
500 hy = x11->randr.max_height;
501 if (constrain_to_range(lx, w, hx)) {
502 syslog(LOG_ERR, "width not in driver range: ! %d < %d < %d",
503 lx, orig_w, hx);
505 if (constrain_to_range(ly, h, hy)) {
506 syslog(LOG_ERR, "height not in driver range: ! %d < %d < %d",
507 ly, orig_h, hy);
512 * The agent config doesn't contain a primary size, just the monitors, but
513 * we need to total size as well, to make sure we have enough memory and
514 * because X needs it.
516 * At the same pass constrain any provided size to what the server accepts.
518 * Exit axioms:
519 * x >= 0, y >= 0 for all x, y in mon_config
520 * max_width >= width >= min_width,
521 * max_height >= height >= min_height for all monitors in mon_config
523 static void zero_base_monitors(struct vdagent_x11 *x11,
524 VDAgentMonitorsConfig *mon_config,
525 uint32_t *width, uint32_t *height)
527 int i = 0;
528 uint32_t min_x, min_y, max_x, max_y;
529 uint32_t *mon_height, *mon_width;
531 mon_width = &mon_config->monitors[i].width;
532 mon_height = &mon_config->monitors[i].height;
533 constrain_to_screen(x11, mon_width, mon_height);
534 min_x = mon_config->monitors[0].x;
535 min_y = mon_config->monitors[0].y;
536 max_x = mon_config->monitors[0].width + min_x;
537 max_y = mon_config->monitors[0].height + min_y;
538 for (++i ; i < mon_config->num_of_monitors; ++i) {
539 mon_width = &mon_config->monitors[i].width;
540 mon_height = &mon_config->monitors[i].height;
541 constrain_to_screen(x11, mon_width, mon_height);
542 min_x = min_int(mon_config->monitors[i].x, min_x);
543 min_y = min_int(mon_config->monitors[i].y, min_y);
544 max_x = max_int(mon_config->monitors[i].x + *mon_width, max_x);
545 max_y = max_int(mon_config->monitors[i].y + *mon_height, max_y);
547 if (min_x != 0 || min_y != 0) {
548 syslog(LOG_ERR, "%s: agent config %d,%d rooted, adjusting to 0,0.",
549 __FUNCTION__, min_x, min_y);
550 for (i = 0 ; i < mon_config->num_of_monitors; ++i) {
551 mon_config->monitors[i].x -= min_x;
552 mon_config->monitors[i].y -= min_y;
555 max_x -= min_x;
556 max_y -= min_y;
557 *width = max_x;
558 *height = max_y;
561 static int same_monitor_configs(struct vdagent_x11 *x11, VDAgentMonitorsConfig *mon)
563 int i;
564 XRRModeInfo *mode;
565 XRRCrtcInfo *crtc;
566 VDAgentMonConfig *client_mode;
567 XRRScreenResources *res = x11->randr.res;
569 if (res->noutput > res->ncrtc) {
570 syslog(LOG_ERR, "error: unexpected noutput > ncrtc in driver");
571 return 0;
574 if (mon->num_of_monitors > res->noutput) {
575 for (i = res->noutput; i < mon->num_of_monitors; i++) {
576 if (mon->monitors[i].width || mon->monitors[i].height) {
577 syslog(LOG_WARNING,
578 "warning: unexpected client request: #mon %d > driver output %d",
579 mon->num_of_monitors, res->noutput);
580 break;
583 mon->num_of_monitors = res->noutput;
586 for (i = 0 ; i < mon->num_of_monitors; ++i) {
587 if (x11->randr.outputs[i]->ncrtc == 0) {
588 return 0;
590 if (x11->randr.outputs[i]->ncrtc != 1) {
591 syslog(LOG_ERR, "error: unexpected driver config, ncrtc %d != 1",
592 x11->randr.outputs[i]->ncrtc);
593 return 0;
595 crtc = crtc_from_id(x11, x11->randr.outputs[i]->crtcs[0]);
596 if (!crtc) {
597 syslog(LOG_ERR, "error: inconsistent or stale data from X");
598 return 0;
600 client_mode = &mon->monitors[i];
601 mode = mode_from_id(x11, crtc->mode);
602 if (!mode) {
603 return 0;
605 /* NOTE: we don't compare depth. */
606 /* NOTE 2: width set by X is a multiple of 8, so ignore lower 3 bits */
607 if ((mode->width & ~7) != (client_mode->width & ~7) ||
608 mode->height != client_mode->height ||
609 (crtc->x & ~7) != (client_mode->x & ~7) ||
610 crtc->y != client_mode->y) {
611 return 0;
614 return 1;
617 static void dump_monitors_config(struct vdagent_x11 *x11,
618 VDAgentMonitorsConfig *mon_config,
619 const char *prefix)
621 int i;
622 VDAgentMonConfig *m;
624 syslog(LOG_DEBUG, "%s: %d, %x", prefix, mon_config->num_of_monitors,
625 mon_config->flags);
626 for (i = 0 ; i < mon_config->num_of_monitors; ++i) {
627 m = &mon_config->monitors[i];
628 syslog(LOG_DEBUG, "received monitor %d config %dx%d+%d+%d", i,
629 m->width, m->height, m->x, m->y);
634 * Set monitor configuration according to client request.
636 * On exit send current configuration to client, regardless of error.
638 * Errors:
639 * screen size too large for driver to handle. (we set the largest/smallest possible)
640 * no randr support in X server.
641 * invalid configuration request from client.
643 void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11,
644 VDAgentMonitorsConfig *mon_config)
646 int i;
647 int width, height;
648 int x, y;
649 uint32_t primary_w, primary_h;
651 if (!x11->has_xrandr)
652 goto exit;
654 if (mon_config->num_of_monitors < 1) {
655 syslog(LOG_ERR, "client sent invalid monitor config number %d",
656 mon_config->num_of_monitors);
657 goto exit;
660 if (same_monitor_configs(x11, mon_config)) {
661 goto exit;
664 if (x11->debug) {
665 dump_monitors_config(x11, mon_config, "from guest");
668 zero_base_monitors(x11, mon_config, &primary_w, &primary_h);
670 constrain_to_screen(x11, &primary_w, &primary_h);
672 if (x11->debug) {
673 dump_monitors_config(x11, mon_config, "after zeroing");
676 for (i = mon_config->num_of_monitors; i < x11->randr.res->noutput; i++)
677 xrandr_disable_output(x11, i);
679 for (i = 0; i < mon_config->num_of_monitors; ++i) {
680 /* Try to create the requested resolution */
681 width = mon_config->monitors[i].width;
682 height = mon_config->monitors[i].height;
683 x = mon_config->monitors[i].x;
684 y = mon_config->monitors[i].y;
685 if (!xrandr_add_and_set(x11, i, x, y, width, height) &&
686 mon_config->num_of_monitors == 1) {
687 set_screen_to_best_size(x11, width, height,
688 &primary_w, &primary_h);
689 goto update;
693 if (primary_w != x11->width || primary_h != x11->height) {
694 arm_error_handler(x11);
695 XRRSetScreenSize(x11->display, x11->root_window, primary_w, primary_h,
696 DisplayWidthMM(x11->display, x11->screen),
697 DisplayHeightMM(x11->display, x11->screen));
698 check_error_handler(x11);
701 update:
702 update_randr_res(x11);
703 x11->width = primary_w;
704 x11->height = primary_h;
706 /* Flush output buffers and consume any pending events (ConfigureNotify) */
707 x11->dont_send_guest_xorg_res = 1;
708 vdagent_x11_do_read(x11);
709 x11->dont_send_guest_xorg_res = 0;
711 exit:
712 vdagent_x11_send_daemon_guest_xorg_res(x11);
714 /* Flush output buffers and consume any pending events */
715 vdagent_x11_do_read(x11);
718 void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11)
720 struct vdagentd_guest_xorg_resolution *res = NULL;
721 XineramaScreenInfo *screen_info = NULL;
722 int i, screen_count = 0;
724 if (x11->has_xinerama) {
725 /* Xinerama reports the same information RANDR reports, so stay
726 * with Xinerama for support of Xinerama only setups */
727 screen_info = XineramaQueryScreens(x11->display, &screen_count);
730 if (screen_count == 0)
731 screen_count = 1;
733 res = malloc(screen_count * sizeof(*res));
734 if (!res) {
735 syslog(LOG_ERR, "out of memory while trying to send resolutions, not sending resolutions.");
736 if (screen_info)
737 XFree(screen_info);
738 return;
741 if (screen_info) {
742 for (i = 0; i < screen_count; i++) {
743 if (screen_info[i].screen_number >= screen_count) {
744 syslog(LOG_ERR, "Invalid screen number in xinerama screen info (%d >= %d)",
745 screen_info[i].screen_number, screen_count);
746 XFree(screen_info);
747 free(res);
748 return;
750 res[screen_info[i].screen_number].width = screen_info[i].width;
751 res[screen_info[i].screen_number].height = screen_info[i].height;
752 res[screen_info[i].screen_number].x = screen_info[i].x_org;
753 res[screen_info[i].screen_number].y = screen_info[i].y_org;
755 XFree(screen_info);
756 } else {
757 res[0].width = x11->width;
758 res[0].height = x11->height;
759 res[0].x = 0;
760 res[0].y = 0;
763 udscs_write(x11->vdagentd, VDAGENTD_GUEST_XORG_RESOLUTION, x11->width,
764 x11->height, (uint8_t *)res, screen_count * sizeof(*res));
765 free(res);