Move xwayland up one directory level

This commit is contained in:
Kristian Høgsberg
2013-12-03 16:38:15 -08:00
parent 873b515aee
commit 2ba10df300
11 changed files with 22 additions and 14 deletions
+42
View File
@@ -0,0 +1,42 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/shared \
-I$(top_srcdir)/src \
-I$(top_builddir)/src \
-I$(top_builddir)/xwayland \
-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
+274
View File
@@ -0,0 +1,274 @@
/*
* 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 "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);
}
+309
View File
@@ -0,0 +1,309 @@
/*
* 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++;
}
}
+49
View File
@@ -0,0 +1,49 @@
/*
* 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
+389
View File
@@ -0,0 +1,389 @@
/*
* 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;
}
+712
View File
@@ -0,0 +1,712 @@
/*
* 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
+175
View File
@@ -0,0 +1,175 @@
/*
* 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);