~darxus/+junk/weston-packaging-fix

« back to all changes in this revision

Viewing changes to src/xserver-launcher.c

  • Committer: Package Import Robot
  • Author(s): Cyril Brulebois
  • Date: 2012-02-21 23:58:19 UTC
  • Revision ID: package-import@ubuntu.com-20120221235819-xjn2lioyl3d0ljkt
Tags: upstream-0.85.0
Import upstream version 0.85.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2011 Intel Corporation
 
3
 *
 
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.
 
13
 *
 
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.
 
21
 */
 
22
 
 
23
#define _GNU_SOURCE
 
24
 
 
25
#include <stdlib.h>
 
26
#include <stdio.h>
 
27
#include <string.h>
 
28
#include <sys/socket.h>
 
29
#include <sys/un.h>
 
30
#include <fcntl.h>
 
31
#include <errno.h>
 
32
#include <unistd.h>
 
33
#include <signal.h>
 
34
 
 
35
#include <xcb/xcb.h>
 
36
#include <xcb/xfixes.h>
 
37
 
 
38
#include <wayland-server.h>
 
39
 
 
40
#include "compositor.h"
 
41
#include "xserver-server-protocol.h"
 
42
#include "hash.h"
 
43
 
 
44
struct xserver {
 
45
        struct wl_resource resource;
 
46
};
 
47
 
 
48
struct weston_xserver {
 
49
        struct wl_display *wl_display;
 
50
        struct wl_event_loop *loop;
 
51
        struct wl_event_source *sigchld_source;
 
52
        int abstract_fd;
 
53
        struct wl_event_source *abstract_source;
 
54
        int unix_fd;
 
55
        struct wl_event_source *unix_source;
 
56
        int display;
 
57
        struct weston_process process;
 
58
        struct wl_resource *resource;
 
59
        struct wl_client *client;
 
60
        struct weston_compositor *compositor;
 
61
        struct weston_wm *wm;
 
62
};
 
63
 
 
64
struct weston_wm {
 
65
        xcb_connection_t *conn;
 
66
        const xcb_query_extension_reply_t *xfixes;
 
67
        struct wl_event_source *source;
 
68
        xcb_screen_t *screen;
 
69
        struct hash_table *window_hash;
 
70
        struct weston_xserver *server;
 
71
        xcb_window_t wm_window;
 
72
 
 
73
        xcb_window_t selection_window;
 
74
        int incr;
 
75
        int data_source_fd;
 
76
        struct wl_event_source *property_source;
 
77
        xcb_get_property_reply_t *property_reply;
 
78
        int property_start;
 
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;
 
86
 
 
87
        struct {
 
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;
 
102
                xcb_atom_t               targets;
 
103
                xcb_atom_t               utf8_string;
 
104
                xcb_atom_t               wl_selection;
 
105
                xcb_atom_t               incr;
 
106
                xcb_atom_t               timestamp;
 
107
                xcb_atom_t               multiple;
 
108
                xcb_atom_t               compound_text;
 
109
                xcb_atom_t               text;
 
110
                xcb_atom_t               string;
 
111
                xcb_atom_t               text_plain_utf8;
 
112
                xcb_atom_t               text_plain;
 
113
        } atom;
 
114
};
 
115
 
 
116
struct weston_wm_window {
 
117
        xcb_window_t id;
 
118
        struct weston_surface *surface;
 
119
        struct wl_listener surface_destroy_listener;
 
120
        char *class;
 
121
        char *name;
 
122
        struct weston_wm_window *transient_for;
 
123
        uint32_t protocols;
 
124
        xcb_atom_t type;
 
125
};
 
126
 
 
127
static struct weston_wm_window *
 
128
get_wm_window(struct weston_surface *surface);
 
129
 
 
130
static const char *
 
131
get_atom_name(xcb_connection_t *c, xcb_atom_t atom)
 
132
{
 
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];
 
137
 
 
138
        if (atom == XCB_ATOM_NONE)
 
139
                return "None";
 
140
 
 
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));
 
146
        free(reply);
 
147
 
 
148
        return buffer;
 
149
}
 
150
 
 
151
static void
 
152
dump_property(struct weston_wm *wm, xcb_atom_t property,
 
153
              xcb_get_property_reply_t *reply)
 
154
{
 
155
        int32_t *incr_value;
 
156
        const char *text_value, *name;
 
157
        xcb_atom_t *atom_value;
 
158
        int i, width, len;
 
159
 
 
160
        width = fprintf(stderr, "  %s: ", get_atom_name(wm->conn, property));
 
161
        if (reply == NULL) {
 
162
                fprintf(stderr, "(no reply)\n");
 
163
                return;
 
164
        }
 
165
 
 
166
        width += fprintf(stderr,
 
167
                         "type %s, format %d, length %d (value_len %d): ",
 
168
                         get_atom_name(wm->conn, reply->type),
 
169
                         reply->format,
 
170
                         xcb_get_property_value_length(reply),
 
171
                         reply->value_len);
 
172
 
 
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)
 
180
                        len = 40;
 
181
                else
 
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    ");
 
190
                                width = 4;
 
191
                        } else if (i > 0) {
 
192
                                width += fprintf(stderr, ", ");
 
193
                        }
 
194
 
 
195
                        width += fprintf(stderr, "%s", name);
 
196
                }
 
197
                fprintf(stderr, "\n");
 
198
        } else {
 
199
                fprintf(stderr, "huh?\n");
 
200
        }
 
201
}
 
202
 
 
203
static void
 
204
dump_window_properties(struct weston_wm *wm, xcb_window_t window)
 
205
{
 
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;
 
210
        xcb_atom_t *atoms;
 
211
        int i, length;
 
212
 
 
213
        list_cookie = xcb_list_properties(wm->conn, window);
 
214
        list_reply = xcb_list_properties_reply(wm->conn, list_cookie, NULL);
 
215
        if (!list_reply)
 
216
                /* Bad window, typically */
 
217
                return;
 
218
 
 
219
        length = xcb_list_properties_atoms_length(list_reply);
 
220
        atoms = xcb_list_properties_atoms(list_reply);
 
221
 
 
222
        for (i = 0; i < length; i++) {
 
223
                property_cookie =
 
224
                        xcb_get_property(wm->conn,
 
225
                                         0, /* delete */
 
226
                                         window,
 
227
                                         atoms[i],
 
228
                                         XCB_ATOM_ANY,
 
229
                                         0, 2048);
 
230
 
 
231
                property_reply = xcb_get_property_reply(wm->conn,
 
232
                                                        property_cookie, NULL);
 
233
                dump_property(wm, atoms[i], property_reply);
 
234
 
 
235
                free(property_reply);
 
236
        }
 
237
 
 
238
        free(list_reply);
 
239
}
 
240
 
 
241
static void
 
