summaryrefslogtreecommitdiff
path: root/vdagent-x11.c
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2010-09-29 14:19:35 +0200
committerHans de Goede <hdegoede@redhat.com>2010-09-29 14:19:35 +0200
commit8a4b92817ffaabcd8234432f9728fad582916f1f (patch)
tree8c02102387a95d4c1dde5b2dc5423d855c4c03e3 /vdagent-x11.c
parent871e9dd90641e0383962cfaa4f4ffceb7496cf42 (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.c198
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);
}