parent
a921901369
commit
102bf0335d
@ -0,0 +1,634 @@ |
||||
/*
|
||||
* Copyright © 2012 Intel Corporation |
||||
* |
||||
* Permission to use, copy, modify, distribute, and sell this software and |
||||
* its documentation for any purpose is hereby granted without fee, provided |
||||
* that the above copyright notice appear in all copies and that both that |
||||
* copyright notice and this permission notice appear in supporting |
||||
* documentation, and that the name of the copyright holders not be used in |
||||
* advertising or publicity pertaining to distribution of the software |
||||
* without specific, written prior permission. The copyright holders make |
||||
* no representations about the suitability of this software for any |
||||
* purpose. It is provided "as is" without express or implied warranty. |
||||
* |
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS |
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND |
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER |
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF |
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
*/ |
||||
|
||||
#define _GNU_SOURCE |
||||
|
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
#include <fcntl.h> |
||||
|
||||
#include "xwayland.h" |
||||
|
||||
static int |
||||
weston_wm_write_property(int fd, uint32_t mask, void *data) |
||||
{ |
||||
struct weston_wm *wm = data; |
||||
unsigned char *property; |
||||
int len, remainder; |
||||
|
||||
property = xcb_get_property_value(wm->property_reply); |
||||
remainder = xcb_get_property_value_length(wm->property_reply) - |
||||
wm->property_start; |
||||
|
||||
len = write(fd, property + wm->property_start, remainder); |
||||
if (len == -1) { |
||||
free(wm->property_reply); |
||||
wl_event_source_remove(wm->property_source); |
||||
close(fd); |
||||
fprintf(stderr, "write error to target fd: %m\n"); |
||||
return 1; |
||||
} |
||||
|
||||
fprintf(stderr, "wrote %d (chunk size %d) of %d bytes\n", |
||||
wm->property_start + len, |
||||
len, xcb_get_property_value_length(wm->property_reply)); |
||||
|
||||
wm->property_start += len; |
||||
if (len == remainder) { |
||||
free(wm->property_reply); |
||||
wl_event_source_remove(wm->property_source); |
||||
|
||||
if (wm->incr) { |
||||
xcb_delete_property(wm->conn, |
||||
wm->selection_window, |
||||
wm->atom.wl_selection); |
||||
} else { |
||||
fprintf(stderr, "transfer complete\n"); |
||||
close(fd); |
||||
} |
||||
} |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
static void |
||||
weston_wm_get_incr_chunk(struct weston_wm *wm) |
||||
{ |
||||
xcb_get_property_cookie_t cookie; |
||||
xcb_get_property_reply_t *reply; |
||||
|
||||
cookie = xcb_get_property(wm->conn, |
||||
0, /* delete */ |
||||
wm->selection_window, |
||||
wm->atom.wl_selection, |
||||
XCB_GET_PROPERTY_TYPE_ANY, |
||||
0, /* offset */ |
||||
0x1fffffff /* length */); |
||||
|
||||
reply = xcb_get_property_reply(wm->conn, cookie, NULL); |
||||
|
||||
dump_property(wm, wm->atom.wl_selection, reply); |
||||
|
||||
if (xcb_get_property_value_length(reply) > 0) { |
||||
wm->property_start = 0; |
||||
wm->property_source = |
||||
wl_event_loop_add_fd(wm->server->loop, |
||||
wm->data_source_fd, |
||||
WL_EVENT_WRITABLE, |
||||
weston_wm_write_property, |
||||
wm); |
||||
wm->property_reply = reply; |
||||
} else { |
||||
fprintf(stderr, "transfer complete\n"); |
||||
close(wm->data_source_fd); |
||||
free(reply); |
||||
} |
||||
} |
||||
|
||||
static void |
||||
data_offer_accept(struct wl_client *client, struct wl_resource *resource, |
||||
uint32_t time, const char *mime_type) |
||||
{ |
||||
} |
||||
|
||||
static void |
||||
data_offer_receive(struct wl_client *client, struct wl_resource *resource, |
||||
const char *mime_type, int32_t fd) |
||||
{ |
||||
struct wl_data_offer *offer = resource->data; |
||||
struct weston_wm *wm = offer->source->resource.data; |
||||
|
||||
if (strcmp(mime_type, "text/plain;charset=utf-8") == 0) { |
||||
/* Get data for the utf8_string target */ |
||||
xcb_convert_selection(wm->conn, |
||||
wm->selection_window, |
||||
wm->atom.clipboard, |
||||
wm->atom.utf8_string, |
||||
wm->atom.wl_selection, |
||||
XCB_TIME_CURRENT_TIME); |
||||
|
||||
xcb_flush(wm->conn); |
||||
|
||||
fcntl(fd, F_SETFL, O_WRONLY | O_NONBLOCK); |
||||
wm->data_source_fd = fd; |
||||
} else { |
||||
close(fd); |
||||
} |
||||
} |
||||
|
||||
static void |
||||
data_offer_destroy(struct wl_client *client, struct wl_resource *resource) |
||||
{ |
||||
wl_resource_destroy(resource); |
||||
} |
||||
|
||||
static const struct wl_data_offer_interface data_offer_interface = { |
||||
data_offer_accept, |
||||
data_offer_receive, |
||||
data_offer_destroy, |
||||
}; |
||||
|
||||
static void |
||||
data_source_cancel(struct wl_data_source *source) |
||||
{ |
||||
} |
||||
|
||||
static void |
||||
weston_wm_get_selection_targets(struct weston_wm *wm) |
||||
{ |
||||
struct wl_data_source *source; |
||||
struct weston_compositor *compositor; |
||||
xcb_get_property_cookie_t cookie; |
||||
xcb_get_property_reply_t *reply; |
||||
xcb_atom_t *value; |
||||
char **p; |
||||
uint32_t i; |
||||
|
||||
cookie = xcb_get_property(wm->conn, |
||||
1, /* delete */ |
||||
wm->selection_window, |
||||
wm->atom.wl_selection, |
||||
XCB_GET_PROPERTY_TYPE_ANY, |
||||
0, /* offset */ |
||||
4096 /* length */); |
||||
|
||||
reply = xcb_get_property_reply(wm->conn, cookie, NULL); |
||||
|
||||
dump_property(wm, wm->atom.wl_selection, reply); |
||||
|
||||
if (reply->type != XCB_ATOM_ATOM) { |
||||
free(reply); |
||||
return; |
||||
} |
||||
|
||||
source = malloc(sizeof *source); |
||||
if (source == NULL) |
||||
return; |
||||
|
||||
wl_signal_init(&source->resource.destroy_signal); |
||||
source->offer_interface = &data_offer_interface; |
||||
source->cancel = data_source_cancel; |
||||
source->resource.data = wm; |
||||
|
||||
wl_array_init(&source->mime_types); |
||||
value = xcb_get_property_value(reply); |
||||
for (i = 0; i < reply->value_len; i++) { |
||||
if (value[i] == wm->atom.utf8_string) { |
||||
p = wl_array_add(&source->mime_types, sizeof *p); |
||||
if (p) |
||||
*p = strdup("text/plain;charset=utf-8"); |
||||
} |
||||
} |
||||
|
||||
compositor = wm->server->compositor; |
||||
wl_seat_set_selection(&compositor->seat->seat, source, |
||||
wl_display_next_serial(compositor->wl_display)); |
||||
|
||||
free(reply); |
||||
} |
||||
|
||||
static void |
||||
weston_wm_get_selection_data(struct weston_wm *wm) |
||||
{ |
||||
xcb_get_property_cookie_t cookie; |
||||
xcb_get_property_reply_t *reply; |
||||
|
||||
cookie = xcb_get_property(wm->conn, |
||||
1, /* delete */ |
||||
wm->selection_window, |
||||
wm->atom.wl_selection, |
||||
XCB_GET_PROPERTY_TYPE_ANY, |
||||
0, /* offset */ |
||||
0x1fffffff /* length */); |
||||
|
||||
reply = xcb_get_property_reply(wm->conn, cookie, NULL); |
||||
|
||||
if (reply->type == wm->atom.incr) { |
||||
dump_property(wm, wm->atom.wl_selection, reply); |
||||
wm->incr = 1; |
||||
free(reply); |
||||
} else { |
||||
dump_property(wm, wm->atom.wl_selection, reply); |
||||
wm->incr = 0; |
||||
wm->property_start = 0; |
||||
wm->property_source = |
||||
wl_event_loop_add_fd(wm->server->loop, |
||||
wm->data_source_fd, |
||||
WL_EVENT_WRITABLE, |
||||
weston_wm_write_property, |
||||
wm); |
||||
wm->property_reply = reply; |
||||
} |
||||
} |
||||
|
||||
static void |
||||
weston_wm_handle_selection_notify(struct weston_wm *wm, |
||||
xcb_generic_event_t *event) |
||||
{ |
||||
xcb_selection_notify_event_t *selection_notify = |
||||
(xcb_selection_notify_event_t *) event; |
||||
|
||||
if (selection_notify->property == XCB_ATOM_NONE) { |
||||
/* convert selection failed */ |
||||
} else if (selection_notify->target == wm->atom.targets) { |
||||
weston_wm_get_selection_targets(wm); |
||||
} else { |
||||
weston_wm_get_selection_data(wm); |
||||
} |
||||
} |
||||
|
||||
static const size_t incr_chunk_size = 64 * 1024; |
||||
|
||||
static void |
||||
weston_wm_send_selection_notify(struct weston_wm *wm, xcb_atom_t property) |
||||
{ |
||||
xcb_selection_notify_event_t selection_notify; |
||||
|
||||
memset(&selection_notify, 0, sizeof selection_notify); |
||||
selection_notify.response_type = XCB_SELECTION_NOTIFY; |
||||
selection_notify.sequence = 0; |
||||
selection_notify.time = wm->selection_request.time; |
||||
selection_notify.requestor = wm->selection_request.requestor; |
||||
selection_notify.selection = wm->selection_request.selection; |
||||
selection_notify.target = wm->selection_request.target; |
||||
selection_notify.property = property; |
||||
|
||||
xcb_send_event(wm->conn, 0, /* propagate */ |
||||
wm->selection_request.requestor, |
||||
XCB_EVENT_MASK_NO_EVENT, (char *) &selection_notify); |
||||
} |
||||
|
||||
static void |
||||
weston_wm_send_targets(struct weston_wm *wm) |
||||
{ |
||||
xcb_atom_t targets[] = { |
||||
wm->atom.timestamp, |
||||
wm->atom.targets, |
||||
wm->atom.utf8_string, |
||||
/* wm->atom.compound_text, */ |
||||
wm->atom.text, |
||||
/* wm->atom.string */ |
||||
}; |
||||
|
||||
xcb_change_property(wm->conn, |
||||
XCB_PROP_MODE_REPLACE, |
||||
wm->selection_request.requestor, |
||||
wm->selection_request.property, |
||||
XCB_ATOM_ATOM, |
||||
32, /* format */ |
||||
ARRAY_LENGTH(targets), targets); |
||||
|
||||
weston_wm_send_selection_notify(wm, wm->selection_request.property); |
||||
} |
||||
|
||||
static void |
||||
weston_wm_send_timestamp(struct weston_wm *wm) |
||||
{ |
||||
xcb_change_property(wm->conn, |
||||
XCB_PROP_MODE_REPLACE, |
||||
wm->selection_request.requestor, |
||||
wm->selection_request.property, |
||||
XCB_ATOM_INTEGER, |
||||
32, /* format */ |
||||
1, &wm->selection_timestamp); |
||||
|
||||
weston_wm_send_selection_notify(wm, wm->selection_request.property); |
||||
} |
||||
|
||||
static int |
||||
weston_wm_flush_source_data(struct weston_wm *wm) |
||||
{ |
||||
int length; |
||||
|
||||
xcb_change_property(wm->conn, |
||||
XCB_PROP_MODE_REPLACE, |
||||
wm->selection_request.requestor, |
||||
wm->selection_request.property, |
||||
wm->selection_target, |
||||
8, /* format */ |
||||
wm->source_data.size, |
||||
wm->source_data.data); |
||||
wm->selection_property_set = 1; |
||||
length = wm->source_data.size; |
||||
wm->source_data.size = 0; |
||||
|
||||
return length; |
||||
} |
||||
|
||||
static int |
||||
weston_wm_read_data_source(int fd, uint32_t mask, void *data) |
||||
{ |
||||
struct weston_wm *wm = data; |
||||
int len, current, available; |
||||
void *p; |
||||
|
||||
current = wm->source_data.size; |
||||
if (wm->source_data.size < incr_chunk_size) |
||||
p = wl_array_add(&wm->source_data, incr_chunk_size); |
||||
else |
||||
p = (char *) wm->source_data.data + wm->source_data.size; |
||||
available = wm->source_data.alloc - current; |
||||
|
||||
len = read(fd, p, available); |
||||
if (len == -1) { |
||||
fprintf(stderr, "read error from data source: %m\n"); |
||||
weston_wm_send_selection_notify(wm, XCB_ATOM_NONE); |
||||
wl_event_source_remove(wm->property_source); |
||||
close(fd); |
||||
wl_array_release(&wm->source_data); |
||||
} |
||||
|
||||
fprintf(stderr, "read %d (available %d, mask 0x%x) bytes: \"%.*s\"\n", |
||||
len, available, mask, len, (char *) p); |
||||
|
||||
wm->source_data.size = current + len; |
||||
if (wm->source_data.size >= incr_chunk_size) { |
||||
if (!wm->incr) { |
||||
fprintf(stderr, "got %zu bytes, starting incr\n", |
||||
wm->source_data.size); |
||||
wm->incr = 1; |
||||
xcb_change_property(wm->conn, |
||||
XCB_PROP_MODE_REPLACE, |
||||
wm->selection_request.requestor, |
||||
wm->selection_request.property, |
||||
wm->atom.incr, |
||||
32, /* format */ |
||||
1, &incr_chunk_size); |
||||
wm->selection_property_set = 1; |
||||
wm->flush_property_on_delete = 1; |
||||
wl_event_source_remove(wm->property_source); |
||||
weston_wm_send_selection_notify(wm, wm->selection_request.property); |
||||
} else if (wm->selection_property_set) { |
||||
fprintf(stderr, "got %zu bytes, waiting for " |
||||
"property delete\n", wm->source_data.size); |
||||
|
||||
wm->flush_property_on_delete = 1; |
||||
wl_event_source_remove(wm->property_source); |
||||
} else { |
||||
fprintf(stderr, "got %zu bytes, " |
||||
"property deleted, seting new property\n", |
||||
wm->source_data.size); |
||||
weston_wm_flush_source_data(wm); |
||||
} |
||||
} else if (len == 0 && !wm->incr) { |
||||
fprintf(stderr, "non-incr transfer complete\n"); |
||||
/* Non-incr transfer all done. */ |
||||
weston_wm_flush_source_data(wm); |
||||
weston_wm_send_selection_notify(wm, wm->selection_request.property); |
||||
xcb_flush(wm->conn); |
||||
wl_event_source_remove(wm->property_source); |
||||
close(fd); |
||||
wl_array_release(&wm->source_data); |
||||
wm->selection_request.requestor = XCB_NONE; |
||||
} else if (len == 0 && wm->incr) { |
||||
fprintf(stderr, "incr transfer complete\n"); |
||||
|
||||
wm->flush_property_on_delete = 1; |
||||
if (wm->selection_property_set) { |
||||
fprintf(stderr, "got %zu bytes, waiting for " |
||||
"property delete\n", wm->source_data.size); |
||||
} else { |
||||
fprintf(stderr, "got %zu bytes, " |
||||
"property deleted, seting new property\n", |
||||
wm->source_data.size); |
||||
weston_wm_flush_source_data(wm); |
||||
} |
||||
xcb_flush(wm->conn); |
||||
wl_event_source_remove(wm->property_source); |
||||
wm->data_source_fd = -1; |
||||
close(fd); |
||||
} else { |
||||
fprintf(stderr, "nothing happened, buffered the bytes\n"); |
||||
} |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
static void |
||||
weston_wm_send_data(struct weston_wm *wm, xcb_atom_t target, const char *mime_type) |
||||
{ |
||||
struct wl_seat *seat = &wm->server->compositor->seat->seat; |
||||
int p[2]; |
||||
|
||||
if (pipe2(p, O_CLOEXEC | O_NONBLOCK) == -1) { |
||||
fprintf(stderr, "pipe2 failed: %m\n"); |
||||
weston_wm_send_selection_notify(wm, XCB_ATOM_NONE); |
||||
return; |
||||
} |
||||
|
||||
wl_array_init(&wm->source_data); |
||||
wm->selection_target = target; |
||||
wm->data_source_fd = p[0]; |
||||
wm->property_source = wl_event_loop_add_fd(wm->server->loop, |
||||
wm->data_source_fd, |
||||
WL_EVENT_READABLE, |
||||
weston_wm_read_data_source, |
||||
wm); |
||||
|
||||
wl_data_source_send_send(&seat->selection_data_source->resource, |
||||
mime_type, p[1]); |
||||
close(p[1]); |
||||
} |
||||
|
||||
static void |
||||
weston_wm_send_incr_chunk(struct weston_wm *wm) |
||||
{ |
||||
int length; |
||||
|
||||
fprintf(stderr, "property deleted\n"); |
||||
|
||||
wm->selection_property_set = 0; |
||||
if (wm->flush_property_on_delete) { |
||||
fprintf(stderr, "setting new property, %zu bytes\n", |
||||
wm->source_data.size); |
||||
wm->flush_property_on_delete = 0; |
||||
length = weston_wm_flush_source_data(wm); |
||||
|
||||
if (wm->data_source_fd >= 0) { |
||||
wm->property_source = |
||||
wl_event_loop_add_fd(wm->server->loop, |
||||
wm->data_source_fd, |
||||
WL_EVENT_READABLE, |
||||
weston_wm_read_data_source, |
||||
wm); |
||||
} else if (length > 0) { |
||||
/* Transfer is all done, but queue a flush for
|
||||
* the delete of the last chunk so we can set |
||||
* the 0 sized propert to signal the end of |
||||
* the transfer. */ |
||||
wm->flush_property_on_delete = 1; |
||||
wl_array_release(&wm->source_data); |
||||
} else { |
||||
wm->selection_request.requestor = XCB_NONE; |
||||
} |
||||
} |
||||
} |
||||
|
||||
static int |
||||
weston_wm_handle_selection_property_notify(struct weston_wm *wm, |
||||
xcb_generic_event_t *event) |
||||
{ |
||||
xcb_property_notify_event_t *property_notify = |
||||
(xcb_property_notify_event_t *) event; |
||||
|
||||
if (property_notify->window == wm->selection_window) { |
||||
if (property_notify->state == XCB_PROPERTY_NEW_VALUE && |
||||
property_notify->atom == wm->atom.wl_selection && |
||||
wm->incr) |
||||
weston_wm_get_incr_chunk(wm); |
||||
return 1; |
||||
} else if (property_notify->window == wm->selection_request.requestor) { |
||||
if (property_notify->state == XCB_PROPERTY_DELETE && |
||||
property_notify->atom == wm->selection_request.property && |
||||
wm->incr) |
||||
weston_wm_send_incr_chunk(wm); |
||||
return 1; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static void |
||||
weston_wm_handle_selection_request(struct weston_wm *wm, |
||||
xcb_generic_event_t *event) |
||||
{ |
||||
xcb_selection_request_event_t *selection_request = |
||||
(xcb_selection_request_event_t *) event; |
||||
|
||||
fprintf(stderr, "selection request, %s, ", |
||||
get_atom_name(wm->conn, selection_request->selection)); |
||||
fprintf(stderr, "target %s, ", |
||||
get_atom_name(wm->conn, selection_request->target)); |
||||
fprintf(stderr, "property %s\n", |
||||
get_atom_name(wm->conn, selection_request->property)); |
||||
|
||||
wm->selection_request = *selection_request; |
||||
wm->incr = 0; |
||||
wm->flush_property_on_delete = 0; |
||||
|
||||
if (selection_request->target == wm->atom.targets) { |
||||
weston_wm_send_targets(wm); |
||||
} else if (selection_request->target == wm->atom.timestamp) { |
||||
weston_wm_send_timestamp(wm); |
||||
} else if (selection_request->target == wm->atom.utf8_string || |
||||
selection_request->target == wm->atom.text) { |
||||
weston_wm_send_data(wm, wm->atom.utf8_string, |
||||
"text/plain;charset=utf-8"); |
||||
} else { |
||||
fprintf(stderr, "can only handle UTF8_STRING targets...\n"); |
||||
weston_wm_send_selection_notify(wm, XCB_ATOM_NONE); |
||||
} |
||||
} |
||||
|
||||
static void |
||||
weston_wm_handle_xfixes_selection_notify(struct weston_wm *wm, |
||||
xcb_generic_event_t *event) |
||||
{ |
||||
xcb_xfixes_selection_notify_event_t *xfixes_selection_notify = |
||||
(xcb_xfixes_selection_notify_event_t *) event; |
||||
|
||||
printf("xfixes selection notify event: owner %d\n", |
||||
xfixes_selection_notify->owner); |
||||
|
||||
/* We have to use XCB_TIME_CURRENT_TIME when we claim the
|
||||
* selection, so grab the actual timestamp here so we can |
||||
* answer TIMESTAMP conversion requests correctly. */ |
||||
if (xfixes_selection_notify->owner == wm->selection_window) { |
||||
wm->selection_timestamp = xfixes_selection_notify->timestamp; |
||||
fprintf(stderr, "our window, skipping\n"); |
||||
return; |
||||
} |
||||
|
||||
wm->incr = 0; |
||||
xcb_convert_selection(wm->conn, wm->selection_window, |
||||
wm->atom.clipboard, |
||||
wm->atom.targets, |
||||
wm->atom.wl_selection, |
||||
xfixes_selection_notify->timestamp); |
||||
|
||||
xcb_flush(wm->conn); |
||||
} |
||||
|
||||
int |
||||
weston_wm_handle_selection_event(struct weston_wm *wm, |
||||
xcb_generic_event_t *event) |
||||
{ |
||||
switch (event->response_type & ~0x80) { |
||||
case XCB_SELECTION_NOTIFY: |
||||
weston_wm_handle_selection_notify(wm, event); |
||||
return 1; |
||||
case XCB_PROPERTY_NOTIFY: |
||||
return weston_wm_handle_selection_property_notify(wm, event); |
||||
case XCB_SELECTION_REQUEST: |
||||
weston_wm_handle_selection_request(wm, event); |
||||
return 1; |
||||
} |
||||
|
||||
switch (event->response_type - wm->xfixes->first_event) { |
||||
case XCB_XFIXES_SELECTION_NOTIFY: |
||||
weston_wm_handle_xfixes_selection_notify(wm, event); |
||||
return 1; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void |
||||
weston_wm_set_selection(struct wl_listener *listener, void *data) |
||||
{ |
||||
struct wl_seat *seat = data; |
||||
struct weston_wm *wm = |
||||
container_of(listener, struct weston_wm, selection_listener); |
||||
struct wl_data_source *source = seat->selection_data_source; |
||||
const char **p, **end; |
||||
int has_text_plain = 0; |
||||
|
||||
if (source->offer_interface == &data_offer_interface) |
||||
return; |
||||
|
||||
fprintf(stderr, "set selection\n"); |
||||
|
||||
p = source->mime_types.data; |
||||
end = (const char **) |
||||
((char *) source->mime_types.data + source->mime_types.size); |
||||
while (p < end) { |
||||
fprintf(stderr, " %s\n", *p); |
||||
if (strcmp(*p, "text/plain") == 0 || |
||||
strcmp(*p, "text/plain;charset=utf-8") == 0) |
||||
has_text_plain = 1; |
||||
p++; |
||||
} |
||||
|
||||
if (has_text_plain) { |
||||
xcb_set_selection_owner(wm->conn, |
||||
wm->selection_window, |
||||
wm->atom.clipboard, |
||||
XCB_TIME_CURRENT_TIME); |
||||
} else { |
||||
xcb_set_selection_owner(wm->conn, |
||||
XCB_ATOM_NONE, |
||||
wm->atom.clipboard, |
||||
XCB_TIME_CURRENT_TIME); |
||||
} |
||||
} |
@ -0,0 +1,134 @@ |
||||
/*
|
||||
* Copyright © 2012 Intel Corporation |
||||
* |
||||
* Permission to use, copy, modify, distribute, and sell this software and |
||||
* its documentation for any purpose is hereby granted without fee, provided |
||||
* that the above copyright notice appear in all copies and that both that |
||||
* copyright notice and this permission notice appear in supporting |
||||
* documentation, and that the name of the copyright holders not be used in |
||||
* advertising or publicity pertaining to distribution of the software |
||||
* without specific, written prior permission. The copyright holders make |
||||
* no representations about the suitability of this software for any |
||||
* purpose. It is provided "as is" without express or implied warranty. |
||||
* |
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS |
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND |
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER |
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF |
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
*/ |
||||
|
||||
#include <wayland-server.h> |
||||
#include <xcb/xcb.h> |
||||
#include <xcb/xfixes.h> |
||||
#include <cairo/cairo-xcb.h> |
||||
|
||||
#include "../compositor.h" |
||||
|
||||
struct xserver { |
||||
struct wl_resource resource; |
||||
}; |
||||
|
||||
struct weston_xserver { |
||||
struct wl_display *wl_display; |
||||
struct wl_event_loop *loop; |
||||
struct wl_event_source *sigchld_source; |
||||
int abstract_fd; |
||||
struct wl_event_source *abstract_source; |
||||
int unix_fd; |
||||
struct wl_event_source *unix_source; |
||||
int display; |
||||
struct weston_process process; |
||||
struct wl_resource *resource; |
||||
struct wl_client *client; |
||||
struct weston_compositor *compositor; |
||||
struct weston_wm *wm; |
||||
struct wl_listener activate_listener; |
||||
struct wl_listener destroy_listener; |
||||
}; |
||||
|
||||
struct weston_wm { |
||||
xcb_connection_t *conn; |
||||
const xcb_query_extension_reply_t *xfixes; |
||||
struct wl_event_source *source; |
||||
xcb_screen_t *screen; |
||||
struct hash_table *window_hash; |
||||
struct weston_xserver *server; |
||||
xcb_window_t wm_window; |
||||
struct weston_wm_window *focus_window; |
||||
struct theme *theme; |
||||
xcb_render_pictforminfo_t render_format; |
||||
|
||||
xcb_window_t selection_window; |
||||
int incr; |
||||
int data_source_fd; |
||||
struct wl_event_source *property_source; |
||||
xcb_get_property_reply_t *property_reply; |
||||
int property_start; |
||||
struct wl_array source_data; |
||||
xcb_selection_request_event_t selection_request; |
||||
xcb_atom_t selection_target; |
||||
xcb_timestamp_t selection_timestamp; |
||||
int selection_property_set; |
||||
int flush_property_on_delete; |
||||
struct wl_listener selection_listener; |
||||
|
||||
struct { |
||||
xcb_atom_t wm_protocols; |
||||
xcb_atom_t wm_take_focus; |
||||
xcb_atom_t wm_delete_window; |
||||
xcb_atom_t net_wm_name; |
||||
xcb_atom_t net_wm_icon; |
||||
xcb_atom_t net_wm_state; |
||||
xcb_atom_t net_wm_state_fullscreen; |
||||
xcb_atom_t net_wm_user_time; |
||||
xcb_atom_t net_wm_icon_name; |
||||
xcb_atom_t net_wm_window_type; |
||||
xcb_atom_t net_wm_window_type_desktop; |
||||
xcb_atom_t net_wm_window_type_dock; |
||||
xcb_atom_t net_wm_window_type_toolbar; |
||||
xcb_atom_t net_wm_window_type_menu; |
||||
xcb_atom_t net_wm_window_type_utility; |
||||
xcb_atom_t net_wm_window_type_splash; |
||||
xcb_atom_t net_wm_window_type_dialog; |
||||
xcb_atom_t net_wm_window_type_dropdown; |
||||
xcb_atom_t net_wm_window_type_popup; |
||||
xcb_atom_t net_wm_window_type_tooltip; |
||||
xcb_atom_t net_wm_window_type_notification; |
||||
xcb_atom_t net_wm_window_type_combo; |
||||
xcb_atom_t net_wm_window_type_dnd; |
||||
xcb_atom_t net_wm_window_type_normal; |
||||
xcb_atom_t net_wm_moveresize; |
||||
xcb_atom_t net_supporting_wm_check; |
||||
xcb_atom_t net_supported; |
||||
xcb_atom_t motif_wm_hints; |
||||
xcb_atom_t clipboard; |
||||
xcb_atom_t targets; |
||||
xcb_atom_t utf8_string; |
||||
xcb_atom_t wl_selection; |
||||
xcb_atom_t incr; |
||||
xcb_atom_t timestamp; |
||||
xcb_atom_t multiple; |
||||
xcb_atom_t compound_text; |
||||
xcb_atom_t text; |
||||
xcb_atom_t string; |
||||
xcb_atom_t text_plain_utf8; |
||||
xcb_atom_t text_plain; |
||||
} atom; |
||||
}; |
||||
|
||||
void |
||||
dump_property(struct weston_wm *wm, xcb_atom_t property, |
||||
xcb_get_property_reply_t *reply); |
||||
|
||||
const char * |
||||
get_atom_name(xcb_connection_t *c, xcb_atom_t atom); |
||||
|
||||
int |
||||
weston_wm_handle_selection_event(struct weston_wm *wm, |
||||
xcb_generic_event_t *event); |
||||
|
||||
void |
||||
weston_wm_set_selection(struct wl_listener *listener, void *data); |
Loading…
Reference in new issue