242
data_offer_accept(struct wl_client *client, struct wl_resource *resource,
 
243
                  uint32_t time, const char *mime_type)
 
244
{
 
245
}
 
246
 
 
247
static void
 
248
data_offer_receive(struct wl_client *client, struct wl_resource *resource,
 
249
                   const char *mime_type, int32_t fd)
 
250
{
 
251
        struct wl_data_offer *offer = resource->data;
 
252
        struct weston_wm *wm = offer->source->resource.data;
 
253
 
 
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,
 
258
                                      wm->atom.clipboard,
 
259
                                      wm->atom.utf8_string,
 
260
                                      wm->atom.wl_selection,
 
261
                                      XCB_TIME_CURRENT_TIME);
 
262
 
 
263
                xcb_flush(wm->conn);
 
264
 
 
265
                fcntl(fd, F_SETFL, O_WRONLY | O_NONBLOCK);
 
266
                wm->data_source_fd = fd;
 
267
        } else {
 
268
                close(fd);
 
269
        }
 
270
}
 
271
 
 
272
static void
 
273
data_offer_destroy(struct wl_client *client, struct wl_resource *resource)
 
274
{
 
275
        wl_resource_destroy(resource, weston_compositor_get_time());
 
276
}
 
277
 
 
278
static const struct wl_data_offer_interface data_offer_interface = {
 
279
        data_offer_accept,
 
280
        data_offer_receive,
 
281
        data_offer_destroy,
 
282
};
 
283
 
 
284
static void
 
285
data_source_cancel(struct wl_data_source *source)
 
286
{
 
287
}
 
288
 
 
289
static void
 
290
weston_wm_get_selection_targets(struct weston_wm *wm)
 
291
{
 
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;
 
296
        xcb_atom_t *value;
 
297
        char **p;
 
298
        int i;
 
299
 
 
300
        cookie = xcb_get_property(wm->conn,
 
301
                                  1, /* delete */
 
302
                                  wm->selection_window,
 
303
                                  wm->atom.wl_selection,
 
304
                                  XCB_GET_PROPERTY_TYPE_ANY,
 
305
                                  0, /* offset */
 
306
                                  4096 /* length */);
 
307
 
 
308
        reply = xcb_get_property_reply(wm->conn, cookie, NULL);
 
309
 
 
310
        dump_property(wm, wm->atom.wl_selection, reply);
 
311
 
 
312
        if (reply->type != XCB_ATOM_ATOM) {
 
313
                free(reply);
 
314
                return;
 
315
        }
 
316
 
 
317
        source = malloc(sizeof *source);
 
318
        if (source == NULL)
 
319
                return;
 
320
 
 
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;
 
325
 
 
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);
 
331
                        if (p)
 
332
                                *p = strdup("text/plain;charset=utf-8");
 
333
                }
 
334
        }
 
335
 
 
336
        device = wm->server->compositor->input_device;
 
337
        wl_input_device_set_selection(device, source,
 
338
                                      weston_compositor_get_time());
 
339
 
 
340
        free(reply);
 
341
}
 
342
 
 
343
static int
 
344
weston_wm_write_property(int fd, uint32_t mask, void *data)
 
345
{
 
346
        struct weston_wm *wm = data;
 
347
        unsigned char *property;
 
348
        int len, remainder;
 
349
 
 
350
        property = xcb_get_property_value(wm->property_reply);
 
351
        remainder = xcb_get_property_value_length(wm->property_reply) -
 
352
                wm->property_start;
 
353
 
 
354
        len = write(fd, property + wm->property_start, remainder);
 
355
        if (len == -1) {
 
356
                free(wm->property_reply);
 
357
                wl_event_source_remove(wm->property_source);
 
358
                close(fd);
 
359
                fprintf(stderr, "write error to target fd: %m\n");
 
360
                return 1;
 
361
        }
 
362
 
 
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));
 
366
 
 
367
        wm->property_start += len;
 
368
        if (len == remainder) {
 
369
                free(wm->property_reply);
 
370
                wl_event_source_remove(wm->property_source);
 
371
 
 
372
                if (wm->incr) {
 
373
                        xcb_delete_property(wm->conn,
 
374
                                            wm->selection_window,
 
375
                                            wm->atom.wl_selection);
 
376
                } else {
 
377
                        fprintf(stderr, "transfer complete\n");
 
378
                        close(fd);
 
379
                }
 
380
        }
 
381
 
 
382
        return 1;
 
383
}
 
384
 
 
385
static void
 
386
weston_wm_get_selection_data(struct weston_wm *wm)
 
387
{
 
388
        xcb_get_property_cookie_t cookie;
 
389
        xcb_get_property_reply_t *reply;
 
390
 
 
391
        cookie = xcb_get_property(wm->conn,
 
392
                                  1, /* delete */
 
393
                                  wm->selection_window,
 
394
                                  wm->atom.wl_selection,
 
395
                                  XCB_GET_PROPERTY_TYPE_ANY,
 
396
                                  0, /* offset */
 
397
                                  0x1fffffff /* length */);
 
398
 
 
399
        reply = xcb_get_property_reply(wm->conn, cookie, NULL);
 
400
 
 
401
        if (reply->type == wm->atom.incr) {
 
402
                dump_property(wm, wm->atom.wl_selection, reply);
 
403
                wm->incr = 1;
 
404
                free(reply);
 
405
        } else {
 
406
                dump_property(wm, wm->atom.wl_selection, reply);
 
407
                wm->incr = 0;
 
408
                wm->property_start = 0;
 
409
                wm->property_source =
 
410
                        wl_event_loop_add_fd(wm->server->loop,
 
411
                                             wm->data_source_fd,
 
412
                                             WL_EVENT_WRITABLE,
 
413
                                             weston_wm_write_property,
 
414
                                             wm);
 
415
                wm->property_reply = reply;
 
416
        }
 
417
}
 
418
 
 
419
static void
 
420
weston_wm_get_incr_chunk(struct weston_wm *wm)
 
421
{
 
422
        xcb_get_property_cookie_t cookie;
 
423
        xcb_get_property_reply_t *reply;
 
424
 
 
425
        cookie = xcb_get_property(wm->conn,
 
426
                                  0, /* delete */
 
427
                                  wm->selection_window,
 
428
                                  wm->atom.wl_selection,
 
429
                                  XCB_GET_PROPERTY_TYPE_ANY,
 
430
                                  0, /* offset */
 
431
                                  0x1fffffff /* length */);
 
432
 
 
433
        reply = xcb_get_property_reply(wm->conn, cookie, NULL);
 
434
 
 
435
        dump_property(wm, wm->atom.wl_selection, reply);
 
436
 
 
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,
 
441
                                             wm->data_source_fd,
 
442
                                             WL_EVENT_WRITABLE,
 
443
                                             weston_wm_write_property,
 
444
                                             wm);
 
