Close monitor position configuration by %8 are same
[vd_agent.git] / src / vdagent-x11-randr.c
blobb316b18f767da59e0d8b483ad0cf0116bb4f31fd
1 #include <string.h>
2 #include <stdlib.h>
4 #include <X11/extensions/Xinerama.h>
6 #include "vdagentd-proto.h"
7 #include "vdagent-x11-priv.h"
9 static int caught_error;
10 static int (*old_error_handler)(Display *, XErrorEvent *);
12 static int error_handler(Display *display, XErrorEvent *error)
14 caught_error = 1;
17 static void arm_error_handler(struct vdagent_x11 *x11)
19 caught_error = 0;
20 XSync(x11->display, True);
21 old_error_handler = XSetErrorHandler(error_handler);
24 static void check_error_handler(struct vdagent_x11 *x11)
26 XSync(x11->display, False);
27 XSetErrorHandler(old_error_handler);
28 if (caught_error) {
29 x11->set_crtc_config_not_functional = 1;
33 static XRRModeInfo *mode_from_id(struct vdagent_x11 *x11, int id)
35 int i;
37 for (i = 0 ; i < x11->randr.res->nmode ; ++i) {
38 if (id == x11->randr.res->modes[i].id) {
39 return &x11->randr.res->modes[i];
42 return NULL;
45 static XRRCrtcInfo *crtc_from_id(struct vdagent_x11 *x11, int id)
47 int i;
49 for (i = 0 ; i < x11->randr.res->ncrtc ; ++i) {
50 if (id == x11->randr.res->crtcs[i]) {
51 return x11->randr.crtcs[i];
54 return NULL;
57 static void free_randr_resources(struct vdagent_x11 *x11)
59 int i;
61 if (!x11->randr.res) {
62 return;
64 if (x11->randr.outputs != NULL) {
65 for (i = 0 ; i < x11->randr.res->noutput; ++i) {
66 XRRFreeOutputInfo(x11->randr.outputs[i]);
68 free(x11->randr.outputs);
70 if (x11->randr.crtcs != NULL) {
71 for (i = 0 ; i < x11->randr.res->ncrtc; ++i) {
72 XRRFreeCrtcInfo(x11->randr.crtcs[i]);
74 free(x11->randr.crtcs);
76 XRRFreeScreenResources(x11->randr.res);
77 x11->randr.res = NULL;
78 x11->randr.outputs = NULL;
79 x11->randr.crtcs = NULL;
82 static int update_randr_res(struct vdagent_x11 *x11)
84 int i;
86 free_randr_resources(x11);
87 /* Note: we don't need XRRGetScreenResourcesCurrent since we cache the changes */
88 x11->randr.res = XRRGetScreenResources(x11->display, x11->root_window);
89 x11->randr.outputs = malloc(x11->randr.res->noutput * sizeof(*x11->randr.outputs));
90 x11->randr.crtcs = malloc(x11->randr.res->ncrtc * sizeof(*x11->randr.crtcs));
91 for (i = 0 ; i < x11->randr.res->noutput; ++i) {
92 x11->randr.outputs[i] = XRRGetOutputInfo(x11->display, x11->randr.res,
93 x11->randr.res->outputs[i]);
95 for (i = 0 ; i < x11->randr.res->ncrtc; ++i) {
96 x11->randr.crtcs[i] = XRRGetCrtcInfo(x11->display, x11->randr.res,
97 x11->randr.res->crtcs[i]);
99 /* XXX is this dynamic? should it be cached? */
100 if (XRRGetScreenSizeRange(x11->display, x11->root_window,
101 &x11->randr.min_width,
102 &x11->randr.min_height,
103 &x11->randr.max_width,
104 &x11->randr.max_height) != 1) {
105 fprintf(x11->errfile, "RRGetScreenSizeRange failed\n");
109 void vdagent_x11_randr_init(struct vdagent_x11 *x11)
111 int i;
113 if (XRRQueryExtension(x11->display, &i, &i)) {
114 x11->has_xrandr = 1;
115 if (!update_randr_res(x11)) {
116 fprintf(x11->errfile, "get screen info failed\n");
118 XRRQueryVersion(x11->display, &x11->xrandr_major, &x11->xrandr_minor);
119 } else {
120 x11->randr.res = NULL;
123 if (XineramaQueryExtension(x11->display, &i, &i))
124 x11->has_xinerama = 1;
126 switch (x11->has_xrandr << 4 | x11->has_xinerama) {
127 case 0x00:
128 fprintf(x11->errfile, "Neither Xrandr nor Xinerama found, assuming single monitor setup\n");
129 break;
130 case 0x01:
131 if (x11->verbose)
132 fprintf(x11->errfile, "Found Xinerama extension without Xrandr, assuming a multi monitor setup\n");
133 break;
134 case 0x10:
135 fprintf(x11->errfile, "Found Xrandr but no Xinerama, weird! Assuming a single monitor setup\n");
136 break;
137 case 0x11:
138 /* Standard single monitor setup, nothing to see here */
139 break;
143 static XRRModeInfo *
144 find_mode_by_name (struct vdagent_x11 *x11, char *name)
146 int m;
147 XRRModeInfo *ret = NULL;
149 for (m = 0; m < x11->randr.res->nmode; m++) {
150 XRRModeInfo *mode = &x11->randr.res->modes[m];
151 if (!strcmp (name, mode->name)) {
152 ret = mode;
153 break;
156 return ret;
159 static XRRModeInfo *
160 find_mode_by_size (struct vdagent_x11 *x11, int width, int height)
162 int m;
163 XRRModeInfo *ret = NULL;
165 for (m = 0; m < x11->randr.res->nmode; m++) {
166 XRRModeInfo *mode = &x11->randr.res->modes[m];
167 if (mode->width == width && mode->height == height) {
168 ret = mode;
169 break;
172 return ret;
175 static int mode_in_use(struct vdagent_x11 *x11, int xid, const char *name)
177 int m;
178 XRRModeInfo *mode;
179 XRROutputInfo *output_info;
180 int crtc;
182 output_info = XRRGetOutputInfo(x11->display, x11->randr.res, xid);
183 crtc = output_info->crtc;
184 XRRFreeOutputInfo(output_info);
185 if (!crtc) {
186 return 0;
188 for (m = 0 ; m < x11->randr.res->nmode; ++m) {
189 mode = &x11->randr.res->modes[m];
190 if (strcmp(mode->name, name) == 0) {
191 return 1;
194 return 0;
197 static void delete_mode(struct vdagent_x11 *x11, int output_index, const char *name)
199 int m;
200 XRRModeInfo *mode;
201 XRRModeInfo *the_mode;
202 XRROutputInfo *output_info;
203 XRRCrtcInfo *crtc_info;
204 RRCrtc crtc;
205 int current_mode = -1;
207 output_info = x11->randr.outputs[output_index];
208 if (output_info->ncrtc != 1) {
209 fprintf(x11->errfile,
210 "output has %d crtcs, expected exactly 1, "
211 "failed to delete mode\n",
212 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 the_mode = NULL;
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 the_mode = mode;
223 break;
226 if (the_mode) {
227 if (crtc && the_mode->id == current_mode) {
228 fprintf(x11->errfile,
229 "delete_mode of in use mode, setting crtc to NULL mode\n");
230 XRRSetCrtcConfig(x11->display, x11->randr.res, crtc,
231 CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0);
233 XRRDeleteOutputMode (x11->display, x11->randr.res->outputs[output_index],
234 mode->id);
235 XRRDestroyMode (x11->display, mode->id);
239 void set_reduced_cvt_mode(XRRModeInfo *mode, int width, int height)
241 /* Code taken from hw/xfree86/modes/xf86cvt.c
242 * See that file for lineage. Originated in public domain code
243 * Would be nice if xorg exported this in a library */
245 /* 1) top/bottom margin size (% of height) - default: 1.8 */
246 #define CVT_MARGIN_PERCENTAGE 1.8
248 /* 2) character cell horizontal granularity (pixels) - default 8 */
249 #define CVT_H_GRANULARITY 8
251 /* 4) Minimum vertical porch (lines) - default 3 */
252 #define CVT_MIN_V_PORCH 3
254 /* 4) Minimum number of vertical back porch lines - default 6 */
255 #define CVT_MIN_V_BPORCH 6
257 /* Pixel Clock step (kHz) */
258 #define CVT_CLOCK_STEP 250
260 /* Minimum vertical blanking interval time (µs) - default 460 */
261 #define CVT_RB_MIN_VBLANK 460.0
263 /* Fixed number of clocks for horizontal sync */
264 #define CVT_RB_H_SYNC 32.0
266 /* Fixed number of clocks for horizontal blanking */
267 #define CVT_RB_H_BLANK 160.0
269 /* Fixed number of lines for vertical front porch - default 3 */
270 #define CVT_RB_VFPORCH 3
272 int VBILines;
273 float VFieldRate = 60.0;
274 int VSync;
275 float HPeriod;
277 /* 2. Horizontal pixels */
278 width = width - (width % CVT_H_GRANULARITY);
280 mode->width = width;
281 mode->height = height;
282 VSync = 10;
284 /* 8. Estimate Horizontal period. */
285 HPeriod = ((float) (1000000.0 / VFieldRate - CVT_RB_MIN_VBLANK)) / height;
287 /* 9. Find number of lines in vertical blanking */
288 VBILines = ((float) CVT_RB_MIN_VBLANK) / HPeriod + 1;
290 /* 10. Check if vertical blanking is sufficient */
291 if (VBILines < (CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH))
292 VBILines = CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH;
294 /* 11. Find total number of lines in vertical field */
295 mode->vTotal = height + VBILines;
297 /* 12. Find total number of pixels in a line */
298 mode->hTotal = mode->width + CVT_RB_H_BLANK;
300 /* Fill in HSync values */
301 mode->hSyncEnd = mode->width + CVT_RB_H_BLANK / 2;
302 mode->hSyncStart = mode->hSyncEnd - CVT_RB_H_SYNC;
304 /* Fill in VSync values */
305 mode->vSyncStart = mode->height + CVT_RB_VFPORCH;
306 mode->vSyncEnd = mode->vSyncStart + VSync;
308 /* 15/13. Find pixel clock frequency (kHz for xf86) */
309 mode->dotClock = mode->hTotal * 1000.0 / HPeriod;
310 mode->dotClock -= mode->dotClock % CVT_CLOCK_STEP;
314 static XRRModeInfo *create_new_mode(struct vdagent_x11 *x11, int output_index,
315 int width, int height)
317 char modename[20];
318 XRRModeInfo mode;
320 /* we may be using this mode from an old invocation - check first */
321 snprintf(modename, sizeof(modename), "vdagent-%d", output_index);
322 arm_error_handler(x11);
323 delete_mode(x11, output_index, modename);
324 check_error_handler(x11);
325 if (x11->set_crtc_config_not_functional) {
326 return NULL;
328 mode.hSkew = 0;
329 mode.name = modename;
330 mode.nameLength = strlen(mode.name);
331 set_reduced_cvt_mode(&mode, width, height);
332 mode.modeFlags = 0;
333 mode.id = 0;
335 XRRCreateMode (x11->display, x11->root_window, &mode);
336 /* silly to update everytime for more then one monitor */
337 if (!update_randr_res(x11)) {
338 fprintf(x11->errfile, "get screen info failed\n");
340 return find_mode_by_name(x11, modename);
343 static int xrandr_add_and_set(struct vdagent_x11 *x11, int output, int x, int y,
344 int width, int height)
346 XRRModeInfo *mode;
347 int xid;
348 Status s;
349 RROutput outputs[1];
351 if (!x11->randr.res || output >= x11->randr.res->noutput || output < 0) {
352 fprintf(x11->errfile, "%s: program error: missing RANDR or bad output\n",
353 __FUNCTION__);
354 return 0;
356 if (x11->set_crtc_config_not_functional) {
357 /* succeed without doing anything. set_best_mode will
358 * find something close. */
359 return 1;
361 xid = x11->randr.res->outputs[output];
362 mode = find_mode_by_size(x11, width, height);
363 if (!mode) {
364 mode = create_new_mode(x11, output, width, height);
366 if (!mode) {
367 fprintf(x11->errfile, "failed to add a new mode\n");
368 return 0;
370 XRRAddOutputMode(x11->display, xid, mode->id); // Call this anyway?
371 outputs[0] = xid;
372 s = XRRSetCrtcConfig(x11->display, x11->randr.res, x11->randr.res->crtcs[output],
373 CurrentTime, x, y, mode->id, RR_Rotate_0, outputs,
375 if (s != RRSetConfigSuccess) {
376 fprintf(x11->errfile, "failed to XRRSetCrtcConfig\n");
377 // TODO - return crtc config to default
378 return 0;
380 return 1;
383 static int set_screen_to_best_size(struct vdagent_x11 *x11, int width, int height,
384 int *out_width, int *out_height){
385 int i, num_sizes = 0;
386 int best = -1;
387 unsigned int closest_diff = -1;
388 XRRScreenSize *sizes;
389 XRRScreenConfiguration *config;
390 Rotation rotation;
392 sizes = XRRSizes(x11->display, x11->screen, &num_sizes);
393 if (!sizes || !num_sizes) {
394 fprintf(x11->errfile, "XRRSizes failed\n");
395 return 0;
398 /* Find the closest size which will fit within the monitor */
399 for (i = 0; i < num_sizes; i++) {
400 if (sizes[i].width > width ||
401 sizes[i].height > height)
402 continue; /* Too large for the monitor */
404 unsigned int wdiff = width - sizes[i].width;
405 unsigned int hdiff = height - sizes[i].height;
406 unsigned int diff = wdiff * wdiff + hdiff * hdiff;
407 if (diff < closest_diff) {
408 closest_diff = diff;
409 best = i;
413 if (best == -1) {
414 fprintf(x11->errfile, "no suitable resolution found for monitor\n");
415 return 0;
418 config = XRRGetScreenInfo(x11->display, x11->root_window);
419 if(!config) {
420 fprintf(x11->errfile, "get screen info failed\n");
421 return 0;
423 XRRConfigCurrentConfiguration(config, &rotation);
424 XRRSetScreenConfig(x11->display, config, x11->root_window, best,
425 rotation, CurrentTime);
426 XRRFreeScreenConfigInfo(config);
428 *out_width = sizes[best].width;
429 *out_height = sizes[best].height;
430 return 1;
433 void vdagent_x11_randr_handle_root_size_change(struct vdagent_x11 *x11,
434 int width, int height)
436 if (width == x11->width && height == x11->height) {
437 return;
440 x11->width = width;
441 x11->height = height;
442 if (!x11->dont_send_guest_xorg_res) {
443 vdagent_x11_send_daemon_guest_xorg_res(x11);
447 static int min_int(int x, int y)
449 return x > y ? y : x;
452 static int max_int(int x, int y)
454 return x > y ? x : y;
457 int constrain_to_range(int low, int *val, int high)
459 if (low <= *val && *val <= high) {
460 return 0;
462 if (low > *val) {
463 *val = low;
465 if (*val > high) {
466 *val = high;
468 return 1;
471 void constrain_to_screen(struct vdagent_x11 *x11, int *w, int *h)
473 int lx, ly, hx, hy;
474 int orig_h = *h;
475 int orig_w = *w;
477 lx = x11->randr.min_width;
478 hx = x11->randr.max_width;
479 ly = x11->randr.min_height;
480 hy = x11->randr.max_height;
481 if (constrain_to_range(lx, w, hx)) {
482 fprintf(x11->errfile,
483 "width not in driver range: ! %d < %d < %d\n",
484 lx, orig_w, hx);
486 if (constrain_to_range(ly, h, hy)) {
487 fprintf(x11->errfile,
488 "height not in driver range: ! %d < %d < %d\n",
489 ly, orig_h, hy);
494 * The agent config doesn't contain a primary size, just the monitors, but
495 * we need to total size as well, to make sure we have enough memory and
496 * because X needs it.
498 * At the same pass constrain any provided size to what the server accepts.
500 * Exit axioms:
501 * x >= 0, y >= 0 for all x, y in mon_config
502 * max_width >= width >= min_width,
503 * max_height >= height >= min_height for all monitors in mon_config
505 static void zero_base_monitors(struct vdagent_x11 *x11,
506 VDAgentMonitorsConfig *mon_config,
507 int *width, int *height)
509 int i = 0;
510 int min_x;
511 int min_y;
512 int max_x;
513 int max_y;
514 int *mon_height;
515 int *mon_width;
517 mon_width = &mon_config->monitors[i].width;
518 mon_height = &mon_config->monitors[i].height;
519 constrain_to_screen(x11, mon_width, mon_height);
520 min_x = mon_config->monitors[0].x;
521 min_y = mon_config->monitors[0].y;
522 max_x = mon_config->monitors[0].width + min_x;
523 max_y = mon_config->monitors[0].height + min_y;
524 for (++i ; i < mon_config->num_of_monitors; ++i) {
525 mon_width = &mon_config->monitors[i].width;
526 mon_height = &mon_config->monitors[i].height;
527 constrain_to_screen(x11, mon_width, mon_height);
528 min_x = min_int(mon_config->monitors[i].x, min_x);
529 min_y = min_int(mon_config->monitors[i].y, min_y);
530 max_x = max_int(mon_config->monitors[i].x + *mon_width, max_x);
531 max_y = max_int(mon_config->monitors[i].y + *mon_height, max_y);
533 if (min_x != 0 || min_y != 0) {
534 fprintf(x11->errfile,
535 "%s: agent config %d,%d rooted, adjusting to 0,0.\n",
536 __FUNCTION__, min_x, min_y);
537 for (i = 0 ; i < mon_config->num_of_monitors; ++i) {
538 mon_config->monitors[i].x -= min_x;
539 mon_config->monitors[i].y -= min_y;
542 max_x -= min_x;
543 max_y -= min_y;
544 *width = max_x;
545 *height = max_y;
548 int same_monitor_configs(struct vdagent_x11 *x11, VDAgentMonitorsConfig *mon)
550 int i;
551 XRRModeInfo *mode;
552 XRRCrtcInfo *crtc;
553 VDAgentMonConfig *client_mode;
554 XRRScreenResources *res = x11->randr.res;
556 if (res->noutput > res->ncrtc) {
557 fprintf(x11->errfile, "error: unexpected noutput > ncrtc in driver\n");
558 return 0;
561 if (mon->num_of_monitors > res->noutput) {
562 fprintf(x11->errfile, "error: unexpected client request: "
563 "#mon %d > driver output %d\n",
564 mon->num_of_monitors, res->noutput);
565 return 0;
568 for (i = 0 ; i < mon->num_of_monitors; ++i) {
569 if (x11->randr.outputs[i]->ncrtc == 0) {
570 return 0;
572 if (x11->randr.outputs[i]->ncrtc != 1) {
573 fprintf(x11->errfile,
574 "error: unexpected driver config, ncrtc %d != 1",
575 x11->randr.outputs[i]->ncrtc);
576 return 0;
578 crtc = crtc_from_id(x11, x11->randr.outputs[i]->crtcs[0]);
579 if (!crtc) {
580 fprintf(x11->errfile, "error: inconsistent or stale data from X\n");
581 return 0;
583 client_mode = &mon->monitors[i];
584 mode = mode_from_id(x11, crtc->mode);
585 if (!mode) {
586 return 0;
588 /* NOTE: we don't compare depth. */
589 /* NOTE 2: width set by X is a multiple of 8, so ignore lower 3 bits */
590 if ((mode->width & ~7) != (client_mode->width & ~7) ||
591 mode->height != client_mode->height ||
592 (crtc->x & ~7) != (client_mode->x & ~7) ||
593 crtc->y != client_mode->y) {
594 return 0;
597 return 1;
600 static void dump_monitors_config(struct vdagent_x11 *x11,
601 VDAgentMonitorsConfig *mon_config,
602 const char *prefix)
604 int i;
605 VDAgentMonConfig *m;
607 fprintf(x11->errfile, "%s: %d, %x\n", prefix, mon_config->num_of_monitors,
608 mon_config->flags);
609 for (i = 0 ; i < mon_config->num_of_monitors; ++i) {
610 m = &mon_config->monitors[i];
611 fprintf(x11->errfile, "received monitor %d config %dx%d+%d+%d\n", i,
612 m->width, m->height, m->x, m->y);
617 * Set monitor configuration according to client request.
619 * On exit send current configuration to client, regardless of error.
621 * Errors:
622 * screen size too large for driver to handle. (we set the largest/smallest possible)
623 * no randr support in X server.
624 * invalid configuration request from client.
626 void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11,
627 VDAgentMonitorsConfig *mon_config)
629 int i;
630 int width, height;
631 int x, y;
632 int primary_w, primary_h;
633 Status s;
635 if (!x11->has_xrandr)
636 goto exit;
638 if (mon_config->num_of_monitors < 1) {
639 fprintf(x11->errfile, "client sent invalid monitor config number %d\n",
640 mon_config->num_of_monitors);
641 goto exit;
644 if (same_monitor_configs(x11, mon_config)) {
645 goto exit;
648 if (x11->verbose) {
649 dump_monitors_config(x11, mon_config, "from guest");
652 zero_base_monitors(x11, mon_config, &primary_w, &primary_h);
654 constrain_to_screen(x11, &primary_w, &primary_h);
656 if (x11->verbose) {
657 dump_monitors_config(x11, mon_config, "after zeroing");
660 for (i = 0; i < mon_config->num_of_monitors; ++i) {
661 /* Try to create the requested resolution */
662 width = mon_config->monitors[i].width;
663 height = mon_config->monitors[i].height;
664 x = mon_config->monitors[i].x;
665 y = mon_config->monitors[i].y;
666 if (!xrandr_add_and_set(x11, i, x, y, width, height) &&
667 mon_config->num_of_monitors == 1) {
668 set_screen_to_best_size(x11, width, height, &width, &height);
672 if (primary_w != x11->width || primary_h != x11->height) {
673 arm_error_handler(x11);
674 XRRSetScreenSize(x11->display, x11->root_window, primary_w, primary_h,
675 DisplayWidthMM(x11->display, x11->screen),
676 DisplayHeightMM(x11->display, x11->screen));
677 check_error_handler(x11);
680 if (!update_randr_res(x11)) {
681 fprintf(x11->errfile, "get screen info failed\n");
683 x11->width = primary_w;
684 x11->height = primary_h;
686 /* Flush output buffers and consume any pending events (ConfigureNotify) */
687 x11->dont_send_guest_xorg_res = 1;
688 vdagent_x11_do_read(x11);
689 x11->dont_send_guest_xorg_res = 0;
691 exit:
692 vdagent_x11_send_daemon_guest_xorg_res(x11);
694 /* Flush output buffers and consume any pending events */
695 vdagent_x11_do_read(x11);
698 void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11)
700 struct vdagentd_guest_xorg_resolution *res = NULL;
701 XineramaScreenInfo *screen_info = NULL;
702 int i, screen_count = 0;
704 if (x11->has_xinerama) {
705 /* Xinerama reports the same information RANDR reports, so stay
706 * with Xinerama for support of Xinerama only setups */
707 screen_info = XineramaQueryScreens(x11->display, &screen_count);
710 if (screen_count == 0)
711 screen_count = 1;
713 res = malloc(screen_count * sizeof(*res));
714 if (!res) {
715 fprintf(x11->errfile, "out of memory while trying to send resolutions, not sending resolutions.\n");
716 if (screen_info)
717 XFree(screen_info);
718 return;
721 if (screen_info) {
722 for (i = 0; i < screen_count; i++) {
723 if (screen_info[i].screen_number >= screen_count) {
724 fprintf(x11->errfile, "Invalid screen number in xinerama screen info (%d >= %d)\n",
725 screen_info[i].screen_number, screen_count);
726 XFree(screen_info);
727 free(res);
728 return;
730 res[screen_info[i].screen_number].width = screen_info[i].width;
731 res[screen_info[i].screen_number].height = screen_info[i].height;
732 res[screen_info[i].screen_number].x = screen_info[i].x_org;
733 res[screen_info[i].screen_number].y = screen_info[i].y_org;
735 XFree(screen_info);
736 } else {
737 res[0].width = x11->width;
738 res[0].height = x11->height;
739 res[0].x = 0;
740 res[0].y = 0;
743 udscs_write(x11->vdagentd, VDAGENTD_GUEST_XORG_RESOLUTION, x11->width,
744 x11->height, (uint8_t *)res, screen_count * sizeof(*res));
745 free(res);