1 /* vdagent-x11.c vdagent x11 code
3 Copyright 2010 Red Hat, Inc.
6 Hans de Goede <hdegoede@redhat.com>
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 /* Note *all* X11 calls in this file which do not wait for a result must be
23 followed by an XFlush, given that the X11 code pumping the event loop
24 (and thus flushing queued writes) is only called when there is data to be
25 read from the X11 socket. */
30 #include <X11/extensions/Xrandr.h>
31 #include "vdagentd-proto.h"
32 #include "vdagent-x11.h"
36 struct udscs_connection
*vdagentd
;
46 static void vdagent_x11_send_guest_xorg_res(struct vdagent_x11
*x11
);
48 struct vdagent_x11
*vdagent_x11_create(struct udscs_connection
*vdagentd
,
51 struct vdagent_x11
*x11
;
52 XWindowAttributes attrib
;
53 int xrandr_event_base
, xrandr_error_base
;
55 x11
= calloc(1, sizeof(*x11
));
57 fprintf(stderr
, "out of memory allocating vdagent_x11 struct\n");
61 x11
->vdagentd
= vdagentd
;
62 x11
->verbose
= verbose
;
64 x11
->display
= XOpenDisplay(NULL
);
66 fprintf(stderr
, "could not connect to X-server\n");
71 x11
->screen
= DefaultScreen(x11
->display
);
72 x11
->root_window
= RootWindow(x11
->display
, x11
->screen
);
73 x11
->fd
= ConnectionNumber(x11
->display
);
75 if (XRRQueryExtension(x11
->display
, &xrandr_event_base
, &xrandr_error_base
))
78 fprintf(stderr
, "no xrandr\n");
80 XSelectInput(x11
->display
, x11
->root_window
, StructureNotifyMask
);
81 XGetWindowAttributes(x11
->display
, x11
->root_window
, &attrib
);
83 x11
->width
= attrib
.width
;
84 x11
->height
= attrib
.height
;
86 vdagent_x11_send_guest_xorg_res(x11
);
91 void vdagent_x11_destroy(struct vdagent_x11
*x11
)
96 XCloseDisplay(x11
->display
);
100 int vdagent_x11_get_fd(struct vdagent_x11
*x11
)
105 void vdagent_x11_do_read(struct vdagent_x11
*x11
)
110 if (!XPending(x11
->display
))
113 XNextEvent(x11
->display
, &event
);
114 switch (event
.type
) {
115 case ConfigureNotify
:
116 if (event
.xconfigure
.window
!= x11
->root_window
)
121 if (event
.xconfigure
.width
== x11
->width
&&
122 event
.xconfigure
.height
== x11
->height
)
125 x11
->width
= event
.xconfigure
.width
;
126 x11
->height
= event
.xconfigure
.height
;
128 vdagent_x11_send_guest_xorg_res(x11
);
131 if (!handled
&& x11
->verbose
)
132 fprintf(stderr
, "unhandled x11 event, type %d, window %d\n",
133 (int)event
.type
, (int)event
.xany
.window
);
136 static void vdagent_x11_send_guest_xorg_res(struct vdagent_x11
*x11
)
138 struct vdagentd_guest_xorg_resolution res
;
139 struct udscs_message_header header
;
141 header
.type
= VDAGENTD_GUEST_XORG_RESOLUTION
;
143 header
.size
= sizeof(res
);
145 res
.width
= x11
->width
;
146 res
.height
= x11
->height
;
148 udscs_write(x11
->vdagentd
, &header
, (uint8_t *)&res
);
151 void vdagent_x11_set_monitor_config(struct vdagent_x11
*x11
,
152 VDAgentMonitorsConfig
*mon_config
)
154 int i
, num_sizes
= 0;
156 unsigned int closest_diff
= -1;
157 XRRScreenSize
* sizes
;
158 XRRScreenConfiguration
* config
;
161 if (!x11
->has_xrandr
)
164 if (mon_config
->num_of_monitors
!= 1) {
165 fprintf(stderr
, "Only 1 monitor supported, ignoring monitor config\n");
169 sizes
= XRRSizes(x11
->display
, x11
->screen
, &num_sizes
);
170 if (!sizes
|| !num_sizes
) {
171 fprintf(stderr
, "XRRSizes failed\n");
175 /* Find the closest size which will fit within the monitor */
176 for (i
= 0; i
< num_sizes
; i
++) {
177 if (sizes
[i
].width
> mon_config
->monitors
[0].width
||
178 sizes
[i
].height
> mon_config
->monitors
[0].height
)
179 continue; /* Too large for the monitor */
181 unsigned int wdiff
= mon_config
->monitors
[0].width
- sizes
[i
].width
;
182 unsigned int hdiff
= mon_config
->monitors
[0].height
- sizes
[i
].height
;
183 unsigned int diff
= wdiff
* wdiff
+ hdiff
* hdiff
;
184 if (diff
< closest_diff
) {
191 fprintf(stderr
, "no suitable resolution found for monitor\n");
195 config
= XRRGetScreenInfo(x11
->display
, x11
->root_window
);
197 fprintf(stderr
, "get screen info failed\n");
200 XRRConfigCurrentConfiguration(config
, &rotation
);
201 XRRSetScreenConfig(x11
->display
, config
, x11
->root_window
, best
,
202 rotation
, CurrentTime
);
203 XRRFreeScreenConfigInfo(config
);
204 XFlush(x11
->display
);