445
                wm->property_reply = reply;
 
446
        } else {
 
447
                fprintf(stderr, "transfer complete\n");
 
448
                close(wm->data_source_fd);
 
449
                free(reply);
 
450
        }
 
451
}
 
452
 
 
453
static void
 
454
weston_wm_set_selection(struct wl_selection_listener *listener,
 
455
                        struct wl_input_device *device)
 
456
{
 
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;
 
462
 
 
463
        if (source->offer_interface == &data_offer_interface)
 
464
                return;
 
465
 
 
466
        fprintf(stderr, "set selection\n");
 
467
 
 
468
        p = source->mime_types.data;
 
469
        end = (const char **)
 
470
                ((char *) source->mime_types.data + source->mime_types.size);
 
471
        while (p < end) {
 
472
                fprintf(stderr, "  %s\n", *p);
 
473
                if (strcmp(*p, "text/plain") == 0 ||
 
474
                    strcmp(*p, "text/plain;charset=utf-8") == 0)
 
475
                        has_text_plain = 1;
 
476
                p++;
 
477
        }
 
478
 
 
479
        if (has_text_plain) {
 
480
                xcb_set_selection_owner(wm->conn,
 
481
                                        wm->selection_window,
 
482
                                        wm->atom.clipboard,
 
483
                                        XCB_TIME_CURRENT_TIME);
 
484
        } else {
 
485
                xcb_set_selection_owner(wm->conn,
 
486
                                        XCB_ATOM_NONE,
 
487
                                        wm->atom.clipboard,
 
488
                                        XCB_TIME_CURRENT_TIME);
 
489
        }
 
490
}
 
491
 
 
492
static void
 
493
weston_wm_handle_configure_request(struct weston_wm *wm, xcb_generic_event_t *event)
 
494
{
 
495
        xcb_configure_request_event_t *configure_request = 
 
496
                (xcb_configure_request_event_t *) event;
 
497
        uint32_t values[16];
 
498
        int i = 0;
 
499
 
 
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);
 
504
 
 
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;
 
519
 
 
520
        xcb_configure_window(wm->conn,
 
521
                             configure_request->window,
 
522
                             configure_request->value_mask, values);
 
523
}
 
524
 
 
525
static void
 
526
weston_wm_handle_configure_notify(struct weston_wm *wm, xcb_generic_event_t *event)
 
527
{
 
528
        xcb_configure_notify_event_t *configure_notify = 
 
529
                (xcb_configure_notify_event_t *) event;
 
530
 
 
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);
 
535
}
 
536
 
 
537
static void
 
538
weston_wm_activate(struct weston_wm *wm,
 
539
                 struct weston_wm_window *window, xcb_timestamp_t time)
 
540
{
 
541
        xcb_client_message_event_t client_message;
 
542
 
 
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;
 
549
 
 
550
        xcb_send_event(wm->conn, 0, window->id, 
 
551
                       XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
 
552
                       (char *) &client_message);
 
553
 
 
554
        xcb_set_input_focus (wm->conn,
 
555
                             XCB_INPUT_FOCUS_POINTER_ROOT, window->id, time);
 
556
}
 
557
 
 
558
WL_EXPORT void
 
559
weston_xserver_surface_activate(struct weston_surface *surface)
 
560
{
 
561
        struct weston_wm_window *window = get_wm_window(surface);
 
562
        struct weston_xserver *wxs = surface->compositor->wxs;
 
563
 
 
564
        if (window)
 
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,
 
569
                                     XCB_NONE,
 
570
                                     XCB_TIME_CURRENT_TIME);
 
571
}
 
572
 
 
573
static void
 
574
weston_wm_handle_map_request(struct weston_wm *wm, xcb_generic_event_t *event)
 
575
{
 
576
        xcb_map_request_event_t *map_request =
 
577
                (xcb_map_request_event_t *) event;
 
578
 
 
579
        fprintf(stderr, "XCB_MAP_REQUEST (window %d)\n", map_request->window);
 
580
 
 
581
        xcb_map_window(wm->conn, map_request->window);
 
582
}
 
583
 
 
584
/* We reuse some predefined, but otherwise useles atoms */
 
585
#define TYPE_WM_PROTOCOLS XCB_ATOM_CUT_BUFFER0
 
586
 
 
587
static void
 
588
weston_wm_handle_map_notify(struct weston_wm *wm, xcb_generic_event_t *event)
 
589
{
 
590
#define F(field) offsetof(struct weston_wm_window, field)
 
591
 
 
592
        const struct {
 
593
                xcb_atom_t atom;
 
594
                xcb_atom_t type;
 
595
                int offset;
 
596
        } props[] = {
 
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) },
 
602
        };
 
603
#undef F
 
604
 
 
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;
 
609
        void *p;
 
610
        uint32_t *xid;
 
611
        xcb_atom_t *atom;
 
612
        int i;
 
613
 
 
614
        fprintf(stderr, "XCB_MAP_NOTIFY (window %d)\n", map_notify->window);
 
615
 
 
616
        dump_window_properties(wm, map_notify->window);
 
617
 
 
618
        window = hash_table_lookup(wm->window_hash, map_notify->window);
 
619
 
 
620
        for (i = 0; i < ARRAY_LENGTH(props); i++)
 
621
                cookie[i] = xcb_get_property(wm->conn,
 
622
                                             0, /* delete */
 
623
                                             window->id,
 
624
                                             props[i].atom,
 
625
                                             XCB_ATOM_ANY, 0, 2048);
 
626
 
 
627
        for (i = 0; i < ARRAY_LENGTH(props); i++)  {
 
628
                reply = xcb_get_property_reply(wm->conn, cookie[i], NULL);
 
629
                if (!reply)
 
630
                        /* Bad window, typically */
 
631
                        continue;
 
632
                if (reply->type == XCB_ATOM_NONE) {
 
633
                        /* No such property */
 
634
                        free(reply);
 
635
                        continue;
 
636
                }
 
637
 
 
638
                p = ((char *) window + props[i].offset);
 
639
 
 
640
                switch (props[i].type) {
 
641
                case XCB_ATOM_STRING:
 
642
                        /* FIXME: We're using this for both string and
 
643
                           utf8_string */
 
644
                        *(char **) p =
 
645
                                strndup(xcb_get_property_value(reply),
 
646
                                        xcb_get_property_value_length(reply));
 
647
                        break;
 
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);
 
652
                        break;
 
653
                case XCB_ATOM_ATOM:
 
654
                        atom = xcb_get_property_value(reply);
 
655
                        *(xcb_atom_t *) p = *atom;
 
656
                        break;
 
657
                case TYPE_WM_PROTOCOLS:
 
658
                        break;
 
659
                default:
 
660
                        break;
 
661
                }
 
662
                free(reply);
 
