Move xwayland up one directory level
This commit is contained in:
@@ -75,13 +75,6 @@ git-version.h : .FORCE
|
||||
|
||||
.FORCE :
|
||||
|
||||
if ENABLE_XWAYLAND
|
||||
SUBDIRS = xwayland
|
||||
endif
|
||||
|
||||
DIST_SUBDIRS = xwayland
|
||||
|
||||
|
||||
if BUILD_WESTON_LAUNCH
|
||||
weston_launch = weston-launch
|
||||
weston_launch_SOURCES = weston-launch.c weston-launch.h
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/shared \
|
||||
-I$(top_builddir)/src \
|
||||
-DDATADIR='"$(datadir)"' \
|
||||
-DMODULEDIR='"$(moduledir)"' \
|
||||
-DLIBEXECDIR='"$(libexecdir)"' \
|
||||
-DXSERVER_PATH='"@XSERVER_PATH@"'
|
||||
|
||||
moduledir = @libdir@/weston
|
||||
module_LTLIBRARIES = xwayland.la
|
||||
|
||||
xwayland = xwayland.la
|
||||
xwayland_la_LDFLAGS = -module -avoid-version
|
||||
xwayland_la_LIBADD = \
|
||||
$(XWAYLAND_LIBS) \
|
||||
$(top_builddir)/shared/libshared-cairo.la
|
||||
xwayland_la_CFLAGS = \
|
||||
$(GCC_CFLAGS) \
|
||||
$(COMPOSITOR_CFLAGS) \
|
||||
$(PIXMAN_CFLAGS) \
|
||||
$(CAIRO_CFLAGS)
|
||||
xwayland_la_SOURCES = \
|
||||
xwayland.h \
|
||||
window-manager.c \
|
||||
selection.c \
|
||||
dnd.c \
|
||||
launcher.c \
|
||||
xserver-protocol.c \
|
||||
xserver-server-protocol.h \
|
||||
hash.c \
|
||||
hash.h
|
||||
|
||||
BUILT_SOURCES = \
|
||||
xserver-protocol.c \
|
||||
xserver-server-protocol.h
|
||||
|
||||
CLEANFILES = $(BUILT_SOURCES)
|
||||
|
||||
wayland_protocoldir = $(top_srcdir)/protocol
|
||||
include $(top_srcdir)/wayland-scanner.mk
|
||||
@@ -1,274 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2013 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 "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
|
||||
#include "xwayland.h"
|
||||
|
||||
#include "../../shared/cairo-util.h"
|
||||
#include "../compositor.h"
|
||||
#include "xserver-server-protocol.h"
|
||||
#include "hash.h"
|
||||
|
||||
static void
|
||||
weston_dnd_start(struct weston_wm *wm, xcb_window_t owner)
|
||||
{
|
||||
uint32_t values[1], version = 4;
|
||||
|
||||
wm->dnd_window = xcb_generate_id(wm->conn);
|
||||
values[0] =
|
||||
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
|
||||
XCB_EVENT_MASK_PROPERTY_CHANGE;
|
||||
|
||||
xcb_create_window(wm->conn,
|
||||
XCB_COPY_FROM_PARENT,
|
||||
wm->dnd_window,
|
||||
wm->screen->root,
|
||||
0, 0,
|
||||
8192, 8192,
|
||||
0,
|
||||
XCB_WINDOW_CLASS_INPUT_ONLY,
|
||||
wm->screen->root_visual,
|
||||
XCB_CW_EVENT_MASK, values);
|
||||
xcb_change_property(wm->conn,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
wm->dnd_window,
|
||||
wm->atom.xdnd_aware,
|
||||
XCB_ATOM_ATOM,
|
||||
32, /* format */
|
||||
1, &version);
|
||||
|
||||
xcb_map_window(wm->conn, wm->dnd_window);
|
||||
wm->dnd_owner = owner;
|
||||
}
|
||||
|
||||
static void
|
||||
weston_dnd_stop(struct weston_wm *wm)
|
||||
{
|
||||
xcb_destroy_window(wm->conn, wm->dnd_window);
|
||||
wm->dnd_window = XCB_WINDOW_NONE;
|
||||
}
|
||||
|
||||
struct dnd_data_source {
|
||||
struct weston_data_source base;
|
||||
struct weston_wm *wm;
|
||||
int version;
|
||||
uint32_t window;
|
||||
};
|
||||
|
||||
static void
|
||||
data_source_accept(struct weston_data_source *base,
|
||||
uint32_t time, const char *mime_type)
|
||||
{
|
||||
struct dnd_data_source *source = (struct dnd_data_source *) base;
|
||||
xcb_client_message_event_t client_message;
|
||||
struct weston_wm *wm = source->wm;
|
||||
|
||||
weston_log("got accept, mime-type %s\n", mime_type);
|
||||
|
||||
/* FIXME: If we rewrote UTF8_STRING to
|
||||
* text/plain;charset=utf-8 and the source doesn't support the
|
||||
* mime-type, we'll have to rewrite the mime-type back to
|
||||
* UTF8_STRING here. */
|
||||
|
||||
client_message.response_type = XCB_CLIENT_MESSAGE;
|
||||
client_message.format = 32;
|
||||
client_message.window = wm->dnd_window;
|
||||
client_message.type = wm->atom.xdnd_status;
|
||||
client_message.data.data32[0] = wm->dnd_window;
|
||||
client_message.data.data32[1] = 2;
|
||||
if (mime_type)
|
||||
client_message.data.data32[1] |= 1;
|
||||
client_message.data.data32[2] = 0;
|
||||
client_message.data.data32[3] = 0;
|
||||
client_message.data.data32[4] = wm->atom.xdnd_action_copy;
|
||||
|
||||
xcb_send_event(wm->conn, 0, wm->dnd_owner,
|
||||
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
|
||||
(char *) &client_message);
|
||||
}
|
||||
|
||||
static void
|
||||
data_source_send(struct weston_data_source *base,
|
||||
const char *mime_type, int32_t fd)
|
||||
{
|
||||
struct dnd_data_source *source = (struct dnd_data_source *) base;
|
||||
struct weston_wm *wm = source->wm;
|
||||
|
||||
weston_log("got send, %s\n", mime_type);
|
||||
|
||||
/* Get data for the utf8_string target */
|
||||
xcb_convert_selection(wm->conn,
|
||||
wm->selection_window,
|
||||
wm->atom.xdnd_selection,
|
||||
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;
|
||||
}
|
||||
|
||||
static void
|
||||
data_source_cancel(struct weston_data_source *source)
|
||||
{
|
||||
weston_log("got cancel\n");
|
||||
}
|
||||
|
||||
static void
|
||||
handle_enter(struct weston_wm *wm, xcb_client_message_event_t *client_message)
|
||||
{
|
||||
struct dnd_data_source *source;
|
||||
struct weston_seat *seat = weston_wm_pick_seat(wm);
|
||||
char **p;
|
||||
const char *name;
|
||||
uint32_t *types;
|
||||
int i, length, has_text;
|
||||
xcb_get_property_cookie_t cookie;
|
||||
xcb_get_property_reply_t *reply;
|
||||
|
||||
source = malloc(sizeof *source);
|
||||
if (source == NULL)
|
||||
return;
|
||||
|
||||
wl_signal_init(&source->base.destroy_signal);
|
||||
source->base.accept = data_source_accept;
|
||||
source->base.send = data_source_send;
|
||||
source->base.cancel = data_source_cancel;
|
||||
source->wm = wm;
|
||||
source->window = client_message->data.data32[0];
|
||||
source->version = client_message->data.data32[1] >> 24;
|
||||
|
||||
if (client_message->data.data32[1] & 1) {
|
||||
cookie = xcb_get_property(wm->conn,
|
||||
0, /* delete */
|
||||
source->window,
|
||||
wm->atom.xdnd_type_list,
|
||||
XCB_ATOM_ANY, 0, 2048);
|
||||
reply = xcb_get_property_reply(wm->conn, cookie, NULL);
|
||||
types = xcb_get_property_value(reply);
|
||||
length = reply->value_len;
|
||||
} else {
|
||||
reply = NULL;
|
||||
types = &client_message->data.data32[2];
|
||||
length = 3;
|
||||
}
|
||||
|
||||
wl_array_init(&source->base.mime_types);
|
||||
has_text = 0;
|
||||
for (i = 0; i < length; i++) {
|
||||
if (types[i] == XCB_ATOM_NONE)
|
||||
continue;
|
||||
|
||||
name = get_atom_name(wm->conn, types[i]);
|
||||
if (types[i] == wm->atom.utf8_string ||
|
||||
types[i] == wm->atom.text_plain_utf8 ||
|
||||
types[i] == wm->atom.text_plain) {
|
||||
if (has_text)
|
||||
continue;
|
||||
|
||||
has_text = 1;
|
||||
p = wl_array_add(&source->base.mime_types, sizeof *p);
|
||||
if (p)
|
||||
*p = strdup("text/plain;charset=utf-8");
|
||||
} else if (strchr(name, '/')) {
|
||||
p = wl_array_add(&source->base.mime_types, sizeof *p);
|
||||
if (p)
|
||||
*p = strdup(name);
|
||||
}
|
||||
}
|
||||
|
||||
free(reply);
|
||||
weston_pointer_start_drag(seat->pointer, &source->base, NULL, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
weston_wm_handle_dnd_event(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;
|
||||
xcb_client_message_event_t *client_message =
|
||||
(xcb_client_message_event_t *) event;
|
||||
|
||||
switch (event->response_type - wm->xfixes->first_event) {
|
||||
case XCB_XFIXES_SELECTION_NOTIFY:
|
||||
if (xfixes_selection_notify->selection != wm->atom.xdnd_selection)
|
||||
return 0;
|
||||
|
||||
weston_log("XdndSelection owner: %d!\n",
|
||||
xfixes_selection_notify->owner);
|
||||
|
||||
if (xfixes_selection_notify->owner != XCB_WINDOW_NONE)
|
||||
weston_dnd_start(wm, xfixes_selection_notify->owner);
|
||||
else
|
||||
weston_dnd_stop(wm);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (EVENT_TYPE(event)) {
|
||||
case XCB_CLIENT_MESSAGE:
|
||||
if (client_message->type == wm->atom.xdnd_enter) {
|
||||
handle_enter(wm, client_message);
|
||||
return 1;
|
||||
} else if (client_message->type == wm->atom.xdnd_leave) {
|
||||
weston_log("got leave!\n");
|
||||
return 1;
|
||||
} else if (client_message->type == wm->atom.xdnd_drop) {
|
||||
weston_log("got drop!\n");
|
||||
return 1;
|
||||
} else if (client_message->type == wm->atom.xdnd_drop) {
|
||||
weston_log("got enter!\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
weston_wm_dnd_init(struct weston_wm *wm)
|
||||
{
|
||||
uint32_t mask;
|
||||
|
||||
mask =
|
||||
XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
|
||||
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
|
||||
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE;
|
||||
xcb_xfixes_select_selection_input(wm->conn, wm->selection_window,
|
||||
wm->atom.xdnd_selection, mask);
|
||||
}
|
||||
@@ -1,309 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2009 Intel Corporation
|
||||
* Copyright © 1988-2004 Keith Packard and Bart Massey.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the names of the authors
|
||||
* or their institutions shall not be used in advertising or
|
||||
* otherwise to promote the sale, use or other dealings in this
|
||||
* Software without prior written authorization from the
|
||||
* authors.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
* Keith Packard <keithp@keithp.com>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hash.h"
|
||||
|
||||
struct hash_entry {
|
||||
uint32_t hash;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct hash_table {
|
||||
struct hash_entry *table;
|
||||
uint32_t size;
|
||||
uint32_t rehash;
|
||||
uint32_t max_entries;
|
||||
uint32_t size_index;
|
||||
uint32_t entries;
|
||||
uint32_t deleted_entries;
|
||||
};
|
||||
|
||||
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
|
||||
|
||||
/*
|
||||
* From Knuth -- a good choice for hash/rehash values is p, p-2 where
|
||||
* p and p-2 are both prime. These tables are sized to have an extra 10%
|
||||
* free to avoid exponential performance degradation as the hash table fills
|
||||
*/
|
||||
|
||||
static const uint32_t deleted_data;
|
||||
|
||||
static const struct {
|
||||
uint32_t max_entries, size, rehash;
|
||||
} hash_sizes[] = {
|
||||
{ 2, 5, 3 },
|
||||
{ 4, 7, 5 },
|
||||
{ 8, 13, 11 },
|
||||
{ 16, 19, 17 },
|
||||
{ 32, 43, 41 },
|
||||
{ 64, 73, 71 },
|
||||
{ 128, 151, 149 },
|
||||
{ 256, 283, 281 },
|
||||
{ 512, 571, 569 },
|
||||
{ 1024, 1153, 1151 },
|
||||
{ 2048, 2269, 2267 },
|
||||
{ 4096, 4519, 4517 },
|
||||
{ 8192, 9013, 9011 },
|
||||
{ 16384, 18043, 18041 },
|
||||
{ 32768, 36109, 36107 },
|
||||
{ 65536, 72091, 72089 },
|
||||
{ 131072, 144409, 144407 },
|
||||
{ 262144, 288361, 288359 },
|
||||
{ 524288, 576883, 576881 },
|
||||
{ 1048576, 1153459, 1153457 },
|
||||
{ 2097152, 2307163, 2307161 },
|
||||
{ 4194304, 4613893, 4613891 },
|
||||
{ 8388608, 9227641, 9227639 },
|
||||
{ 16777216, 18455029, 18455027 },
|
||||
{ 33554432, 36911011, 36911009 },
|
||||
{ 67108864, 73819861, 73819859 },
|
||||
{ 134217728, 147639589, 147639587 },
|
||||
{ 268435456, 295279081, 295279079 },
|
||||
{ 536870912, 590559793, 590559791 },
|
||||
{ 1073741824, 1181116273, 1181116271},
|
||||
{ 2147483648ul, 2362232233ul, 2362232231ul}
|
||||
};
|
||||
|
||||
static int
|
||||
entry_is_free(struct hash_entry *entry)
|
||||
{
|
||||
return entry->data == NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
entry_is_deleted(struct hash_entry *entry)
|
||||
{
|
||||
return entry->data == &deleted_data;
|
||||
}
|
||||
|
||||
static int
|
||||
entry_is_present(struct hash_entry *entry)
|
||||
{
|
||||
return entry->data != NULL && entry->data != &deleted_data;
|
||||
}
|
||||
|
||||
struct hash_table *
|
||||
hash_table_create(void)
|
||||
{
|
||||
struct hash_table *ht;
|
||||
|
||||
ht = malloc(sizeof(*ht));
|
||||
if (ht == NULL)
|
||||
return NULL;
|
||||
|
||||
ht->size_index = 0;
|
||||
ht->size = hash_sizes[ht->size_index].size;
|
||||
ht->rehash = hash_sizes[ht->size_index].rehash;
|
||||
ht->max_entries = hash_sizes[ht->size_index].max_entries;
|
||||
ht->table = calloc(ht->size, sizeof(*ht->table));
|
||||
ht->entries = 0;
|
||||
ht->deleted_entries = 0;
|
||||
|
||||
if (ht->table == NULL) {
|
||||
free(ht);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ht;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the given hash table.
|
||||
*/
|
||||
void
|
||||
hash_table_destroy(struct hash_table *ht)
|
||||
{
|
||||
if (!ht)
|
||||
return;
|
||||
|
||||
free(ht->table);
|
||||
free(ht);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a hash table entry with the given key and hash of that key.
|
||||
*
|
||||
* Returns NULL if no entry is found. Note that the data pointer may be
|
||||
* modified by the user.
|
||||
*/
|
||||
static void *
|
||||
hash_table_search(struct hash_table *ht, uint32_t hash)
|
||||
{
|
||||
uint32_t hash_address;
|
||||
|
||||
hash_address = hash % ht->size;
|
||||
do {
|
||||
uint32_t double_hash;
|
||||
|
||||
struct hash_entry *entry = ht->table + hash_address;
|
||||
|
||||
if (entry_is_free(entry)) {
|
||||
return NULL;
|
||||
} else if (entry_is_present(entry) && entry->hash == hash) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
double_hash = 1 + hash % ht->rehash;
|
||||
|
||||
hash_address = (hash_address + double_hash) % ht->size;
|
||||
} while (hash_address != hash % ht->size);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
hash_table_for_each(struct hash_table *ht,
|
||||
hash_table_iterator_func_t func, void *data)
|
||||
{
|
||||
struct hash_entry *entry;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < ht->size; i++) {
|
||||
entry = ht->table + i;
|
||||
if (entry_is_present(entry))
|
||||
func(entry->data, data);
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
hash_table_lookup(struct hash_table *ht, uint32_t hash)
|
||||
{
|
||||
struct hash_entry *entry;
|
||||
|
||||
entry = hash_table_search(ht, hash);
|
||||
if (entry != NULL)
|
||||
return entry->data;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
hash_table_rehash(struct hash_table *ht, unsigned int new_size_index)
|
||||
{
|
||||
struct hash_table old_ht;
|
||||
struct hash_entry *table, *entry;
|
||||
|
||||
if (new_size_index >= ARRAY_SIZE(hash_sizes))
|
||||
return;
|
||||
|
||||
table = calloc(hash_sizes[new_size_index].size, sizeof(*ht->table));
|
||||
if (table == NULL)
|
||||
return;
|
||||
|
||||
old_ht = *ht;
|
||||
|
||||
ht->table = table;
|
||||
ht->size_index = new_size_index;
|
||||
ht->size = hash_sizes[ht->size_index].size;
|
||||
ht->rehash = hash_sizes[ht->size_index].rehash;
|
||||
ht->max_entries = hash_sizes[ht->size_index].max_entries;
|
||||
ht->entries = 0;
|
||||
ht->deleted_entries = 0;
|
||||
|
||||
for (entry = old_ht.table;
|
||||
entry != old_ht.table + old_ht.size;
|
||||
entry++) {
|
||||
if (entry_is_present(entry)) {
|
||||
hash_table_insert(ht, entry->hash, entry->data);
|
||||
}
|
||||
}
|
||||
|
||||
free(old_ht.table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the data with the given hash into the table.
|
||||
*
|
||||
* Note that insertion may rearrange the table on a resize or rehash,
|
||||
* so previously found hash_entries are no longer valid after this function.
|
||||
*/
|
||||
int
|
||||
hash_table_insert(struct hash_table *ht, uint32_t hash, void *data)
|
||||
{
|
||||
uint32_t hash_address;
|
||||
|
||||
if (ht->entries >= ht->max_entries) {
|
||||
hash_table_rehash(ht, ht->size_index + 1);
|
||||
} else if (ht->deleted_entries + ht->entries >= ht->max_entries) {
|
||||
hash_table_rehash(ht, ht->size_index);
|
||||
}
|
||||
|
||||
hash_address = hash % ht->size;
|
||||
do {
|
||||
struct hash_entry *entry = ht->table + hash_address;
|
||||
uint32_t double_hash;
|
||||
|
||||
if (!entry_is_present(entry)) {
|
||||
if (entry_is_deleted(entry))
|
||||
ht->deleted_entries--;
|
||||
entry->hash = hash;
|
||||
entry->data = data;
|
||||
ht->entries++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
double_hash = 1 + hash % ht->rehash;
|
||||
|
||||
hash_address = (hash_address + double_hash) % ht->size;
|
||||
} while (hash_address != hash % ht->size);
|
||||
|
||||
/* We could hit here if a required resize failed. An unchecked-malloc
|
||||
* application could ignore this result.
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function deletes the given hash table entry.
|
||||
*
|
||||
* Note that deletion doesn't otherwise modify the table, so an iteration over
|
||||
* the table deleting entries is safe.
|
||||
*/
|
||||
void
|
||||
hash_table_remove(struct hash_table *ht, uint32_t hash)
|
||||
{
|
||||
struct hash_entry *entry;
|
||||
|
||||
entry = hash_table_search(ht, hash);
|
||||
if (entry != NULL) {
|
||||
entry->data = (void *) &deleted_data;
|
||||
ht->entries--;
|
||||
ht->deleted_entries++;
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2009 Intel Corporation
|
||||
* Copyright © 1988-2004 Keith Packard and Bart Massey.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the names of the authors
|
||||
* or their institutions shall not be used in advertising or
|
||||
* otherwise to promote the sale, use or other dealings in this
|
||||
* Software without prior written authorization from the
|
||||
* authors.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
* Keith Packard <keithp@keithp.com>
|
||||
*/
|
||||
|
||||
#ifndef HASH_H
|
||||
#define HASH_H
|
||||
|
||||
struct hash_table;
|
||||
struct hash_table *hash_table_create(void);
|
||||
typedef void (*hash_table_iterator_func_t)(void *element, void *data);
|
||||
|
||||
void hash_table_destroy(struct hash_table *ht);
|
||||
void *hash_table_lookup(struct hash_table *ht, uint32_t hash);
|
||||
int hash_table_insert(struct hash_table *ht, uint32_t hash, void *data);
|
||||
void hash_table_remove(struct hash_table *ht, uint32_t hash);
|
||||
void hash_table_for_each(struct hash_table *ht,
|
||||
hash_table_iterator_func_t func, void *data);
|
||||
|
||||
#endif
|
||||
@@ -1,389 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2011 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 "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "xwayland.h"
|
||||
#include "xserver-server-protocol.h"
|
||||
|
||||
|
||||
static int
|
||||
weston_xserver_handle_event(int listen_fd, uint32_t mask, void *data)
|
||||
{
|
||||
struct weston_xserver *wxs = data;
|
||||
char display[8], s[8];
|
||||
int sv[2], client_fd;
|
||||
char *xserver = NULL;
|
||||
struct weston_config_section *section;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
|
||||
weston_log("socketpair failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
wxs->process.pid = fork();
|
||||
switch (wxs->process.pid) {
|
||||
case 0:
|
||||
/* SOCK_CLOEXEC closes both ends, so we need to unset
|
||||
* the flag on the client fd. */
|
||||
client_fd = dup(sv[1]);
|
||||
if (client_fd < 0)
|
||||
return 1;
|
||||
|
||||
snprintf(s, sizeof s, "%d", client_fd);
|
||||
setenv("WAYLAND_SOCKET", s, 1);
|
||||
|
||||
snprintf(display, sizeof display, ":%d", wxs->display);
|
||||
|
||||
section = weston_config_get_section(wxs->compositor->config, "xwayland", NULL, NULL);
|
||||
weston_config_section_get_string(section, "path", &xserver, XSERVER_PATH);
|
||||
|
||||
if (execl(xserver,
|
||||
xserver,
|
||||
display,
|
||||
"-wayland",
|
||||
"-rootless",
|
||||
"-retro",
|
||||
"-nolisten", "all",
|
||||
"-terminate",
|
||||
NULL) < 0)
|
||||
weston_log("exec failed: %m\n");
|
||||
free(xserver);
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
default:
|
||||
weston_log("forked X server, pid %d\n", wxs->process.pid);
|
||||
|
||||
close(sv[1]);
|
||||
wxs->client = wl_client_create(wxs->wl_display, sv[0]);
|
||||
|
||||
weston_watch_process(&wxs->process);
|
||||
|
||||
wl_event_source_remove(wxs->abstract_source);
|
||||
wl_event_source_remove(wxs->unix_source);
|
||||
break;
|
||||
|
||||
case -1:
|
||||
weston_log( "failed to fork\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
weston_xserver_shutdown(struct weston_xserver *wxs)
|
||||
{
|
||||
char path[256];
|
||||
|
||||
snprintf(path, sizeof path, "/tmp/.X%d-lock", wxs->display);
|
||||
unlink(path);
|
||||
snprintf(path, sizeof path, "/tmp/.X11-unix/X%d", wxs->display);
|
||||
unlink(path);
|
||||
if (wxs->process.pid == 0) {
|
||||
wl_event_source_remove(wxs->abstract_source);
|
||||
wl_event_source_remove(wxs->unix_source);
|
||||
}
|
||||
close(wxs->abstract_fd);
|
||||
close(wxs->unix_fd);
|
||||
if (wxs->wm)
|
||||
weston_wm_destroy(wxs->wm);
|
||||
wxs->loop = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
weston_xserver_cleanup(struct weston_process *process, int status)
|
||||
{
|
||||
struct weston_xserver *wxs =
|
||||
container_of(process, struct weston_xserver, process);
|
||||
|
||||
wxs->process.pid = 0;
|
||||
wxs->client = NULL;
|
||||
wxs->resource = NULL;
|
||||
|
||||
wxs->abstract_source =
|
||||
wl_event_loop_add_fd(wxs->loop, wxs->abstract_fd,
|
||||
WL_EVENT_READABLE,
|
||||
weston_xserver_handle_event, wxs);
|
||||
|
||||
wxs->unix_source =
|
||||
wl_event_loop_add_fd(wxs->loop, wxs->unix_fd,
|
||||
WL_EVENT_READABLE,
|
||||
weston_xserver_handle_event, wxs);
|
||||
|
||||
if (wxs->wm) {
|
||||
weston_log("xserver exited, code %d\n", status);
|
||||
weston_wm_destroy(wxs->wm);
|
||||
wxs->wm = NULL;
|
||||
} else {
|
||||
/* If the X server crashes before it binds to the
|
||||
* xserver interface, shut down and don't try
|
||||
* again. */
|
||||
weston_log("xserver crashing too fast: %d\n", status);
|
||||
weston_xserver_shutdown(wxs);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bind_xserver(struct wl_client *client,
|
||||
void *data, uint32_t version, uint32_t id)
|
||||
{
|
||||
struct weston_xserver *wxs = data;
|
||||
|
||||
/* If it's a different client than the xserver we launched,
|
||||
* don't start the wm. */
|
||||
if (client != wxs->client)
|
||||
return;
|
||||
|
||||
wxs->resource =
|
||||
wl_resource_create(client, &xserver_interface,
|
||||
1, id);
|
||||
wl_resource_set_implementation(wxs->resource, &xserver_implementation,
|
||||
wxs, NULL);
|
||||
|
||||
wxs->wm = weston_wm_create(wxs);
|
||||
if (wxs->wm == NULL) {
|
||||
weston_log("failed to create wm\n");
|
||||
}
|
||||
|
||||
xserver_send_listen_socket(wxs->resource, wxs->abstract_fd);
|
||||
xserver_send_listen_socket(wxs->resource, wxs->unix_fd);
|
||||
}
|
||||
|
||||
static int
|
||||
bind_to_abstract_socket(int display)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
socklen_t size, name_size;
|
||||
int fd;
|
||||
|
||||
fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
addr.sun_family = AF_LOCAL;
|
||||
name_size = snprintf(addr.sun_path, sizeof addr.sun_path,
|
||||
"%c/tmp/.X11-unix/X%d", 0, display);
|
||||
size = offsetof(struct sockaddr_un, sun_path) + name_size;
|
||||
if (bind(fd, (struct sockaddr *) &addr, size) < 0) {
|
||||
weston_log("failed to bind to @%s: %s\n",
|
||||
addr.sun_path + 1, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(fd, 1) < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int
|
||||
bind_to_unix_socket(int display)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
socklen_t size, name_size;
|
||||
int fd;
|
||||
|
||||
fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
addr.sun_family = AF_LOCAL;
|
||||
name_size = snprintf(addr.sun_path, sizeof addr.sun_path,
|
||||
"/tmp/.X11-unix/X%d", display) + 1;
|
||||
size = offsetof(struct sockaddr_un, sun_path) + name_size;
|
||||
unlink(addr.sun_path);
|
||||
if (bind(fd, (struct sockaddr *) &addr, size) < 0) {
|
||||
weston_log("failed to bind to %s (%s)\n",
|
||||
addr.sun_path, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(fd, 1) < 0) {
|
||||
unlink(addr.sun_path);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int
|
||||
create_lockfile(int display, char *lockfile, size_t lsize)
|
||||
{
|
||||
char pid[16], *end;
|
||||
int fd, size;
|
||||
pid_t other;
|
||||
|
||||
snprintf(lockfile, lsize, "/tmp/.X%d-lock", display);
|
||||
fd = open(lockfile, O_WRONLY | O_CLOEXEC | O_CREAT | O_EXCL, 0444);
|
||||
if (fd < 0 && errno == EEXIST) {
|
||||
fd = open(lockfile, O_CLOEXEC, O_RDONLY);
|
||||
if (fd < 0 || read(fd, pid, 11) != 11) {
|
||||
weston_log("can't read lock file %s: %s\n",
|
||||
lockfile, strerror(errno));
|
||||
if (fd >= 0)
|
||||
close (fd);
|
||||
|
||||
errno = EEXIST;
|
||||
return -1;
|
||||
}
|
||||
|
||||
other = strtol(pid, &end, 0);
|
||||
if (end != pid + 10) {
|
||||
weston_log("can't parse lock file %s\n",
|
||||
lockfile);
|
||||
close(fd);
|
||||
errno = EEXIST;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (kill(other, 0) < 0 && errno == ESRCH) {
|
||||
/* stale lock file; unlink and try again */
|
||||
weston_log("unlinking stale lock file %s\n", lockfile);
|
||||
close(fd);
|
||||
if (unlink(lockfile))
|
||||
/* If we fail to unlink, return EEXIST
|
||||
so we try the next display number.*/
|
||||
errno = EEXIST;
|
||||
else
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
errno = EEXIST;
|
||||
return -1;
|
||||
} else if (fd < 0) {
|
||||
weston_log("failed to create lock file %s: %s\n",
|
||||
lockfile, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Subtle detail: we use the pid of the wayland
|
||||
* compositor, not the xserver in the lock file. */
|
||||
size = snprintf(pid, sizeof pid, "%10d\n", getpid());
|
||||
if (write(fd, pid, size) != size) {
|
||||
unlink(lockfile);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
weston_xserver_destroy(struct wl_listener *l, void *data)
|
||||
{
|
||||
struct weston_xserver *wxs =
|
||||
container_of(l, struct weston_xserver, destroy_listener);
|
||||
|
||||
if (!wxs)
|
||||
return;
|
||||
|
||||
if (wxs->loop)
|
||||
weston_xserver_shutdown(wxs);
|
||||
|
||||
free(wxs);
|
||||
}
|
||||
|
||||
WL_EXPORT int
|
||||
module_init(struct weston_compositor *compositor,
|
||||
int *argc, char *argv[])
|
||||
|
||||
{
|
||||
struct wl_display *display = compositor->wl_display;
|
||||
struct weston_xserver *wxs;
|
||||
char lockfile[256], display_name[8];
|
||||
|
||||
wxs = zalloc(sizeof *wxs);
|
||||
wxs->process.cleanup = weston_xserver_cleanup;
|
||||
wxs->wl_display = display;
|
||||
wxs->compositor = compositor;
|
||||
|
||||
wxs->display = 0;
|
||||
|
||||
retry:
|
||||
if (create_lockfile(wxs->display, lockfile, sizeof lockfile) < 0) {
|
||||
if (errno == EAGAIN) {
|
||||
goto retry;
|
||||
} else if (errno == EEXIST) {
|
||||
wxs->display++;
|
||||
goto retry;
|
||||
} else {
|
||||
free(wxs);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
wxs->abstract_fd = bind_to_abstract_socket(wxs->display);
|
||||
if (wxs->abstract_fd < 0 && errno == EADDRINUSE) {
|
||||
wxs->display++;
|
||||
unlink(lockfile);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
wxs->unix_fd = bind_to_unix_socket(wxs->display);
|
||||
if (wxs->unix_fd < 0) {
|
||||
unlink(lockfile);
|
||||
close(wxs->abstract_fd);
|
||||
free(wxs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(display_name, sizeof display_name, ":%d", wxs->display);
|
||||
weston_log("xserver listening on display %s\n", display_name);
|
||||
setenv("DISPLAY", display_name, 1);
|
||||
|
||||
wxs->loop = wl_display_get_event_loop(display);
|
||||
wxs->abstract_source =
|
||||
wl_event_loop_add_fd(wxs->loop, wxs->abstract_fd,
|
||||
WL_EVENT_READABLE,
|
||||
weston_xserver_handle_event, wxs);
|
||||
wxs->unix_source =
|
||||
wl_event_loop_add_fd(wxs->loop, wxs->unix_fd,
|
||||
WL_EVENT_READABLE,
|
||||
weston_xserver_handle_event, wxs);
|
||||
|
||||
wl_global_create(display, &xserver_interface, 1, wxs, bind_xserver);
|
||||
|
||||
wxs->destroy_listener.notify = weston_xserver_destroy;
|
||||
wl_signal_add(&compositor->destroy_signal, &wxs->destroy_listener);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,712 +0,0 @@
|
||||
/*
|
||||
* 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 "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "xwayland.h"
|
||||
|
||||
static int
|
||||
writable_callback(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);
|
||||
wm->property_reply = NULL;
|
||||
if (wm->property_source)
|
||||
wl_event_source_remove(wm->property_source);
|
||||
close(fd);
|
||||
weston_log("write error to target fd: %m\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
weston_log("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);
|
||||
wm->property_reply = NULL;
|
||||
if (wm->property_source)
|
||||
wl_event_source_remove(wm->property_source);
|
||||
|
||||
if (wm->incr) {
|
||||
xcb_delete_property(wm->conn,
|
||||
wm->selection_window,
|
||||
wm->atom.wl_selection);
|
||||
} else {
|
||||
weston_log("transfer complete\n");
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
weston_wm_write_property(struct weston_wm *wm, xcb_get_property_reply_t *reply)
|
||||
{
|
||||
wm->property_start = 0;
|
||||
wm->property_reply = reply;
|
||||
writable_callback(wm->data_source_fd, WL_EVENT_WRITABLE, wm);
|
||||
|
||||
if (wm->property_reply)
|
||||
wm->property_source =
|
||||
wl_event_loop_add_fd(wm->server->loop,
|
||||
wm->data_source_fd,
|
||||
WL_EVENT_WRITABLE,
|
||||
writable_callback, wm);
|
||||
}
|
||||
|
||||
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) {
|
||||
weston_wm_write_property(wm, reply);
|
||||
} else {
|
||||
weston_log("transfer complete\n");
|
||||
close(wm->data_source_fd);
|
||||
free(reply);
|
||||
}
|
||||
}
|
||||
|
||||
struct x11_data_source {
|
||||
struct weston_data_source base;
|
||||
struct weston_wm *wm;
|
||||
};
|
||||
|
||||
static void
|
||||
data_source_accept(struct weston_data_source *source,
|
||||
uint32_t time, const char *mime_type)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
data_source_send(struct weston_data_source *base,
|
||||
const char *mime_type, int32_t fd)
|
||||
{
|
||||
struct x11_data_source *source = (struct x11_data_source *) base;
|
||||
struct weston_wm *wm = source->wm;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
data_source_cancel(struct weston_data_source *source)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
weston_wm_get_selection_targets(struct weston_wm *wm)
|
||||
{
|
||||
struct x11_data_source *source;
|
||||
struct weston_compositor *compositor;
|
||||
struct weston_seat *seat = weston_wm_pick_seat(wm);
|
||||
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->base.destroy_signal);
|
||||
source->base.accept = data_source_accept;
|
||||
source->base.send = data_source_send;
|
||||
source->base.cancel = data_source_cancel;
|
||||
source->wm = wm;
|
||||
|
||||
wl_array_init(&source->base.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->base.mime_types, sizeof *p);
|
||||
if (p)
|
||||
*p = strdup("text/plain;charset=utf-8");
|
||||
}
|
||||
}
|
||||
|
||||
compositor = wm->server->compositor;
|
||||
weston_seat_set_selection(seat, &source->base,
|
||||
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;
|
||||
weston_wm_write_property(wm, 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) {
|
||||
weston_log("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);
|
||||
}
|
||||
|
||||
weston_log("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) {
|
||||
weston_log("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) {
|
||||
weston_log("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 {
|
||||
weston_log("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) {
|
||||
weston_log("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) {
|
||||
weston_log("incr transfer complete\n");
|
||||
|
||||
wm->flush_property_on_delete = 1;
|
||||
if (wm->selection_property_set) {
|
||||
weston_log("got %zu bytes, waiting for "
|
||||
"property delete\n", wm->source_data.size);
|
||||
} else {
|
||||
weston_log("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);
|
||||
close(wm->data_source_fd);
|
||||
wm->data_source_fd = -1;
|
||||
close(fd);
|
||||
} else {
|
||||
weston_log("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 weston_data_source *source;
|
||||
struct weston_seat *seat = weston_wm_pick_seat(wm);
|
||||
int p[2];
|
||||
|
||||
if (pipe2(p, O_CLOEXEC | O_NONBLOCK) == -1) {
|
||||
weston_log("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);
|
||||
|
||||
source = seat->selection_data_source;
|
||||
source->send(source, mime_type, p[1]);
|
||||
close(p[1]);
|
||||
}
|
||||
|
||||
static void
|
||||
weston_wm_send_incr_chunk(struct weston_wm *wm)
|
||||
{
|
||||
int length;
|
||||
|
||||
weston_log("property deleted\n");
|
||||
|
||||
wm->selection_property_set = 0;
|
||||
if (wm->flush_property_on_delete) {
|
||||
weston_log("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;
|
||||
|
||||
weston_log("selection request, %s, ",
|
||||
get_atom_name(wm->conn, selection_request->selection));
|
||||
weston_log_continue("target %s, ",
|
||||
get_atom_name(wm->conn, selection_request->target));
|
||||
weston_log_continue("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->selection == wm->atom.clipboard_manager) {
|
||||
/* The weston clipboard should already have grabbed
|
||||
* the first target, so just send selection notify
|
||||
* now. This isn't synchronized with the clipboard
|
||||
* finishing getting the data, so there's a race here. */
|
||||
weston_wm_send_selection_notify(wm, wm->selection_request.property);
|
||||
return;
|
||||
}
|
||||
|
||||
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 {
|
||||
weston_log("can only handle UTF8_STRING targets...\n");
|
||||
weston_wm_send_selection_notify(wm, XCB_ATOM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
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;
|
||||
struct weston_compositor *compositor;
|
||||
struct weston_seat *seat = weston_wm_pick_seat(wm);
|
||||
uint32_t serial;
|
||||
|
||||
if (xfixes_selection_notify->selection != wm->atom.clipboard)
|
||||
return 0;
|
||||
|
||||
weston_log("xfixes selection notify event: owner %d\n",
|
||||
xfixes_selection_notify->owner);
|
||||
|
||||
if (xfixes_selection_notify->owner == XCB_WINDOW_NONE) {
|
||||
if (wm->selection_owner != wm->selection_window) {
|
||||
/* A real X client selection went away, not our
|
||||
* proxy selection. Clear the wayland selection. */
|
||||
compositor = wm->server->compositor;
|
||||
serial = wl_display_next_serial(compositor->wl_display);
|
||||
weston_seat_set_selection(seat, NULL, serial);
|
||||
}
|
||||
|
||||
wm->selection_owner = XCB_WINDOW_NONE;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
wm->selection_owner = 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;
|
||||
weston_log("our window, skipping\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
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:
|
||||
return weston_wm_handle_xfixes_selection_notify(wm, event);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
weston_wm_set_selection(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct weston_seat *seat = data;
|
||||
struct weston_wm *wm =
|
||||
container_of(listener, struct weston_wm, selection_listener);
|
||||
struct weston_data_source *source = seat->selection_data_source;
|
||||
const char **p, **end;
|
||||
int has_text_plain = 0;
|
||||
|
||||
if (source == NULL) {
|
||||
if (wm->selection_owner == wm->selection_window)
|
||||
xcb_set_selection_owner(wm->conn,
|
||||
XCB_ATOM_NONE,
|
||||
wm->atom.clipboard,
|
||||
wm->selection_timestamp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (source->send == data_source_send)
|
||||
return;
|
||||
|
||||
p = source->mime_types.data;
|
||||
end = (const char **)
|
||||
((char *) source->mime_types.data + source->mime_types.size);
|
||||
while (p < end) {
|
||||
weston_log(" %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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
weston_wm_selection_init(struct weston_wm *wm)
|
||||
{
|
||||
struct weston_seat *seat;
|
||||
uint32_t values[1], mask;
|
||||
|
||||
wm->selection_request.requestor = XCB_NONE;
|
||||
|
||||
values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE;
|
||||
wm->selection_window = xcb_generate_id(wm->conn);
|
||||
xcb_create_window(wm->conn,
|
||||
XCB_COPY_FROM_PARENT,
|
||||
wm->selection_window,
|
||||
wm->screen->root,
|
||||
0, 0,
|
||||
10, 10,
|
||||
0,
|
||||
XCB_WINDOW_CLASS_INPUT_OUTPUT,
|
||||
wm->screen->root_visual,
|
||||
XCB_CW_EVENT_MASK, values);
|
||||
|
||||
xcb_set_selection_owner(wm->conn,
|
||||
wm->selection_window,
|
||||
wm->atom.clipboard_manager,
|
||||
XCB_TIME_CURRENT_TIME);
|
||||
|
||||
mask =
|
||||
XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
|
||||
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
|
||||
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE;
|
||||
xcb_xfixes_select_selection_input(wm->conn, wm->selection_window,
|
||||
wm->atom.clipboard, mask);
|
||||
|
||||
seat = weston_wm_pick_seat(wm);
|
||||
wm->selection_listener.notify = weston_wm_set_selection;
|
||||
wl_signal_add(&seat->selection_signal, &wm->selection_listener);
|
||||
|
||||
weston_wm_set_selection(&wm->selection_listener, seat);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,175 +0,0 @@
|
||||
/*
|
||||
* 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 <xcb/composite.h>
|
||||
#include <cairo/cairo-xcb.h>
|
||||
|
||||
#include "../compositor.h"
|
||||
|
||||
#define SEND_EVENT_MASK (0x80)
|
||||
#define EVENT_TYPE(event) ((event)->response_type & ~SEND_EVENT_MASK)
|
||||
|
||||
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 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_cursor_t *cursors;
|
||||
int last_cursor;
|
||||
xcb_render_pictforminfo_t format_rgb, format_rgba;
|
||||
xcb_visualid_t visual_id;
|
||||
xcb_colormap_t colormap;
|
||||
struct wl_listener activate_listener;
|
||||
struct wl_listener transform_listener;
|
||||
struct wl_listener kill_listener;
|
||||
|
||||
xcb_window_t selection_window;
|
||||
xcb_window_t selection_owner;
|
||||
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;
|
||||
|
||||
xcb_window_t dnd_window;
|
||||
xcb_window_t dnd_owner;
|
||||
|
||||
struct {
|
||||
xcb_atom_t wm_protocols;
|
||||
xcb_atom_t wm_normal_hints;
|
||||
xcb_atom_t wm_take_focus;
|
||||
xcb_atom_t wm_delete_window;
|
||||
xcb_atom_t wm_state;
|
||||
xcb_atom_t wm_s0;
|
||||
xcb_atom_t wm_client_machine;
|
||||
xcb_atom_t net_wm_cm_s0;
|
||||
xcb_atom_t net_wm_name;
|
||||
xcb_atom_t net_wm_pid;
|
||||
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 clipboard_manager;
|
||||
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;
|
||||
xcb_atom_t xdnd_selection;
|
||||
xcb_atom_t xdnd_aware;
|
||||
xcb_atom_t xdnd_enter;
|
||||
xcb_atom_t xdnd_leave;
|
||||
xcb_atom_t xdnd_drop;
|
||||
xcb_atom_t xdnd_status;
|
||||
xcb_atom_t xdnd_finished;
|
||||
xcb_atom_t xdnd_type_list;
|
||||
xcb_atom_t xdnd_action_copy;
|
||||
} 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);
|
||||
|
||||
void
|
||||
weston_wm_selection_init(struct weston_wm *wm);
|
||||
int
|
||||
weston_wm_handle_selection_event(struct weston_wm *wm,
|
||||
xcb_generic_event_t *event);
|
||||
|
||||
extern const struct xserver_interface xserver_implementation;
|
||||
|
||||
struct weston_wm *
|
||||
weston_wm_create(struct weston_xserver *wxs);
|
||||
void
|
||||
weston_wm_destroy(struct weston_wm *wm);
|
||||
|
||||
struct weston_seat *
|
||||
weston_wm_pick_seat(struct weston_wm *wm);
|
||||
|
||||
int
|
||||
weston_wm_handle_dnd_event(struct weston_wm *wm,
|
||||
xcb_generic_event_t *event);
|
||||
void
|
||||
weston_wm_dnd_init(struct weston_wm *wm);
|
||||
Reference in New Issue
Block a user