diff options
author | Hans de Goede <hdegoede@redhat.com> | 2010-09-29 14:19:35 +0200 |
---|---|---|
committer | Hans de Goede <hdegoede@redhat.com> | 2010-09-29 14:19:35 +0200 |
commit | 8a4b92817ffaabcd8234432f9728fad582916f1f (patch) | |
tree | 8c02102387a95d4c1dde5b2dc5423d855c4c03e3 /vdagent-x11.c | |
parent | 871e9dd90641e0383962cfaa4f4ffceb7496cf42 (diff) |
Use XConvertSelection(... TARGETS) to query which type of data lives in the clipboard
Diffstat (limited to 'vdagent-x11.c')
-rw-r--r-- | vdagent-x11.c | 198 |
1 files changed, 162 insertions, 36 deletions
diff --git a/vdagent-x11.c b/vdagent-x11.c index 08d93db..5112041 100644 --- a/vdagent-x11.c +++ b/vdagent-x11.c @@ -27,6 +27,7 @@ #include <stdio.h> #include <stdlib.h> #include <limits.h> +#include <X11/Xatom.h> #include <X11/Xlib.h> #include <X11/extensions/Xrandr.h> #include <X11/extensions/Xfixes.h> @@ -56,11 +57,17 @@ struct vdagent_x11 { int has_xrandr; int has_xfixes; int xfixes_event_base; + int own_client_clipboard; + int own_guest_clipboard; + uint32_t clipboard_agent_type; + Atom clipboard_x11_type; }; 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); +static void vdagent_x11_handle_targets_notify(struct vdagent_x11 *x11, + XEvent *event); struct vdagent_x11 *vdagent_x11_create(struct udscs_connection *vdagentd, int verbose) @@ -164,11 +171,25 @@ void vdagent_x11_do_read(struct vdagent_x11 *x11) return; } - /* FIXME plenty, we need to request the selection with a type of - TARGETS and then compare the TARGETS against our list of known - UTF-8 targets. */ - udscs_write(x11->vdagentd, VDAGENTD_CLIPBOARD_GRAB, - VD_AGENT_CLIPBOARD_UTF8_TEXT, NULL, 0); + /* If the clipboard owner is changed we no longer own it */ + x11->own_guest_clipboard = 0; + + /* If the clipboard is released and we've grabbed the client clipboard + release it */ + if (ev.xfev.owner == None) { + if (x11->own_client_clipboard) { + udscs_write(x11->vdagentd, VDAGENTD_CLIPBOARD_RELEASE, 0, + NULL, 0); + x11->own_client_clipboard = 0; + } + return; + } + + /* Request the supported targets from the new owner */ + XConvertSelection(x11->display, x11->clipboard_atom, x11->targets_atom, + x11->clipboard_atom, x11->selection_window, + CurrentTime); + XFlush(x11->display); handled = 1; } else switch (event.type) { case ConfigureNotify: @@ -187,13 +208,12 @@ void vdagent_x11_do_read(struct vdagent_x11 *x11) vdagent_x11_send_daemon_guest_xorg_res(x11); break; case SelectionNotify: - handled = 1; - - if (event.xselection.target == x11->targets_atom) { - /* FIXME */ - } else { + if (event.xselection.target == x11->targets_atom) + vdagent_x11_handle_targets_notify(x11, &event); + else vdagent_x11_handle_selection_notify(x11, &event); - } + + handled = 1; break; } if (!handled && x11->verbose) @@ -212,48 +232,84 @@ static void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11) (uint8_t *)&res, sizeof(res)); } -static void vdagent_x11_handle_selection_notify(struct vdagent_x11 *x11, - XEvent *event) +static int vdagent_x11_get_selection(struct vdagent_x11 *x11, XEvent *event, + Atom type, int format, unsigned char **data) { - Atom type; - int format; + Atom type_ret; + int format_ret; unsigned long len, remain; - unsigned char *data = NULL; + if (event->xselection.property == None) { + if (x11->verbose) + fprintf(stderr, "XConverSelection refused by clipboard owner\n"); + return -1; + } + + if (event->xselection.requestor != x11->selection_window || + event->xselection.property != x11->clipboard_atom || + event->xselection.selection != x11->clipboard_atom) { + fprintf(stderr, "SelectionNotify parameters mismatch\n"); + return -1; + } + + /* FIXME when we've incr support we should not immediately + delete the property (as we need to first register for + property change events) */ if (XGetWindowProperty(x11->display, x11->selection_window, x11->clipboard_atom, 0, LONG_MAX, True, - event->xselection.target, &type, &format, &len, - &remain, &data) != Success) { - fprintf(stderr, "XGetWindowProperty(size) failed\n"); - goto error; + type, &type_ret, &format_ret, &len, + &remain, data) != Success) { + fprintf(stderr, "XGetWindowProperty failed\n"); + return -1; } - if (type == x11->incr_atom) { + if (type_ret == x11->incr_atom) { /* FIXME */ fprintf(stderr, "incr properties are currently unsupported\n"); - goto error; + return -1; } - if (type != event->xselection.target) { + if (type_ret != type) { fprintf(stderr, "expected property type: %s, got: %s\n", - XGetAtomName(x11->display, event->xselection.target), - XGetAtomName(x11->display, type)); - goto error; + XGetAtomName(x11->display, type), + XGetAtomName(x11->display, type_ret)); + return -1; } - if (format != 8) { - fprintf(stderr, "only 8 bit formats are supported\n"); - goto error; + if (format_ret != format) { + fprintf(stderr, "expected %d bit format, got %d bits\n", format, + format_ret); + return -1; } if (len == 0) { fprintf(stderr, "property contains no data (zero length)\n"); + return -1; + } + + return len; +} + +static void vdagent_x11_handle_selection_notify(struct vdagent_x11 *x11, + XEvent *event) +{ + int len; + unsigned char *data = NULL; + + if (event->xselection.target != x11->clipboard_x11_type) { + fprintf(stderr, "expecting %s data, got %s\n", + XGetAtomName(x11->display, x11->clipboard_x11_type), + XGetAtomName(x11->display, event->xselection.target)); goto error; } - /* FIXME don't hardcode VD_AGENT_CLIPBOARD_UTF8_TEXT */ - udscs_write(x11->vdagentd, VDAGENTD_CLIPBOARD_DATA, - VD_AGENT_CLIPBOARD_UTF8_TEXT, data, len); + len = vdagent_x11_get_selection(x11, event, event->xselection.target, 8, + &data); + if (len == -1) + goto error; + + udscs_write(x11->vdagentd, VDAGENTD_CLIPBOARD_DATA, + x11->clipboard_agent_type, data, len); XFree(data); return; @@ -265,6 +321,62 @@ error: VD_AGENT_CLIPBOARD_NONE, NULL, 0); } +static Atom atom_lists_overlap(Atom *atoms1, Atom *atoms2, int l1, int l2) +{ + int i, j; + + for (i = 0; i < l1; i++) + for (j = 0; j < l2; j++) + if (atoms1[i] == atoms2[j]) + return atoms1[i]; + + return 0; +} + +static void vdagent_x11_handle_targets_notify(struct vdagent_x11 *x11, + XEvent *event) +{ + int i, len; + Atom x11_type, atom, *atoms = NULL; + uint32_t agent_type = VD_AGENT_CLIPBOARD_NONE; + + len = vdagent_x11_get_selection(x11, event, XA_ATOM, 32, + (unsigned char **)&atoms); + if (len == -1) + goto error; + + if (x11->verbose) { + fprintf(stderr, "found: %d targets:\n", (int)len); + for (i = 0; i < len; i++) + fprintf(stderr, "%s\n", XGetAtomName(x11->display, atoms[i])); + } + + atom = atom_lists_overlap(x11->utf8_atoms, atoms, + sizeof(utf8_atom_names)/sizeof(utf8_atom_names[0]), len); + if (atom) { + agent_type = VD_AGENT_CLIPBOARD_UTF8_TEXT; + x11_type = atom; + } + + /* TODO Place holder for checking for image type atoms */ + + if (agent_type != VD_AGENT_CLIPBOARD_NONE) { + x11->clipboard_agent_type = agent_type; + x11->clipboard_x11_type = x11_type; + udscs_write(x11->vdagentd, VDAGENTD_CLIPBOARD_GRAB, agent_type, + NULL, 0); + x11->own_client_clipboard = 1; + return; + } + + /* New selection contains an unsupported type release the clipboard */ +error: + if (x11->own_client_clipboard) { + udscs_write(x11->vdagentd, VDAGENTD_CLIPBOARD_RELEASE, 0, NULL, 0); + x11->own_client_clipboard = 0; + } +} + void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11, VDAgentMonitorsConfig *mon_config) { @@ -323,11 +435,25 @@ void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11, void vdagent_x11_clipboard_request(struct vdagent_x11 *x11, uint32_t type) { - /* FIXME use atom which we figured out matches one of our supported - types when we first got notified of a selection owner change */ - Atom target = x11->utf8_atoms[0]; + if (!x11->own_client_clipboard) { + fprintf(stderr, + "received clipboard req while not owning client clipboard\n"); + goto error; + } + if (type != x11->clipboard_agent_type) { + fprintf(stderr, "have type %u clipboard data, client asked for %u\n", + x11->clipboard_agent_type, type); + goto error; + } - XConvertSelection(x11->display, x11->clipboard_atom, target, + XConvertSelection(x11->display, x11->clipboard_atom, + x11->clipboard_x11_type, x11->clipboard_atom, x11->selection_window, CurrentTime); XFlush(x11->display); + return; + +error: + /* Notify the spice client that no answer is forthcoming */ + udscs_write(x11->vdagentd, VDAGENTD_CLIPBOARD_DATA, + VD_AGENT_CLIPBOARD_NONE, NULL, 0); } |