663
        }
 
664
 
 
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);
 
669
}
 
670
 
 
671
static const int incr_chunk_size = 64 * 1024;
 
672
 
 
673
static void
 
674
weston_wm_send_selection_notify(struct weston_wm *wm, xcb_atom_t property)
 
675
{
 
676
        xcb_selection_notify_event_t selection_notify;
 
677
 
 
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;
 
686
 
 
687
        xcb_send_event(wm->conn, 0, /* propagate */
 
688
                       wm->selection_request.requestor,
 
689
                       XCB_EVENT_MASK_NO_EVENT, (char *) &selection_notify);
 
690
}
 
691
 
 
692
static void
 
693
weston_wm_send_targets(struct weston_wm *wm)
 
694
{
 
695
        xcb_atom_t targets[] = {
 
696
                wm->atom.timestamp,
 
697
                wm->atom.targets,
 
698
                wm->atom.utf8_string,
 
699
                /* wm->atom.compound_text, */
 
700
                wm->atom.text,
 
701
                /* wm->atom.string */
 
702
        };
 
703
 
 
704
        xcb_change_property(wm->conn,
 
705
                            XCB_PROP_MODE_REPLACE,
 
706
                            wm->selection_request.requestor,
 
707
                            wm->selection_request.property,
 
708
                            XCB_ATOM_ATOM,
 
709
                            32, /* format */
 
710
                            ARRAY_LENGTH(targets), targets);
 
711
 
 
712
        weston_wm_send_selection_notify(wm, wm->selection_request.property);
 
713
}
 
714
 
 
715
static void
 
716
weston_wm_send_timestamp(struct weston_wm *wm)
 
717
{
 
718
        xcb_change_property(wm->conn,
 
719
                            XCB_PROP_MODE_REPLACE,
 
720
                            wm->selection_request.requestor,
 
721
                            wm->selection_request.property,
 
722
                            XCB_ATOM_INTEGER,
 
723
                            32, /* format */
 
724
                            1, &wm->selection_timestamp);
 
725
 
 
726
        weston_wm_send_selection_notify(wm, wm->selection_request.property);
 
727
}
 
728
 
 
729
static int
 
730
weston_wm_flush_source_data(struct weston_wm *wm)
 
731
{
 
732
        int length;
 
733
 
 
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,
 
739
                            8, /* format */
 
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;
 
745
 
 
746
        return length;
 
747
}
 
748
 
 
749
static int
 
750
weston_wm_read_data_source(int fd, uint32_t mask, void *data)
 
751
{
 
752
        struct weston_wm *wm = data;
 
753
        int len, current, available;
 
754
        void *p;
 
755
 
 
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);
 
759
        else
 
760
                p = (char *) wm->source_data.data + wm->source_data.size;
 
761
        available = wm->source_data.alloc - current;
 
762
 
 
763
        len = read(fd, p, available);
 
764
        if (len == -1) {
 
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);
 
768
                close(fd);
 
769
                wl_array_release(&wm->source_data);
 
770
        }
 
771
 
 
772
        fprintf(stderr, "read %d (available %d, mask 0x%x) bytes: \"%.*s\"\n",
 
773
                len, available, mask, len, (char *) p);
 
774
 
 
775
        wm->source_data.size = current + len;
 
776
        if (wm->source_data.size >= incr_chunk_size) {
 
777
                if (!wm->incr) {
 
778
                        fprintf(stderr, "got %d bytes, starting incr\n",
 
779
                                wm->source_data.size);
 
780
                        wm->incr = 1;
 
781
                        xcb_change_property(wm->conn,
 
782
                                            XCB_PROP_MODE_REPLACE,
 
783
                                            wm->selection_request.requestor,
 
784
                                            wm->selection_request.property,
 
785
                                            wm->atom.incr,
 
786
                                            32, /* format */
 
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);
 
795
 
 
796
                        wm->flush_property_on_delete = 1;
 
797
                        wl_event_source_remove(wm->property_source);
 
798
                } else {
 
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);
 
803
                }
 
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);
 
809
                xcb_flush(wm->conn);
 
810
                wl_event_source_remove(wm->property_source);
 
811
                close(fd);
 
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");
 
816
 
 
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);
 
821
                } else {
 
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);
 
826
                }
 
827
                xcb_flush(wm->conn);
 
828
                wl_event_source_remove(wm->property_source);
 
829
                wm->data_source_fd = -1;
 
830
                close(fd);
 
831
        } else {
 
832
                fprintf(stderr, "nothing happened, buffered the bytes\n");
 
833
        }
 
834
 
 
835
        return 1;
 
836
}
 
837
 
 
838
static void
 
839
weston_wm_send_data(struct weston_wm *wm, xcb_atom_t target, const char *mime_type)
 
840
{
 
841
        struct wl_input_device *device = wm->server->compositor->input_device;
 
842
        int p[2];
 
843
 
 
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);
 
847
                return;
 
848
        }
 
849
 
 
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,
 
854
                                                   wm->data_source_fd,
 
855
                                                   WL_EVENT_READABLE,
 
856
                                                   weston_wm_read_data_source,
 
857
                                                   wm);
 
858
 
 
859
        wl_resource_post_event(&device->selection_data_source->resource,
 
860
                               WL_DATA_SOURCE_SEND, mime_type, p[1]);
 
861
        close(p[1]);
 
862
}
 
863
 
 
864
static void
 
865
weston_wm_send_incr_chunk(struct weston_wm *wm)
 
866
{
 
867
        fprintf(stderr, "property deleted\n");
 
868
        int length;
 
869
 
 
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);
 
876
 
 
877
                if (wm->data_source_fd >= 0) {
 
878
                        wm->property_source =
 
879
                                wl_event_loop_add_fd(wm->server->loop,
 
880
                                                     wm->data_source_fd,
 
881
                                                     WL_EVENT_READABLE,
 
882
                                                     weston_wm_read_data_source,
 
883
                                                     wm);
 
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
 
888
                         * the transfer. */
 
889
                        wm->flush_property_on_delete = 1;
 
890
                        wl_array_release(&wm->source_data);
 
891
                } else {
 
892
                        wm->selection_request.requestor = XCB_NONE;
 
893
                }
 
894
        }
 
895
}
 
896
 
 
897
static void
 
898
weston_wm_handle_selection_request(struct weston_wm *wm,
 
899
                                 xcb_generic_event_t *event)
 
900
{
 
901
        xcb_selection_request_event_t *selection_request =
 
902
                (xcb_selection_request_event_t *) event;
 
903
 
 
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));
 
910
 
 
911
        wm->selection_request = *selection_request;
 
912
        wm->incr = 0;
 
913
        wm->flush_property_on_delete = 0;
 
914
 
 
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");
 
