2
* Copyright © 2011 Intel Corporation
4
* Permission to use, copy, modify, distribute, and sell this software and
5
* its documentation for any purpose is hereby granted without fee, provided
6
* that the above copyright notice appear in all copies and that both that
7
* copyright notice and this permission notice appear in supporting
8
* documentation, and that the name of the copyright holders not be used in
9
* advertising or publicity pertaining to distribution of the software
10
* without specific, written prior permission. The copyright holders make
11
* no representations about the suitability of this software for any
12
* purpose. It is provided "as is" without express or implied warranty.
14
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28
#include <sys/socket.h>
36
#include <xcb/xfixes.h>
38
#include <wayland-server.h>
40
#include "compositor.h"
41
#include "xserver-server-protocol.h"
45
struct wl_resource resource;
48
struct weston_xserver {
49
struct wl_display *wl_display;
50
struct wl_event_loop *loop;
51
struct wl_event_source *sigchld_source;
53
struct wl_event_source *abstract_source;
55
struct wl_event_source *unix_source;
57
struct weston_process process;
58
struct wl_resource *resource;
59
struct wl_client *client;
60
struct weston_compositor *compositor;
65
xcb_connection_t *conn;
66
const xcb_query_extension_reply_t *xfixes;
67
struct wl_event_source *source;
69
struct hash_table *window_hash;
70
struct weston_xserver *server;
71
xcb_window_t wm_window;
73
xcb_window_t selection_window;
76
struct wl_event_source *property_source;
77
xcb_get_property_reply_t *property_reply;
79
struct wl_array source_data;
80
xcb_selection_request_event_t selection_request;
81
xcb_atom_t selection_target;
82
xcb_timestamp_t selection_timestamp;
83
int selection_property_set;
84
int flush_property_on_delete;
85
struct wl_selection_listener selection_listener;
88
xcb_atom_t wm_protocols;
89
xcb_atom_t wm_take_focus;
90
xcb_atom_t wm_delete_window;
91
xcb_atom_t net_wm_name;
92
xcb_atom_t net_wm_icon;
93
xcb_atom_t net_wm_state;
94
xcb_atom_t net_wm_state_fullscreen;
95
xcb_atom_t net_wm_user_time;
96
xcb_atom_t net_wm_icon_name;
97
xcb_atom_t net_wm_window_type;
98
xcb_atom_t net_wm_moveresize;
99
xcb_atom_t net_supporting_wm_check;
100
xcb_atom_t net_supported;
101
xcb_atom_t clipboard;
103
xcb_atom_t utf8_string;
104
xcb_atom_t wl_selection;
106
xcb_atom_t timestamp;
108
xcb_atom_t compound_text;
111
xcb_atom_t text_plain_utf8;
112
xcb_atom_t text_plain;
116
struct weston_wm_window {
118
struct weston_surface *surface;
119
struct wl_listener surface_destroy_listener;
122
struct weston_wm_window *transient_for;
127
static struct weston_wm_window *
128
get_wm_window(struct weston_surface *surface);
131
get_atom_name(xcb_connection_t *c, xcb_atom_t atom)
133
xcb_get_atom_name_cookie_t cookie;
134
xcb_get_atom_name_reply_t *reply;
135
xcb_generic_error_t *e;
136
static char buffer[64];
138
if (atom == XCB_ATOM_NONE)
141
cookie = xcb_get_atom_name (c, atom);
142
reply = xcb_get_atom_name_reply (c, cookie, &e);
143
snprintf(buffer, sizeof buffer, "%.*s",
144
xcb_get_atom_name_name_length (reply),
145
xcb_get_atom_name_name (reply));
152
dump_property(struct weston_wm *wm, xcb_atom_t property,
153
xcb_get_property_reply_t *reply)
156
const char *text_value, *name;
157
xcb_atom_t *atom_value;
160
width = fprintf(stderr, " %s: ", get_atom_name(wm->conn, property));
162
fprintf(stderr, "(no reply)\n");
166
width += fprintf(stderr,
167
"type %s, format %d, length %d (value_len %d): ",
168
get_atom_name(wm->conn, reply->type),
170
xcb_get_property_value_length(reply),
173
if (reply->type == wm->atom.incr) {
174
incr_value = xcb_get_property_value(reply);
175
fprintf(stderr, "%d\n", *incr_value);
176
} else if (reply->type == wm->atom.utf8_string ||
177
reply->type == wm->atom.string) {
178
text_value = xcb_get_property_value(reply);
179
if (reply->value_len > 40)
182
len = reply->value_len;
183
fprintf(stderr, "\"%.*s\"\n", len, text_value);
184
} else if (reply->type == XCB_ATOM_ATOM) {
185
atom_value = xcb_get_property_value(reply);
186
for (i = 0; i < reply->value_len; i++) {
187
name = get_atom_name(wm->conn, atom_value[i]);
188
if (width + strlen(name) + 2 > 78) {
189
fprintf(stderr, "\n ");
192
width += fprintf(stderr, ", ");
195
width += fprintf(stderr, "%s", name);
197
fprintf(stderr, "\n");
199
fprintf(stderr, "huh?\n");
204
dump_window_properties(struct weston_wm *wm, xcb_window_t window)
206
xcb_list_properties_cookie_t list_cookie;
207
xcb_list_properties_reply_t *list_reply;
208
xcb_get_property_cookie_t property_cookie;
209
xcb_get_property_reply_t *property_reply;
213
list_cookie = xcb_list_properties(wm->conn, window);
214
list_reply = xcb_list_properties_reply(wm->conn, list_cookie, NULL);
216
/* Bad window, typically */
219
length = xcb_list_properties_atoms_length(list_reply);
220
atoms = xcb_list_properties_atoms(list_reply);
222
for (i = 0; i < length; i++) {
224
xcb_get_property(wm->conn,
231
property_reply = xcb_get_property_reply(wm->conn,
232
property_cookie, NULL);
233
dump_property(wm, atoms[i], property_reply);
235
free(property_reply);
242
data_offer_accept(struct wl_client *client, struct wl_resource *resource,
243
uint32_t time, const char *mime_type)
248
data_offer_receive(struct wl_client *client, struct wl_resource *resource,
249
const char *mime_type, int32_t fd)
251
struct wl_data_offer *offer = resource->data;
252
struct weston_wm *wm = offer->source->resource.data;
254
if (strcmp(mime_type, "text/plain;charset=utf-8") == 0) {
255
/* Get data for the utf8_string target */
256
xcb_convert_selection(wm->conn,
257
wm->selection_window,
259
wm->atom.utf8_string,
260
wm->atom.wl_selection,
261
XCB_TIME_CURRENT_TIME);
265
fcntl(fd, F_SETFL, O_WRONLY | O_NONBLOCK);
266
wm->data_source_fd = fd;
273
data_offer_destroy(struct wl_client *client, struct wl_resource *resource)
275
wl_resource_destroy(resource, weston_compositor_get_time());
278
static const struct wl_data_offer_interface data_offer_interface = {
285
data_source_cancel(struct wl_data_source *source)
290
weston_wm_get_selection_targets(struct weston_wm *wm)
292
struct wl_data_source *source;
293
struct wl_input_device *device;
294
xcb_get_property_cookie_t cookie;
295
xcb_get_property_reply_t *reply;
300
cookie = xcb_get_property(wm->conn,
302
wm->selection_window,
303
wm->atom.wl_selection,
304
XCB_GET_PROPERTY_TYPE_ANY,
308
reply = xcb_get_property_reply(wm->conn, cookie, NULL);
310
dump_property(wm, wm->atom.wl_selection, reply);
312
if (reply->type != XCB_ATOM_ATOM) {
317
source = malloc(sizeof *source);
321
wl_list_init(&source->resource.destroy_listener_list);
322
source->offer_interface = &data_offer_interface;
323
source->cancel = data_source_cancel;
324
source->resource.data = wm;
326
wl_array_init(&source->mime_types);
327
value = xcb_get_property_value(reply);
328
for (i = 0; i < reply->value_len; i++) {
329
if (value[i] == wm->atom.utf8_string) {
330
p = wl_array_add(&source->mime_types, sizeof *p);
332
*p = strdup("text/plain;charset=utf-8");
336
device = wm->server->compositor->input_device;
337
wl_input_device_set_selection(device, source,
338
weston_compositor_get_time());
344
weston_wm_write_property(int fd, uint32_t mask, void *data)
346
struct weston_wm *wm = data;
347
unsigned char *property;
350
property = xcb_get_property_value(wm->property_reply);
351
remainder = xcb_get_property_value_length(wm->property_reply) -
354
len = write(fd, property + wm->property_start, remainder);
356
free(wm->property_reply);
357
wl_event_source_remove(wm->property_source);
359
fprintf(stderr, "write error to target fd: %m\n");
363
fprintf(stderr, "wrote %d (chunk size %d) of %d bytes\n",
364
wm->property_start + len,
365
len, xcb_get_property_value_length(wm->property_reply));
367
wm->property_start += len;
368
if (len == remainder) {
369
free(wm->property_reply);
370
wl_event_source_remove(wm->property_source);
373
xcb_delete_property(wm->conn,
374
wm->selection_window,
375
wm->atom.wl_selection);
377
fprintf(stderr, "transfer complete\n");
386
weston_wm_get_selection_data(struct weston_wm *wm)
388
xcb_get_property_cookie_t cookie;
389
xcb_get_property_reply_t *reply;
391
cookie = xcb_get_property(wm->conn,
393
wm->selection_window,
394
wm->atom.wl_selection,
395
XCB_GET_PROPERTY_TYPE_ANY,
397
0x1fffffff /* length */);
399
reply = xcb_get_property_reply(wm->conn, cookie, NULL);
401
if (reply->type == wm->atom.incr) {
402
dump_property(wm, wm->atom.wl_selection, reply);
406
dump_property(wm, wm->atom.wl_selection, reply);
408
wm->property_start = 0;
409
wm->property_source =
410
wl_event_loop_add_fd(wm->server->loop,
413
weston_wm_write_property,
415
wm->property_reply = reply;
420
weston_wm_get_incr_chunk(struct weston_wm *wm)
422
xcb_get_property_cookie_t cookie;
423
xcb_get_property_reply_t *reply;
425
cookie = xcb_get_property(wm->conn,
427
wm->selection_window,
428
wm->atom.wl_selection,
429
XCB_GET_PROPERTY_TYPE_ANY,
431
0x1fffffff /* length */);
433
reply = xcb_get_property_reply(wm->conn, cookie, NULL);
435
dump_property(wm, wm->atom.wl_selection, reply);
437
if (xcb_get_property_value_length(reply) > 0) {
438
wm->property_start = 0;
439
wm->property_source =
440
wl_event_loop_add_fd(wm->server->loop,
443
weston_wm_write_property,
445
wm->property_reply = reply;
447
fprintf(stderr, "transfer complete\n");
448
close(wm->data_source_fd);
454
weston_wm_set_selection(struct wl_selection_listener *listener,
455
struct wl_input_device *device)
457
struct weston_wm *wm =
458
container_of(listener, struct weston_wm, selection_listener);
459
struct wl_data_source *source = device->selection_data_source;
460
const char **p, **end;
461
int has_text_plain = 0;
463
if (source->offer_interface == &data_offer_interface)
466
fprintf(stderr, "set selection\n");
468
p = source->mime_types.data;
469
end = (const char **)
470
((char *) source->mime_types.data + source->mime_types.size);
472
fprintf(stderr, " %s\n", *p);
473
if (strcmp(*p, "text/plain") == 0 ||
474
strcmp(*p, "text/plain;charset=utf-8") == 0)
479
if (has_text_plain) {
480
xcb_set_selection_owner(wm->conn,
481
wm->selection_window,
483
XCB_TIME_CURRENT_TIME);
485
xcb_set_selection_owner(wm->conn,
488
XCB_TIME_CURRENT_TIME);
493
weston_wm_handle_configure_request(struct weston_wm *wm, xcb_generic_event_t *event)
495
xcb_configure_request_event_t *configure_request =
496
(xcb_configure_request_event_t *) event;
500
fprintf(stderr, "XCB_CONFIGURE_REQUEST (window %d) %d,%d @ %dx%d\n",
501
configure_request->window,
502
configure_request->x, configure_request->y,
503
configure_request->width, configure_request->height);
505
if (configure_request->value_mask & XCB_CONFIG_WINDOW_X)
506
values[i++] = configure_request->x;
507
if (configure_request->value_mask & XCB_CONFIG_WINDOW_Y)
508
values[i++] = configure_request->y;
509
if (configure_request->value_mask & XCB_CONFIG_WINDOW_WIDTH)
510
values[i++] = configure_request->width;
511
if (configure_request->value_mask & XCB_CONFIG_WINDOW_HEIGHT)
512
values[i++] = configure_request->height;
513
if (configure_request->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH)
514
values[i++] = configure_request->border_width;
515
if (configure_request->value_mask & XCB_CONFIG_WINDOW_SIBLING)
516
values[i++] = configure_request->sibling;
517
if (configure_request->value_mask & XCB_CONFIG_WINDOW_STACK_MODE)
518
values[i++] = configure_request->stack_mode;
520
xcb_configure_window(wm->conn,
521
configure_request->window,
522
configure_request->value_mask, values);
526
weston_wm_handle_configure_notify(struct weston_wm *wm, xcb_generic_event_t *event)
528
xcb_configure_notify_event_t *configure_notify =
529
(xcb_configure_notify_event_t *) event;
531
fprintf(stderr, "XCB_CONFIGURE_NOTIFY (window %d) %d,%d @ %dx%d\n",
532
configure_notify->window,
533
configure_notify->x, configure_notify->y,
534
configure_notify->width, configure_notify->height);
538
weston_wm_activate(struct weston_wm *wm,
539
struct weston_wm_window *window, xcb_timestamp_t time)
541
xcb_client_message_event_t client_message;
543
client_message.response_type = XCB_CLIENT_MESSAGE;
544
client_message.format = 32;
545
client_message.window = window->id;
546
client_message.type = wm->atom.wm_protocols;
547
client_message.data.data32[0] = wm->atom.wm_take_focus;
548
client_message.data.data32[1] = XCB_TIME_CURRENT_TIME;
550
xcb_send_event(wm->conn, 0, window->id,
551
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
552
(char *) &client_message);
554
xcb_set_input_focus (wm->conn,
555
XCB_INPUT_FOCUS_POINTER_ROOT, window->id, time);
559
weston_xserver_surface_activate(struct weston_surface *surface)
561
struct weston_wm_window *window = get_wm_window(surface);
562
struct weston_xserver *wxs = surface->compositor->wxs;
565
weston_wm_activate(wxs->wm, window, XCB_TIME_CURRENT_TIME);
566
else if (wxs && wxs->wm)
567
xcb_set_input_focus (wxs->wm->conn,
568
XCB_INPUT_FOCUS_POINTER_ROOT,
570
XCB_TIME_CURRENT_TIME);
574
weston_wm_handle_map_request(struct weston_wm *wm, xcb_generic_event_t *event)
576
xcb_map_request_event_t *map_request =
577
(xcb_map_request_event_t *) event;
579
fprintf(stderr, "XCB_MAP_REQUEST (window %d)\n", map_request->window);
581
xcb_map_window(wm->conn, map_request->window);
584
/* We reuse some predefined, but otherwise useles atoms */
585
#define TYPE_WM_PROTOCOLS XCB_ATOM_CUT_BUFFER0
588
weston_wm_handle_map_notify(struct weston_wm *wm, xcb_generic_event_t *event)
590
#define F(field) offsetof(struct weston_wm_window, field)
597
{ XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, F(class) },
598
{ XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, F(transient_for) },
599
{ wm->atom.wm_protocols, TYPE_WM_PROTOCOLS, F(protocols) },
600
{ wm->atom.net_wm_window_type, XCB_ATOM_ATOM, F(type) },
601
{ wm->atom.net_wm_name, XCB_ATOM_STRING, F(name) },
605
xcb_map_notify_event_t *map_notify = (xcb_map_notify_event_t *) event;
606
xcb_get_property_cookie_t cookie[ARRAY_LENGTH(props)];
607
xcb_get_property_reply_t *reply;
608
struct weston_wm_window *window;
614
fprintf(stderr, "XCB_MAP_NOTIFY (window %d)\n", map_notify->window);
616
dump_window_properties(wm, map_notify->window);
618
window = hash_table_lookup(wm->window_hash, map_notify->window);
620
for (i = 0; i < ARRAY_LENGTH(props); i++)
621
cookie[i] = xcb_get_property(wm->conn,
625
XCB_ATOM_ANY, 0, 2048);
627
for (i = 0; i < ARRAY_LENGTH(props); i++) {
628
reply = xcb_get_property_reply(wm->conn, cookie[i], NULL);
630
/* Bad window, typically */
632
if (reply->type == XCB_ATOM_NONE) {
633
/* No such property */
638
p = ((char *) window + props[i].offset);
640
switch (props[i].type) {
641
case XCB_ATOM_STRING:
642
/* FIXME: We're using this for both string and
645
strndup(xcb_get_property_value(reply),
646
xcb_get_property_value_length(reply));
648
case XCB_ATOM_WINDOW:
649
xid = xcb_get_property_value(reply);
650
*(struct weston_wm_window **) p =
651
hash_table_lookup(wm->window_hash, *xid);
654
atom = xcb_get_property_value(reply);
655
*(xcb_atom_t *) p = *atom;
657
case TYPE_WM_PROTOCOLS:
665
fprintf(stderr, "window %d: name %s, class %s, transient_for %d\n",
666
window->id, window->name, window->class,
667
window->transient_for ? window->transient_for->id : 0);
668
weston_wm_activate(wm, window, XCB_TIME_CURRENT_TIME);
671
static const int incr_chunk_size = 64 * 1024;
674
weston_wm_send_selection_notify(struct weston_wm *wm, xcb_atom_t property)
676
xcb_selection_notify_event_t selection_notify;
678
memset(&selection_notify, 0, sizeof selection_notify);
679
selection_notify.response_type = XCB_SELECTION_NOTIFY;
680
selection_notify.sequence = 0;
681
selection_notify.time = wm->selection_request.time;
682
selection_notify.requestor = wm->selection_request.requestor;
683
selection_notify.selection = wm->selection_request.selection;
684
selection_notify.target = wm->selection_request.target;
685
selection_notify.property = property;
687
xcb_send_event(wm->conn, 0, /* propagate */
688
wm->selection_request.requestor,
689
XCB_EVENT_MASK_NO_EVENT, (char *) &selection_notify);
693
weston_wm_send_targets(struct weston_wm *wm)
695
xcb_atom_t targets[] = {
698
wm->atom.utf8_string,
699
/* wm->atom.compound_text, */
701
/* wm->atom.string */
704
xcb_change_property(wm->conn,
705
XCB_PROP_MODE_REPLACE,
706
wm->selection_request.requestor,
707
wm->selection_request.property,
710
ARRAY_LENGTH(targets), targets);
712
weston_wm_send_selection_notify(wm, wm->selection_request.property);
716
weston_wm_send_timestamp(struct weston_wm *wm)
718
xcb_change_property(wm->conn,
719
XCB_PROP_MODE_REPLACE,
720
wm->selection_request.requestor,
721
wm->selection_request.property,
724
1, &wm->selection_timestamp);
726
weston_wm_send_selection_notify(wm, wm->selection_request.property);
730
weston_wm_flush_source_data(struct weston_wm *wm)
734
xcb_change_property(wm->conn,
735
XCB_PROP_MODE_REPLACE,
736
wm->selection_request.requestor,
737
wm->selection_request.property,
738
wm->selection_target,
740
wm->source_data.size,
741
wm->source_data.data);
742
wm->selection_property_set = 1;
743
length = wm->source_data.size;
744
wm->source_data.size = 0;
750
weston_wm_read_data_source(int fd, uint32_t mask, void *data)
752
struct weston_wm *wm = data;
753
int len, current, available;
756
current = wm->source_data.size;
757
if (wm->source_data.size < incr_chunk_size)
758
p = wl_array_add(&wm->source_data, incr_chunk_size);
760
p = (char *) wm->source_data.data + wm->source_data.size;
761
available = wm->source_data.alloc - current;
763
len = read(fd, p, available);
765
fprintf(stderr, "read error from data source: %m\n");
766
weston_wm_send_selection_notify(wm, XCB_ATOM_NONE);
767
wl_event_source_remove(wm->property_source);
769
wl_array_release(&wm->source_data);
772
fprintf(stderr, "read %d (available %d, mask 0x%x) bytes: \"%.*s\"\n",
773
len, available, mask, len, (char *) p);
775
wm->source_data.size = current + len;
776
if (wm->source_data.size >= incr_chunk_size) {
778
fprintf(stderr, "got %d bytes, starting incr\n",
779
wm->source_data.size);
781
xcb_change_property(wm->conn,
782
XCB_PROP_MODE_REPLACE,
783
wm->selection_request.requestor,
784
wm->selection_request.property,
787
1, &incr_chunk_size);
788
wm->selection_property_set = 1;
789
wm->flush_property_on_delete = 1;
790
wl_event_source_remove(wm->property_source);
791
weston_wm_send_selection_notify(wm, wm->selection_request.property);
792
} else if (wm->selection_property_set) {
793
fprintf(stderr, "got %d bytes, waiting for "
794
"property delete\n", wm->source_data.size);
796
wm->flush_property_on_delete = 1;
797
wl_event_source_remove(wm->property_source);
799
fprintf(stderr, "got %d bytes, "
800
"property deleted, seting new property\n",
801
wm->source_data.size);
802
weston_wm_flush_source_data(wm);
804
} else if (len == 0 && !wm->incr) {
805
fprintf(stderr, "non-incr transfer complete\n");
806
/* Non-incr transfer all done. */
807
weston_wm_flush_source_data(wm);
808
weston_wm_send_selection_notify(wm, wm->selection_request.property);
810
wl_event_source_remove(wm->property_source);
812
wl_array_release(&wm->source_data);
813
wm->selection_request.requestor = XCB_NONE;
814
} else if (len == 0 && wm->incr) {
815
fprintf(stderr, "incr transfer complete\n");
817
wm->flush_property_on_delete = 1;
818
if (wm->selection_property_set) {
819
fprintf(stderr, "got %d bytes, waiting for "
820
"property delete\n", wm->source_data.size);
822
fprintf(stderr, "got %d bytes, "
823
"property deleted, seting new property\n",
824
wm->source_data.size);
825
weston_wm_flush_source_data(wm);
828
wl_event_source_remove(wm->property_source);
829
wm->data_source_fd = -1;
832
fprintf(stderr, "nothing happened, buffered the bytes\n");
839
weston_wm_send_data(struct weston_wm *wm, xcb_atom_t target, const char *mime_type)
841
struct wl_input_device *device = wm->server->compositor->input_device;
844
if (pipe2(p, O_CLOEXEC | O_NONBLOCK) == -1) {
845
fprintf(stderr, "pipe2 failed: %m\n");
846
weston_wm_send_selection_notify(wm, XCB_ATOM_NONE);
850
wl_array_init(&wm->source_data);
851
wm->selection_target = target;
852
wm->data_source_fd = p[0];
853
wm->property_source = wl_event_loop_add_fd(wm->server->loop,
856
weston_wm_read_data_source,
859
wl_resource_post_event(&device->selection_data_source->resource,
860
WL_DATA_SOURCE_SEND, mime_type, p[1]);
865
weston_wm_send_incr_chunk(struct weston_wm *wm)
867
fprintf(stderr, "property deleted\n");
870
wm->selection_property_set = 0;
871
if (wm->flush_property_on_delete) {
872
fprintf(stderr, "setting new property, %d bytes\n",
873
wm->source_data.size);
874
wm->flush_property_on_delete = 0;
875
length = weston_wm_flush_source_data(wm);
877
if (wm->data_source_fd >= 0) {
878
wm->property_source =
879
wl_event_loop_add_fd(wm->server->loop,
882
weston_wm_read_data_source,
884
} else if (length > 0) {
885
/* Transfer is all done, but queue a flush for
886
* the delete of the last chunk so we can set
887
* the 0 sized propert to signal the end of
889
wm->flush_property_on_delete = 1;
890
wl_array_release(&wm->source_data);
892
wm->selection_request.requestor = XCB_NONE;
898
weston_wm_handle_selection_request(struct weston_wm *wm,
899
xcb_generic_event_t *event)
901
xcb_selection_request_event_t *selection_request =
902
(xcb_selection_request_event_t *) event;
904
fprintf(stderr, "selection request, %s, ",
905
get_atom_name(wm->conn, selection_request->selection));
906
fprintf(stderr, "target %s, ",
907
get_atom_name(wm->conn, selection_request->target));
908
fprintf(stderr, "property %s\n",
909
get_atom_name(wm->conn, selection_request->property));
911
wm->selection_request = *selection_request;
913
wm->flush_property_on_delete = 0;
915
if (selection_request->target == wm->atom.targets) {
916
weston_wm_send_targets(wm);
917
} else if (selection_request->target == wm->atom.timestamp) {
918
weston_wm_send_timestamp(wm);
919
} else if (selection_request->target == wm->atom.utf8_string ||
920
selection_request->target == wm->atom.text) {
921
weston_wm_send_data(wm, wm->atom.utf8_string,
922
"text/plain;charset=utf-8");
924
fprintf(stderr, "can only handle UTF8_STRING targets...\n");
925
weston_wm_send_selection_notify(wm, XCB_ATOM_NONE);
930
weston_wm_handle_property_notify(struct weston_wm *wm, xcb_generic_event_t *event)
932
xcb_property_notify_event_t *property_notify =
933
(xcb_property_notify_event_t *) event;
935
if (property_notify->window == wm->selection_window) {
936
if (property_notify->state == XCB_PROPERTY_NEW_VALUE &&
937
property_notify->atom == wm->atom.wl_selection &&
939
weston_wm_get_incr_chunk(wm);
940
} else if (property_notify->window == wm->selection_request.requestor) {
941
if (property_notify->state == XCB_PROPERTY_DELETE &&
942
property_notify->atom == wm->selection_request.property &&
944
weston_wm_send_incr_chunk(wm);
945
} else if (property_notify->atom == XCB_ATOM_WM_CLASS) {
946
fprintf(stderr, "wm_class changed\n");
947
} else if (property_notify->atom == XCB_ATOM_WM_TRANSIENT_FOR) {
948
fprintf(stderr, "wm_transient_for changed\n");
949
} else if (property_notify->atom == wm->atom.wm_protocols) {
950
fprintf(stderr, "wm_protocols changed\n");
951
} else if (property_notify->atom == wm->atom.net_wm_name) {
952
fprintf(stderr, "_net_wm_name changed\n");
953
} else if (property_notify->atom == wm->atom.net_wm_user_time) {
954
fprintf(stderr, "_net_wm_user_time changed\n");
955
} else if (property_notify->atom == wm->atom.net_wm_icon_name) {
956
fprintf(stderr, "_net_wm_icon_name changed\n");
957
} else if (property_notify->atom == XCB_ATOM_WM_NAME) {
958
fprintf(stderr, "wm_name changed\n");
959
} else if (property_notify->atom == XCB_ATOM_WM_ICON_NAME) {
960
fprintf(stderr, "wm_icon_name changed\n");
962
fprintf(stderr, "XCB_PROPERTY_NOTIFY: "
963
"unhandled property change: %s\n",
964
get_atom_name(wm->conn, property_notify->atom));
969
weston_wm_handle_create_notify(struct weston_wm *wm, xcb_generic_event_t *event)
971
xcb_create_notify_event_t *create_notify =
972
(xcb_create_notify_event_t *) event;
973
struct weston_wm_window *window;
976
fprintf(stderr, "XCB_CREATE_NOTIFY (window %d)\n",
977
create_notify->window);
979
window = malloc(sizeof *window);
980
if (window == NULL) {
981
fprintf(stderr, "failed to allocate window\n");
985
values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE;
986
xcb_change_window_attributes(wm->conn, create_notify->window,
987
XCB_CW_EVENT_MASK, values);
989
memset(window, 0, sizeof *window);
990
window->id = create_notify->window;
991
hash_table_insert(wm->window_hash, window->id, window);
995
weston_wm_handle_destroy_notify(struct weston_wm *wm, xcb_generic_event_t *event)
997
xcb_destroy_notify_event_t *destroy_notify =
998
(xcb_destroy_notify_event_t *) event;
999
struct weston_wm_window *window;
1001
fprintf(stderr, "XCB_DESTROY_NOTIFY, win %d\n",
1002
destroy_notify->window);
1004
window = hash_table_lookup(wm->window_hash, destroy_notify->window);
1005
if (window == NULL) {
1006
fprintf(stderr, "destroy notify for unknow window %d\n",
1007
destroy_notify->window);
1011
fprintf(stderr, "destroy window %p\n", window);
1012
hash_table_remove(wm->window_hash, window->id);
1013
if (window->surface)
1014
wl_list_remove(&window->surface_destroy_listener.link);
1019
weston_wm_handle_selection_notify(struct weston_wm *wm,
1020
xcb_generic_event_t *event)
1022
xcb_selection_notify_event_t *selection_notify =
1023
(xcb_selection_notify_event_t *) event;
1025
if (selection_notify->property == XCB_ATOM_NONE) {
1026
/* convert selection failed */
1027
} else if (selection_notify->target == wm->atom.targets) {
1028
weston_wm_get_selection_targets(wm);
1030
weston_wm_get_selection_data(wm);
1035
weston_wm_handle_xfixes_selection_notify(struct weston_wm *wm,
1036
xcb_generic_event_t *event)
1038
xcb_xfixes_selection_notify_event_t *xfixes_selection_notify =
1039
(xcb_xfixes_selection_notify_event_t *) event;
1041
printf("xfixes selection notify event: owner %d\n",
1042
xfixes_selection_notify->owner);
1044
/* We have to use XCB_TIME_CURRENT_TIME when we claim the
1045
* selection, so grab the actual timestamp here so we can
1046
* answer TIMESTAMP conversion requests correctly. */
1047
if (xfixes_selection_notify->owner == wm->selection_window) {
1048
wm->selection_timestamp = xfixes_selection_notify->timestamp;
1049
fprintf(stderr, "our window, skipping\n");
1054
xcb_convert_selection(wm->conn, wm->selection_window,
1057
wm->atom.wl_selection,
1058
xfixes_selection_notify->timestamp);
1060
xcb_flush(wm->conn);
1064
weston_wm_handle_client_message(struct weston_wm *wm,
1065
xcb_generic_event_t *event)
1067
xcb_client_message_event_t *client_message =
1068
(xcb_client_message_event_t *) event;
1070
fprintf(stderr, "got client message, type: %s\n",
1071
get_atom_name(wm->conn, client_message->type));
1075
weston_wm_handle_event(int fd, uint32_t mask, void *data)
1077
struct weston_wm *wm = data;
1078
xcb_generic_event_t *event;
1081
while (event = xcb_poll_for_event(wm->conn), event != NULL) {
1082
switch (event->response_type & ~0x80) {
1083
case XCB_CREATE_NOTIFY:
1084
weston_wm_handle_create_notify(wm, event);
1086
case XCB_MAP_REQUEST:
1087
weston_wm_handle_map_request(wm, event);
1089
case XCB_MAP_NOTIFY:
1090
weston_wm_handle_map_notify(wm, event);
1092
case XCB_UNMAP_NOTIFY:
1093
fprintf(stderr, "XCB_UNMAP_NOTIFY\n");
1095
case XCB_CONFIGURE_REQUEST:
1096
weston_wm_handle_configure_request(wm, event);
1098
case XCB_CONFIGURE_NOTIFY:
1099
weston_wm_handle_configure_notify(wm, event);
1101
case XCB_DESTROY_NOTIFY:
1102
weston_wm_handle_destroy_notify(wm, event);
1104
case XCB_MAPPING_NOTIFY:
1105
fprintf(stderr, "XCB_MAPPING_NOTIFY\n");
1107
case XCB_PROPERTY_NOTIFY:
1108
weston_wm_handle_property_notify(wm, event);
1110
case XCB_SELECTION_NOTIFY:
1111
weston_wm_handle_selection_notify(wm, event);
1113
case XCB_SELECTION_REQUEST:
1114
weston_wm_handle_selection_request(wm, event);
1116
case XCB_CLIENT_MESSAGE:
1117
weston_wm_handle_client_message(wm, event);
1121
switch (event->response_type - wm->xfixes->first_event) {
1122
case XCB_XFIXES_SELECTION_NOTIFY:
1123
weston_wm_handle_xfixes_selection_notify(wm, event);
1132
xcb_flush(wm->conn);
1138
wxs_wm_get_resources(struct weston_wm *wm)
1141
#define F(field) offsetof(struct weston_wm, field)
1143
static const struct { const char *name; int offset; } atoms[] = {
1144
{ "WM_PROTOCOLS", F(atom.wm_protocols) },
1145
{ "WM_TAKE_FOCUS", F(atom.wm_take_focus) },
1146
{ "WM_DELETE_WINDOW", F(atom.wm_delete_window) },
1147
{ "_NET_WM_NAME", F(atom.net_wm_name) },
1148
{ "_NET_WM_ICON", F(atom.net_wm_icon) },
1149
{ "_NET_WM_STATE", F(atom.net_wm_state) },
1150
{ "_NET_WM_STATE_FULLSCREEN", F(atom.net_wm_state_fullscreen) },
1151
{ "_NET_WM_USER_TIME", F(atom.net_wm_user_time) },
1152
{ "_NET_WM_ICON_NAME", F(atom.net_wm_icon_name) },
1153
{ "_NET_WM_WINDOW_TYPE", F(atom.net_wm_window_type) },
1154
{ "_NET_WM_MOVERESIZE", F(atom.net_wm_moveresize) },
1155
{ "_NET_SUPPORTING_WM_CHECK",
1156
F(atom.net_supporting_wm_check) },
1157
{ "_NET_SUPPORTED", F(atom.net_supported) },
1158
{ "CLIPBOARD", F(atom.clipboard) },
1159
{ "TARGETS", F(atom.targets) },
1160
{ "UTF8_STRING", F(atom.utf8_string) },
1161
{ "_WL_SELECTION", F(atom.wl_selection) },
1162
{ "INCR", F(atom.incr) },
1163
{ "TIMESTAMP", F(atom.timestamp) },
1164
{ "MULTIPLE", F(atom.multiple) },
1165
{ "UTF8_STRING" , F(atom.utf8_string) },
1166
{ "COMPOUND_TEXT", F(atom.compound_text) },
1167
{ "TEXT", F(atom.text) },
1168
{ "STRING", F(atom.string) },
1169
{ "text/plain;charset=utf-8", F(atom.text_plain_utf8) },
1170
{ "text/plain", F(atom.text_plain) },
1173
xcb_xfixes_query_version_cookie_t xfixes_cookie;
1174
xcb_xfixes_query_version_reply_t *xfixes_reply;
1175
xcb_intern_atom_cookie_t cookies[ARRAY_LENGTH(atoms)];
1176
xcb_intern_atom_reply_t *reply;
1179
xcb_prefetch_extension_data (wm->conn, &xcb_xfixes_id);
1181
for (i = 0; i < ARRAY_LENGTH(atoms); i++)
1182
cookies[i] = xcb_intern_atom (wm->conn, 0,
1183
strlen(atoms[i].name),
1186
for (i = 0; i < ARRAY_LENGTH(atoms); i++) {
1187
reply = xcb_intern_atom_reply (wm->conn, cookies[i], NULL);
1188
*(xcb_atom_t *) ((char *) wm + atoms[i].offset) = reply->atom;
1192
wm->xfixes = xcb_get_extension_data(wm->conn, &xcb_xfixes_id);
1193
if (!wm->xfixes || !wm->xfixes->present)
1194
fprintf(stderr, "xfixes not available\n");
1196
xfixes_cookie = xcb_xfixes_query_version(wm->conn,
1197
XCB_XFIXES_MAJOR_VERSION,
1198
XCB_XFIXES_MINOR_VERSION);
1199
xfixes_reply = xcb_xfixes_query_version_reply(wm->conn,
1200
xfixes_cookie, NULL);
1202
printf("xfixes version: %d.%d\n",
1203
xfixes_reply->major_version, xfixes_reply->minor_version);
1209
weston_wm_create_wm_window(struct weston_wm *wm)
1211
static const char name[] = "Weston WM";
1213
wm->wm_window = xcb_generate_id(wm->conn);
1214
xcb_create_window(wm->conn,
1215
XCB_COPY_FROM_PARENT,
1221
XCB_WINDOW_CLASS_INPUT_OUTPUT,
1222
wm->screen->root_visual,
1225
xcb_change_property(wm->conn,
1226
XCB_PROP_MODE_REPLACE,
1228
wm->atom.net_supporting_wm_check,
1233
xcb_change_property(wm->conn,
1234
XCB_PROP_MODE_REPLACE,
1236
wm->atom.net_wm_name,
1237
wm->atom.utf8_string,
1239
strlen(name), name);
1241
xcb_change_property(wm->conn,
1242
XCB_PROP_MODE_REPLACE,
1244
wm->atom.net_supporting_wm_check,
1251
static struct weston_wm *
1252
weston_wm_create(struct weston_xserver *wxs)
1254
struct wl_input_device *device;
1255
struct weston_wm *wm;
1256
struct wl_event_loop *loop;
1257
xcb_screen_iterator_t s;
1258
uint32_t values[1], mask;
1260
xcb_atom_t supported[1];
1262
wm = malloc(sizeof *wm);
1267
wm->window_hash = hash_table_create();
1268
if (wm->window_hash == NULL) {
1273
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
1274
fprintf(stderr, "socketpair failed\n");
1275
hash_table_destroy(wm->window_hash);
1280
wl_resource_post_event(wxs->resource, XSERVER_CLIENT, sv[1]);
1281
wl_client_flush(wxs->resource->client);
1284
/* xcb_connect_to_fd takes ownership of the fd. */
1285
wm->conn = xcb_connect_to_fd(sv[0], NULL);
1286
if (xcb_connection_has_error(wm->conn)) {
1287
fprintf(stderr, "xcb_connect_to_fd failed\n");
1289
hash_table_destroy(wm->window_hash);
1294
s = xcb_setup_roots_iterator(xcb_get_setup(wm->conn));
1295
wm->screen = s.data;
1297
loop = wl_display_get_event_loop(wxs->wl_display);
1299
wl_event_loop_add_fd(loop, sv[0],
1301
weston_wm_handle_event, wm);
1302
wl_event_source_check(wm->source);
1304
wxs_wm_get_resources(wm);
1307
XCB_EVENT_MASK_STRUCTURE_NOTIFY |
1308
XCB_EVENT_MASK_RESIZE_REDIRECT |
1309
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
1310
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
1311
XCB_EVENT_MASK_PROPERTY_CHANGE;
1312
xcb_change_window_attributes(wm->conn, wm->screen->root,
1313
XCB_CW_EVENT_MASK, values);
1315
weston_wm_create_wm_window(wm);
1317
supported[0] = wm->atom.net_wm_moveresize;
1318
xcb_change_property(wm->conn,
1319
XCB_PROP_MODE_REPLACE,
1321
wm->atom.net_supported,
1324
ARRAY_LENGTH(supported), supported);
1326
wm->selection_request.requestor = XCB_NONE;
1328
wm->selection_window = xcb_generate_id(wm->conn);
1329
xcb_create_window(wm->conn,
1330
XCB_COPY_FROM_PARENT,
1331
wm->selection_window,
1336
XCB_WINDOW_CLASS_INPUT_OUTPUT,
1337
wm->screen->root_visual,
1338
XCB_CW_EVENT_MASK, values);
1341
XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
1342
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
1343
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE;
1345
xcb_xfixes_select_selection_input(wm->conn, wm->selection_window,
1346
wm->atom.clipboard, mask);
1348
xcb_flush(wm->conn);
1350
device = wxs->compositor->input_device;
1351
wm->selection_listener.func = weston_wm_set_selection;
1352
wl_list_insert(&device->selection_listener_list,
1353
&wm->selection_listener.link);
1355
fprintf(stderr, "created wm\n");
1361
weston_wm_destroy(struct weston_wm *wm)
1363
/* FIXME: Free windows in hash. */
1364
hash_table_destroy(wm->window_hash);
1365
xcb_disconnect(wm->conn);
1366
wl_event_source_remove(wm->source);
1367
wl_list_remove(&wm->selection_listener.link);
1372
weston_xserver_handle_event(int listen_fd, uint32_t mask, void *data)
1374
struct weston_xserver *mxs = data;
1375
char display[8], s[8];
1376
int sv[2], client_fd;
1378
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
1379
fprintf(stderr, "socketpair failed\n");
1383
mxs->process.pid = fork();
1384
switch (mxs->process.pid) {
1386
/* SOCK_CLOEXEC closes both ends, so we need to unset
1387
* the flag on the client fd. */
1388
client_fd = dup(sv[1]);
1392
snprintf(s, sizeof s, "%d", client_fd);
1393
setenv("WAYLAND_SOCKET", s, 1);
1395
snprintf(display, sizeof display, ":%d", mxs->display);
1397
if (execl(XSERVER_PATH,
1406
fprintf(stderr, "exec failed: %m\n");
1410
fprintf(stderr, "forked X server, pid %d\n", mxs->process.pid);
1413
mxs->client = wl_client_create(mxs->wl_display, sv[0]);
1415
weston_watch_process(&mxs->process);
1417
wl_event_source_remove(mxs->abstract_source);
1418
wl_event_source_remove(mxs->unix_source);
1422
fprintf(stderr, "failed to fork\n");
1430
weston_xserver_shutdown(struct weston_xserver *wxs)
1434
snprintf(path, sizeof path, "/tmp/.X%d-lock", wxs->display);
1436
snprintf(path, sizeof path, "/tmp/.X11-unix/X%d", wxs->display);
1438
if (wxs->process.pid == 0) {
1439
wl_event_source_remove(wxs->abstract_source);
1440
wl_event_source_remove(wxs->unix_source);
1442
close(wxs->abstract_fd);
1443
close(wxs->unix_fd);
1445
weston_wm_destroy(wxs->wm);
1450
weston_xserver_cleanup(struct weston_process *process, int status)
1452
struct weston_xserver *mxs =
1453
container_of(process, struct weston_xserver, process);
1455
mxs->process.pid = 0;
1457
mxs->resource = NULL;
1459
mxs->abstract_source =
1460
wl_event_loop_add_fd(mxs->loop, mxs->abstract_fd,
1462
weston_xserver_handle_event, mxs);
1465
wl_event_loop_add_fd(mxs->loop, mxs->unix_fd,
1467
weston_xserver_handle_event, mxs);
1470
fprintf(stderr, "xserver exited, code %d\n", status);
1471
weston_wm_destroy(mxs->wm);
1474
/* If the X server crashes before it binds to the
1475
* xserver interface, shut down and don't try
1477
fprintf(stderr, "xserver crashing too fast: %d\n", status);
1478
weston_xserver_shutdown(mxs);
1483
surface_destroy(struct wl_listener *listener,
1484
struct wl_resource *resource, uint32_t time)
1486
struct weston_wm_window *window =
1487
container_of(listener,
1488
struct weston_wm_window, surface_destroy_listener);
1490
fprintf(stderr, "surface for xid %d destroyed\n", window->id);
1493
static struct weston_wm_window *
1494
get_wm_window(struct weston_surface *surface)
1496
struct wl_resource *resource = &surface->surface.resource;
1497
struct wl_listener *listener;
1499
wl_list_for_each(listener, &resource->destroy_listener_list, link) {
1500
if (listener->func == surface_destroy)
1501
return container_of(listener,
1502
struct weston_wm_window,
1503
surface_destroy_listener);
1510
xserver_set_window_id(struct wl_client *client, struct wl_resource *resource,
1511
struct wl_resource *surface_resource, uint32_t id)
1513
struct weston_xserver *wxs = resource->data;
1514
struct weston_wm *wm = wxs->wm;
1515
struct wl_surface *surface = surface_resource->data;
1516
struct weston_wm_window *window;
1518
if (client != wxs->client)
1521
window = hash_table_lookup(wm->window_hash, id);
1522
if (window == NULL) {
1523
fprintf(stderr, "set_window_id for unknown window %d\n", id);
1527
fprintf(stderr, "set_window_id %d for surface %p\n", id, surface);
1529
window->surface = (struct weston_surface *) surface;
1530
window->surface_destroy_listener.func = surface_destroy;
1531
wl_list_insert(surface->resource.destroy_listener_list.prev,
1532
&window->surface_destroy_listener.link);
1535
static const struct xserver_interface xserver_implementation = {
1536
xserver_set_window_id
1540
bind_xserver(struct wl_client *client,
1541
void *data, uint32_t version, uint32_t id)
1543
struct weston_xserver *wxs = data;
1545
/* If it's a different client than the xserver we launched,
1546
* don't start the wm. */
1547
if (client != wxs->client)
1551
wl_client_add_object(client, &xserver_interface,
1552
&xserver_implementation, id, wxs);
1554
wxs->wm = weston_wm_create(wxs);
1555
if (wxs->wm == NULL) {
1556
fprintf(stderr, "failed to create wm\n");
1559
wl_resource_post_event(wxs->resource,
1560
XSERVER_LISTEN_SOCKET, wxs->abstract_fd);
1562
wl_resource_post_event(wxs->resource,
1563
XSERVER_LISTEN_SOCKET, wxs->unix_fd);
1567
bind_to_abstract_socket(int display)
1569
struct sockaddr_un addr;
1570
socklen_t size, name_size;
1573
fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
1577
addr.sun_family = AF_LOCAL;
1578
name_size = snprintf(addr.sun_path, sizeof addr.sun_path,
1579
"%c/tmp/.X11-unix/X%d", 0, display);
1580
size = offsetof(struct sockaddr_un, sun_path) + name_size;
1581
if (bind(fd, (struct sockaddr *) &addr, size) < 0) {
1582
fprintf(stderr, "failed to bind to @%s: %s\n",
1583
addr.sun_path + 1, strerror(errno));
1588
if (listen(fd, 1) < 0) {
1597
bind_to_unix_socket(int display)
1599
struct sockaddr_un addr;
1600
socklen_t size, name_size;
1603
fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
1607
addr.sun_family = AF_LOCAL;
1608
name_size = snprintf(addr.sun_path, sizeof addr.sun_path,
1609
"/tmp/.X11-unix/X%d", display) + 1;
1610
size = offsetof(struct sockaddr_un, sun_path) + name_size;
1611
unlink(addr.sun_path);
1612
if (bind(fd, (struct sockaddr *) &addr, size) < 0) {
1613
fprintf(stderr, "failed to bind to %s (%s)\n",
1614
addr.sun_path, strerror(errno));
1619
if (listen(fd, 1) < 0) {
1620
unlink(addr.sun_path);
1629
create_lockfile(int display, char *lockfile, size_t lsize)
1635
snprintf(lockfile, lsize, "/tmp/.X%d-lock", display);
1636
fd = open(lockfile, O_WRONLY | O_CLOEXEC | O_CREAT | O_EXCL, 0444);
1637
if (fd < 0 && errno == EEXIST) {
1638
fd = open(lockfile, O_CLOEXEC, O_RDONLY);
1639
if (fd < 0 || read(fd, pid, 11) != 11) {
1640
fprintf(stderr, "can't read lock file %s: %s\n",
1641
lockfile, strerror(errno));
1646
other = strtol(pid, &end, 0);
1647
if (end != pid + 10) {
1648
fprintf(stderr, "can't parse lock file %s\n",
1654
if (kill(other, 0) < 0 && errno == ESRCH) {
1655
/* stale lock file; unlink and try again */
1657
"unlinking stale lock file %s\n", lockfile);
1665
} else if (fd < 0) {
1666
fprintf(stderr, "failed to create lock file %s: %s\n",
1667
lockfile, strerror(errno));
1671
/* Subtle detail: we use the pid of the wayland
1672
* compositor, not the xserver in the lock file. */
1673
size = snprintf(pid, sizeof pid, "%10d\n", getpid());
1674
if (write(fd, pid, size) != size) {
1686
weston_xserver_init(struct weston_compositor *compositor)
1688
struct wl_display *display = compositor->wl_display;
1689
struct weston_xserver *mxs;
1690
char lockfile[256], display_name[8];
1692
mxs = malloc(sizeof *mxs);
1693
memset(mxs, 0, sizeof *mxs);
1695
mxs->process.cleanup = weston_xserver_cleanup;
1696
mxs->wl_display = display;
1697
mxs->compositor = compositor;
1702
if (create_lockfile(mxs->display, lockfile, sizeof lockfile) < 0) {
1703
if (errno == EAGAIN) {
1705
} else if (errno == EEXIST) {
1714
mxs->abstract_fd = bind_to_abstract_socket(mxs->display);
1715
if (mxs->abstract_fd < 0 && errno == EADDRINUSE) {
1721
mxs->unix_fd = bind_to_unix_socket(mxs->display);
1722
if (mxs->unix_fd < 0) {
1724
close(mxs->abstract_fd);
1729
snprintf(display_name, sizeof display_name, ":%d", mxs->display);
1730
fprintf(stderr, "xserver listening on display %s\n", display_name);
1731
setenv("DISPLAY", display_name, 1);
1733
mxs->loop = wl_display_get_event_loop(display);
1734
mxs->abstract_source =
1735
wl_event_loop_add_fd(mxs->loop, mxs->abstract_fd,
1737
weston_xserver_handle_event, mxs);
1739
wl_event_loop_add_fd(mxs->loop, mxs->unix_fd,
1741
weston_xserver_handle_event, mxs);
1743
wl_display_add_global(display, &xserver_interface, mxs, bind_xserver);
1745
compositor->wxs = mxs;
1751
weston_xserver_destroy(struct weston_compositor *compositor)
1753
struct weston_xserver *wxs = compositor->wxs;
1759
weston_xserver_shutdown(wxs);