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;
62 struct wl_listener activate_listener;
63 struct wl_listener destroy_listener;
67 xcb_connection_t *conn;
68 const xcb_query_extension_reply_t *xfixes;
69 struct wl_event_source *source;
71 struct hash_table *window_hash;
72 struct weston_xserver *server;
73 xcb_window_t wm_window;
75 xcb_window_t selection_window;
78 struct wl_event_source *property_source;
79 xcb_get_property_reply_t *property_reply;
81 struct wl_array source_data;
82 xcb_selection_request_event_t selection_request;
83 xcb_atom_t selection_target;
84 xcb_timestamp_t selection_timestamp;
85 int selection_property_set;
86 int flush_property_on_delete;
87 struct wl_listener selection_listener;
90 xcb_atom_t wm_protocols;
91 xcb_atom_t wm_take_focus;
92 xcb_atom_t wm_delete_window;
93 xcb_atom_t net_wm_name;
94 xcb_atom_t net_wm_icon;
95 xcb_atom_t net_wm_state;
96 xcb_atom_t net_wm_state_fullscreen;
97 xcb_atom_t net_wm_user_time;
98 xcb_atom_t net_wm_icon_name;
99 xcb_atom_t net_wm_window_type;
100 xcb_atom_t net_wm_moveresize;
101 xcb_atom_t net_supporting_wm_check;
102 xcb_atom_t net_supported;
103 xcb_atom_t clipboard;
105 xcb_atom_t utf8_string;
106 xcb_atom_t wl_selection;
108 xcb_atom_t timestamp;
110 xcb_atom_t compound_text;
113 xcb_atom_t text_plain_utf8;
114 xcb_atom_t text_plain;
118 struct weston_wm_window {
120 struct weston_surface *surface;
121 struct shell_surface *shsurf;
122 struct wl_listener surface_destroy_listener;
125 struct weston_wm_window *transient_for;
130 static struct weston_wm_window *
131 get_wm_window(struct weston_surface *surface);
134 get_atom_name(xcb_connection_t *c, xcb_atom_t atom)
136 xcb_get_atom_name_cookie_t cookie;
137 xcb_get_atom_name_reply_t *reply;
138 xcb_generic_error_t *e;
139 static char buffer[64];
141 if (atom == XCB_ATOM_NONE)
144 cookie = xcb_get_atom_name (c, atom);
145 reply = xcb_get_atom_name_reply (c, cookie, &e);
146 snprintf(buffer, sizeof buffer, "%.*s",
147 xcb_get_atom_name_name_length (reply),
148 xcb_get_atom_name_name (reply));
155 dump_property(struct weston_wm *wm, xcb_atom_t property,
156 xcb_get_property_reply_t *reply)
159 const char *text_value, *name;
160 xcb_atom_t *atom_value;
164 width = fprintf(stderr, " %s: ", get_atom_name(wm->conn, property));
166 fprintf(stderr, "(no reply)\n");
170 width += fprintf(stderr,
171 "type %s, format %d, length %d (value_len %d): ",
172 get_atom_name(wm->conn, reply->type),
174 xcb_get_property_value_length(reply),
177 if (reply->type == wm->atom.incr) {
178 incr_value = xcb_get_property_value(reply);
179 fprintf(stderr, "%d\n", *incr_value);
180 } else if (reply->type == wm->atom.utf8_string ||
181 reply->type == wm->atom.string) {
182 text_value = xcb_get_property_value(reply);
183 if (reply->value_len > 40)
186 len = reply->value_len;
187 fprintf(stderr, "\"%.*s\"\n", len, text_value);
188 } else if (reply->type == XCB_ATOM_ATOM) {
189 atom_value = xcb_get_property_value(reply);
190 for (i = 0; i < reply->value_len; i++) {
191 name = get_atom_name(wm->conn, atom_value[i]);
192 if (width + strlen(name) + 2 > 78) {
193 fprintf(stderr, "\n ");
196 width += fprintf(stderr, ", ");
199 width += fprintf(stderr, "%s", name);
201 fprintf(stderr, "\n");
203 fprintf(stderr, "huh?\n");
208 dump_window_properties(struct weston_wm *wm, xcb_window_t window)
210 xcb_list_properties_cookie_t list_cookie;
211 xcb_list_properties_reply_t *list_reply;
212 xcb_get_property_cookie_t property_cookie;
213 xcb_get_property_reply_t *property_reply;
217 list_cookie = xcb_list_properties(wm->conn, window);
218 list_reply = xcb_list_properties_reply(wm->conn, list_cookie, NULL);
220 /* Bad window, typically */
223 length = xcb_list_properties_atoms_length(list_reply);
224 atoms = xcb_list_properties_atoms(list_reply);
226 for (i = 0; i < length; i++) {
228 xcb_get_property(wm->conn,
235 property_reply = xcb_get_property_reply(wm->conn,
236 property_cookie, NULL);
237 dump_property(wm, atoms[i], property_reply);
239 free(property_reply);
246 data_offer_accept(struct wl_client *client, struct wl_resource *resource,
247 uint32_t time, const char *mime_type)
252 data_offer_receive(struct wl_client *client, struct wl_resource *resource,
253 const char *mime_type, int32_t fd)
255 struct wl_data_offer *offer = resource->data;
256 struct weston_wm *wm = offer->source->resource.data;
258 if (strcmp(mime_type, "text/plain;charset=utf-8") == 0) {
259 /* Get data for the utf8_string target */
260 xcb_convert_selection(wm->conn,
261 wm->selection_window,
263 wm->atom.utf8_string,
264 wm->atom.wl_selection,
265 XCB_TIME_CURRENT_TIME);
269 fcntl(fd, F_SETFL, O_WRONLY | O_NONBLOCK);
270 wm->data_source_fd = fd;
277 data_offer_destroy(struct wl_client *client, struct wl_resource *resource)
279 wl_resource_destroy(resource);
282 static const struct wl_data_offer_interface data_offer_interface = {
289 data_source_cancel(struct wl_data_source *source)
294 weston_wm_get_selection_targets(struct weston_wm *wm)
296 struct wl_data_source *source;
297 struct weston_compositor *compositor;
298 xcb_get_property_cookie_t cookie;
299 xcb_get_property_reply_t *reply;
304 cookie = xcb_get_property(wm->conn,
306 wm->selection_window,
307 wm->atom.wl_selection,
308 XCB_GET_PROPERTY_TYPE_ANY,
312 reply = xcb_get_property_reply(wm->conn, cookie, NULL);
314 dump_property(wm, wm->atom.wl_selection, reply);
316 if (reply->type != XCB_ATOM_ATOM) {
321 source = malloc(sizeof *source);
325 wl_signal_init(&source->resource.destroy_signal);
326 source->offer_interface = &data_offer_interface;
327 source->cancel = data_source_cancel;
328 source->resource.data = wm;
330 wl_array_init(&source->mime_types);
331 value = xcb_get_property_value(reply);
332 for (i = 0; i < reply->value_len; i++) {
333 if (value[i] == wm->atom.utf8_string) {
334 p = wl_array_add(&source->mime_types, sizeof *p);
336 *p = strdup("text/plain;charset=utf-8");
340 compositor = wm->server->compositor;
341 wl_input_device_set_selection(compositor->input_device, source,
342 wl_display_next_serial(compositor->wl_display));
348 weston_wm_write_property(int fd, uint32_t mask, void *data)
350 struct weston_wm *wm = data;
351 unsigned char *property;
354 property = xcb_get_property_value(wm->property_reply);
355 remainder = xcb_get_property_value_length(wm->property_reply) -
358 len = write(fd, property + wm->property_start, remainder);
360 free(wm->property_reply);
361 wl_event_source_remove(wm->property_source);
363 fprintf(stderr, "write error to target fd: %m\n");
367 fprintf(stderr, "wrote %d (chunk size %d) of %d bytes\n",
368 wm->property_start + len,
369 len, xcb_get_property_value_length(wm->property_reply));
371 wm->property_start += len;
372 if (len == remainder) {
373 free(wm->property_reply);
374 wl_event_source_remove(wm->property_source);
377 xcb_delete_property(wm->conn,
378 wm->selection_window,
379 wm->atom.wl_selection);
381 fprintf(stderr, "transfer complete\n");
390 weston_wm_get_selection_data(struct weston_wm *wm)
392 xcb_get_property_cookie_t cookie;
393 xcb_get_property_reply_t *reply;
395 cookie = xcb_get_property(wm->conn,
397 wm->selection_window,
398 wm->atom.wl_selection,
399 XCB_GET_PROPERTY_TYPE_ANY,
401 0x1fffffff /* length */);
403 reply = xcb_get_property_reply(wm->conn, cookie, NULL);
405 if (reply->type == wm->atom.incr) {
406 dump_property(wm, wm->atom.wl_selection, reply);
410 dump_property(wm, wm->atom.wl_selection, reply);
412 wm->property_start = 0;
413 wm->property_source =
414 wl_event_loop_add_fd(wm->server->loop,
417 weston_wm_write_property,
419 wm->property_reply = reply;
424 weston_wm_get_incr_chunk(struct weston_wm *wm)
426 xcb_get_property_cookie_t cookie;
427 xcb_get_property_reply_t *reply;
429 cookie = xcb_get_property(wm->conn,
431 wm->selection_window,
432 wm->atom.wl_selection,
433 XCB_GET_PROPERTY_TYPE_ANY,
435 0x1fffffff /* length */);
437 reply = xcb_get_property_reply(wm->conn, cookie, NULL);
439 dump_property(wm, wm->atom.wl_selection, reply);
441 if (xcb_get_property_value_length(reply) > 0) {
442 wm->property_start = 0;
443 wm->property_source =
444 wl_event_loop_add_fd(wm->server->loop,
447 weston_wm_write_property,
449 wm->property_reply = reply;
451 fprintf(stderr, "transfer complete\n");
452 close(wm->data_source_fd);
458 weston_wm_set_selection(struct wl_listener *listener, void *data)
460 struct wl_input_device *device = data;
461 struct weston_wm *wm =
462 container_of(listener, struct weston_wm, selection_listener);
463 struct wl_data_source *source = device->selection_data_source;
464 const char **p, **end;
465 int has_text_plain = 0;
467 if (source->offer_interface == &data_offer_interface)
470 fprintf(stderr, "set selection\n");
472 p = source->mime_types.data;
473 end = (const char **)
474 ((char *) source->mime_types.data + source->mime_types.size);
476 fprintf(stderr, " %s\n", *p);
477 if (strcmp(*p, "text/plain") == 0 ||
478 strcmp(*p, "text/plain;charset=utf-8") == 0)
483 if (has_text_plain) {
484 xcb_set_selection_owner(wm->conn,
485 wm->selection_window,
487 XCB_TIME_CURRENT_TIME);
489 xcb_set_selection_owner(wm->conn,
492 XCB_TIME_CURRENT_TIME);
497 weston_wm_handle_configure_request(struct weston_wm *wm, xcb_generic_event_t *event)
499 xcb_configure_request_event_t *configure_request =
500 (xcb_configure_request_event_t *) event;
504 fprintf(stderr, "XCB_CONFIGURE_REQUEST (window %d) %d,%d @ %dx%d\n",
505 configure_request->window,
506 configure_request->x, configure_request->y,
507 configure_request->width, configure_request->height);
509 if (configure_request->value_mask & XCB_CONFIG_WINDOW_X)
510 values[i++] = configure_request->x;
511 if (configure_request->value_mask & XCB_CONFIG_WINDOW_Y)
512 values[i++] = configure_request->y;
513 if (configure_request->value_mask & XCB_CONFIG_WINDOW_WIDTH)
514 values[i++] = configure_request->width;
515 if (configure_request->value_mask & XCB_CONFIG_WINDOW_HEIGHT)
516 values[i++] = configure_request->height;
517 if (configure_request->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH)
518 values[i++] = configure_request->border_width;
519 if (configure_request->value_mask & XCB_CONFIG_WINDOW_SIBLING)
520 values[i++] = configure_request->sibling;
521 if (configure_request->value_mask & XCB_CONFIG_WINDOW_STACK_MODE)
522 values[i++] = configure_request->stack_mode;
524 xcb_configure_window(wm->conn,
525 configure_request->window,
526 configure_request->value_mask, values);
530 weston_wm_handle_configure_notify(struct weston_wm *wm, xcb_generic_event_t *event)
532 xcb_configure_notify_event_t *configure_notify =
533 (xcb_configure_notify_event_t *) event;
535 fprintf(stderr, "XCB_CONFIGURE_NOTIFY (window %d) %d,%d @ %dx%d\n",
536 configure_notify->window,
537 configure_notify->x, configure_notify->y,
538 configure_notify->width, configure_notify->height);
542 weston_wm_activate(struct weston_wm *wm,
543 struct weston_wm_window *window, xcb_timestamp_t time)
545 xcb_client_message_event_t client_message;
547 client_message.response_type = XCB_CLIENT_MESSAGE;
548 client_message.format = 32;
549 client_message.window = window->id;
550 client_message.type = wm->atom.wm_protocols;
551 client_message.data.data32[0] = wm->atom.wm_take_focus;
552 client_message.data.data32[1] = XCB_TIME_CURRENT_TIME;
554 xcb_send_event(wm->conn, 0, window->id,
555 XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
556 (char *) &client_message);
558 xcb_set_input_focus (wm->conn,
559 XCB_INPUT_FOCUS_POINTER_ROOT, window->id, time);
563 weston_xserver_surface_activate(struct wl_listener *listener, void *data)
565 struct weston_surface *surface = data;
566 struct weston_wm_window *window = get_wm_window(surface);
567 struct weston_xserver *wxs =
568 container_of(listener,
569 struct weston_xserver, activate_listener);
572 weston_wm_activate(wxs->wm, window, XCB_TIME_CURRENT_TIME);
573 else if (wxs && wxs->wm)
574 xcb_set_input_focus (wxs->wm->conn,
575 XCB_INPUT_FOCUS_POINTER_ROOT,
577 XCB_TIME_CURRENT_TIME);
581 weston_wm_handle_map_request(struct weston_wm *wm, xcb_generic_event_t *event)
583 xcb_map_request_event_t *map_request =
584 (xcb_map_request_event_t *) event;
586 fprintf(stderr, "XCB_MAP_REQUEST (window %d)\n", map_request->window);
588 xcb_map_window(wm->conn, map_request->window);
592 weston_wm_handle_map_notify(struct weston_wm *wm, xcb_generic_event_t *event)
594 xcb_map_notify_event_t *map_notify = (xcb_map_notify_event_t *) event;
595 struct weston_wm_window *window;
597 fprintf(stderr, "XCB_MAP_NOTIFY (window %d)\n", map_notify->window);
599 window = hash_table_lookup(wm->window_hash, map_notify->window);
600 weston_wm_activate(wm, window, XCB_TIME_CURRENT_TIME);
603 static const size_t incr_chunk_size = 64 * 1024;
606 weston_wm_send_selection_notify(struct weston_wm *wm, xcb_atom_t property)
608 xcb_selection_notify_event_t selection_notify;
610 memset(&selection_notify, 0, sizeof selection_notify);
611 selection_notify.response_type = XCB_SELECTION_NOTIFY;
612 selection_notify.sequence = 0;
613 selection_notify.time = wm->selection_request.time;
614 selection_notify.requestor = wm->selection_request.requestor;
615 selection_notify.selection = wm->selection_request.selection;
616 selection_notify.target = wm->selection_request.target;
617 selection_notify.property = property;
619 xcb_send_event(wm->conn, 0, /* propagate */
620 wm->selection_request.requestor,
621 XCB_EVENT_MASK_NO_EVENT, (char *) &selection_notify);
625 weston_wm_send_targets(struct weston_wm *wm)
627 xcb_atom_t targets[] = {
630 wm->atom.utf8_string,
631 /* wm->atom.compound_text, */
633 /* wm->atom.string */
636 xcb_change_property(wm->conn,
637 XCB_PROP_MODE_REPLACE,
638 wm->selection_request.requestor,
639 wm->selection_request.property,
642 ARRAY_LENGTH(targets), targets);
644 weston_wm_send_selection_notify(wm, wm->selection_request.property);
648 weston_wm_send_timestamp(struct weston_wm *wm)
650 xcb_change_property(wm->conn,
651 XCB_PROP_MODE_REPLACE,
652 wm->selection_request.requestor,
653 wm->selection_request.property,
656 1, &wm->selection_timestamp);
658 weston_wm_send_selection_notify(wm, wm->selection_request.property);
662 weston_wm_flush_source_data(struct weston_wm *wm)
666 xcb_change_property(wm->conn,
667 XCB_PROP_MODE_REPLACE,
668 wm->selection_request.requestor,
669 wm->selection_request.property,
670 wm->selection_target,
672 wm->source_data.size,
673 wm->source_data.data);
674 wm->selection_property_set = 1;
675 length = wm->source_data.size;
676 wm->source_data.size = 0;
682 weston_wm_read_data_source(int fd, uint32_t mask, void *data)
684 struct weston_wm *wm = data;
685 int len, current, available;
688 current = wm->source_data.size;
689 if (wm->source_data.size < incr_chunk_size)
690 p = wl_array_add(&wm->source_data, incr_chunk_size);
692 p = (char *) wm->source_data.data + wm->source_data.size;
693 available = wm->source_data.alloc - current;
695 len = read(fd, p, available);
697 fprintf(stderr, "read error from data source: %m\n");
698 weston_wm_send_selection_notify(wm, XCB_ATOM_NONE);
699 wl_event_source_remove(wm->property_source);
701 wl_array_release(&wm->source_data);
704 fprintf(stderr, "read %d (available %d, mask 0x%x) bytes: \"%.*s\"\n",
705 len, available, mask, len, (char *) p);
707 wm->source_data.size = current + len;
708 if (wm->source_data.size >= incr_chunk_size) {
710 fprintf(stderr, "got %zu bytes, starting incr\n",
711 wm->source_data.size);
713 xcb_change_property(wm->conn,
714 XCB_PROP_MODE_REPLACE,
715 wm->selection_request.requestor,
716 wm->selection_request.property,
719 1, &incr_chunk_size);
720 wm->selection_property_set = 1;
721 wm->flush_property_on_delete = 1;
722 wl_event_source_remove(wm->property_source);
723 weston_wm_send_selection_notify(wm, wm->selection_request.property);
724 } else if (wm->selection_property_set) {
725 fprintf(stderr, "got %zu bytes, waiting for "
726 "property delete\n", wm->source_data.size);
728 wm->flush_property_on_delete = 1;
729 wl_event_source_remove(wm->property_source);
731 fprintf(stderr, "got %zu bytes, "
732 "property deleted, seting new property\n",
733 wm->source_data.size);
734 weston_wm_flush_source_data(wm);
736 } else if (len == 0 && !wm->incr) {
737 fprintf(stderr, "non-incr transfer complete\n");
738 /* Non-incr transfer all done. */
739 weston_wm_flush_source_data(wm);
740 weston_wm_send_selection_notify(wm, wm->selection_request.property);
742 wl_event_source_remove(wm->property_source);
744 wl_array_release(&wm->source_data);
745 wm->selection_request.requestor = XCB_NONE;
746 } else if (len == 0 && wm->incr) {
747 fprintf(stderr, "incr transfer complete\n");
749 wm->flush_property_on_delete = 1;
750 if (wm->selection_property_set) {
751 fprintf(stderr, "got %zu bytes, waiting for "
752 "property delete\n", wm->source_data.size);
754 fprintf(stderr, "got %zu bytes, "
755 "property deleted, seting new property\n",
756 wm->source_data.size);
757 weston_wm_flush_source_data(wm);
760 wl_event_source_remove(wm->property_source);
761 wm->data_source_fd = -1;
764 fprintf(stderr, "nothing happened, buffered the bytes\n");
771 weston_wm_send_data(struct weston_wm *wm, xcb_atom_t target, const char *mime_type)
773 struct wl_input_device *device = wm->server->compositor->input_device;
776 if (pipe2(p, O_CLOEXEC | O_NONBLOCK) == -1) {
777 fprintf(stderr, "pipe2 failed: %m\n");
778 weston_wm_send_selection_notify(wm, XCB_ATOM_NONE);
782 wl_array_init(&wm->source_data);
783 wm->selection_target = target;
784 wm->data_source_fd = p[0];
785 wm->property_source = wl_event_loop_add_fd(wm->server->loop,
788 weston_wm_read_data_source,
791 wl_data_source_send_send(&device->selection_data_source->resource,
797 weston_wm_send_incr_chunk(struct weston_wm *wm)
799 fprintf(stderr, "property deleted\n");
802 wm->selection_property_set = 0;
803 if (wm->flush_property_on_delete) {
804 fprintf(stderr, "setting new property, %zu bytes\n",
805 wm->source_data.size);
806 wm->flush_property_on_delete = 0;
807 length = weston_wm_flush_source_data(wm);
809 if (wm->data_source_fd >= 0) {
810 wm->property_source =
811 wl_event_loop_add_fd(wm->server->loop,
814 weston_wm_read_data_source,
816 } else if (length > 0) {
817 /* Transfer is all done, but queue a flush for
818 * the delete of the last chunk so we can set
819 * the 0 sized propert to signal the end of
821 wm->flush_property_on_delete = 1;
822 wl_array_release(&wm->source_data);
824 wm->selection_request.requestor = XCB_NONE;
830 weston_wm_handle_selection_request(struct weston_wm *wm,
831 xcb_generic_event_t *event)
833 xcb_selection_request_event_t *selection_request =
834 (xcb_selection_request_event_t *) event;
836 fprintf(stderr, "selection request, %s, ",
837 get_atom_name(wm->conn, selection_request->selection));
838 fprintf(stderr, "target %s, ",
839 get_atom_name(wm->conn, selection_request->target));
840 fprintf(stderr, "property %s\n",
841 get_atom_name(wm->conn, selection_request->property));
843 wm->selection_request = *selection_request;
845 wm->flush_property_on_delete = 0;
847 if (selection_request->target == wm->atom.targets) {
848 weston_wm_send_targets(wm);
849 } else if (selection_request->target == wm->atom.timestamp) {
850 weston_wm_send_timestamp(wm);
851 } else if (selection_request->target == wm->atom.utf8_string ||
852 selection_request->target == wm->atom.text) {
853 weston_wm_send_data(wm, wm->atom.utf8_string,
854 "text/plain;charset=utf-8");
856 fprintf(stderr, "can only handle UTF8_STRING targets...\n");
857 weston_wm_send_selection_notify(wm, XCB_ATOM_NONE);
862 weston_wm_handle_property_notify(struct weston_wm *wm, xcb_generic_event_t *event)
864 xcb_property_notify_event_t *property_notify =
865 (xcb_property_notify_event_t *) event;
867 if (property_notify->window == wm->selection_window) {
868 if (property_notify->state == XCB_PROPERTY_NEW_VALUE &&
869 property_notify->atom == wm->atom.wl_selection &&
871 weston_wm_get_incr_chunk(wm);
872 } else if (property_notify->window == wm->selection_request.requestor) {
873 if (property_notify->state == XCB_PROPERTY_DELETE &&
874 property_notify->atom == wm->selection_request.property &&
876 weston_wm_send_incr_chunk(wm);
877 } else if (property_notify->atom == XCB_ATOM_WM_CLASS) {
878 fprintf(stderr, "wm_class changed\n");
879 } else if (property_notify->atom == XCB_ATOM_WM_TRANSIENT_FOR) {
880 fprintf(stderr, "wm_transient_for changed\n");
881 } else if (property_notify->atom == wm->atom.wm_protocols) {
882 fprintf(stderr, "wm_protocols changed\n");
883 } else if (property_notify->atom == wm->atom.net_wm_name) {
884 fprintf(stderr, "_net_wm_name changed\n");
885 } else if (property_notify->atom == wm->atom.net_wm_user_time) {
886 fprintf(stderr, "_net_wm_user_time changed\n");
887 } else if (property_notify->atom == wm->atom.net_wm_icon_name) {
888 fprintf(stderr, "_net_wm_icon_name changed\n");
889 } else if (property_notify->atom == XCB_ATOM_WM_NAME) {
890 fprintf(stderr, "wm_name changed\n");
891 } else if (property_notify->atom == XCB_ATOM_WM_ICON_NAME) {
892 fprintf(stderr, "wm_icon_name changed\n");
894 fprintf(stderr, "XCB_PROPERTY_NOTIFY: "
895 "unhandled property change: %s\n",
896 get_atom_name(wm->conn, property_notify->atom));
901 weston_wm_handle_create_notify(struct weston_wm *wm, xcb_generic_event_t *event)
903 xcb_create_notify_event_t *create_notify =
904 (xcb_create_notify_event_t *) event;
905 struct weston_wm_window *window;
908 fprintf(stderr, "XCB_CREATE_NOTIFY (window %d)\n",
909 create_notify->window);
911 window = malloc(sizeof *window);
912 if (window == NULL) {
913 fprintf(stderr, "failed to allocate window\n");
917 values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE;
918 xcb_change_window_attributes(wm->conn, create_notify->window,
919 XCB_CW_EVENT_MASK, values);
921 memset(window, 0, sizeof *window);
922 window->id = create_notify->window;
923 hash_table_insert(wm->window_hash, window->id, window);
927 weston_wm_handle_destroy_notify(struct weston_wm *wm, xcb_generic_event_t *event)
929 xcb_destroy_notify_event_t *destroy_notify =
930 (xcb_destroy_notify_event_t *) event;
931 struct weston_wm_window *window;
933 fprintf(stderr, "XCB_DESTROY_NOTIFY, win %d\n",
934 destroy_notify->window);
936 window = hash_table_lookup(wm->window_hash, destroy_notify->window);
937 if (window == NULL) {
938 fprintf(stderr, "destroy notify for unknow window %d\n",
939 destroy_notify->window);
943 fprintf(stderr, "destroy window %p\n", window);
944 hash_table_remove(wm->window_hash, window->id);
946 wl_list_remove(&window->surface_destroy_listener.link);
951 weston_wm_handle_selection_notify(struct weston_wm *wm,
952 xcb_generic_event_t *event)
954 xcb_selection_notify_event_t *selection_notify =
955 (xcb_selection_notify_event_t *) event;
957 if (selection_notify->property == XCB_ATOM_NONE) {
958 /* convert selection failed */
959 } else if (selection_notify->target == wm->atom.targets) {
960 weston_wm_get_selection_targets(wm);
962 weston_wm_get_selection_data(wm);
967 weston_wm_handle_xfixes_selection_notify(struct weston_wm *wm,
968 xcb_generic_event_t *event)
970 xcb_xfixes_selection_notify_event_t *xfixes_selection_notify =
971 (xcb_xfixes_selection_notify_event_t *) event;
973 printf("xfixes selection notify event: owner %d\n",
974 xfixes_selection_notify->owner);
976 /* We have to use XCB_TIME_CURRENT_TIME when we claim the
977 * selection, so grab the actual timestamp here so we can
978 * answer TIMESTAMP conversion requests correctly. */
979 if (xfixes_selection_notify->owner == wm->selection_window) {
980 wm->selection_timestamp = xfixes_selection_notify->timestamp;
981 fprintf(stderr, "our window, skipping\n");
986 xcb_convert_selection(wm->conn, wm->selection_window,
989 wm->atom.wl_selection,
990 xfixes_selection_notify->timestamp);
996 weston_wm_handle_client_message(struct weston_wm *wm,
997 xcb_generic_event_t *event)
999 xcb_client_message_event_t *client_message =
1000 (xcb_client_message_event_t *) event;
1002 fprintf(stderr, "got client message, type: %s\n",
1003 get_atom_name(wm->conn, client_message->type));
1007 weston_wm_handle_event(int fd, uint32_t mask, void *data)
1009 struct weston_wm *wm = data;
1010 xcb_generic_event_t *event;
1013 while (event = xcb_poll_for_event(wm->conn), event != NULL) {
1014 switch (event->response_type & ~0x80) {
1015 case XCB_CREATE_NOTIFY:
1016 weston_wm_handle_create_notify(wm, event);
1018 case XCB_MAP_REQUEST:
1019 weston_wm_handle_map_request(wm, event);
1021 case XCB_MAP_NOTIFY:
1022 weston_wm_handle_map_notify(wm, event);
1024 case XCB_UNMAP_NOTIFY:
1025 fprintf(stderr, "XCB_UNMAP_NOTIFY\n");
1027 case XCB_CONFIGURE_REQUEST:
1028 weston_wm_handle_configure_request(wm, event);
1030 case XCB_CONFIGURE_NOTIFY:
1031 weston_wm_handle_configure_notify(wm, event);
1033 case XCB_DESTROY_NOTIFY:
1034 weston_wm_handle_destroy_notify(wm, event);
1036 case XCB_MAPPING_NOTIFY:
1037 fprintf(stderr, "XCB_MAPPING_NOTIFY\n");
1039 case XCB_PROPERTY_NOTIFY:
1040 weston_wm_handle_property_notify(wm, event);
1042 case XCB_SELECTION_NOTIFY:
1043 weston_wm_handle_selection_notify(wm, event);
1045 case XCB_SELECTION_REQUEST:
1046 weston_wm_handle_selection_request(wm, event);
1048 case XCB_CLIENT_MESSAGE:
1049 weston_wm_handle_client_message(wm, event);
1053 switch (event->response_type - wm->xfixes->first_event) {
1054 case XCB_XFIXES_SELECTION_NOTIFY:
1055 weston_wm_handle_xfixes_selection_notify(wm, event);
1064 xcb_flush(wm->conn);
1070 wxs_wm_get_resources(struct weston_wm *wm)
1073 #define F(field) offsetof(struct weston_wm, field)
1075 static const struct { const char *name; int offset; } atoms[] = {
1076 { "WM_PROTOCOLS", F(atom.wm_protocols) },
1077 { "WM_TAKE_FOCUS", F(atom.wm_take_focus) },
1078 { "WM_DELETE_WINDOW", F(atom.wm_delete_window) },
1079 { "_NET_WM_NAME", F(atom.net_wm_name) },
1080 { "_NET_WM_ICON", F(atom.net_wm_icon) },
1081 { "_NET_WM_STATE", F(atom.net_wm_state) },
1082 { "_NET_WM_STATE_FULLSCREEN", F(atom.net_wm_state_fullscreen) },
1083 { "_NET_WM_USER_TIME", F(atom.net_wm_user_time) },
1084 { "_NET_WM_ICON_NAME", F(atom.net_wm_icon_name) },
1085 { "_NET_WM_WINDOW_TYPE", F(atom.net_wm_window_type) },
1086 { "_NET_WM_MOVERESIZE", F(atom.net_wm_moveresize) },
1087 { "_NET_SUPPORTING_WM_CHECK",
1088 F(atom.net_supporting_wm_check) },
1089 { "_NET_SUPPORTED", F(atom.net_supported) },
1090 { "CLIPBOARD", F(atom.clipboard) },
1091 { "TARGETS", F(atom.targets) },
1092 { "UTF8_STRING", F(atom.utf8_string) },
1093 { "_WL_SELECTION", F(atom.wl_selection) },
1094 { "INCR", F(atom.incr) },
1095 { "TIMESTAMP", F(atom.timestamp) },
1096 { "MULTIPLE", F(atom.multiple) },
1097 { "UTF8_STRING" , F(atom.utf8_string) },
1098 { "COMPOUND_TEXT", F(atom.compound_text) },
1099 { "TEXT", F(atom.text) },
1100 { "STRING", F(atom.string) },
1101 { "text/plain;charset=utf-8", F(atom.text_plain_utf8) },
1102 { "text/plain", F(atom.text_plain) },
1106 xcb_xfixes_query_version_cookie_t xfixes_cookie;
1107 xcb_xfixes_query_version_reply_t *xfixes_reply;
1108 xcb_intern_atom_cookie_t cookies[ARRAY_LENGTH(atoms)];
1109 xcb_intern_atom_reply_t *reply;
1112 xcb_prefetch_extension_data (wm->conn, &xcb_xfixes_id);
1114 for (i = 0; i < ARRAY_LENGTH(atoms); i++)
1115 cookies[i] = xcb_intern_atom (wm->conn, 0,
1116 strlen(atoms[i].name),
1119 for (i = 0; i < ARRAY_LENGTH(atoms); i++) {
1120 reply = xcb_intern_atom_reply (wm->conn, cookies[i], NULL);
1121 *(xcb_atom_t *) ((char *) wm + atoms[i].offset) = reply->atom;
1125 wm->xfixes = xcb_get_extension_data(wm->conn, &xcb_xfixes_id);
1126 if (!wm->xfixes || !wm->xfixes->present)
1127 fprintf(stderr, "xfixes not available\n");
1129 xfixes_cookie = xcb_xfixes_query_version(wm->conn,
1130 XCB_XFIXES_MAJOR_VERSION,
1131 XCB_XFIXES_MINOR_VERSION);
1132 xfixes_reply = xcb_xfixes_query_version_reply(wm->conn,
1133 xfixes_cookie, NULL);
1135 printf("xfixes version: %d.%d\n",
1136 xfixes_reply->major_version, xfixes_reply->minor_version);
1142 weston_wm_create_wm_window(struct weston_wm *wm)
1144 static const char name[] = "Weston WM";
1146 wm->wm_window = xcb_generate_id(wm->conn);
1147 xcb_create_window(wm->conn,
1148 XCB_COPY_FROM_PARENT,
1154 XCB_WINDOW_CLASS_INPUT_OUTPUT,
1155 wm->screen->root_visual,
1158 xcb_change_property(wm->conn,
1159 XCB_PROP_MODE_REPLACE,
1161 wm->atom.net_supporting_wm_check,
1166 xcb_change_property(wm->conn,
1167 XCB_PROP_MODE_REPLACE,
1169 wm->atom.net_wm_name,
1170 wm->atom.utf8_string,
1172 strlen(name), name);
1174 xcb_change_property(wm->conn,
1175 XCB_PROP_MODE_REPLACE,
1177 wm->atom.net_supporting_wm_check,
1184 static struct weston_wm *
1185 weston_wm_create(struct weston_xserver *wxs)
1187 struct wl_input_device *device;
1188 struct weston_wm *wm;
1189 struct wl_event_loop *loop;
1190 xcb_screen_iterator_t s;
1191 uint32_t values[1], mask;
1193 xcb_atom_t supported[1];
1195 wm = malloc(sizeof *wm);
1200 wm->window_hash = hash_table_create();
1201 if (wm->window_hash == NULL) {
1206 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
1207 fprintf(stderr, "socketpair failed\n");
1208 hash_table_destroy(wm->window_hash);
1213 xserver_send_client(wxs->resource, sv[1]);
1214 wl_client_flush(wxs->resource->client);
1217 /* xcb_connect_to_fd takes ownership of the fd. */
1218 wm->conn = xcb_connect_to_fd(sv[0], NULL);
1219 if (xcb_connection_has_error(wm->conn)) {
1220 fprintf(stderr, "xcb_connect_to_fd failed\n");
1222 hash_table_destroy(wm->window_hash);
1227 s = xcb_setup_roots_iterator(xcb_get_setup(wm->conn));
1228 wm->screen = s.data;
1230 loop = wl_display_get_event_loop(wxs->wl_display);
1232 wl_event_loop_add_fd(loop, sv[0],
1234 weston_wm_handle_event, wm);
1235 wl_event_source_check(wm->source);
1237 wxs_wm_get_resources(wm);
1240 XCB_EVENT_MASK_STRUCTURE_NOTIFY |
1241 XCB_EVENT_MASK_RESIZE_REDIRECT |
1242 XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
1243 XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
1244 XCB_EVENT_MASK_PROPERTY_CHANGE;
1245 xcb_change_window_attributes(wm->conn, wm->screen->root,
1246 XCB_CW_EVENT_MASK, values);
1248 weston_wm_create_wm_window(wm);
1250 supported[0] = wm->atom.net_wm_moveresize;
1251 xcb_change_property(wm->conn,
1252 XCB_PROP_MODE_REPLACE,
1254 wm->atom.net_supported,
1257 ARRAY_LENGTH(supported), supported);
1259 wm->selection_request.requestor = XCB_NONE;
1261 wm->selection_window = xcb_generate_id(wm->conn);
1262 xcb_create_window(wm->conn,
1263 XCB_COPY_FROM_PARENT,
1264 wm->selection_window,
1269 XCB_WINDOW_CLASS_INPUT_OUTPUT,
1270 wm->screen->root_visual,
1271 XCB_CW_EVENT_MASK, values);
1274 XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
1275 XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
1276 XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE;
1278 xcb_xfixes_select_selection_input(wm->conn, wm->selection_window,
1279 wm->atom.clipboard, mask);
1281 xcb_flush(wm->conn);
1283 device = wxs->compositor->input_device;
1284 wm->selection_listener.notify = weston_wm_set_selection;
1285 wl_signal_add(&device->selection_signal, &wm->selection_listener);
1287 fprintf(stderr, "created wm\n");
1293 weston_wm_destroy(struct weston_wm *wm)
1295 /* FIXME: Free windows in hash. */
1296 hash_table_destroy(wm->window_hash);
1297 xcb_disconnect(wm->conn);
1298 wl_event_source_remove(wm->source);
1299 wl_list_remove(&wm->selection_listener.link);
1304 weston_xserver_handle_event(int listen_fd, uint32_t mask, void *data)
1306 struct weston_xserver *mxs = data;
1307 char display[8], s[8];
1308 int sv[2], client_fd;
1310 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
1311 fprintf(stderr, "socketpair failed\n");
1315 mxs->process.pid = fork();
1316 switch (mxs->process.pid) {
1318 /* SOCK_CLOEXEC closes both ends, so we need to unset
1319 * the flag on the client fd. */
1320 client_fd = dup(sv[1]);
1324 snprintf(s, sizeof s, "%d", client_fd);
1325 setenv("WAYLAND_SOCKET", s, 1);
1327 snprintf(display, sizeof display, ":%d", mxs->display);
1329 if (execl(XSERVER_PATH,
1338 fprintf(stderr, "exec failed: %m\n");
1342 fprintf(stderr, "forked X server, pid %d\n", mxs->process.pid);
1345 mxs->client = wl_client_create(mxs->wl_display, sv[0]);
1347 weston_watch_process(&mxs->process);
1349 wl_event_source_remove(mxs->abstract_source);
1350 wl_event_source_remove(mxs->unix_source);
1354 fprintf(stderr, "failed to fork\n");
1362 weston_xserver_shutdown(struct weston_xserver *wxs)
1366 snprintf(path, sizeof path, "/tmp/.X%d-lock", wxs->display);
1368 snprintf(path, sizeof path, "/tmp/.X11-unix/X%d", wxs->display);
1370 if (wxs->process.pid == 0) {
1371 wl_event_source_remove(wxs->abstract_source);
1372 wl_event_source_remove(wxs->unix_source);
1374 close(wxs->abstract_fd);
1375 close(wxs->unix_fd);
1377 weston_wm_destroy(wxs->wm);
1382 weston_xserver_cleanup(struct weston_process *process, int status)
1384 struct weston_xserver *mxs =
1385 container_of(process, struct weston_xserver, process);
1387 mxs->process.pid = 0;
1389 mxs->resource = NULL;
1391 mxs->abstract_source =
1392 wl_event_loop_add_fd(mxs->loop, mxs->abstract_fd,
1394 weston_xserver_handle_event, mxs);
1397 wl_event_loop_add_fd(mxs->loop, mxs->unix_fd,
1399 weston_xserver_handle_event, mxs);
1402 fprintf(stderr, "xserver exited, code %d\n", status);
1403 weston_wm_destroy(mxs->wm);
1406 /* If the X server crashes before it binds to the
1407 * xserver interface, shut down and don't try
1409 fprintf(stderr, "xserver crashing too fast: %d\n", status);
1410 weston_xserver_shutdown(mxs);
1415 surface_destroy(struct wl_listener *listener, void *data)
1417 struct weston_wm_window *window =
1418 container_of(listener,
1419 struct weston_wm_window, surface_destroy_listener);
1421 fprintf(stderr, "surface for xid %d destroyed\n", window->id);
1424 static struct weston_wm_window *
1425 get_wm_window(struct weston_surface *surface)
1427 struct wl_resource *resource = &surface->surface.resource;
1428 struct wl_listener *listener;
1430 listener = wl_signal_get(&resource->destroy_signal, surface_destroy);
1432 return container_of(listener, struct weston_wm_window,
1433 surface_destroy_listener);
1438 /* We reuse some predefined, but otherwise useles atoms */
1439 #define TYPE_WM_PROTOCOLS XCB_ATOM_CUT_BUFFER0
1442 read_window_properties(struct weston_wm *wm, struct weston_wm_window *window)
1444 #define F(field) offsetof(struct weston_wm_window, field)
1450 { XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, F(class) },
1451 { XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, F(transient_for) },
1452 { wm->atom.wm_protocols, TYPE_WM_PROTOCOLS, F(protocols) },
1453 { wm->atom.net_wm_window_type, XCB_ATOM_ATOM, F(type) },
1454 { wm->atom.net_wm_name, XCB_ATOM_STRING, F(name) },
1458 xcb_get_property_cookie_t cookie[ARRAY_LENGTH(props)];
1459 xcb_get_property_reply_t *reply;
1465 dump_window_properties(wm, window->id);
1467 for (i = 0; i < ARRAY_LENGTH(props); i++)
1468 cookie[i] = xcb_get_property(wm->conn,
1472 XCB_ATOM_ANY, 0, 2048);
1474 for (i = 0; i < ARRAY_LENGTH(props); i++) {
1475 reply = xcb_get_property_reply(wm->conn, cookie[i], NULL);
1477 /* Bad window, typically */
1479 if (reply->type == XCB_ATOM_NONE) {
1480 /* No such property */
1485 p = ((char *) window + props[i].offset);
1487 switch (props[i].type) {
1488 case XCB_ATOM_STRING:
1489 /* FIXME: We're using this for both string and
1492 strndup(xcb_get_property_value(reply),
1493 xcb_get_property_value_length(reply));
1495 case XCB_ATOM_WINDOW:
1496 xid = xcb_get_property_value(reply);
1497 *(struct weston_wm_window **) p =
1498 hash_table_lookup(wm->window_hash, *xid);
1501 atom = xcb_get_property_value(reply);
1502 *(xcb_atom_t *) p = *atom;
1504 case TYPE_WM_PROTOCOLS:
1512 fprintf(stderr, "window %d: name %s, class %s, transient_for %d\n",
1513 window->id, window->name, window->class,
1514 window->transient_for ? window->transient_for->id : 0);
1518 xserver_set_window_id(struct wl_client *client, struct wl_resource *resource,
1519 struct wl_resource *surface_resource, uint32_t id)
1521 struct weston_xserver *wxs = resource->data;
1522 struct weston_wm *wm = wxs->wm;
1523 struct wl_surface *surface = surface_resource->data;
1524 struct weston_wm_window *window;
1525 struct weston_shell_interface *shell_interface =
1526 &wm->server->compositor->shell_interface;
1528 if (client != wxs->client)
1531 window = hash_table_lookup(wm->window_hash, id);
1532 if (window == NULL) {
1533 fprintf(stderr, "set_window_id for unknown window %d\n", id);
1537 fprintf(stderr, "set_window_id %d for surface %p\n", id, surface);
1539 read_window_properties(wm, window);
1541 window->surface = (struct weston_surface *) surface;
1542 window->surface_destroy_listener.notify = surface_destroy;
1543 wl_signal_add(&surface->resource.destroy_signal,
1544 &window->surface_destroy_listener);
1546 if (shell_interface->create_shell_surface) {
1547 shell_interface->create_shell_surface(shell_interface->shell,
1551 shell_interface->set_toplevel(window->shsurf);
1555 static const struct xserver_interface xserver_implementation = {
1556 xserver_set_window_id
1560 bind_xserver(struct wl_client *client,
1561 void *data, uint32_t version, uint32_t id)
1563 struct weston_xserver *wxs = data;
1565 /* If it's a different client than the xserver we launched,
1566 * don't start the wm. */
1567 if (client != wxs->client)
1571 wl_client_add_object(client, &xserver_interface,
1572 &xserver_implementation, id, wxs);
1574 wxs->wm = weston_wm_create(wxs);
1575 if (wxs->wm == NULL) {
1576 fprintf(stderr, "failed to create wm\n");
1579 xserver_send_listen_socket(wxs->resource, wxs->abstract_fd);
1580 xserver_send_listen_socket(wxs->resource, wxs->unix_fd);
1584 bind_to_abstract_socket(int display)
1586 struct sockaddr_un addr;
1587 socklen_t size, name_size;
1590 fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
1594 addr.sun_family = AF_LOCAL;
1595 name_size = snprintf(addr.sun_path, sizeof addr.sun_path,
1596 "%c/tmp/.X11-unix/X%d", 0, display);
1597 size = offsetof(struct sockaddr_un, sun_path) + name_size;
1598 if (bind(fd, (struct sockaddr *) &addr, size) < 0) {
1599 fprintf(stderr, "failed to bind to @%s: %s\n",
1600 addr.sun_path + 1, strerror(errno));
1605 if (listen(fd, 1) < 0) {
1614 bind_to_unix_socket(int display)
1616 struct sockaddr_un addr;
1617 socklen_t size, name_size;
1620 fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
1624 addr.sun_family = AF_LOCAL;
1625 name_size = snprintf(addr.sun_path, sizeof addr.sun_path,
1626 "/tmp/.X11-unix/X%d", display) + 1;
1627 size = offsetof(struct sockaddr_un, sun_path) + name_size;
1628 unlink(addr.sun_path);
1629 if (bind(fd, (struct sockaddr *) &addr, size) < 0) {
1630 fprintf(stderr, "failed to bind to %s (%s)\n",
1631 addr.sun_path, strerror(errno));
1636 if (listen(fd, 1) < 0) {
1637 unlink(addr.sun_path);
1646 create_lockfile(int display, char *lockfile, size_t lsize)
1652 snprintf(lockfile, lsize, "/tmp/.X%d-lock", display);
1653 fd = open(lockfile, O_WRONLY | O_CLOEXEC | O_CREAT | O_EXCL, 0444);
1654 if (fd < 0 && errno == EEXIST) {
1655 fd = open(lockfile, O_CLOEXEC, O_RDONLY);
1656 if (fd < 0 || read(fd, pid, 11) != 11) {
1657 fprintf(stderr, "can't read lock file %s: %s\n",
1658 lockfile, strerror(errno));
1663 other = strtol(pid, &end, 0);
1664 if (end != pid + 10) {
1665 fprintf(stderr, "can't parse lock file %s\n",
1672 if (kill(other, 0) < 0 && errno == ESRCH) {
1673 /* stale lock file; unlink and try again */
1675 "unlinking stale lock file %s\n", lockfile);
1677 if (unlink(lockfile))
1678 /* If we fail to unlink, return EEXIST
1679 so we try the next display number.*/
1688 } else if (fd < 0) {
1689 fprintf(stderr, "failed to create lock file %s: %s\n",
1690 lockfile, strerror(errno));
1694 /* Subtle detail: we use the pid of the wayland
1695 * compositor, not the xserver in the lock file. */
1696 size = snprintf(pid, sizeof pid, "%10d\n", getpid());
1697 if (write(fd, pid, size) != size) {
1709 weston_xserver_destroy(struct wl_listener *l, void *data)
1711 struct weston_xserver *wxs =
1712 container_of(l, struct weston_xserver, destroy_listener);
1718 weston_xserver_shutdown(wxs);
1724 weston_xserver_init(struct weston_compositor *compositor)
1726 struct wl_display *display = compositor->wl_display;
1727 struct weston_xserver *mxs;
1728 char lockfile[256], display_name[8];
1730 mxs = malloc(sizeof *mxs);
1731 memset(mxs, 0, sizeof *mxs);
1733 mxs->process.cleanup = weston_xserver_cleanup;
1734 mxs->wl_display = display;
1735 mxs->compositor = compositor;
1740 if (create_lockfile(mxs->display, lockfile, sizeof lockfile) < 0) {
1741 if (errno == EAGAIN) {
1743 } else if (errno == EEXIST) {
1752 mxs->abstract_fd = bind_to_abstract_socket(mxs->display);
1753 if (mxs->abstract_fd < 0 && errno == EADDRINUSE) {
1759 mxs->unix_fd = bind_to_unix_socket(mxs->display);
1760 if (mxs->unix_fd < 0) {
1762 close(mxs->abstract_fd);
1767 snprintf(display_name, sizeof display_name, ":%d", mxs->display);
1768 fprintf(stderr, "xserver listening on display %s\n", display_name);
1769 setenv("DISPLAY", display_name, 1);
1771 mxs->loop = wl_display_get_event_loop(display);
1772 mxs->abstract_source =
1773 wl_event_loop_add_fd(mxs->loop, mxs->abstract_fd,
1775 weston_xserver_handle_event, mxs);
1777 wl_event_loop_add_fd(mxs->loop, mxs->unix_fd,
1779 weston_xserver_handle_event, mxs);
1781 wl_display_add_global(display, &xserver_interface, mxs, bind_xserver);
1783 mxs->destroy_listener.notify = weston_xserver_destroy;
1784 wl_signal_add(&compositor->destroy_signal, &mxs->destroy_listener);
1787 mxs->activate_listener.notify = weston_xserver_surface_activate;
1788 wl_signal_add(&compositor->activate_signal, &mxs->activate_listener);