923
        } else {
 
924
                fprintf(stderr, "can only handle UTF8_STRING targets...\n");
 
925
                weston_wm_send_selection_notify(wm, XCB_ATOM_NONE);
 
926
        }
 
927
}
 
928
 
 
929
static void
 
930
weston_wm_handle_property_notify(struct weston_wm *wm, xcb_generic_event_t *event)
 
931
{
 
932
        xcb_property_notify_event_t *property_notify =
 
933
                (xcb_property_notify_event_t *) event;
 
934
 
 
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 &&
 
938
                    wm->incr)
 
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 &&
 
943
                    wm->incr)
 
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");
 
961
        } else {
 
962
                fprintf(stderr, "XCB_PROPERTY_NOTIFY: "
 
963
                        "unhandled property change: %s\n",
 
964
                        get_atom_name(wm->conn, property_notify->atom));
 
965
        }
 
966
}
 
967
 
 
968
static void
 
969
weston_wm_handle_create_notify(struct weston_wm *wm, xcb_generic_event_t *event)
 
970
{
 
971
        xcb_create_notify_event_t *create_notify =
 
972
                (xcb_create_notify_event_t *) event;
 
973
        struct weston_wm_window *window;
 
974
        uint32_t values[1];
 
975
 
 
976
        fprintf(stderr, "XCB_CREATE_NOTIFY (window %d)\n",
 
977
                create_notify->window);
 
978
 
 
979
        window = malloc(sizeof *window);
 
980
        if (window == NULL) {
 
981
                fprintf(stderr, "failed to allocate window\n");
 
982
                return;
 
983
        }
 
984
 
 
985
        values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE;
 
986
        xcb_change_window_attributes(wm->conn, create_notify->window,
 
987
                                     XCB_CW_EVENT_MASK, values);
 
988
 
 
989
        memset(window, 0, sizeof *window);
 
990
        window->id = create_notify->window;
 
991
        hash_table_insert(wm->window_hash, window->id, window);
 
992
}
 
993
 
 
994
static void
 
995
weston_wm_handle_destroy_notify(struct weston_wm *wm, xcb_generic_event_t *event)
 
996
{
 
997
        xcb_destroy_notify_event_t *destroy_notify =
 
998
                (xcb_destroy_notify_event_t *) event;
 
999
        struct weston_wm_window *window;
 
1000
 
 
1001
        fprintf(stderr, "XCB_DESTROY_NOTIFY, win %d\n",
 
1002
                destroy_notify->window);
 
1003
 
 
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);
 
1008
                return;
 
1009
        }
 
1010
 
 
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);
 
1015
        free(window);
 
1016
}
 
1017
 
 
1018
static void
 
1019
weston_wm_handle_selection_notify(struct weston_wm *wm,
 
1020
                                xcb_generic_event_t *event)
 
1021
{
 
1022
        xcb_selection_notify_event_t *selection_notify =
 
1023
                (xcb_selection_notify_event_t *) event;
 
1024
 
 
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);
 
1029
        } else {
 
1030
                weston_wm_get_selection_data(wm);
 
1031
        }
 
1032
}
 
1033
 
 
1034
static void
 
1035
weston_wm_handle_xfixes_selection_notify(struct weston_wm *wm,
 
1036
                                       xcb_generic_event_t *event)
 
1037
{
 
1038
        xcb_xfixes_selection_notify_event_t *xfixes_selection_notify =
 
1039
                (xcb_xfixes_selection_notify_event_t *) event;
 
1040
 
 
1041
        printf("xfixes selection notify event: owner %d\n",
 
1042
               xfixes_selection_notify->owner);
 
1043
 
 
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");
 
1050
                return;
 
1051
        }
 
1052
 
 
1053
        wm->incr = 0;
 
1054
        xcb_convert_selection(wm->conn, wm->selection_window,
 
1055
                              wm->atom.clipboard,
 
1056
                              wm->atom.targets,
 
1057
                              wm->atom.wl_selection,
 
1058
                              xfixes_selection_notify->timestamp);
 
1059
 
 
1060
        xcb_flush(wm->conn);
 
1061
}
 
1062
 
 
1063
static void
 
1064
weston_wm_handle_client_message(struct weston_wm *wm,
 
1065
                                xcb_generic_event_t *event)
 
1066
{
 
1067
        xcb_client_message_event_t *client_message =
 
1068
                (xcb_client_message_event_t *) event;
 
1069
 
 
1070
        fprintf(stderr, "got client message, type: %s\n",
 
1071
                get_atom_name(wm->conn, client_message->type));
 
1072
}
 
1073
 
 
1074
static int
 
1075
weston_wm_handle_event(int fd, uint32_t mask, void *data)
 
1076
{
 
1077
        struct weston_wm *wm = data;
 
1078
        xcb_generic_event_t *event;
 
1079
        int count = 0;
 
1080
 
 
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);
 
1085
                        break;
 
1086
                case XCB_MAP_REQUEST:
 
1087
                        weston_wm_handle_map_request(wm, event);
 
1088
                        break;
 
1089
                case XCB_MAP_NOTIFY:
 
1090
                        weston_wm_handle_map_notify(wm, event);
 
1091
                        break;
 
1092
                case XCB_UNMAP_NOTIFY:
 
1093
                        fprintf(stderr, "XCB_UNMAP_NOTIFY\n");
 
1094
                        break;
 
1095
                case XCB_CONFIGURE_REQUEST:
 
1096
                        weston_wm_handle_configure_request(wm, event);
 
1097
                        break;
 
1098
                case XCB_CONFIGURE_NOTIFY:
 
1099
                        weston_wm_handle_configure_notify(wm, event);
 
1100
                        break;
 
1101
                case XCB_DESTROY_NOTIFY:
 
1102
                        weston_wm_handle_destroy_notify(wm, event);
 
1103
                        break;
 
1104
                case XCB_MAPPING_NOTIFY:
 
1105
                        fprintf(stderr, "XCB_MAPPING_NOTIFY\n");
 
1106
                        break;
 
1107
                case XCB_PROPERTY_NOTIFY:
 
1108
                        weston_wm_handle_property_notify(wm, event);
 
1109
                        break;
 
1110
                case XCB_SELECTION_NOTIFY:
 
1111
                        weston_wm_handle_selection_notify(wm, event);
 
1112
                        break;
 
1113
                case XCB_SELECTION_REQUEST:
 
1114
                        weston_wm_handle_selection_request(wm, event);
 
1115
                        break;
 
1116
                case XCB_CLIENT_MESSAGE:
 
1117
                        weston_wm_handle_client_message(wm, event);
 
1118
                        break;
 
1119
                }
 
1120
 
 
1121
                switch (event->response_type - wm->xfixes->first_event) {
 
1122
                case XCB_XFIXES_SELECTION_NOTIFY:
 
1123
                        weston_wm_handle_xfixes_selection_notify(wm, event);
 
1124
                        break;
 
1125
                }
 
