diff options
author | Alon Levy <alevy@redhat.com> | 2012-06-20 18:09:25 +0300 |
---|---|---|
committer | Alon Levy <alevy@redhat.com> | 2012-06-20 23:30:07 +0300 |
commit | 648c36bab431221e5a1263c4e4442235b9db9fbc (patch) | |
tree | 14666e5cb500fd5eb470c5ecbd59f7f82e4547c5 | |
parent | 99559f13c964a7adea7fd8fa98a33bd2502f09a3 (diff) |
vdagent-x11-randr.c: introduce as split from vdagent-x11.c
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | src/vdagent-x11-priv.h | 114 | ||||
-rw-r--r-- | src/vdagent-x11-randr.c | 169 | ||||
-rw-r--r-- | src/vdagent-x11.c | 245 |
4 files changed, 289 insertions, 241 deletions
diff --git a/Makefile.am b/Makefile.am index e75d694..72aaba7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,7 +5,7 @@ sbin_PROGRAMS = src/spice-vdagentd src_spice_vdagent_CFLAGS = $(X_CFLAGS) $(SPICE_CFLAGS) src_spice_vdagent_LDADD = $(X_LIBS) $(SPICE_LIBS) -src_spice_vdagent_SOURCES = src/vdagent.c src/vdagent-x11.c src/udscs.c +src_spice_vdagent_SOURCES = src/vdagent.c src/vdagent-x11.c src/vdagent-x11-randr.c src/udscs.c src_spice_vdagentd_CFLAGS = $(DBUS_CFLAGS) $(LIBSYSTEMD_LOGIN_CFLAGS) $(PCIACCESS_CFLAGS) $(SPICE_CFLAGS) src_spice_vdagentd_LDADD = $(DBUS_LIBS) $(LIBSYSTEMD_LOGIN_LIBS) $(PCIACCESS_LIBS) $(SPICE_LIBS) diff --git a/src/vdagent-x11-priv.h b/src/vdagent-x11-priv.h new file mode 100644 index 0000000..5c53fda --- /dev/null +++ b/src/vdagent-x11-priv.h @@ -0,0 +1,114 @@ +#ifndef VDAGENT_X11_PRIV +#define VDAGENT_X11_PRIV + +#include <stdint.h> +#include <stdio.h> + +#include <spice/vd_agent.h> + +#include <X11/extensions/Xrandr.h> + +/* Macros to print a message to the logfile prefixed by the selection */ +#define SELPRINTF(format, ...) \ + fprintf(x11->errfile, "%s: " format, \ + vdagent_x11_sel_to_str(selection), ##__VA_ARGS__) + +#define VSELPRINTF(format, ...) \ + do { \ + if (x11->verbose) { \ + fprintf(x11->errfile, "%s: " format, \ + vdagent_x11_sel_to_str(selection), ##__VA_ARGS__); \ + } \ + } while (0) + +enum { owner_none, owner_guest, owner_client }; + +/* X11 terminology is confusing a selection request is a request from an + app to get clipboard data from us, so iow from the spice client through + the vdagent channel. We handle these one at a time and queue any which + come in while we are still handling the current one. */ +struct vdagent_x11_selection_request { + XEvent event; + uint8_t selection; + struct vdagent_x11_selection_request *next; +}; + +/* A conversion request is X11 speak for asking an other app to give its + clipboard data to us, we do these on behalf of the spice client to copy + data from the guest to the client. Like selection requests we process + these one at a time. */ +struct vdagent_x11_conversion_request { + Atom target; + uint8_t selection; + struct vdagent_x11_conversion_request *next; +}; + +struct clipboard_format_tmpl { + uint32_t type; + const char *atom_names[16]; +}; + +struct clipboard_format_info { + uint32_t type; + Atom atoms[16]; + int atom_count; +}; + +static const struct clipboard_format_tmpl clipboard_format_templates[] = { + { VD_AGENT_CLIPBOARD_UTF8_TEXT, { "UTF8_STRING", + "text/plain;charset=UTF-8", "text/plain;charset=utf-8", NULL }, }, + { VD_AGENT_CLIPBOARD_IMAGE_PNG, { "image/png", NULL }, }, + { VD_AGENT_CLIPBOARD_IMAGE_BMP, { "image/bmp", "image/x-bmp", + "image/x-MS-bmp", "image/x-win-bitmap", NULL }, }, + { VD_AGENT_CLIPBOARD_IMAGE_TIFF, { "image/tiff", NULL }, }, + { VD_AGENT_CLIPBOARD_IMAGE_JPG, { "image/jpeg", NULL }, }, +}; + +#define clipboard_format_count (sizeof(clipboard_format_templates)/sizeof(clipboard_format_templates[0])) + +struct vdagent_x11 { + struct clipboard_format_info clipboard_formats[clipboard_format_count]; + Display *display; + Atom clipboard_atom; + Atom clipboard_primary_atom; + Atom targets_atom; + Atom incr_atom; + Atom multiple_atom; + Window root_window; + Window selection_window; + struct udscs_connection *vdagentd; + FILE *errfile; + int verbose; + int fd; + int screen; + int width; + int height; + int has_xrandr; + int has_xinerama; + int has_xfixes; + int xfixes_event_base; + int max_prop_size; + int expected_targets_notifies[256]; + int clipboard_owner[256]; + int clipboard_type_count[256]; + uint32_t clipboard_agent_types[256][256]; + Atom clipboard_x11_targets[256][256]; + /* Data for conversion_req which is currently being processed */ + struct vdagent_x11_conversion_request *conversion_req; + int expect_property_notify; + uint8_t *clipboard_data; + uint32_t clipboard_data_size; + uint32_t clipboard_data_space; + /* Data for selection_req which is currently being processed */ + struct vdagent_x11_selection_request *selection_req; + uint8_t *selection_req_data; + uint32_t selection_req_data_pos; + uint32_t selection_req_data_size; + Atom selection_req_atom; +}; + +void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11); +void vdagent_x11_randr_handle_root_size_change(struct vdagent_x11 *x11, + int width, int height); + +#endif // VDAGENT_X11_PRIV diff --git a/src/vdagent-x11-randr.c b/src/vdagent-x11-randr.c new file mode 100644 index 0000000..b88bee3 --- /dev/null +++ b/src/vdagent-x11-randr.c @@ -0,0 +1,169 @@ +#include <string.h> +#include <stdlib.h> + +#include <X11/extensions/Xinerama.h> + +#include "vdagentd-proto.h" +#include "vdagent-x11-priv.h" + +void vdagent_x11_randr_init(struct vdagent_x11 *x11) +{ + int i; + + if (XRRQueryExtension(x11->display, &i, &i)) { + x11->has_xrandr = 1; + } + + if (XineramaQueryExtension(x11->display, &i, &i)) + x11->has_xinerama = 1; + + switch (x11->has_xrandr << 4 | x11->has_xinerama) { + case 0x00: + fprintf(x11->errfile, "Neither Xrandr nor Xinerama found, assuming single monitor setup\n"); + break; + case 0x01: + if (x11->verbose) + fprintf(x11->errfile, "Found Xinerama extension without Xrandr, assuming a multi monitor setup\n"); + break; + case 0x10: + fprintf(x11->errfile, "Found Xrandr but no Xinerama, weird! Assuming a single monitor setup\n"); + break; + case 0x11: + /* Standard single monitor setup, nothing to see here */ + break; + } +} + +void vdagent_x11_randr_handle_root_size_change(struct vdagent_x11 *x11, + int width, int height) +{ + if (width == x11->width && height == x11->height) { + return; + } + + x11->width = width; + x11->height = height; + + vdagent_x11_send_daemon_guest_xorg_res(x11); +} + +/* + * Set monitor configuration according to client request. + * + * On exit send current configuration to client, regardless of error. + * + * Errors: + * screen size too large for driver to handle. (we set the largest/smallest possible) + * no randr support in X server. + * invalid configuration request from client. + */ +void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11, + VDAgentMonitorsConfig *mon_config) +{ + int i, num_sizes = 0; + int best = -1; + unsigned int closest_diff = -1; + XRRScreenSize *sizes; + XRRScreenConfiguration *config; + Rotation rotation; + + if (!x11->has_xrandr) + return; + + if (mon_config->num_of_monitors != 1) { + fprintf(x11->errfile, + "Only 1 monitor supported, ignoring additional monitors\n"); + } + + sizes = XRRSizes(x11->display, x11->screen, &num_sizes); + if (!sizes || !num_sizes) { + fprintf(x11->errfile, "XRRSizes failed\n"); + return; + } + + /* Find the closest size which will fit within the monitor */ + for (i = 0; i < num_sizes; i++) { + if (sizes[i].width > mon_config->monitors[0].width || + sizes[i].height > mon_config->monitors[0].height) + continue; /* Too large for the monitor */ + + unsigned int wdiff = mon_config->monitors[0].width - sizes[i].width; + unsigned int hdiff = mon_config->monitors[0].height - sizes[i].height; + unsigned int diff = wdiff * wdiff + hdiff * hdiff; + if (diff < closest_diff) { + closest_diff = diff; + best = i; + } + } + + if (best == -1) { + fprintf(x11->errfile, "no suitable resolution found for monitor\n"); + return; + } + + config = XRRGetScreenInfo(x11->display, x11->root_window); + if(!config) { + fprintf(x11->errfile, "get screen info failed\n"); + return; + } + XRRConfigCurrentConfiguration(config, &rotation); + XRRSetScreenConfig(x11->display, config, x11->root_window, best, + rotation, CurrentTime); + XRRFreeScreenConfigInfo(config); + x11->width = sizes[best].width; + x11->height = sizes[best].height; + vdagent_x11_send_daemon_guest_xorg_res(x11); + + /* Flush output buffers and consume any pending events (ConfigureNotify) */ + vdagent_x11_do_read(x11); +} + +void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11) +{ + struct vdagentd_guest_xorg_resolution *res = NULL; + XineramaScreenInfo *screen_info = NULL; + int i, screen_count = 0; + + if (x11->has_xinerama) { + /* Xinerama reports the same information RANDR reports, so stay + * with Xinerama for support of Xinerama only setups */ + screen_info = XineramaQueryScreens(x11->display, &screen_count); + } + + if (screen_count == 0) + screen_count = 1; + + res = malloc(screen_count * sizeof(*res)); + if (!res) { + fprintf(x11->errfile, "out of memory while trying to send resolutions, not sending resolutions.\n"); + if (screen_info) + XFree(screen_info); + return; + } + + if (screen_info) { + for (i = 0; i < screen_count; i++) { + if (screen_info[i].screen_number >= screen_count) { + fprintf(x11->errfile, "Invalid screen number in xinerama screen info (%d >= %d)\n", + screen_info[i].screen_number, screen_count); + XFree(screen_info); + free(res); + return; + } + res[screen_info[i].screen_number].width = screen_info[i].width; + res[screen_info[i].screen_number].height = screen_info[i].height; + res[screen_info[i].screen_number].x = screen_info[i].x_org; + res[screen_info[i].screen_number].y = screen_info[i].y_org; + } + XFree(screen_info); + } else { + res[0].width = x11->width; + res[0].height = x11->height; + res[0].x = 0; + res[0].y = 0; + } + + udscs_write(x11->vdagentd, VDAGENTD_GUEST_XORG_RESOLUTION, x11->width, + x11->height, (uint8_t *)res, screen_count * sizeof(*res)); + free(res); +} diff --git a/src/vdagent-x11.c b/src/vdagent-x11.c index c9e99ee..38c4205 100644 --- a/src/vdagent-x11.c +++ b/src/vdagent-x11.c @@ -37,112 +37,11 @@ #include <assert.h> #include <X11/Xatom.h> #include <X11/Xlib.h> -#include <X11/extensions/Xrandr.h> -#include <X11/extensions/Xinerama.h> #include <X11/extensions/Xfixes.h> #include "vdagentd-proto.h" #include "vdagent-x11.h" +#include "vdagent-x11-priv.h" -/* Macros to print a message to the logfile prefixed by the selection */ -#define SELPRINTF(format, ...) \ - fprintf(x11->errfile, "%s: " format, \ - vdagent_x11_sel_to_str(selection), ##__VA_ARGS__) - -#define VSELPRINTF(format, ...) \ - do { \ - if (x11->verbose) { \ - fprintf(x11->errfile, "%s: " format, \ - vdagent_x11_sel_to_str(selection), ##__VA_ARGS__); \ - } \ - } while (0) - -enum { owner_none, owner_guest, owner_client }; - -/* X11 terminology is confusing a selection request is a request from an - app to get clipboard data from us, so iow from the spice client through - the vdagent channel. We handle these one at a time and queue any which - come in while we are still handling the current one. */ -struct vdagent_x11_selection_request { - XEvent event; - uint8_t selection; - struct vdagent_x11_selection_request *next; -}; - -/* A conversion request is X11 speak for asking an other app to give its - clipboard data to us, we do these on behalf of the spice client to copy - data from the guest to the client. Like selection requests we process - these one at a time. */ -struct vdagent_x11_conversion_request { - Atom target; - uint8_t selection; - struct vdagent_x11_conversion_request *next; -}; - -struct clipboard_format_tmpl { - uint32_t type; - const char *atom_names[16]; -}; - -struct clipboard_format_info { - uint32_t type; - Atom atoms[16]; - int atom_count; -}; - -static const struct clipboard_format_tmpl clipboard_format_templates[] = { - { VD_AGENT_CLIPBOARD_UTF8_TEXT, { "UTF8_STRING", - "text/plain;charset=UTF-8", "text/plain;charset=utf-8", NULL }, }, - { VD_AGENT_CLIPBOARD_IMAGE_PNG, { "image/png", NULL }, }, - { VD_AGENT_CLIPBOARD_IMAGE_BMP, { "image/bmp", "image/x-bmp", - "image/x-MS-bmp", "image/x-win-bitmap", NULL }, }, - { VD_AGENT_CLIPBOARD_IMAGE_TIFF, { "image/tiff", NULL }, }, - { VD_AGENT_CLIPBOARD_IMAGE_JPG, { "image/jpeg", NULL }, }, -}; - -#define clipboard_format_count (sizeof(clipboard_format_templates)/sizeof(clipboard_format_templates[0])) - -struct vdagent_x11 { - struct clipboard_format_info clipboard_formats[clipboard_format_count]; - Display *display; - Atom clipboard_atom; - Atom clipboard_primary_atom; - Atom targets_atom; - Atom incr_atom; - Atom multiple_atom; - Window root_window; - Window selection_window; - struct udscs_connection *vdagentd; - FILE *errfile; - int verbose; - int fd; - int screen; - int width; - int height; - int has_xrandr; - int has_xinerama; - int has_xfixes; - int xfixes_event_base; - int max_prop_size; - int expected_targets_notifies[256]; - int clipboard_owner[256]; - int clipboard_type_count[256]; - uint32_t clipboard_agent_types[256][256]; - Atom clipboard_x11_targets[256][256]; - /* Data for conversion_req which is currently being processed */ - struct vdagent_x11_conversion_request *conversion_req; - int expect_property_notify; - uint8_t *clipboard_data; - uint32_t clipboard_data_size; - uint32_t clipboard_data_space; - /* Data for selection_req which is currently being processed */ - struct vdagent_x11_selection_request *selection_req; - uint8_t *selection_req_data; - uint32_t selection_req_data_pos; - uint32_t selection_req_data_size; - Atom selection_req_atom; -}; - -static void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11); static void vdagent_x11_handle_selection_notify(struct vdagent_x11 *x11, XEvent *event, int incr); static void vdagent_x11_handle_selection_request(struct vdagent_x11 *x11); @@ -218,27 +117,7 @@ struct vdagent_x11 *vdagent_x11_create(struct udscs_connection *vdagentd, fprintf(x11->errfile, "Selection window: %u\n", (unsigned int)x11->selection_window); - if (XRRQueryExtension(x11->display, &i, &i)) - x11->has_xrandr = 1; - - if (XineramaQueryExtension(x11->display, &i, &i)) - x11->has_xinerama = 1; - - switch (x11->has_xrandr << 4 | x11->has_xinerama) { - case 0x00: - fprintf(x11->errfile, "Neither Xrandr nor Xinerama found, assuming single monitor setup\n"); - break; - case 0x01: - if (x11->verbose) - fprintf(x11->errfile, "Found Xinerama extension without Xrandr, assuming a multi monitor setup\n"); - break; - case 0x10: - fprintf(x11->errfile, "Found Xrandr but no Xinerama, weird! Assuming a single monitor setup\n"); - break; - case 0x11: - /* Standard single monitor setup, nothing to see here */ - break; - } + vdagent_x11_randr_init(x11); if (XFixesQueryExtension(x11->display, &x11->xfixes_event_base, &i) && XFixesQueryVersion(x11->display, &major, &minor) && major >= 1) { @@ -488,19 +367,13 @@ static void vdagent_x11_handle_event(struct vdagent_x11 *x11, XEvent event) switch (event.type) { case ConfigureNotify: + // TODO: handle CrtcConfigureNotify, OutputConfigureNotify can be ignored. if (event.xconfigure.window != x11->root_window) break; handled = 1; - - if (event.xconfigure.width == x11->width && - event.xconfigure.height == x11->height) - break; - - x11->width = event.xconfigure.width; - x11->height = event.xconfigure.height; - - vdagent_x11_send_daemon_guest_xorg_res(x11); + vdagent_x11_randr_handle_root_size_change(x11, + event.xconfigure.width, event.xconfigure.height); break; case MappingNotify: /* These are uninteresting */ @@ -581,53 +454,6 @@ void vdagent_x11_do_read(struct vdagent_x11 *x11) } } -static void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11) -{ - struct vdagentd_guest_xorg_resolution *res = NULL; - XineramaScreenInfo *screen_info = NULL; - int i, screen_count = 0; - - if (x11->has_xinerama) - screen_info = XineramaQueryScreens(x11->display, &screen_count); - - if (screen_count == 0) - screen_count = 1; - - res = malloc(screen_count * sizeof(*res)); - if (!res) { - fprintf(x11->errfile, "out of memory while trying to send resolutions, not sending resolutions.\n"); - if (screen_info) - XFree(screen_info); - return; - } - - if (screen_info) { - for (i = 0; i < screen_count; i++) { - if (screen_info[i].screen_number >= screen_count) { - fprintf(x11->errfile, "Invalid screen number in xinerama screen info (%d >= %d)\n", - screen_info[i].screen_number, screen_count); - XFree(screen_info); - free(res); - return; - } - res[screen_info[i].screen_number].width = screen_info[i].width; - res[screen_info[i].screen_number].height = screen_info[i].height; - res[screen_info[i].screen_number].x = screen_info[i].x_org; - res[screen_info[i].screen_number].y = screen_info[i].y_org; - } - XFree(screen_info); - } else { - res[0].width = x11->width; - res[0].height = x11->height; - res[0].x = 0; - res[0].y = 0; - } - - udscs_write(x11->vdagentd, VDAGENTD_GUEST_XORG_RESOLUTION, x11->width, - x11->height, (uint8_t *)res, screen_count * sizeof(*res)); - free(res); -} - static const char *vdagent_x11_get_atom_name(struct vdagent_x11 *x11, Atom a) { if (a == None) @@ -1124,67 +950,6 @@ static void vdagent_x11_handle_property_delete_notify(struct vdagent_x11 *x11, } } -void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11, - VDAgentMonitorsConfig *mon_config) -{ - int i, num_sizes = 0; - int best = -1; - unsigned int closest_diff = -1; - XRRScreenSize* sizes; - XRRScreenConfiguration* config; - Rotation rotation; - - if (!x11->has_xrandr) - return; - - if (mon_config->num_of_monitors != 1) { - fprintf(x11->errfile, - "Only 1 monitor supported, ignoring additional monitors\n"); - } - - sizes = XRRSizes(x11->display, x11->screen, &num_sizes); - if (!sizes || !num_sizes) { - fprintf(x11->errfile, "XRRSizes failed\n"); - return; - } - - /* Find the closest size which will fit within the monitor */ - for (i = 0; i < num_sizes; i++) { - if (sizes[i].width > mon_config->monitors[0].width || - sizes[i].height > mon_config->monitors[0].height) - continue; /* Too large for the monitor */ - - unsigned int wdiff = mon_config->monitors[0].width - sizes[i].width; - unsigned int hdiff = mon_config->monitors[0].height - sizes[i].height; - unsigned int diff = wdiff * wdiff + hdiff * hdiff; - if (diff < closest_diff) { - closest_diff = diff; - best = i; - } - } - - if (best == -1) { - fprintf(x11->errfile, "no suitable resolution found for monitor\n"); - return; - } - - config = XRRGetScreenInfo(x11->display, x11->root_window); - if(!config) { - fprintf(x11->errfile, "get screen info failed\n"); - return; - } - XRRConfigCurrentConfiguration(config, &rotation); - XRRSetScreenConfig(x11->display, config, x11->root_window, best, - rotation, CurrentTime); - XRRFreeScreenConfigInfo(config); - x11->width = sizes[best].width; - x11->height = sizes[best].height; - vdagent_x11_send_daemon_guest_xorg_res(x11); - - /* Flush output buffers and consume any pending events */ - vdagent_x11_do_read(x11); -} - void vdagent_x11_clipboard_request(struct vdagent_x11 *x11, uint8_t selection, uint32_t type) { |