Force processing of ownerchange event when releasing the clipboard
[vd_agent/hramrach.git] / vdagent-x11.c
blobbe6524cdd0bfe62f7f96a4a9c1ee7e59eb2a68ca
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 <limits.h>
30 #include <X11/Xatom.h>
31 #include <X11/Xlib.h>
32 #include <X11/extensions/Xrandr.h>
33 #include <X11/extensions/Xfixes.h>
34 #include "vdagentd-proto.h"
35 #include "vdagent-x11.h"
37 enum { owner_none, owner_guest, owner_client };
39 const char *utf8_atom_names[] = {
40 "UTF8_STRING",
41 "text/plain;charset=UTF-8",
42 "text/plain;charset=utf-8",
45 #define utf8_atom_count (sizeof(utf8_atom_names)/sizeof(utf8_atom_names[0]))
47 struct vdagent_x11_selection_request {
48 XEvent event;
49 struct vdagent_x11_selection_request *next;
52 struct vdagent_x11 {
53 Display *display;
54 Atom clipboard_atom;
55 Atom targets_atom;
56 Atom incr_atom;
57 Atom multiple_atom;
58 Atom utf8_atoms[utf8_atom_count];
59 Window root_window;
60 Window selection_window;
61 struct udscs_connection *vdagentd;
62 int verbose;
63 int fd;
64 int screen;
65 int width;
66 int height;
67 int has_xrandr;
68 int has_xfixes;
69 int xfixes_event_base;
70 int expected_targets_notifies;
71 int clipboard_owner;
72 int clipboard_type_count;
73 /* Warning the size of these needs to be increased each time we add
74 support for a new type!! */
75 uint32_t clipboard_agent_types[1];
76 Atom clipboard_x11_targets[1];
77 struct vdagent_x11_selection_request *selection_request;
80 static void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11);
81 static void vdagent_x11_handle_selection_notify(struct vdagent_x11 *x11,
82 XEvent *event);
83 static void vdagent_x11_handle_selection_request(struct vdagent_x11 *x11);
84 static void vdagent_x11_handle_targets_notify(struct vdagent_x11 *x11,
85 XEvent *event);
86 static void vdagent_x11_send_selection_notify(struct vdagent_x11 *x11,
87 Atom prop,
88 int process_next_req);
90 struct vdagent_x11 *vdagent_x11_create(struct udscs_connection *vdagentd,
91 int verbose)
93 struct vdagent_x11 *x11;
94 XWindowAttributes attrib;
95 int i, major, minor;
97 x11 = calloc(1, sizeof(*x11));
98 if (!x11) {
99 fprintf(stderr, "out of memory allocating vdagent_x11 struct\n");
100 return NULL;
103 x11->vdagentd = vdagentd;
104 x11->verbose = verbose;
106 x11->display = XOpenDisplay(NULL);
107 if (!x11->display) {
108 fprintf(stderr, "could not connect to X-server\n");
109 free(x11);
110 return NULL;
113 x11->screen = DefaultScreen(x11->display);
114 x11->root_window = RootWindow(x11->display, x11->screen);
115 x11->fd = ConnectionNumber(x11->display);
116 x11->clipboard_atom = XInternAtom(x11->display, "CLIPBOARD", False);
117 x11->targets_atom = XInternAtom(x11->display, "TARGETS", False);
118 x11->incr_atom = XInternAtom(x11->display, "INCR", False);
119 x11->multiple_atom = XInternAtom(x11->display, "MULTIPLE", False);
120 for(i = 0; i < utf8_atom_count; i++)
121 x11->utf8_atoms[i] = XInternAtom(x11->display, utf8_atom_names[i],
122 False);
124 /* We should not store properties (for selections) on the root window */
125 x11->selection_window = XCreateSimpleWindow(x11->display, x11->root_window,
126 0, 0, 1, 1, 0, 0, 0);
127 if (x11->verbose)
128 fprintf(stderr, "Selection window: %u\n",
129 (unsigned int)x11->selection_window);
131 if (XRRQueryExtension(x11->display, &i, &i))
132 x11->has_xrandr = 1;
133 else
134 fprintf(stderr, "no xrandr\n");
136 if (XFixesQueryExtension(x11->display, &x11->xfixes_event_base, &i) &&
137 XFixesQueryVersion(x11->display, &major, &minor) && major >= 1) {
138 x11->has_xfixes = 1;
139 XFixesSelectSelectionInput(x11->display, x11->root_window,
140 x11->clipboard_atom,
141 XFixesSetSelectionOwnerNotifyMask);
142 } else
143 fprintf(stderr, "no xfixes, no guest -> client copy paste support\n");
145 /* Catch resolution changes */
146 XSelectInput(x11->display, x11->root_window, StructureNotifyMask);
148 /* Get the current resolution */
149 XGetWindowAttributes(x11->display, x11->root_window, &attrib);
150 x11->width = attrib.width;
151 x11->height = attrib.height;
152 vdagent_x11_send_daemon_guest_xorg_res(x11);
154 /* No need for XFlush as XGetWindowAttributes does an implicit Xflush */
156 return x11;
159 void vdagent_x11_destroy(struct vdagent_x11 *x11)
161 if (!x11)
162 return;
164 XCloseDisplay(x11->display);
165 free(x11);
168 int vdagent_x11_get_fd(struct vdagent_x11 *x11)
170 return x11->fd;
173 static void vdagent_x11_set_clipboard_owner(struct vdagent_x11 *x11,
174 int new_owner)
176 if (x11->selection_request) {
177 fprintf(stderr,
178 "selection requests pending on clipboard ownership change, "
179 "clearing");
180 while (x11->selection_request)
181 vdagent_x11_send_selection_notify(x11, None, 0);
184 if (new_owner == owner_none) {
185 /* When going from owner_guest to owner_none we need to send a
186 clipboard release message to the client */
187 if (x11->clipboard_owner == owner_guest)
188 udscs_write(x11->vdagentd, VDAGENTD_CLIPBOARD_RELEASE, 0, NULL, 0);
190 x11->clipboard_type_count = 0;
192 x11->clipboard_owner = new_owner;
195 static void vdagent_x11_handle_event(struct vdagent_x11 *x11, XEvent event)
197 int handled = 0;
200 if (event.type == x11->xfixes_event_base) {
201 union {
202 XEvent ev;
203 XFixesSelectionNotifyEvent xfev;
204 } ev;
206 ev.ev = event;
207 if (ev.xfev.subtype != XFixesSetSelectionOwnerNotify) {
208 if (x11->verbose)
209 fprintf(stderr, "unexpected xfix event subtype %d window %d\n",
210 (int)ev.xfev.subtype, (int)event.xany.window);
211 return;
214 if (x11->verbose)
215 fprintf(stderr, "New selection owner: %u\n",
216 (unsigned int)ev.xfev.owner);
218 /* Ignore becoming the owner ourselves */
219 if (ev.xfev.owner == x11->selection_window)
220 return;
222 /* If the clipboard owner is changed we no longer own it */
223 vdagent_x11_set_clipboard_owner(x11, owner_none);
225 if (ev.xfev.owner == None)
226 return;
228 /* Request the supported targets from the new owner */
229 XConvertSelection(x11->display, x11->clipboard_atom, x11->targets_atom,
230 x11->targets_atom, x11->selection_window,
231 CurrentTime);
232 XFlush(x11->display);
233 x11->expected_targets_notifies++;
234 return;
237 switch (event.type) {
238 case ConfigureNotify:
239 if (event.xconfigure.window != x11->root_window)
240 break;
242 handled = 1;
244 if (event.xconfigure.width == x11->width &&
245 event.xconfigure.height == x11->height)
246 break;
248 x11->width = event.xconfigure.width;
249 x11->height = event.xconfigure.height;
251 vdagent_x11_send_daemon_guest_xorg_res(x11);
252 break;
253 case SelectionNotify:
254 if (event.xselection.target == x11->targets_atom)
255 vdagent_x11_handle_targets_notify(x11, &event);
256 else
257 vdagent_x11_handle_selection_notify(x11, &event);
259 handled = 1;
260 break;
261 case SelectionClear:
262 /* Do nothing the clipboard ownership will get updated through
263 the XFixesSetSelectionOwnerNotify event */
264 handled = 1;
265 break;
266 case SelectionRequest: {
267 struct vdagent_x11_selection_request *req, *new_req;
269 new_req = malloc(sizeof(*new_req));
270 if (!new_req) {
271 fprintf(stderr, "out of memory on SelectionRequest, ignoring.\n");
272 break;
275 handled = 1;
277 new_req->event = event;
278 new_req->next = NULL;
280 if (!x11->selection_request) {
281 x11->selection_request = new_req;
282 vdagent_x11_handle_selection_request(x11);
283 break;
286 /* maybe we should limit the selection_request stack depth ? */
287 req = x11->selection_request;
288 while (req->next)
289 req = req->next;
291 req->next = new_req;
292 break;
295 if (!handled && x11->verbose)
296 fprintf(stderr, "unhandled x11 event, type %d, window %d\n",
297 (int)event.type, (int)event.xany.window);
300 void vdagent_x11_do_read(struct vdagent_x11 *x11)
302 XEvent event;
304 while (XPending(x11->display)) {
305 XNextEvent(x11->display, &event);
306 vdagent_x11_handle_event(x11, event);
310 static void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11)
312 struct vdagentd_guest_xorg_resolution res;
314 res.width = x11->width;
315 res.height = x11->height;
317 udscs_write(x11->vdagentd, VDAGENTD_GUEST_XORG_RESOLUTION, 0,
318 (uint8_t *)&res, sizeof(res));
321 static const char *vdagent_x11_get_atom_name(struct vdagent_x11 *x11, Atom a)
323 if (a == None)
324 return "None";
326 return XGetAtomName(x11->display, a);
329 static int vdagent_x11_get_selection(struct vdagent_x11 *x11, XEvent *event,
330 Atom type, Atom prop, int format,
331 unsigned char **data)
333 Atom type_ret;
334 int format_ret;
335 unsigned long len, remain;
337 if (event->xselection.property == None) {
338 if (x11->verbose)
339 fprintf(stderr, "XConvertSelection refused by clipboard owner\n");
340 return -1;
343 if (event->xselection.requestor != x11->selection_window ||
344 event->xselection.selection != x11->clipboard_atom ||
345 event->xselection.property != prop) {
346 fprintf(stderr, "SelectionNotify parameters mismatch\n");
347 return -1;
350 /* FIXME when we've incr support we should not immediately
351 delete the property (as we need to first register for
352 property change events) */
353 if (XGetWindowProperty(x11->display, x11->selection_window, prop, 0,
354 LONG_MAX, True, type, &type_ret, &format_ret, &len,
355 &remain, data) != Success) {
356 fprintf(stderr, "XGetWindowProperty failed\n");
357 return -1;
360 if (type_ret == x11->incr_atom) {
361 /* FIXME */
362 fprintf(stderr, "incr properties are currently unsupported\n");
363 return -1;
366 if (type_ret != type) {
367 fprintf(stderr, "expected property type: %s, got: %s\n",
368 vdagent_x11_get_atom_name(x11, type),
369 vdagent_x11_get_atom_name(x11, type_ret));
370 return -1;
373 if (format_ret != format) {
374 fprintf(stderr, "expected %d bit format, got %d bits\n", format,
375 format_ret);
376 return -1;
379 if (len == 0) {
380 fprintf(stderr, "property contains no data (zero length)\n");
381 return -1;
384 return len;
387 static uint32_t vdagent_x11_target_to_type(struct vdagent_x11 *x11,
388 Atom target)
390 int i;
392 for (i = 0; i < utf8_atom_count; i++)
393 if (x11->utf8_atoms[i] == target)
394 return VD_AGENT_CLIPBOARD_UTF8_TEXT;
396 /* TODO Add support for more types here */
398 fprintf(stderr, "unexpected selection type %s\n",
399 vdagent_x11_get_atom_name(x11, target));
400 return VD_AGENT_CLIPBOARD_NONE;
403 static Atom vdagent_x11_type_to_target(struct vdagent_x11 *x11, uint32_t type)
405 int i;
407 for (i = 0; i < x11->clipboard_type_count; i++)
408 if (x11->clipboard_agent_types[i] == type)
409 return x11->clipboard_x11_targets[i];
411 fprintf(stderr, "client requested unavailable type %u\n", type);
412 return None;
415 static void vdagent_x11_handle_selection_notify(struct vdagent_x11 *x11,
416 XEvent *event)
418 int len;
419 unsigned char *data = NULL;
420 uint32_t type;
422 type = vdagent_x11_target_to_type(x11, event->xselection.target);
423 if (type == VD_AGENT_CLIPBOARD_NONE) {
424 udscs_write(x11->vdagentd, VDAGENTD_CLIPBOARD_DATA,
425 VD_AGENT_CLIPBOARD_NONE, NULL, 0);
426 return;
429 len = vdagent_x11_get_selection(x11, event, event->xselection.target,
430 x11->clipboard_atom, 8, &data);
431 if (len == -1) {
432 if (data)
433 XFree(data);
434 udscs_write(x11->vdagentd, VDAGENTD_CLIPBOARD_DATA,
435 VD_AGENT_CLIPBOARD_NONE, NULL, 0);
436 return;
439 udscs_write(x11->vdagentd, VDAGENTD_CLIPBOARD_DATA, type, data, len);
440 XFree(data);
443 static Atom atom_lists_overlap(Atom *atoms1, Atom *atoms2, int l1, int l2)
445 int i, j;
447 for (i = 0; i < l1; i++)
448 for (j = 0; j < l2; j++)
449 if (atoms1[i] == atoms2[j])
450 return atoms1[i];
452 return 0;
455 static void vdagent_x11_print_targets(struct vdagent_x11 *x11,
456 const char *action, Atom *atoms, int c)
458 int i;
460 if (!x11->verbose)
461 return;
463 fprintf(stderr, "%s %d targets:\n", action, c);
464 for (i = 0; i < c; i++)
465 fprintf(stderr, "%s\n", vdagent_x11_get_atom_name(x11, atoms[i]));
468 static void vdagent_x11_handle_targets_notify(struct vdagent_x11 *x11,
469 XEvent *event)
471 int len;
472 Atom atom, *atoms = NULL;
474 if (!x11->expected_targets_notifies) {
475 fprintf(stderr, "unexpected selection notify TARGETS\n");
476 return;
479 x11->expected_targets_notifies--;
481 /* If we have more targets_notifies pending, ignore this one, we
482 are only interested in the targets list of the current owner
483 (which is the last one we've requested a targets list from) */
484 if (x11->expected_targets_notifies)
485 return;
487 len = vdagent_x11_get_selection(x11, event, XA_ATOM, x11->targets_atom, 32,
488 (unsigned char **)&atoms);
489 if (len == -1) {
490 if (atoms)
491 XFree(atoms);
492 return;
495 vdagent_x11_print_targets(x11, "received", atoms, len);
497 x11->clipboard_type_count = 0;
498 atom = atom_lists_overlap(x11->utf8_atoms, atoms, utf8_atom_count, len);
499 if (atom) {
500 x11->clipboard_agent_types[x11->clipboard_type_count] =
501 VD_AGENT_CLIPBOARD_UTF8_TEXT;
502 x11->clipboard_x11_targets[x11->clipboard_type_count] = atom;
503 x11->clipboard_type_count++;
506 /* TODO Add support for more types here */
508 if (x11->clipboard_type_count) {
509 udscs_write(x11->vdagentd, VDAGENTD_CLIPBOARD_GRAB, 0,
510 (uint8_t *)x11->clipboard_agent_types,
511 x11->clipboard_type_count * sizeof(uint32_t));
512 vdagent_x11_set_clipboard_owner(x11, owner_guest);
514 XFree(atoms);
517 static void vdagent_x11_send_selection_notify(struct vdagent_x11 *x11,
518 Atom prop, int process_next_req)
520 XEvent res, *event = &x11->selection_request->event;
521 struct vdagent_x11_selection_request *selection_request;
523 res.xselection.property = prop;
524 res.xselection.type = SelectionNotify;
525 res.xselection.display = event->xselectionrequest.display;
526 res.xselection.requestor = event->xselectionrequest.requestor;
527 res.xselection.selection = event->xselectionrequest.selection;
528 res.xselection.target = event->xselectionrequest.target;
529 res.xselection.time = event->xselectionrequest.time;
530 XSendEvent(x11->display, event->xselectionrequest.requestor, 0, 0, &res);
531 XFlush(x11->display);
533 selection_request = x11->selection_request;
534 x11->selection_request = selection_request->next;
535 free(selection_request);
536 if (process_next_req)
537 vdagent_x11_handle_selection_request(x11);
540 static void vdagent_x11_send_targets(struct vdagent_x11 *x11, XEvent *event)
542 /* Warning the size of this needs to be increased each time we add support
543 for a new type, or the atom count of an existing type changes */
544 Atom prop, targets[4] = { x11->targets_atom, };
545 int i, j, target_count = 1;
547 for (i = 0; i < x11->clipboard_type_count; i++) {
548 switch (x11->clipboard_agent_types[i]) {
549 case VD_AGENT_CLIPBOARD_UTF8_TEXT:
550 for (j = 0; j < utf8_atom_count; j++) {
551 targets[target_count] = x11->utf8_atoms[j];
552 target_count++;
554 break;
555 /* TODO Add support for more types here */
559 prop = event->xselectionrequest.property;
560 if (prop == None)
561 prop = event->xselectionrequest.target;
563 XChangeProperty(x11->display, event->xselectionrequest.requestor, prop,
564 XA_ATOM, 32, PropModeReplace, (unsigned char *)&targets,
565 target_count);
566 vdagent_x11_print_targets(x11, "sent", targets, target_count);
567 vdagent_x11_send_selection_notify(x11, prop, 1);
570 static void vdagent_x11_handle_selection_request(struct vdagent_x11 *x11)
572 XEvent *event;
573 uint32_t type = VD_AGENT_CLIPBOARD_NONE;
575 if (!x11->selection_request)
576 return;
578 event = &x11->selection_request->event;
580 if (x11->clipboard_owner != owner_client) {
581 fprintf(stderr,
582 "received selection request event for target %s, "
583 "while not owning client clipboard\n",
584 vdagent_x11_get_atom_name(x11, event->xselectionrequest.target));
585 vdagent_x11_send_selection_notify(x11, None, 1);
586 return;
589 if (event->xselectionrequest.target == x11->multiple_atom) {
590 fprintf(stderr, "multiple target not supported\n");
591 vdagent_x11_send_selection_notify(x11, None, 1);
592 return;
595 if (event->xselectionrequest.target == x11->targets_atom) {
596 vdagent_x11_send_targets(x11, event);
597 return;
600 type = vdagent_x11_target_to_type(x11, event->xselectionrequest.target);
601 if (type == VD_AGENT_CLIPBOARD_NONE) {
602 vdagent_x11_send_selection_notify(x11, None, 1);
603 return;
606 udscs_write(x11->vdagentd, VDAGENTD_CLIPBOARD_REQUEST, type, NULL, 0);
609 void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11,
610 VDAgentMonitorsConfig *mon_config)
612 int i, num_sizes = 0;
613 int best = -1;
614 unsigned int closest_diff = -1;
615 XRRScreenSize* sizes;
616 XRRScreenConfiguration* config;
617 Rotation rotation;
619 if (!x11->has_xrandr)
620 return;
622 if (mon_config->num_of_monitors != 1) {
623 fprintf(stderr, "Only 1 monitor supported, ignoring monitor config\n");
624 return;
627 sizes = XRRSizes(x11->display, x11->screen, &num_sizes);
628 if (!sizes || !num_sizes) {
629 fprintf(stderr, "XRRSizes failed\n");
630 return;
633 /* Find the closest size which will fit within the monitor */
634 for (i = 0; i < num_sizes; i++) {
635 if (sizes[i].width > mon_config->monitors[0].width ||
636 sizes[i].height > mon_config->monitors[0].height)
637 continue; /* Too large for the monitor */
639 unsigned int wdiff = mon_config->monitors[0].width - sizes[i].width;
640 unsigned int hdiff = mon_config->monitors[0].height - sizes[i].height;
641 unsigned int diff = wdiff * wdiff + hdiff * hdiff;
642 if (diff < closest_diff) {
643 closest_diff = diff;
644 best = i;
648 if (best == -1) {
649 fprintf(stderr, "no suitable resolution found for monitor\n");
650 return;
653 config = XRRGetScreenInfo(x11->display, x11->root_window);
654 if(!config) {
655 fprintf(stderr, "get screen info failed\n");
656 return;
658 XRRConfigCurrentConfiguration(config, &rotation);
659 XRRSetScreenConfig(x11->display, config, x11->root_window, best,
660 rotation, CurrentTime);
661 XRRFreeScreenConfigInfo(config);
662 XFlush(x11->display);
665 void vdagent_x11_clipboard_request(struct vdagent_x11 *x11, uint32_t type)
667 Atom target;
669 if (x11->clipboard_owner != owner_guest) {
670 fprintf(stderr,
671 "received clipboard req while not owning guest clipboard\n");
672 udscs_write(x11->vdagentd, VDAGENTD_CLIPBOARD_DATA,
673 VD_AGENT_CLIPBOARD_NONE, NULL, 0);
674 return;
677 target = vdagent_x11_type_to_target(x11, type);
678 if (target == None) {
679 udscs_write(x11->vdagentd, VDAGENTD_CLIPBOARD_DATA,
680 VD_AGENT_CLIPBOARD_NONE, NULL, 0);
681 return;
684 XConvertSelection(x11->display, x11->clipboard_atom, target,
685 x11->clipboard_atom, x11->selection_window, CurrentTime);
686 XFlush(x11->display);
689 void vdagent_x11_clipboard_grab(struct vdagent_x11 *x11, uint32_t *types,
690 uint32_t type_count)
692 int i;
694 x11->clipboard_type_count = 0;
695 for (i = 0; i < type_count; i++) {
696 /* TODO Add support for more types here */
697 /* Check if we support the type */
698 if (types[i] != VD_AGENT_CLIPBOARD_UTF8_TEXT)
699 continue;
701 x11->clipboard_agent_types[x11->clipboard_type_count] = types[i];
702 x11->clipboard_type_count++;
705 if (!x11->clipboard_type_count)
706 return;
708 XSetSelectionOwner(x11->display, x11->clipboard_atom,
709 x11->selection_window, CurrentTime);
710 XFlush(x11->display);
711 vdagent_x11_set_clipboard_owner(x11, owner_client);
714 void vdagent_x11_clipboard_data(struct vdagent_x11 *x11, uint32_t type,
715 const uint8_t *data, uint32_t size)
717 Atom prop;
718 XEvent *event;
719 uint32_t type_from_event;
721 if (!x11->selection_request) {
722 fprintf(stderr, "received clipboard data without an outstanding"
723 "selection request, ignoring\n");
724 return;
727 event = &x11->selection_request->event;
728 type_from_event = vdagent_x11_target_to_type(x11,
729 event->xselectionrequest.target);
730 if (type_from_event != type) {
731 fprintf(stderr, "expecting type %u clipboard data got %u\n",
732 type_from_event, type);
733 vdagent_x11_send_selection_notify(x11, None, 1);
734 return;
737 prop = event->xselectionrequest.property;
738 if (prop == None)
739 prop = event->xselectionrequest.target;
741 /* FIXME: use INCR for large data transfers */
742 XChangeProperty(x11->display, event->xselectionrequest.requestor, prop,
743 event->xselectionrequest.target, 8, PropModeReplace,
744 data, size);
745 vdagent_x11_send_selection_notify(x11, prop, 1);
748 void vdagent_x11_clipboard_release(struct vdagent_x11 *x11)
750 XEvent event;
752 if (x11->clipboard_owner != owner_client) {
753 fprintf(stderr,
754 "received clipboard release while not owning client clipboard\n");
755 return;
758 XSetSelectionOwner(x11->display, x11->clipboard_atom, None, CurrentTime);
759 /* Make sure we process the XFixesSetSelectionOwnerNotify event caused
760 by this, so we don't end up changing the clipboard owner to none, after
761 it has already been re-owned because this event is still pending. */
762 XSync(x11->display, False);
763 while (XCheckTypedEvent(x11->display, x11->xfixes_event_base,
764 &event))
765 vdagent_x11_handle_event(x11, event);
767 /* Note no need to do a set_clipboard_owner(owner_none) here, as that is
768 already done by processing the XFixesSetSelectionOwnerNotify event. */