1126
 
 
1127
 
 
1128
                free(event);
 
1129
                count++;
 
1130
        }
 
1131
 
 
1132
        xcb_flush(wm->conn);
 
1133
 
 
1134
        return count;
 
1135
}
 
1136
 
 
1137
static void
 
1138
wxs_wm_get_resources(struct weston_wm *wm)
 
1139
{
 
1140
 
 
1141
#define F(field) offsetof(struct weston_wm, field)
 
1142
 
 
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) },
 
1171
        };
 
1172
 
 
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;
 
1177
        int i;
 
1178
 
 
1179
        xcb_prefetch_extension_data (wm->conn, &xcb_xfixes_id);
 
1180
 
 
1181
        for (i = 0; i < ARRAY_LENGTH(atoms); i++)
 
1182
                cookies[i] = xcb_intern_atom (wm->conn, 0,
 
1183
                                              strlen(atoms[i].name),
 
1184
                                              atoms[i].name);
 
1185
 
 
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;
 
1189
                free(reply);
 
1190
        }
 
1191
 
 
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");
 
1195
 
 
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);
 
1201
 
 
1202
        printf("xfixes version: %d.%d\n",
 
1203
               xfixes_reply->major_version, xfixes_reply->minor_version);
 
1204
 
 
1205
        free(xfixes_reply);
 
1206
}
 
1207
 
 
1208
static void
 
1209
weston_wm_create_wm_window(struct weston_wm *wm)
 
1210
{
 
1211
        static const char name[] = "Weston WM";
 
1212
 
 
1213
        wm->wm_window = xcb_generate_id(wm->conn);
 
1214
        xcb_create_window(wm->conn,
 
1215
                          XCB_COPY_FROM_PARENT,
 
1216
                          wm->wm_window,
 
1217
                          wm->screen->root,
 
1218
                          0, 0,
 
1219
                          10, 10,
 
1220
                          0,
 
1221
                          XCB_WINDOW_CLASS_INPUT_OUTPUT,
 
1222
                          wm->screen->root_visual,
 
1223
                          0, NULL);
 
1224
 
 
1225
        xcb_change_property(wm->conn,
 
1226
                            XCB_PROP_MODE_REPLACE,
 
1227
                            wm->wm_window,
 
1228
                            wm->atom.net_supporting_wm_check,
 
1229
                            XCB_ATOM_WINDOW,
 
1230
                            32, /* format */
 
1231
                            1, &wm->wm_window);
 
1232
 
 
1233
        xcb_change_property(wm->conn,
 
1234
                            XCB_PROP_MODE_REPLACE,
 
1235
                            wm->wm_window,
 
1236
                            wm->atom.net_wm_name,
 
1237
                            wm->atom.utf8_string,
 
1238
                            8, /* format */
 
1239
                            strlen(name), name);
 
1240
 
 
1241
        xcb_change_property(wm->conn,
 
1242
                            XCB_PROP_MODE_REPLACE,
 
1243
                            wm->screen->root,
 
1244
                            wm->atom.net_supporting_wm_check,
 
1245
                            XCB_ATOM_WINDOW,
 
1246
                            32, /* format */
 
1247
                            1, &wm->wm_window);
 
1248
 
 
1249
}
 
1250
 
 
1251
static struct weston_wm *
 
1252
weston_wm_create(struct weston_xserver *wxs)
 
1253
{
 
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;
 
1259
        int sv[2];
 
1260
        xcb_atom_t supported[1];
 
1261
 
 
1262
        wm = malloc(sizeof *wm);
 
1263
        if (wm == NULL)
 
1264
                return NULL;
 
1265
 
 
1266
        wm->server = wxs;
 
1267
        wm->window_hash = hash_table_create();
 
1268
        if (wm->window_hash == NULL) {
 
1269
                free(wm);
 
1270
                return NULL;
 
1271
        }
 
1272
 
 
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);
 
1276
                free(wm);
 
1277
                return NULL;
 
1278
        }
 
1279
 
 
1280
        wl_resource_post_event(wxs->resource, XSERVER_CLIENT, sv[1]);
 
1281
        wl_client_flush(wxs->resource->client);
 
1282
        close(sv[1]);
 
1283
        
 
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");
 
1288
                close(sv[0]);
 
1289
                hash_table_destroy(wm->window_hash);
 
1290
                free(wm);
 
1291
                return NULL;
 
1292
        }
 
1293
 
 
1294
        s = xcb_setup_roots_iterator(xcb_get_setup(wm->conn));
 
1295
        wm->screen = s.data;
 
1296
 
 
1297
        loop = wl_display_get_event_loop(wxs->wl_display);
 
1298
        wm->source =
 
1299
                wl_event_loop_add_fd(loop, sv[0],
 
1300
                                     WL_EVENT_READABLE,
 
1301
                                     weston_wm_handle_event, wm);
 
1302
        wl_event_source_check(wm->source);
 
1303
 
 
1304
        wxs_wm_get_resources(wm);
 
1305
 
 
1306
        values[0] =
 
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);
 
1314
 
 
1315
        weston_wm_create_wm_window(wm);
 
1316
 
 
1317
        supported[0] = wm->atom.net_wm_moveresize;
 
1318
        xcb_change_property(wm->conn,
 
1319
                            XCB_PROP_MODE_REPLACE,
 
1320
                            wm->screen->root,
 
1321
                            wm->atom.net_supported,
 
1322
                            XCB_ATOM_ATOM,
 
1323
                            32, /* format */
 
1324
                            ARRAY_LENGTH(supported), supported);
 
1325
 
 
1326
        wm->selection_request.requestor = XCB_NONE;
 
1327
 
 
1328
        wm->selection_window = xcb_generate_id(wm->conn);
 
1329
        xcb_create_window(wm->conn,
 
1330
                          XCB_COPY_FROM_PARENT,
 
1331
                          wm->selection_window,
 
1332
                          wm->screen->root,
 
1333
                          0, 0,
 
1334
                          10, 10,
 
1335
                          0,
 
1336
                          XCB_WINDOW_CLASS_INPUT_OUTPUT,
 
1337
                          wm->screen->root_visual,
 
1338
                          XCB_CW_EVENT_MASK, values);
 
1339
 
 
1340
        mask =
 
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;
 
1344
 
 
1345
        xcb_xfixes_select_selection_input(wm->conn, wm->selection_window,
 
1346
                                          wm->atom.clipboard, mask);
 
1347
 
 
1348
        xcb_flush(wm->conn);
 
1349
 
 
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);
 
1354
 
 
1355
        fprintf(stderr, "created wm\n");
 
1356
 
 
1357
        return wm;
 
1358
}
 
1359
 
 
1360
static void
 
1361
weston_wm_destroy(struct weston_wm *wm)
 
