Put uinput code into its own file
[vd_agent/hramrach.git] / vdagent-x11.c
blob0047a1252b6dd32b6a9146be1682a6cea1f0f11c
1 /* vdagent-x11.c vdagent x11 code
3 Copyright 2010 Red Hat, Inc.
5 Red Hat Authors:
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. */
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <X11/Xlib.h>
30 #include <X11/extensions/Xrandr.h>
31 #include "vdagentd-proto.h"
32 #include "vdagent-x11.h"
34 struct vdagent_x11 {
35 Display *display;
36 struct udscs_connection *vdagentd;
37 int verbose;
38 int fd;
39 int screen;
40 int root_window;
41 int width;
42 int height;
43 int has_xrandr;
46 static void vdagent_x11_send_guest_xorg_res(struct vdagent_x11 *x11);
48 struct vdagent_x11 *vdagent_x11_create(struct udscs_connection *vdagentd,
49 int verbose)
51 struct vdagent_x11 *x11;
52 XWindowAttributes attrib;
53 int xrandr_event_base, xrandr_error_base;
55 x11 = calloc(1, sizeof(*x11));
56 if (!x11) {
57 fprintf(stderr, "out of memory allocating vdagent_x11 struct\n");
58 return NULL;
61 x11->vdagentd = vdagentd;
62 x11->verbose = verbose;
64 x11->display = XOpenDisplay(NULL);
65 if (!x11->display) {
66 fprintf(stderr, "could not connect to X-server\n");
67 free(x11);
68 return NULL;
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))
76 x11->has_xrandr = 1;
77 else
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);
88 return x11;
91 void vdagent_x11_destroy(struct vdagent_x11 *x11)
93 if (!x11)
94 return;
96 XCloseDisplay(x11->display);
97 free(x11);
100 int vdagent_x11_get_fd(struct vdagent_x11 *x11)
102 return x11->fd;
105 void vdagent_x11_do_read(struct vdagent_x11 *x11)
107 XEvent event;
108 int handled = 0;
110 if (!XPending(x11->display))
111 return;
113 XNextEvent(x11->display, &event);
114 switch (event.type) {
115 case ConfigureNotify:
116 if (event.xconfigure.window != x11->root_window)
117 break;
119 handled = 1;
121 if (event.xconfigure.width == x11->width &&
122 event.xconfigure.height == x11->height)
123 break;
125 x11->width = event.xconfigure.width;
126 x11->height = event.xconfigure.height;
128 vdagent_x11_send_guest_xorg_res(x11);
129 break;
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;
142 header.opaque = 0;
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;
155 int best = -1;
156 unsigned int closest_diff = -1;
157 XRRScreenSize* sizes;
158 XRRScreenConfiguration* config;
159 Rotation rotation;
161 if (!x11->has_xrandr)
162 return;
164 if (mon_config->num_of_monitors != 1) {
165 fprintf(stderr, "Only 1 monitor supported, ignoring monitor config\n");
166 return;
169 sizes = XRRSizes(x11->display, x11->screen, &num_sizes);
170 if (!sizes || !num_sizes) {
171 fprintf(stderr, "XRRSizes failed\n");
172 return;
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) {
185 closest_diff = diff;
186 best = i;
190 if (best == -1) {
191 fprintf(stderr, "no suitable resolution found for monitor\n");
192 return;
195 config = XRRGetScreenInfo(x11->display, x11->root_window);
196 if(!config) {
197 fprintf(stderr, "get screen info failed\n");
198 return;
200 XRRConfigCurrentConfiguration(config, &rotation);
201 XRRSetScreenConfig(x11->display, config, x11->root_window, best,
202 rotation, CurrentTime);
203 XRRFreeScreenConfigInfo(config);
204 XFlush(x11->display);