xwayland: Split selection code into its own file
This commit is contained in:
parent
a921901369
commit
102bf0335d
|
@ -15,6 +15,7 @@ xserver_launcher_la_LIBADD = \
|
|||
xserver_launcher_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
|
||||
xserver_launcher_la_SOURCES = \
|
||||
xserver-launcher.c \
|
||||
selection.c \
|
||||
xserver-protocol.c \
|
||||
xserver-server-protocol.h \
|
||||
hash.c \
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -32,39 +32,13 @@
|
|||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xfixes.h>
|
||||
#include <cairo/cairo-xcb.h>
|
||||
|
||||
#include <wayland-server.h>
|
||||
#include "xwayland.h"
|
||||
|
||||
#include "../../shared/cairo-util.h"
|
||||
#include "../compositor.h"
|
||||
#include "xserver-server-protocol.h"
|
||||
#include "hash.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 motif_wm_hints {
|
||||
uint32_t flags;
|
||||
uint32_t functions;
|
||||
|
@ -114,75 +88,7 @@ struct motif_wm_hints {
|
|||
#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */
|
||||
#define _NET_WM_MOVERESIZE_CANCEL 11 /* cancel operation */
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
struct weston_wm_window {
|
||||
struct weston_wm *wm;
|
||||
|
@ -207,7 +113,7 @@ struct weston_wm_window {
|
|||
static struct weston_wm_window *
|
||||
get_wm_window(struct weston_surface *surface);
|
||||
|
||||
static const char *
|
||||
const char *
|
||||
get_atom_name(xcb_connection_t *c, xcb_atom_t atom)
|
||||
{
|
||||
xcb_get_atom_name_cookie_t cookie;
|
||||
|
@ -228,7 +134,7 @@ get_atom_name(xcb_connection_t *c, xcb_atom_t atom)
|
|||
return buffer;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
dump_property(struct weston_wm *wm, xcb_atom_t property,
|
||||
xcb_get_property_reply_t *reply)
|
||||
{
|
||||
|
@ -413,257 +319,6 @@ weston_wm_window_read_properties(struct weston_wm_window *window)
|
|||
}
|
||||
}
|
||||
|
||||
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 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_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_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
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
weston_wm_handle_configure_request(struct weston_wm *wm, xcb_generic_event_t *event)
|
||||
{
|
||||
|
@ -1002,264 +657,6 @@ weston_wm_handle_expose(struct weston_wm *wm, xcb_generic_event_t *event)
|
|||
weston_wm_window_schedule_repaint(window);
|
||||
}
|
||||
|
||||
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 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_property_notify(struct weston_wm *wm, xcb_generic_event_t *event)
|
||||
|
@ -1272,17 +669,7 @@ weston_wm_handle_property_notify(struct weston_wm *wm, xcb_generic_event_t *even
|
|||
if (window)
|
||||
window->properties_dirty = 1;
|
||||
|
||||
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);
|
||||
} 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);
|
||||
} else if (property_notify->atom == XCB_ATOM_WM_CLASS) {
|
||||
if (property_notify->atom == XCB_ATOM_WM_CLASS) {
|
||||
fprintf(stderr, "wm_class changed\n");
|
||||
} else if (property_notify->atom == XCB_ATOM_WM_TRANSIENT_FOR) {
|
||||
fprintf(stderr, "wm_transient_for changed\n");
|
||||
|
@ -1377,51 +764,6 @@ weston_wm_handle_destroy_notify(struct weston_wm *wm, xcb_generic_event_t *event
|
|||
free(window);
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
||||
static void
|
||||
weston_wm_handle_client_message(struct weston_wm *wm,
|
||||
xcb_generic_event_t *event)
|
||||
|
@ -1478,6 +820,13 @@ weston_wm_handle_event(int fd, uint32_t mask, void *data)
|
|||
int count = 0;
|
||||
|
||||
while (event = xcb_poll_for_event(wm->conn), event != NULL) {
|
||||
if (weston_wm_handle_selection_event(wm, event)) {
|
||||
fprintf(stderr, "handled by selection code\n");
|
||||
free(event);
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (event->response_type & ~0x80) {
|
||||
case XCB_BUTTON_PRESS:
|
||||
case XCB_BUTTON_RELEASE:
|
||||
|
@ -1513,23 +862,11 @@ weston_wm_handle_event(int fd, uint32_t mask, void *data)
|
|||
case XCB_PROPERTY_NOTIFY:
|
||||
weston_wm_handle_property_notify(wm, event);
|
||||
break;
|
||||
case XCB_SELECTION_NOTIFY:
|
||||
weston_wm_handle_selection_notify(wm, event);
|
||||
break;
|
||||
case XCB_SELECTION_REQUEST:
|
||||
weston_wm_handle_selection_request(wm, event);
|
||||
break;
|
||||
case XCB_CLIENT_MESSAGE:
|
||||
weston_wm_handle_client_message(wm, event);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (event->response_type - wm->xfixes->first_event) {
|
||||
case XCB_XFIXES_SELECTION_NOTIFY:
|
||||
weston_wm_handle_xfixes_selection_notify(wm, event);
|
||||
break;
|
||||
}
|
||||
|
||||
free(event);
|
||||
count++;
|
||||
}
|
||||
|
|
|
@ -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