1362
{
 
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);
 
1368
        free(wm);
 
1369
}
 
1370
 
 
1371
static int
 
1372
weston_xserver_handle_event(int listen_fd, uint32_t mask, void *data)
 
1373
{
 
1374
        struct weston_xserver *mxs = data;
 
1375
        char display[8], s[8];
 
1376
        int sv[2], client_fd;
 
1377
 
 
1378
        if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
 
1379
                fprintf(stderr, "socketpair failed\n");
 
1380
                return 1;
 
1381
        }
 
1382
 
 
1383
        mxs->process.pid = fork();
 
1384
        switch (mxs->process.pid) {
 
1385
        case 0:
 
1386
                /* SOCK_CLOEXEC closes both ends, so we need to unset
 
1387
                 * the flag on the client fd. */
 
1388
                client_fd = dup(sv[1]);
 
1389
                if (client_fd < 0)
 
1390
                        return 1;
 
1391
 
 
1392
                snprintf(s, sizeof s, "%d", client_fd);
 
1393
                setenv("WAYLAND_SOCKET", s, 1);
 
1394
 
 
1395
                snprintf(display, sizeof display, ":%d", mxs->display);
 
1396
 
 
1397
                if (execl(XSERVER_PATH,
 
1398
                          XSERVER_PATH,
 
1399
                          display,
 
1400
                          "-wayland",
 
1401
                          "-rootless",
 
1402
                          "-retro",
 
1403
                          "-nolisten", "all",
 
1404
                          "-terminate",
 
1405
                          NULL) < 0)
 
1406
                        fprintf(stderr, "exec failed: %m\n");
 
1407
                exit(-1);
 
1408
 
 
1409
        default:
 
1410
                fprintf(stderr, "forked X server, pid %d\n", mxs->process.pid);
 
1411
 
 
1412
                close(sv[1]);
 
1413
                mxs->client = wl_client_create(mxs->wl_display, sv[0]);
 
1414
 
 
1415
                weston_watch_process(&mxs->process);
 
1416
 
 
1417
                wl_event_source_remove(mxs->abstract_source);
 
1418
                wl_event_source_remove(mxs->unix_source);
 
1419
                break;
 
1420
 
 
1421
        case -1:
 
1422
                fprintf(stderr, "failed to fork\n");
 
1423
                break;
 
1424
        }
 
1425
 
 
1426
        return 1;
 
1427
}
 
1428
 
 
1429
static void
 
1430
weston_xserver_shutdown(struct weston_xserver *wxs)
 
1431
{
 
1432
        char path[256];
 
1433
 
 
1434
        snprintf(path, sizeof path, "/tmp/.X%d-lock", wxs->display);
 
1435
        unlink(path);
 
1436
        snprintf(path, sizeof path, "/tmp/.X11-unix/X%d", wxs->display);
 
1437
        unlink(path);
 
1438
        if (wxs->process.pid == 0) {
 
1439
                wl_event_source_remove(wxs->abstract_source);
 
1440
                wl_event_source_remove(wxs->unix_source);
 
1441
        }
 
1442
        close(wxs->abstract_fd);
 
1443
        close(wxs->unix_fd);
 
1444
        if (wxs->wm)
 
1445
                weston_wm_destroy(wxs->wm);
 
1446
        wxs->loop = NULL;
 
1447
}
 
1448
 
 
1449
static void
 
1450
weston_xserver_cleanup(struct weston_process *process, int status)
 
1451
{
 
1452
        struct weston_xserver *mxs =
 
1453
                container_of(process, struct weston_xserver, process);
 
1454
 
 
1455
        mxs->process.pid = 0;
 
1456
        mxs->client = NULL;
 
1457
        mxs->resource = NULL;
 
1458
 
 
1459
        mxs->abstract_source =
 
1460
                wl_event_loop_add_fd(mxs->loop, mxs->abstract_fd,
 
1461
                                     WL_EVENT_READABLE,
 
1462
                                     weston_xserver_handle_event, mxs);
 
1463
 
 
1464
        mxs->unix_source =
 
1465
                wl_event_loop_add_fd(mxs->loop, mxs->unix_fd,
 
1466
                                     WL_EVENT_READABLE,
 
1467
                                     weston_xserver_handle_event, mxs);
 
1468
 
 
1469
        if (mxs->wm) {
 
1470
                fprintf(stderr, "xserver exited, code %d\n", status);
 
1471
                weston_wm_destroy(mxs->wm);
 
1472
                mxs->wm = NULL;
 
1473
        } else {
 
1474
                /* If the X server crashes before it binds to the
 
1475
                 * xserver interface, shut down and don't try
 
1476
                 * again. */
 
1477
                fprintf(stderr, "xserver crashing too fast: %d\n", status);
 
1478
                weston_xserver_shutdown(mxs);
 
1479
        }
 
1480
}
 
1481
 
 
1482
static void
 
1483
surface_destroy(struct wl_listener *listener,
 
1484
                struct wl_resource *resource, uint32_t time)
 
1485
{
 
1486
        struct weston_wm_window *window =
 
1487
                container_of(listener,
 
1488
                             struct weston_wm_window, surface_destroy_listener);
 
1489
 
 
1490
        fprintf(stderr, "surface for xid %d destroyed\n", window->id);
 
1491
}
 
1492
 
 
1493
static struct weston_wm_window *
 
1494
get_wm_window(struct weston_surface *surface)
 
1495
{
 
1496
        struct wl_resource *resource = &surface->surface.resource;
 
1497
        struct wl_listener *listener;
 
1498
 
 
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);
 
1504
        }
 
1505
 
 
1506
        return NULL;
 
1507
}
 
1508
 
 
1509
static void
 
1510
xserver_set_window_id(struct wl_client *client, struct wl_resource *resource,
 
1511
                      struct wl_resource *surface_resource, uint32_t id)
 
1512
{
 
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;
 
1517
 
 
1518
        if (client != wxs->client)
 
1519
                return;
 
1520
 
 
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);
 
1524
                return;
 
1525
        }
 
1526
 
 
1527
        fprintf(stderr, "set_window_id %d for surface %p\n", id, surface);
 
1528
 
 
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);
 
1533
}
 
1534
 
 
1535
static const struct xserver_interface xserver_implementation = {
 
1536
        xserver_set_window_id
 
1537
};
 
1538
 
 
1539
static void
 
1540
bind_xserver(struct wl_client *client,
 
1541
             void *data, uint32_t version, uint32_t id)
 
