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/>.
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
)
43 static void arm_error_handler(struct vdagent_x11
*x11
)
46 XSync(x11
->display
, False
);
47 old_error_handler
= XSetErrorHandler(error_handler
);
50 static int check_error_handler(struct vdagent_x11
*x11
)
54 XSync(x11
->display
, False
);
55 XSetErrorHandler(old_error_handler
);
62 static XRRModeInfo
*mode_from_id(struct vdagent_x11
*x11
, int id
)
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
];
74 static XRRCrtcInfo
*crtc_from_id(struct vdagent_x11
*x11
, int id
)
78 for (i
= 0 ; i
< x11
->randr
.res
->ncrtc
; ++i
) {
79 if (id
== x11
->randr
.res
->crtcs
[i
]) {
80 return x11
->randr
.crtcs
[i
];
86 static void free_randr_resources(struct vdagent_x11
*x11
)
90 if (!x11
->randr
.res
) {
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
;
109 x11
->randr
.num_monitors
= 0;
112 static void update_randr_res(struct vdagent_x11
*x11
)
116 free_randr_resources(x11
);
117 /* Note: we don't need XRRGetScreenResourcesCurrent since we cache the changes */
118 x11
->randr
.res
= XRRGetScreenResources(x11
->display
, x11
->root_window
);
119 x11
->randr
.outputs
= malloc(x11
->randr
.res
->noutput
* sizeof(*x11
->randr
.outputs
));
120 x11
->randr
.crtcs
= malloc(x11
->randr
.res
->ncrtc
* sizeof(*x11
->randr
.crtcs
));
121 for (i
= 0 ; i
< x11
->randr
.res
->noutput
; ++i
) {
122 x11
->randr
.outputs
[i
] = XRRGetOutputInfo(x11
->display
, x11
->randr
.res
,
123 x11
->randr
.res
->outputs
[i
]);
124 if (x11
->randr
.outputs
[i
]->connection
== RR_Connected
)
125 x11
->randr
.num_monitors
++;
127 for (i
= 0 ; i
< x11
->randr
.res
->ncrtc
; ++i
) {
128 x11
->randr
.crtcs
[i
] = XRRGetCrtcInfo(x11
->display
, x11
->randr
.res
,
129 x11
->randr
.res
->crtcs
[i
]);
131 /* XXX is this dynamic? should it be cached? */
132 if (XRRGetScreenSizeRange(x11
->display
, x11
->root_window
,
133 &x11
->randr
.min_width
,
134 &x11
->randr
.min_height
,
135 &x11
->randr
.max_width
,
136 &x11
->randr
.max_height
) != 1) {
137 syslog(LOG_ERR
, "update_randr_res: RRGetScreenSizeRange failed");
141 void vdagent_x11_randr_init(struct vdagent_x11
*x11
)
145 if (XRRQueryExtension(x11
->display
, &i
, &i
)) {
147 update_randr_res(x11
);
148 XRRQueryVersion(x11
->display
, &x11
->xrandr_major
, &x11
->xrandr_minor
);
150 x11
->randr
.res
= NULL
;
153 if (XineramaQueryExtension(x11
->display
, &i
, &i
))
154 x11
->has_xinerama
= 1;
156 switch (x11
->has_xrandr
<< 4 | x11
->has_xinerama
) {
158 syslog(LOG_ERR
, "Neither Xrandr nor Xinerama found, assuming single monitor setup");
162 syslog(LOG_DEBUG
, "Found Xinerama extension without Xrandr, assuming Xinerama multi monitor setup");
165 syslog(LOG_ERR
, "Found Xrandr but no Xinerama, weird!");
168 /* Standard xrandr setup, nothing to see here */
174 find_mode_by_name (struct vdagent_x11
*x11
, char *name
)
177 XRRModeInfo
*ret
= NULL
;
179 for (m
= 0; m
< x11
->randr
.res
->nmode
; m
++) {
180 XRRModeInfo
*mode
= &x11
->randr
.res
->modes
[m
];
181 if (!strcmp (name
, mode
->name
)) {
190 find_mode_by_size (struct vdagent_x11
*x11
, int width
, int height
)
193 XRRModeInfo
*ret
= NULL
;
195 for (m
= 0; m
< x11
->randr
.res
->nmode
; m
++) {
196 XRRModeInfo
*mode
= &x11
->randr
.res
->modes
[m
];
197 if (mode
->width
== width
&& mode
->height
== height
) {
205 static void delete_mode(struct vdagent_x11
*x11
, int output_index
, const char* name
)
209 XRROutputInfo
*output_info
;
210 XRRCrtcInfo
*crtc_info
;
212 int current_mode
= -1;
215 syslog(LOG_DEBUG
, "Deleting mode %s", name
);
217 output_info
= x11
->randr
.outputs
[output_index
];
218 if (output_info
->ncrtc
!= 1) {
219 syslog(LOG_ERR
, "output has %d crtcs, expected exactly 1, "
220 "failed to delete mode", output_info
->ncrtc
);
223 crtc_info
= crtc_from_id(x11
, output_info
->crtcs
[0]);
224 current_mode
= crtc_info
->mode
;
225 crtc
= output_info
->crtc
;
226 for (m
= 0 ; m
< x11
->randr
.res
->nmode
; ++m
) {
227 mode
= &x11
->randr
.res
->modes
[m
];
228 if (strcmp(mode
->name
, name
) == 0)
231 if (m
< x11
->randr
.res
->nmode
) {
232 arm_error_handler(x11
);
233 XRRDeleteOutputMode (x11
->display
, x11
->randr
.res
->outputs
[output_index
],
235 XRRDestroyMode (x11
->display
, mode
->id
);
236 // ignore race error, if mode is created by others
237 check_error_handler(x11
);
240 /* silly to update everytime for more then one monitor */
241 update_randr_res(x11
);
244 static void set_reduced_cvt_mode(XRRModeInfo
*mode
, int width
, int height
)
246 /* Code taken from hw/xfree86/modes/xf86cvt.c
247 * See that file for lineage. Originated in public domain code
248 * Would be nice if xorg exported this in a library */
250 /* 1) top/bottom margin size (% of height) - default: 1.8 */
251 #define CVT_MARGIN_PERCENTAGE 1.8
253 /* 2) character cell horizontal granularity (pixels) - default 8 */
254 #define CVT_H_GRANULARITY 8
256 /* 4) Minimum vertical porch (lines) - default 3 */
257 #define CVT_MIN_V_PORCH 3
259 /* 4) Minimum number of vertical back porch lines - default 6 */
260 #define CVT_MIN_V_BPORCH 6
262 /* Pixel Clock step (kHz) */
263 #define CVT_CLOCK_STEP 250
265 /* Minimum vertical blanking interval time (µs) - default 460 */
266 #define CVT_RB_MIN_VBLANK 460.0
268 /* Fixed number of clocks for horizontal sync */
269 #define CVT_RB_H_SYNC 32.0
271 /* Fixed number of clocks for horizontal blanking */
272 #define CVT_RB_H_BLANK 160.0
274 /* Fixed number of lines for vertical front porch - default 3 */
275 #define CVT_RB_VFPORCH 3
278 float VFieldRate
= 60.0;
282 /* 2. Horizontal pixels */
283 width
= width
- (width
% CVT_H_GRANULARITY
);
286 mode
->height
= height
;
289 /* 8. Estimate Horizontal period. */
290 HPeriod
= ((float) (1000000.0 / VFieldRate
- CVT_RB_MIN_VBLANK
)) / height
;
292 /* 9. Find number of lines in vertical blanking */
293 VBILines
= ((float) CVT_RB_MIN_VBLANK
) / HPeriod
+ 1;
295 /* 10. Check if vertical blanking is sufficient */
296 if (VBILines
< (CVT_RB_VFPORCH
+ VSync
+ CVT_MIN_V_BPORCH
))
297 VBILines
= CVT_RB_VFPORCH
+ VSync
+ CVT_MIN_V_BPORCH
;
299 /* 11. Find total number of lines in vertical field */
300 mode
->vTotal
= height
+ VBILines
;
302 /* 12. Find total number of pixels in a line */
303 mode
->hTotal
= mode
->width
+ CVT_RB_H_BLANK
;
305 /* Fill in HSync values */
306 mode
->hSyncEnd
= mode
->width
+ CVT_RB_H_BLANK
/ 2;
307 mode
->hSyncStart
= mode
->hSyncEnd
- CVT_RB_H_SYNC
;
309 /* Fill in VSync values */
310 mode
->vSyncStart
= mode
->height
+ CVT_RB_VFPORCH
;
311 mode
->vSyncEnd
= mode
->vSyncStart
+ VSync
;
313 /* 15/13. Find pixel clock frequency (kHz for xf86) */
314 mode
->dotClock
= mode
->hTotal
* 1000.0 / HPeriod
;
315 mode
->dotClock
-= mode
->dotClock
% CVT_CLOCK_STEP
;
319 static XRRModeInfo
*create_new_mode(struct vdagent_x11
*x11
, int output_index
,
320 int width
, int height
)
325 snprintf(modename
, sizeof(modename
), "%dx%d-%d", width
, height
, output_index
);
327 mode
.name
= modename
;
328 mode
.nameLength
= strlen(mode
.name
);
329 set_reduced_cvt_mode(&mode
, width
, height
);
332 arm_error_handler(x11
);
333 XRRCreateMode (x11
->display
, x11
->root_window
, &mode
);
334 // ignore race error, if mode is created by others
335 check_error_handler(x11
);
337 /* silly to update everytime for more then one monitor */
338 update_randr_res(x11
);
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
)
352 if (!x11
->randr
.res
|| output
>= x11
->randr
.res
->noutput
|| output
< 0) {
353 syslog(LOG_ERR
, "%s: program error: missing RANDR or bad output",
357 if (x11
->set_crtc_config_not_functional
) {
358 /* fail, set_best_mode will find something close. */
361 xid
= x11
->randr
.res
->outputs
[output
];
362 mode
= find_mode_by_size(x11
, width
, height
);
364 mode
= create_new_mode(x11
, output
, width
, height
);
367 syslog(LOG_ERR
, "failed to add a new mode");
370 XRRAddOutputMode(x11
->display
, xid
, mode
->id
);
372 s
= XRRSetCrtcConfig(x11
->display
, x11
->randr
.res
, x11
->randr
.res
->crtcs
[output
],
373 CurrentTime
, x
, y
, mode
->id
, RR_Rotate_0
, outputs
,
376 if (s
!= RRSetConfigSuccess
) {
377 syslog(LOG_ERR
, "failed to XRRSetCrtcConfig");
378 x11
->set_crtc_config_not_functional
= 1;
382 /* clean the previous name, if any */
383 snprintf(modename
, sizeof(modename
), "%dx%d-%d", x11
->width
, x11
->height
, output
);
384 delete_mode(x11
, output
, modename
);
389 static void xrandr_disable_output(struct vdagent_x11
*x11
, int output
)
393 if (!x11
->randr
.res
|| output
>= x11
->randr
.res
->noutput
|| output
< 0) {
394 syslog(LOG_ERR
, "%s: program error: missing RANDR or bad output",
399 s
= XRRSetCrtcConfig(x11
->display
, x11
->randr
.res
,
400 x11
->randr
.res
->crtcs
[output
],
401 CurrentTime
, 0, 0, None
, RR_Rotate_0
,
404 if (s
!= RRSetConfigSuccess
)
405 syslog(LOG_ERR
, "failed to disable monitor");
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
, x11
->screen
, &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
);
447 syslog(LOG_ERR
, "get screen info failed");
450 XRRConfigCurrentConfiguration(config
, &rotation
);
451 XRRSetScreenConfig(x11
->display
, config
, x11
->root_window
, 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 width
, int height
)
466 if (width
== x11
->width
&& height
== x11
->height
) {
471 syslog(LOG_DEBUG
, "Root size changed to %dx%d send %d",
472 width
, height
, !x11
->dont_send_guest_xorg_res
);
475 x11
->height
= height
;
476 if (!x11
->dont_send_guest_xorg_res
) {
477 vdagent_x11_send_daemon_guest_xorg_res(x11
);
481 static uint32_t min_int(uint32_t x
, uint32_t y
)
483 return x
> y
? y
: x
;
486 static uint32_t max_int(uint32_t x
, uint32_t y
)
488 return x
> y
? x
: y
;
491 static int constrain_to_range(uint32_t low
, uint32_t *val
, uint32_t high
)
493 if (low
<= *val
&& *val
<= high
) {
505 static void constrain_to_screen(struct vdagent_x11
*x11
, uint32_t *w
, uint32_t *h
)
507 uint32_t lx
, ly
, hx
, hy
;
508 uint32_t orig_h
= *h
;
509 uint32_t orig_w
= *w
;
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",
526 * The agent config doesn't contain a primary size, just the monitors, but
527 * we need to total size as well, to make sure we have enough memory and
528 * because X needs it.
530 * At the same pass constrain any provided size to what the server accepts.
533 * x >= 0, y >= 0 for all x, y in mon_config
534 * max_width >= width >= min_width,
535 * max_height >= height >= min_height for all monitors in mon_config
537 static void zero_base_monitors(struct vdagent_x11
*x11
,
538 VDAgentMonitorsConfig
*mon_config
,
539 uint32_t *width
, uint32_t *height
)
542 uint32_t min_x
, min_y
, max_x
, max_y
;
543 uint32_t *mon_height
, *mon_width
;
545 mon_config
->monitors
[0].x
&= ~7;
546 mon_config
->monitors
[0].width
&= ~7;
547 mon_width
= &mon_config
->monitors
[i
].width
;
548 mon_height
= &mon_config
->monitors
[i
].height
;
549 constrain_to_screen(x11
, mon_width
, mon_height
);
550 min_x
= mon_config
->monitors
[0].x
;
551 min_y
= mon_config
->monitors
[0].y
;
552 max_x
= mon_config
->monitors
[0].width
+ min_x
;
553 max_y
= mon_config
->monitors
[0].height
+ min_y
;
554 for (++i
; i
< mon_config
->num_of_monitors
; ++i
) {
555 mon_config
->monitors
[i
].x
&= ~7;
556 mon_config
->monitors
[i
].width
&= ~7;
557 mon_width
= &mon_config
->monitors
[i
].width
;
558 mon_height
= &mon_config
->monitors
[i
].height
;
559 constrain_to_screen(x11
, mon_width
, mon_height
);
560 min_x
= min_int(mon_config
->monitors
[i
].x
, min_x
);
561 min_y
= min_int(mon_config
->monitors
[i
].y
, min_y
);
562 max_x
= max_int(mon_config
->monitors
[i
].x
+ *mon_width
, max_x
);
563 max_y
= max_int(mon_config
->monitors
[i
].y
+ *mon_height
, max_y
);
565 if (min_x
!= 0 || min_y
!= 0) {
566 syslog(LOG_ERR
, "%s: agent config %d,%d rooted, adjusting to 0,0.",
567 __FUNCTION__
, min_x
, min_y
);
568 for (i
= 0 ; i
< mon_config
->num_of_monitors
; ++i
) {
569 mon_config
->monitors
[i
].x
-= min_x
;
570 mon_config
->monitors
[i
].y
-= min_y
;
579 static int same_monitor_configs(struct vdagent_x11
*x11
,
580 VDAgentMonitorsConfig
*mon
,
581 uint32_t primary_w
, uint32_t primary_h
)
586 VDAgentMonConfig
*client_mode
;
587 XRRScreenResources
*res
;
589 update_randr_res(x11
);
590 res
= x11
->randr
.res
;
592 if (res
->noutput
> res
->ncrtc
) {
593 syslog(LOG_ERR
, "error: unexpected noutput > ncrtc in driver");
597 if (mon
->num_of_monitors
> res
->noutput
) {
598 for (i
= res
->noutput
; i
< mon
->num_of_monitors
; i
++) {
599 if (mon
->monitors
[i
].width
|| mon
->monitors
[i
].height
) {
601 "warning: unexpected client request: #mon %d > driver output %d",
602 mon
->num_of_monitors
, res
->noutput
);
606 mon
->num_of_monitors
= res
->noutput
;
609 if (x11
->width
!= primary_w
|| x11
->height
!= primary_h
)
612 if (x11
->randr
.num_monitors
!= mon
->num_of_monitors
)
615 for (i
= 0 ; i
< mon
->num_of_monitors
; ++i
) {
616 if (x11
->randr
.outputs
[i
]->ncrtc
== 0) {
619 if (x11
->randr
.outputs
[i
]->ncrtc
!= 1) {
620 syslog(LOG_ERR
, "error: unexpected driver config, ncrtc %d != 1",
621 x11
->randr
.outputs
[i
]->ncrtc
);
624 crtc
= crtc_from_id(x11
, x11
->randr
.outputs
[i
]->crtcs
[0]);
626 syslog(LOG_ERR
, "error: inconsistent or stale data from X");
629 client_mode
= &mon
->monitors
[i
];
630 mode
= mode_from_id(x11
, crtc
->mode
);
634 /* NOTE: we don't compare depth. */
635 /* NOTE 2: width set by X is a multiple of 8, so ignore lower 3 bits */
636 if ((mode
->width
& ~7) != (client_mode
->width
& ~7) ||
637 mode
->height
!= client_mode
->height
||
638 (crtc
->x
& ~7) != (client_mode
->x
& ~7) ||
639 crtc
->y
!= client_mode
->y
) {
646 static void dump_monitors_config(struct vdagent_x11
*x11
,
647 VDAgentMonitorsConfig
*mon_config
,
653 syslog(LOG_DEBUG
, "%s: %d, %x", prefix
, mon_config
->num_of_monitors
,
655 for (i
= 0 ; i
< mon_config
->num_of_monitors
; ++i
) {
656 m
= &mon_config
->monitors
[i
];
657 syslog(LOG_DEBUG
, "received monitor %d config %dx%d+%d+%d", i
,
658 m
->width
, m
->height
, m
->x
, m
->y
);
663 * Set monitor configuration according to client request.
665 * On exit send current configuration to client, regardless of error.
668 * screen size too large for driver to handle. (we set the largest/smallest possible)
669 * no randr support in X server.
670 * invalid configuration request from client.
672 void vdagent_x11_set_monitor_config(struct vdagent_x11
*x11
,
673 VDAgentMonitorsConfig
*mon_config
)
678 uint32_t primary_w
, primary_h
;
680 if (!x11
->has_xrandr
)
683 if (mon_config
->num_of_monitors
< 1) {
684 syslog(LOG_ERR
, "client sent invalid monitor config number %d",
685 mon_config
->num_of_monitors
);
690 dump_monitors_config(x11
, mon_config
, "from guest");
693 zero_base_monitors(x11
, mon_config
, &primary_w
, &primary_h
);
695 constrain_to_screen(x11
, &primary_w
, &primary_h
);
697 if (same_monitor_configs(x11
, mon_config
, primary_w
, primary_h
)) {
702 dump_monitors_config(x11
, mon_config
, "after zeroing");
705 for (i
= mon_config
->num_of_monitors
; i
< x11
->randr
.res
->noutput
; i
++)
706 xrandr_disable_output(x11
, i
);
708 for (i
= 0; i
< mon_config
->num_of_monitors
; ++i
) {
709 /* Try to create the requested resolution */
710 width
= mon_config
->monitors
[i
].width
;
711 height
= mon_config
->monitors
[i
].height
;
712 x
= mon_config
->monitors
[i
].x
;
713 y
= mon_config
->monitors
[i
].y
;
714 if (!xrandr_add_and_set(x11
, i
, x
, y
, width
, height
) &&
715 mon_config
->num_of_monitors
== 1) {
716 set_screen_to_best_size(x11
, width
, height
,
717 &primary_w
, &primary_h
);
722 if (primary_w
!= x11
->width
|| primary_h
!= x11
->height
) {
724 syslog(LOG_DEBUG
, "Changing screen size to %dx%d",
725 primary_w
, primary_h
);
726 arm_error_handler(x11
);
727 XRRSetScreenSize(x11
->display
, x11
->root_window
, primary_w
, primary_h
,
728 DisplayWidthMM(x11
->display
, x11
->screen
),
729 DisplayHeightMM(x11
->display
, x11
->screen
));
730 if (check_error_handler(x11
)) {
731 syslog(LOG_ERR
, "failed to XRRSetScreenSize");
732 x11
->set_crtc_config_not_functional
= 1;
737 update_randr_res(x11
);
738 x11
->width
= primary_w
;
739 x11
->height
= primary_h
;
741 /* Flush output buffers and consume any pending events (ConfigureNotify) */
742 x11
->dont_send_guest_xorg_res
= 1;
743 vdagent_x11_do_read(x11
);
744 x11
->dont_send_guest_xorg_res
= 0;
747 vdagent_x11_send_daemon_guest_xorg_res(x11
);
749 /* Flush output buffers and consume any pending events */
750 vdagent_x11_do_read(x11
);
753 void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11
*x11
)
755 struct vdagentd_guest_xorg_resolution
*res
= NULL
;
756 XineramaScreenInfo
*screen_info
= NULL
;
757 int i
, screen_count
= 0;
759 if (x11
->has_xinerama
) {
760 /* Xinerama reports the same information RANDR reports, so stay
761 * with Xinerama for support of Xinerama only setups */
762 screen_info
= XineramaQueryScreens(x11
->display
, &screen_count
);
765 if (screen_count
== 0)
768 res
= malloc(screen_count
* sizeof(*res
));
770 syslog(LOG_ERR
, "out of memory while trying to send resolutions, not sending resolutions.");
777 for (i
= 0; i
< screen_count
; i
++) {
778 if (screen_info
[i
].screen_number
>= screen_count
) {
779 syslog(LOG_ERR
, "Invalid screen number in xinerama screen info (%d >= %d)",
780 screen_info
[i
].screen_number
, screen_count
);
785 res
[screen_info
[i
].screen_number
].width
= screen_info
[i
].width
;
786 res
[screen_info
[i
].screen_number
].height
= screen_info
[i
].height
;
787 res
[screen_info
[i
].screen_number
].x
= screen_info
[i
].x_org
;
788 res
[screen_info
[i
].screen_number
].y
= screen_info
[i
].y_org
;
792 res
[0].width
= x11
->width
;
793 res
[0].height
= x11
->height
;
798 udscs_write(x11
->vdagentd
, VDAGENTD_GUEST_XORG_RESOLUTION
, x11
->width
,
799 x11
->height
, (uint8_t *)res
, screen_count
* sizeof(*res
));