1542
{
 
1543
        struct weston_xserver *wxs = data;
 
1544
 
 
1545
        /* If it's a different client than the xserver we launched,
 
1546
         * don't start the wm. */
 
1547
        if (client != wxs->client)
 
1548
                return;
 
1549
 
 
1550
        wxs->resource = 
 
1551
                wl_client_add_object(client, &xserver_interface,
 
1552
                                     &xserver_implementation, id, wxs);
 
1553
 
 
1554
        wxs->wm = weston_wm_create(wxs);
 
1555
        if (wxs->wm == NULL) {
 
1556
                fprintf(stderr, "failed to create wm\n");
 
1557
        }
 
1558
 
 
1559
        wl_resource_post_event(wxs->resource,
 
1560
                               XSERVER_LISTEN_SOCKET, wxs->abstract_fd);
 
1561
 
 
1562
        wl_resource_post_event(wxs->resource,
 
1563
                               XSERVER_LISTEN_SOCKET, wxs->unix_fd);
 
1564
}
 
1565
 
 
1566
static int
 
1567
bind_to_abstract_socket(int display)
 
1568
{
 
1569
        struct sockaddr_un addr;
 
1570
        socklen_t size, name_size;
 
1571
        int fd;
 
1572
 
 
1573
        fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
 
1574
        if (fd < 0)
 
1575
                return -1;
 
1576
 
 
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));
 
1584
                close(fd);
 
1585
                return -1;
 
1586
        }
 
1587
 
 
1588
        if (listen(fd, 1) < 0) {
 
1589
                close(fd);
 
1590
                return -1;
 
1591
        }
 
1592
 
 
1593
        return fd;
 
1594
}
 
1595
 
 
1596
static int
 
1597
bind_to_unix_socket(int display)
 
1598
{
 
1599
        struct sockaddr_un addr;
 
1600
        socklen_t size, name_size;
 
1601
        int fd;
 
1602
 
 
1603
        fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
 
1604
        if (fd < 0)
 
1605
                return -1;
 
1606
 
 
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));
 
1615
                close(fd);
 
1616
                return -1;
 
1617
        }
 
1618
 
 
1619
        if (listen(fd, 1) < 0) {
 
1620
                unlink(addr.sun_path);
 
1621
                close(fd);
 
1622
                return -1;
 
1623
        }
 
1624
 
 
1625
        return fd;
 
1626
}
 
1627
 
 
1628
static int
 
1629
create_lockfile(int display, char *lockfile, size_t lsize)
 
1630
{
 
1631
        char pid[16], *end;
 
1632
        int fd, size;
 
1633
        pid_t other;
 
1634
 
 
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));
 
1642
                        errno = EEXIST;
 
1643
                        return -1;
 
1644
                }
 
1645
 
 
1646
                other = strtol(pid, &end, 0);
 
1647
                if (end != pid + 10) {
 
1648
                        fprintf(stderr, "can't parse lock file %s\n",
 
1649
                                lockfile);
 
1650
                        errno = EEXIST;
 
1651
                        return -1;
 
1652
                }
 
1653
 
 
1654
                if (kill(other, 0) < 0 && errno == ESRCH) {
 
1655
                        /* stale lock file; unlink and try again */
 
1656
                        fprintf(stderr,
 
1657
                                "unlinking stale lock file %s\n", lockfile);
 
1658
                        unlink(lockfile);
 
1659
                        errno = EAGAIN;
 
1660
                        return -1;
 
1661
                }
 
1662
 
 
1663
                errno = EEXIST;
 
1664
                return -1;
 
1665
        } else if (fd < 0) {
 
1666
                fprintf(stderr, "failed to create lock file %s: %s\n",
 
1667
                        lockfile, strerror(errno));
 
1668
                return -1;
 
1669
        }
 
1670
 
 
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) {
 
1675
                unlink(lockfile);
 
1676
                close(fd);
 
1677
                return -1;
 
1678
        }
 
1679
 
 
1680
        close(fd);
 
1681
 
 
1682
        return 0;
 
1683
}
 
1684
 
 
1685
int
 
1686
weston_xserver_init(struct weston_compositor *compositor)
 
1687
{
 
1688
        struct wl_display *display = compositor->wl_display;
 
1689
        struct weston_xserver *mxs;
 
1690
        char lockfile[256], display_name[8];
 
1691
 
 
1692
        mxs = malloc(sizeof *mxs);
 
1693
        memset(mxs, 0, sizeof *mxs);
 
1694
 
 
1695
        mxs->process.cleanup = weston_xserver_cleanup;
 
1696
        mxs->wl_display = display;
 
1697
        mxs->compositor = compositor;
 
1698
 
 
1699
        mxs->display = 0;
 
1700
 
 
1701
 retry:
 
1702
        if (create_lockfile(mxs->display, lockfile, sizeof lockfile) < 0) {
 
1703
                if (errno == EAGAIN) {
 
1704
                        goto retry;
 
1705
                } else if (errno == EEXIST) {
 
1706
                        mxs->display++;
 
1707
                        goto retry;
 
1708
                } else {
 
1709
                        free(mxs);
 
1710
                        return -1;
 
1711
                }
 
1712
        }                               
 
1713
 
 
1714
        mxs->abstract_fd = bind_to_abstract_socket(mxs->display);
 
1715
        if (mxs->abstract_fd < 0 && errno == EADDRINUSE) {
 
1716
                mxs->display++;
 
1717
                unlink(lockfile);
 
1718
                goto retry;
 
1719
        }
 
1720
 
 
1721
        mxs->unix_fd = bind_to_unix_socket(mxs->display);
 
1722
        if (mxs->unix_fd < 0) {
 
1723
                unlink(lockfile);
 
1724
                close(mxs->abstract_fd);
 
1725
                free(mxs);
 
1726
                return -1;
 
1727
        }
 
1728
 
 
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);
 
1732
 
 
1733
        mxs->loop = wl_display_get_event_loop(display);
 
1734
        mxs->abstract_source =
 
1735
                wl_event_loop_add_fd(mxs->loop, mxs->abstract_fd,
 
1736
                                     WL_EVENT_READABLE,
 
1737
                                     weston_xserver_handle_event, mxs);
 
1738
        mxs->unix_source =
 
1739
                wl_event_loop_add_fd(mxs->loop, mxs->unix_fd,
 
1740
                                     WL_EVENT_READABLE,
 
1741
                                     weston_xserver_handle_event, mxs);
 
1742
 
 
1743
        wl_display_add_global(display, &xserver_interface, mxs, bind_xserver);
 
1744
 
 
1745
        compositor->wxs = mxs;
 
1746
 
 
1747
        return 0;
 
1748
}
 
1749
 
 
1750
void
 
1751
weston_xserver_destroy(struct weston_compositor *compositor)
 
1752
{
 
1753
        struct weston_xserver *wxs = compositor->wxs;
 
1754
 
 
1755
        if (!wxs)
 
1756
                return;
 
1757
 
 
1758
        if (wxs->loop)
 
1759
                weston_xserver_shutdown(wxs);
 
1760
 
 
1761
        free(wxs);
 
1762
}