[PATCH weston 09/16] Introduce new XWayland protocol and implementation

Tiago Vignatti tiago.vignatti at intel.com
Wed Dec 12 07:26:21 PST 2012


The new protocol features the separation of the X Window Manager from Wayland
compositor. Compared with the previous protocol, it aims to avoid mutual
deadlock where Weston waits for a reply to get xcb_get_property(), while X is
waiting in some wl_display_roundtrip(). Other advantages exist also like the
ease for replacing the decoration logics (border, cursors, icons etc) or even
the whole implementation of XWayland on different compositors.

A WM client now notifies the compositor about X Windows configuration
(wm.set_window) while X creates their Wayland surfaces. All the information is
combined (xserver.set_window_surface) inside the compositor which itself map
the windows on screen (eg create_shell_surface -> set_toplevel, at
window-manager.c).

The implementation consists of a new toytoolkit client, the weston-xwm. The
client at the moment is not using any toytoolkit drawing API; it simply
uses for its high-level abstraction and convenience. I have plans later
though, to replace the weston-xwm cursor settings and border decorations by
the ones toytoolkit provide.

Changes on XWayland X server side are needed as well. Some features are still
missing from the previous implementation though:

  #1 opaque region box (4496fd6a)
  #2 selection support (8e25a7eb)
  #3 window positioning (2aee1248)
  #4 drawing scheduling and window activation (21c685d9)

Signed-off-by: Tiago Vignatti <tiago.vignatti at intel.com>
---
 clients/Makefile.am           |   16 +-
 clients/xwm.c                 |  350 ++++++++++++++++++++---------------------
 clients/xwm.h                 |    8 +-
 configure.ac                  |    2 +-
 protocol/xserver.xml          |  107 ++++++++++++-
 src/xwayland/Makefile.am      |    5 +-
 src/xwayland/launcher.c       |   75 ++++++---
 src/xwayland/window-manager.c |  262 ++++++++++++++++++++++++++++++
 src/xwayland/xwayland.h       |   19 ++-
 9 files changed, 618 insertions(+), 226 deletions(-)
 create mode 100644 src/xwayland/window-manager.c

diff --git a/clients/Makefile.am b/clients/Makefile.am
index a4d09f9..d2eb4c3 100644
--- a/clients/Makefile.am
+++ b/clients/Makefile.am
@@ -1,6 +1,7 @@
 bin_PROGRAMS =					\
 	weston-info				\
-	$(terminal)
+	$(terminal)				\
+	$(xwm)
 
 noinst_PROGRAMS =				\
 	$(clients_programs)			\
@@ -74,6 +75,8 @@ endif
 
 screenshooter = weston-screenshooter
 
+xwm = weston-xwm
+
 noinst_LIBRARIES = libtoytoolkit.a
 
 libtoytoolkit_a_SOURCES =			\
@@ -165,6 +168,13 @@ weston_tablet_shell_SOURCES =			\
 	tablet-shell-protocol.c
 weston_tablet_shell_LDADD = $(toolkit_libs)
 
+weston_xwm_SOURCES =				\
+	xwm.h					\
+	xwm.c					\
+	xserver-client-protocol.h		\
+	xserver-protocol.c
+weston_xwm_LDADD = $(toolkit_libs)
+
 BUILT_SOURCES =					\
 	screenshooter-client-protocol.h		\
 	screenshooter-protocol.c		\
@@ -179,7 +189,9 @@ BUILT_SOURCES =					\
 	tablet-shell-client-protocol.h		\
 	tablet-shell-protocol.c			\
 	workspaces-client-protocol.h		\
-	workspaces-protocol.c
+	workspaces-protocol.c			\
+	xserver-client-protocol.h		\
+	xserver-protocol.c
 
 CLEANFILES = $(BUILT_SOURCES)
 endif
diff --git a/clients/xwm.c b/clients/xwm.c
index f7d3805..7d681f1 100644
--- a/clients/xwm.c
+++ b/clients/xwm.c
@@ -23,23 +23,27 @@
 #define _GNU_SOURCE
 
 #include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/socket.h>
 #include <sys/un.h>
-#include <fcntl.h>
-#include <errno.h>
 #include <unistd.h>
-#include <signal.h>
+#include <sys/epoll.h>
+#include <sys/wait.h>
 #include <X11/Xcursor/Xcursor.h>
 
-#include "xwayland.h"
-#include "window-manager.h"
+#include <wayland-client.h>
+#include "xwm.h"
+#include "window.h"
+#include "xserver-client-protocol.h"
+#include "../shared/cairo-util.h"
+#include "../shared/xwayland-hash.h"
 
-#include "../../shared/cairo-util.h"
-#include "../../shared/xwayland-hash.h"
-#include "../compositor.h"
-#include "xserver-server-protocol.h"
+struct xwm {
+	struct wl_registry *registry;
+	struct wl_display *wl_display;
+	struct wm *wm;
+	struct display *display;
+
+	struct weston_wm *weston_wm;
+};
 
 struct motif_wm_hints {
 	uint32_t flags;
@@ -97,9 +101,6 @@ struct weston_wm_window {
 	xcb_window_t id;
 	xcb_window_t frame_id;
 	cairo_surface_t *cairo_surface;
-	struct weston_surface *surface;
-	struct shell_surface *shsurf;
-	struct wl_listener surface_destroy_listener;
 	int properties_dirty;
 	int pid;
 	char *machine;
@@ -114,9 +115,6 @@ struct weston_wm_window {
 	int override_redirect;
 };
 
-static struct weston_wm_window *
-get_wm_window(struct weston_surface *surface);
-
 static void
 weston_wm_window_draw_decoration(struct weston_wm_window *window);
 
@@ -483,36 +481,21 @@ weston_wm_handle_configure_notify(struct weston_wm *wm, xcb_generic_event_t *eve
 	weston_wm_window_get_child_position(window, &x, &y);
 	window->x = configure_notify->x - x;
 	window->y = configure_notify->y - y;
-}
 
-static void
-weston_wm_kill_client(struct wl_listener *listener, void *data)
-{
-	struct weston_surface *surface = data;
-	struct weston_wm_window *window = get_wm_window(surface);
-	char name[1024];
-
-	if (!window)
-		return;
-
-	gethostname(name, 1024);
-
-	/* this is only one heuristic to guess the PID of a client is valid,
-	 * assuming it's compliant with icccm and ewmh. Non-compliants and
-	 * remote applications of course fail. */
-	if (!strcmp(window->machine, name) && window->pid != 0)
-		kill(window->pid, SIGKILL);
+	wm_set_window(wm->xwm->wm, window->id, window->x, window->y,
+		      configure_notify->width, configure_notify->height,
+		      window->override_redirect);
+	wl_display_flush(wm->xwm->wl_display);
 }
 
 static void
-weston_wm_window_activate(struct wl_listener *listener, void *data)
+set_state_activate(struct xwm *xwm, uint32_t id)
 {
-	struct weston_surface *surface = data;
-	struct weston_wm_window *window = get_wm_window(surface);
-	struct weston_wm *wm =
-		container_of(listener, struct weston_wm, activate_listener);
+	struct weston_wm *wm = xwm->weston_wm;
+	struct weston_wm_window *window;
 	xcb_client_message_event_t client_message;
 
+	window = hash_table_lookup(wm->window_hash, id);
 	if (window) {
 		client_message.response_type = XCB_CLIENT_MESSAGE;
 		client_message.format = 32;
@@ -541,6 +524,45 @@ weston_wm_window_activate(struct wl_listener *listener, void *data)
 		weston_wm_window_draw_decoration(wm->focus_window);
 }
 
+static void
+set_state_kill(struct xwm *xwm, uint32_t id)
+{
+        struct weston_wm *wm = xwm->weston_wm;
+        struct weston_wm_window *window;
+        char name[1024];
+
+        window = hash_table_lookup(wm->window_hash, id);
+        if (!window)
+                return;
+
+        gethostname(name, 1024);
+
+        /* this is only one heuristic to guess the PID of a client is valid,
+         * assuming it's compliant with icccm and ewmh. Non-compliants and
+         * remote applications of course fail. */
+        if (!strcmp(window->machine, name) && window->pid != 0)
+                kill(window->pid, SIGKILL);
+}
+
+static void
+get_window_state(void *data, struct wm *w, uint32_t id, enum wm_state state)
+{
+	struct xwm *xwm = data;
+
+	if (!xwm)
+		return;
+
+	switch (state) {
+	case WM_STATE_DEACTIVATE:
+		set_state_activate(xwm, 0);
+	case WM_STATE_ACTIVATE:
+		set_state_activate(xwm, id);
+		break;
+	case WM_STATE_KILL:
+		set_state_kill(xwm, id);
+		break;
+	}
+}
 static int
 our_resource(struct weston_wm *wm, uint32_t id)
 {
@@ -621,6 +643,11 @@ weston_wm_handle_map_request(struct weston_wm *wm, xcb_generic_event_t *event)
 			  wm->screen->root_visual,
 			  XCB_CW_EVENT_MASK, values);
 	xcb_reparent_window(wm->conn, window->id, window->frame_id, x, y);
+	hash_table_insert(wm->window_hash, window->frame_id, window);
+	wm_set_window(wm->xwm->wm, window->frame_id, window->x, window->y,
+			width, height, 0);
+
+	wl_display_flush(wm->xwm->wl_display);
 
 	values[0] = 0;
 	xcb_configure_window(wm->conn, window->id,
@@ -639,8 +666,6 @@ weston_wm_handle_map_request(struct weston_wm *wm, xcb_generic_event_t *event)
 							     window->frame_id,
 							     &wm->format_rgb,
 							     width, height);
-
-	hash_table_insert(wm->window_hash, window->frame_id, window);
 }
 
 static void
@@ -691,9 +716,7 @@ weston_wm_handle_unmap_notify(struct weston_wm *wm, xcb_generic_event_t *event)
 
 	if (wm->focus_window == window)
 		wm->focus_window = NULL;
-	if (window->surface)
-		wl_list_remove(&window->surface_destroy_listener.link);
-	window->surface = NULL;
+	/*TODO: need to send a message to remove the window on compositor */
 }
 
 static void
@@ -820,6 +843,9 @@ weston_wm_window_create(struct weston_wm *wm,
 	window->height = height;
 
 	hash_table_insert(wm->window_hash, id, window);
+	wm_set_window(wm->xwm->wm, window->id, window->x, window->y,
+		      width, height, window->override_redirect);
+	wl_display_flush(wm->xwm->wl_display);
 }
 
 static void
@@ -890,13 +916,6 @@ weston_wm_handle_reparent_notify(struct weston_wm *wm, xcb_generic_event_t *even
 	}
 }
 
-struct weston_seat *
-weston_wm_pick_seat(struct weston_wm *wm)
-{
-	return container_of(wm->server->compositor->seat_list.next,
-			    struct weston_seat, link);
-}
-
 static void
 weston_wm_window_handle_moveresize(struct weston_wm_window *window,
 				   xcb_client_message_event_t *client_message)
@@ -911,21 +930,13 @@ weston_wm_window_handle_moveresize(struct weston_wm_window *window,
 		THEME_LOCATION_RESIZING_BOTTOM_LEFT,
 		THEME_LOCATION_RESIZING_LEFT
 	};
-
 	struct weston_wm *wm = window->wm;
-	struct weston_seat *seat = weston_wm_pick_seat(wm);
 	int detail;
-	struct weston_shell_interface *shell_interface =
-		&wm->server->compositor->shell_interface;
-
-	if (seat->seat.pointer->button_count != 1 ||
-	    seat->seat.pointer->focus != &window->surface->surface)
-		return;
 
 	detail = client_message->data.data32[2];
 	switch (detail) {
 	case _NET_WM_MOVERESIZE_MOVE:
-		shell_interface->move(window->shsurf, seat);
+		wm_move(wm->xwm->wm, window->frame_id);
 		break;
 	case _NET_WM_MOVERESIZE_SIZE_TOPLEFT:
 	case _NET_WM_MOVERESIZE_SIZE_TOP:
@@ -935,7 +946,7 @@ weston_wm_window_handle_moveresize(struct weston_wm_window *window,
 	case _NET_WM_MOVERESIZE_SIZE_BOTTOM:
 	case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT:
 	case _NET_WM_MOVERESIZE_SIZE_LEFT:
-		shell_interface->resize(window->shsurf, seat, map[detail]);
+		wm_resize(wm->xwm->wm, window->frame_id, map[detail]);
 		break;
 	case _NET_WM_MOVERESIZE_CANCEL:
 		break;
@@ -964,7 +975,7 @@ weston_wm_handle_client_message(struct weston_wm *wm,
 		weston_wm_window_handle_moveresize(window, client_message);
 }
 
-enum cursor_type {
+enum xwm_cursor_type {
 	XWM_CURSOR_TOP,
 	XWM_CURSOR_BOTTOM,
 	XWM_CURSOR_LEFT,
@@ -1063,9 +1074,6 @@ static void
 weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event)
 {
 	xcb_button_press_event_t *button = (xcb_button_press_event_t *) event;
-	struct weston_shell_interface *shell_interface =
-		&wm->server->compositor->shell_interface;
-	struct weston_seat *seat = weston_wm_pick_seat(wm);
 	struct weston_wm_window *window;
 	enum theme_location location;
 	struct theme *t = wm->theme;
@@ -1087,7 +1095,7 @@ weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event)
 
 		switch (location) {
 		case THEME_LOCATION_TITLEBAR:
-			shell_interface->move(window->shsurf, seat);
+			wm_move(wm->xwm->wm, window->frame_id);
 			break;
 		case THEME_LOCATION_RESIZING_TOP:
 		case THEME_LOCATION_RESIZING_BOTTOM:
@@ -1097,8 +1105,7 @@ weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event)
 		case THEME_LOCATION_RESIZING_TOP_RIGHT:
 		case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
 		case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
-			shell_interface->resize(window->shsurf,
-						seat, location);
+			wm_resize(wm->xwm->wm, window->frame_id, location);
 			break;
 		default:
 			break;
@@ -1398,59 +1405,51 @@ weston_wm_create_wm_window(struct weston_wm *wm)
 				XCB_TIME_CURRENT_TIME);
 }
 
-struct weston_wm *
-weston_wm_create(struct weston_xserver *wxs)
+static void
+wm_func(struct task *task, uint32_t events)
+{
+	struct weston_wm *wm =
+		container_of(task, struct weston_wm, wm_task);
+
+	weston_wm_handle_event(0, 0, wm);
+}
+
+static void
+weston_wm_create(struct xwm *xwm, int fd)
 {
+	struct display *display = xwm->display;
 	struct weston_wm *wm;
-	struct wl_event_loop *loop;
 	xcb_screen_iterator_t s;
 	uint32_t values[1];
-	int sv[2];
 	xcb_atom_t supported[1];
 
 	wm = malloc(sizeof *wm);
 	if (wm == NULL)
-		return NULL;
+		return;
 
 	memset(wm, 0, sizeof *wm);
-	wm->server = wxs;
 	wm->window_hash = hash_table_create();
 	if (wm->window_hash == NULL) {
 		free(wm);
-		return NULL;
-	}
-
-	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
-		fprintf(stderr, "socketpair failed\n");
-		hash_table_destroy(wm->window_hash);
-		free(wm);
-		return NULL;
+		return;
 	}
 
-	xserver_send_client(wxs->resource, sv[1]);
-	wl_client_flush(wxs->resource->client);
-	close(sv[1]);
-	
 	/* xcb_connect_to_fd takes ownership of the fd. */
-	wm->conn = xcb_connect_to_fd(sv[0], NULL);
+	wm->conn = xcb_connect_to_fd(fd, NULL);
 	if (xcb_connection_has_error(wm->conn)) {
 		fprintf(stderr, "xcb_connect_to_fd failed\n");
-		close(sv[0]);
+		close(fd);
 		hash_table_destroy(wm->window_hash);
 		free(wm);
-		return NULL;
+		return;
 	}
 
+	wm->wm_task.run = wm_func;
+	display_watch_fd(display, fd, EPOLLIN, &wm->wm_task);
+
 	s = xcb_setup_roots_iterator(xcb_get_setup(wm->conn));
 	wm->screen = s.data;
 
-	loop = wl_display_get_event_loop(wxs->wl_display);
-	wm->source =
-		wl_event_loop_add_fd(loop, sv[0],
-				     WL_EVENT_READABLE,
-				     weston_wm_handle_event, wm);
-	wl_event_source_check(wm->source);
-
 	weston_wm_get_resources(wm);
 
 	values[0] =
@@ -1476,64 +1475,47 @@ weston_wm_create(struct weston_xserver *wxs)
 #endif
 	xcb_flush(wm->conn);
 
-	wm->activate_listener.notify = weston_wm_window_activate;
-	wl_signal_add(&wxs->compositor->activate_signal,
-		      &wm->activate_listener);
-	wm->kill_listener.notify = weston_wm_kill_client;
-	wl_signal_add(&wxs->compositor->kill_signal,
-		      &wm->kill_listener);
-
 	weston_wm_create_cursors(wm);
 	weston_wm_window_set_cursor(wm, wm->screen->root, XWM_CURSOR_LEFT_PTR);
 
-	fprintf(stderr, "created wm\n");
+	wm->xwm = xwm;
+	xwm->weston_wm = wm;
 
-	return wm;
+	fprintf(stderr, "weston-xwm: connected to X\n");
+	wm_is_ready(wm->xwm->wm);
 }
 
-void
+static void
 weston_wm_destroy(struct weston_wm *wm)
 {
 	/* FIXME: Free windows in hash. */
 	hash_table_destroy(wm->window_hash);
 	weston_wm_destroy_cursors(wm);
 	xcb_disconnect(wm->conn);
-	wl_event_source_remove(wm->source);
-	wl_list_remove(&wm->kill_listener.link);
 
 	free(wm);
 }
 
 static void
-surface_destroy(struct wl_listener *listener, void *data)
+get_configure(void *data, struct wm *w, uint32_t id, uint32_t edges,
+	      int width, int height)
 {
-	struct weston_wm_window *window =
-		container_of(listener,
-			     struct weston_wm_window, surface_destroy_listener);
-
-	fprintf(stderr, "surface for xid %d destroyed\n", window->id);
-}
-
-static struct weston_wm_window *
-get_wm_window(struct weston_surface *surface)
-{
-	struct wl_resource *resource = &surface->surface.resource;
-	struct wl_listener *listener;
-
-	listener = wl_signal_get(&resource->destroy_signal, surface_destroy);
-	if (listener)
-		return container_of(listener, struct weston_wm_window,
-				    surface_destroy_listener);
+	struct xwm *xwm = data;
+	struct weston_wm *wm = xwm->weston_wm;
+	struct theme *t = wm->theme;
+	struct weston_wm_window *window;
+	uint32_t values[2];
 
-	return NULL;
-}
+	window = hash_table_lookup(wm->window_hash, id);
 
-static void
-weston_wm_window_configure(struct weston_wm_window *window)
-{
-	struct weston_wm *wm = window->wm;
-	uint32_t values[2];
-	int width, height;
+	if (window->decorate) {
+		window->width = width - 2 * (t->margin + t->width);
+		window->height = height - 2 * t->margin -
+			t->titlebar_height - t->width;
+	} else {
+		window->width = width - 2 * t->margin;
+		window->height = height - 2 * t->margin;
+	}
 
 	values[0] = window->width;
 	values[1] = window->height;
@@ -1551,72 +1533,76 @@ weston_wm_window_configure(struct weston_wm_window *window)
 			     XCB_CONFIG_WINDOW_WIDTH |
 			     XCB_CONFIG_WINDOW_HEIGHT,
 			     values);
+	xcb_flush(wm->conn);
 
 	weston_wm_window_draw_decoration(window);
 }
 
 static void
-send_configure(struct weston_surface *surface,
-	       uint32_t edges, int32_t width, int32_t height)
+get_xserver(void *data, struct wm *w, int32_t fd)
 {
-	struct weston_wm_window *window = get_wm_window(surface);
-	struct theme *t = window->wm->theme;
-
-	if (window->decorate) {
-		window->width = width - 2 * (t->margin + t->width);
-		window->height = height - 2 * t->margin -
-			t->titlebar_height - t->width;
-	} else {
-		window->width = width - 2 * t->margin;
-		window->height = height - 2 * t->margin;
-	}
+	struct xwm *xwm = data;
 
-	weston_wm_window_configure(window);
+	weston_wm_create(xwm, fd);
 }
 
-static const struct weston_shell_client shell_client = {
-	send_configure
+static const struct wm_listener wm_listener = {
+	get_xserver,
+	get_configure,
+	get_window_state
 };
 
 static void
-xserver_set_window_id(struct wl_client *client, struct wl_resource *resource,
-		      struct wl_resource *surface_resource, uint32_t id)
+registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
+		       const char *interface, uint32_t version)
 {
-	struct weston_xserver *wxs = resource->data;
-	struct weston_wm *wm = wxs->wm;
-	struct wl_surface *surface = surface_resource->data;
-	struct weston_wm_window *window;
-	struct weston_shell_interface *shell_interface =
-		&wm->server->compositor->shell_interface;
-
-	if (client != wxs->client)
-		return;
+	struct xwm *xwm = data;
 
-	window = hash_table_lookup(wm->window_hash, id);
-	if (window == NULL) {
-		fprintf(stderr, "set_window_id for unknown window %d\n", id);
-		return;
+	if (!strcmp(interface, "wm")) {
+		xwm->wm = wl_registry_bind(registry, id,
+					&wm_interface, 1);
+		wm_add_listener(xwm->wm, &wm_listener, xwm);
 	}
+}
 
-	fprintf(stderr, "set_window_id %d for surface %p\n", id, surface);
+static void
+sigchild_handler(int s)
+{
+	int status;
+	pid_t pid;
 
-	weston_wm_window_read_properties(window);
+	while (pid = waitpid(-1, &status, WNOHANG), pid > 0)
+		fprintf(stderr, "child %d exited\n", pid);
+}
 
-	window->surface = (struct weston_surface *) surface;
-	window->surface_destroy_listener.notify = surface_destroy;
-	wl_signal_add(&surface->resource.destroy_signal,
-		      &window->surface_destroy_listener);
+static const struct wl_registry_listener registry_listener = {
+	registry_handle_global
+};
 
-	weston_wm_window_draw_decoration(window);
+int
+main(int argc, char **argv)
+{
+	struct xwm xwm = { 0 };
 
-	window->shsurf =
-		shell_interface->create_shell_surface(shell_interface->shell,
-						      window->surface,
-						      &shell_client);
+	xwm.display = display_create(argc, argv);
+	if (xwm.display == NULL) {
+		fprintf(stderr, "failed to create display: %m\n");
+		return -1;
+	}
+	display_set_user_data(xwm.display, &xwm);
+
+	xwm.wl_display = display_get_display(xwm.display);
+	xwm.registry = wl_display_get_registry(xwm.wl_display);
+	wl_registry_add_listener(xwm.registry, &registry_listener, &xwm);
+	wl_display_dispatch(xwm.wl_display);
+
+	signal(SIGCHLD, sigchild_handler);
 
-	shell_interface->set_toplevel(window->shsurf);
+	display_run(xwm.display);
+
+	weston_wm_destroy(xwm.weston_wm);
+	display_destroy(xwm.display);
+
+	return 0;
 }
 
-const struct xserver_interface xserver_implementation = {
-	xserver_set_window_id
-};
diff --git a/clients/xwm.h b/clients/xwm.h
index 3409fa2..8862fc4 100644
--- a/clients/xwm.h
+++ b/clients/xwm.h
@@ -24,21 +24,21 @@
 #include <xcb/xfixes.h>
 #include <cairo/cairo-xcb.h>
 
+#include "window.h"
+
 struct weston_wm {
+	struct xwm *xwm;
+	struct task wm_task;
 	xcb_connection_t *conn;
 	const xcb_query_extension_reply_t *xfixes;
-	struct wl_event_source *source;
 	xcb_screen_t *screen;
 	struct hash_table *window_hash;
-	struct weston_xserver *server;
 	xcb_window_t wm_window;
 	struct weston_wm_window *focus_window;
 	struct theme *theme;
 	xcb_cursor_t *cursors;
 	int last_cursor;
 	xcb_render_pictforminfo_t format_rgb, format_rgba;
-	struct wl_listener activate_listener;
-	struct wl_listener kill_listener;
 
 	xcb_window_t selection_window;
 	xcb_window_t selection_owner;
diff --git a/configure.ac b/configure.ac
index 8cff8dc..6a8f975 100644
--- a/configure.ac
+++ b/configure.ac
@@ -196,7 +196,7 @@ AM_CONDITIONAL(BUILD_CLIENTS, test x$enable_clients = xyes)
 if test x$enable_clients = xyes; then
   AC_DEFINE([BUILD_CLIENTS], [1], [Build the Wayland clients])
 
-  PKG_CHECK_MODULES(CLIENT, [wayland-client cairo >= 1.10.0 xkbcommon wayland-cursor])
+  PKG_CHECK_MODULES(CLIENT, [wayland-client cairo >= 1.10.0 xkbcommon wayland-cursor xcursor])
   PKG_CHECK_MODULES(WESTON_INFO, [wayland-client])
 
   PKG_CHECK_MODULES(POPPLER, [poppler-glib glib-2.0 gobject-2.0 gio-2.0 ],
diff --git a/protocol/xserver.xml b/protocol/xserver.xml
index 9e25f5c..2b3d614 100644
--- a/protocol/xserver.xml
+++ b/protocol/xserver.xml
@@ -1,18 +1,121 @@
 <protocol name="xserver">
 
   <interface name="xserver" version="1">
-    <request name="set_window_id">
+    <description summary="global object to connect X with Wayland">
+    </description>
+
+    <request name="set_window_surface">
+      <description summary="specify window surface">
+	It specifies the assignment between an X Window 'id' and an Wayland
+	'surface'. The compositor will cache it internally, then create a
+	shell_surface which will be mapped on the screen based on the
+	information the wm interface will provide for the given window.
+      </description>
+
       <arg name="surface" type="object" interface="wl_surface"/>
       <arg name="id" type="uint"/>
     </request>
 
+    <event name="wm">
+      <description summary="send window manager fd to X">
+	This is one tip of the opened socketpair; the other has to be sent via
+	wm interface in order to plug both X and Window Manager (WM). This
+	event must be used only once in principle.
+      </description>
+      <arg name="fd" type="fd"/>
+    </event>
+
     <event name="client">
+      <description summary="send client to be listened on opened fd">
+	This event should be used to send the first real X client fd to the X
+	server; this is the client that triggered X initialization but had to
+	wait for the WM gets connected before. A good practice is to call this
+	event after receiving wm.is_ready.
+      </description>
       <arg name="fd" type="fd"/>
     </event>
+  </interface>
+
+  <interface name="wm" version="1">
+    <description summary="XWayland window manager global object">
+    </description>
+
+    <request name="is_ready">
+      <description summary="notifies that WM is ready and connected to X">
+      </description>
+    </request>
+
+    <request name="set_window">
+      <description summary="specify window id, geometries and positioning">
+	Notifies the compositor about X Window id and its configuration
+	regarding size and location on the screen. The compositor is
+	responsible for looking the surface based on the id and map it on the
+	screen. The x and y arguments specify the global position of the
+	surface on the current output, exactly how X11 works. The flags
+	argument can be used to tell the type of window or control whether the
+	surface will receive the keyboard focus or not, after being mapped.
+      </description>
+
+      <arg name="id" type="uint"/>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+      <arg name="flags" type="uint"/>
+    </request>
+
+    <request name="move">
+      <arg name="id" type="uint"/>
+    </request>
+
+    <request name="resize">
+      <arg name="id" type="uint"/>
+      <arg name="edges" type="uint"/>
+    </request>
+
+    <event name="xserver">
+      <description summary="send X fd to window manager">
+	This is the other tip of the socketpair used for connecting X and
+	window manager with each other; see xserver.wm.
+      </description>
 
-    <event name="listen_socket">
       <arg name="fd" type="fd"/>
     </event>
+
+    <event name="configure">
+      <description summary="suggest resize">
+	The configure event asks the client to resize its surface. The size is
+	a hint, in the sense that the client is free to ignore it if it
+	doesn't resize, pick a smaller size (to satisfy aspect ration or
+	resize in steps of NxM pixels). The client is free to dismiss all but
+	the last configure event it received.
+      </description>
+
+      <arg name="id" type="uint"/>
+      <arg name="edges" type="uint"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </event>
+
+    <enum name="state">
+      <description summary="window states">
+        Describes the window state the Wayland compositor desires.
+      </description>
+
+      <entry name="deactivate" value="0" summary="deactivate all the windows"/>
+      <entry name="activate" value="1" summary="activate and give focus"/>
+      <entry name="kill" value="2" summary="send a kill signal"/>
+    </enum>
+
+    <event name="window_state">
+      <description summary="notifies window manager about window state">
+	'activate' and 'kill' require 'id' argument while 'deactivate' does
+	not.
+      </description>
+
+      <arg name="id" type="uint"/>
+      <arg name="state" type="uint"/>
+    </event>
   </interface>
 
 </protocol>
diff --git a/src/xwayland/Makefile.am b/src/xwayland/Makefile.am
index 10ee641..cd222d1 100644
--- a/src/xwayland/Makefile.am
+++ b/src/xwayland/Makefile.am
@@ -1,7 +1,5 @@
 AM_CPPFLAGS =					\
-	-DDATADIR='"$(datadir)"'		\
-	-DMODULEDIR='"$(moduledir)"'		\
-	-DLIBEXECDIR='"$(libexecdir)"'		\
+	-DBINDIR='"$(bindir)"'			\
 	-DXSERVER_PATH='"@XSERVER_PATH@"'
 
 moduledir = @libdir@/weston
@@ -19,7 +17,6 @@ xwayland_la_CFLAGS =				\
 	$(CAIRO_CFLAGS)
 xwayland_la_SOURCES =				\
 	xwayland.h				\
-	window-manager.h			\
 	window-manager.c			\
 	launcher.c				\
 	xserver-protocol.c			\
diff --git a/src/xwayland/launcher.c b/src/xwayland/launcher.c
index ddd9640..dc28746 100644
--- a/src/xwayland/launcher.c
+++ b/src/xwayland/launcher.c
@@ -33,21 +33,41 @@
 #include <signal.h>
 
 #include "xwayland.h"
+#include "../../shared/xwayland-hash.h"
 #include "xserver-server-protocol.h"
 
+static void
+wm_sigchld(struct weston_process *process, int status)
+{
+	struct weston_xserver *wxs =
+		container_of(process, struct weston_xserver, wm_child.process);
+
+	wxs->wm_child.process.pid = 0;
+	wxs->wm_child.client = NULL;
+
+	wxs->wm_resource = NULL;
+}
 
 static int
 weston_xserver_handle_event(int listen_fd, uint32_t mask, void *data)
 {
 	struct weston_xserver *wxs = data;
 	char display[8], s[8];
-	int sv[2], client_fd;
+	int sv[2], swm[2], client_fd;
+	const char *wm_exe = BINDIR "/weston-xwm";
 
 	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
 		weston_log("socketpair failed\n");
 		return 1;
 	}
 
+	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, swm) < 0) {
+		weston_log("socketpair failed\n");
+		return 1;
+	}
+	wxs->wm_xfd = swm[0];
+	wxs->wm_fd = swm[1];
+
 	wxs->process.pid = fork();
 	switch (wxs->process.pid) {
 	case 0:
@@ -84,6 +104,14 @@ weston_xserver_handle_event(int listen_fd, uint32_t mask, void *data)
 
 		wl_event_source_remove(wxs->abstract_source);
 		wl_event_source_remove(wxs->unix_source);
+
+		wxs->wm_child.client = weston_client_launch(wxs->compositor,
+				&wxs->wm_child.process, wm_exe, wm_sigchld);
+		if (!wxs->wm_child.client) {
+			weston_log("failed to fork XWM\n");
+			return 1;
+		}
+		weston_log("forked Weston XWM, pid %d\n", wxs->wm_child.process.pid);
 		break;
 
 	case -1:
@@ -109,8 +137,6 @@ weston_xserver_shutdown(struct weston_xserver *wxs)
 	}
 	close(wxs->abstract_fd);
 	close(wxs->unix_fd);
-	if (wxs->wm)
-		weston_wm_destroy(wxs->wm);
 	wxs->loop = NULL;
 }
 
@@ -134,17 +160,10 @@ weston_xserver_cleanup(struct weston_process *process, int status)
 				     WL_EVENT_READABLE,
 				     weston_xserver_handle_event, wxs);
 
-	if (wxs->wm) {
-		weston_log("xserver exited, code %d\n", status);
-		weston_wm_destroy(wxs->wm);
-		wxs->wm = NULL;
-	} else {
-		/* If the X server crashes before it binds to the
-		 * xserver interface, shut down and don't try
-		 * again. */
-		weston_log("xserver crashing too fast: %d\n", status);
-		weston_xserver_shutdown(wxs);
-	}
+	/* If the X server crashes before it binds to the xserver interface,
+	 * shut down and don't try again. */
+	weston_log("xserver crashing too fast: %d\n", status);
+	weston_xserver_shutdown(wxs);
 }
 
 static void
@@ -153,22 +172,27 @@ bind_xserver(struct wl_client *client,
 {
 	struct weston_xserver *wxs = data;
 
-	/* If it's a different client than the xserver we launched,
-	 * don't start the wm. */
-	if (client != wxs->client)
-		return;
-
 	wxs->resource = 
 		wl_client_add_object(client, &xserver_interface,
 				     &xserver_implementation, id, wxs);
+}
 
-	wxs->wm = weston_wm_create(wxs);
-	if (wxs->wm == NULL) {
-		weston_log("failed to create wm\n");
-	}
+static void
+bind_wm(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+	struct weston_xserver *wxs = data;
+
+	wxs->wm_resource = wl_client_add_object(client, &wm_interface,
+						&wm_implementation, id, wxs);
+
+	/* sending X fd (from the socketpair) to client WM, which will connect
+	 * onto it and initialize the first WM related procedures */
+	wm_send_xserver(wxs->wm_resource, wxs->wm_xfd);
 
-	xserver_send_listen_socket(wxs->resource, wxs->abstract_fd);
-	xserver_send_listen_socket(wxs->resource, wxs->unix_fd);
+	/* meanwhile X will be in fact managing the WM connecting by sending
+	 * the other socketpair file descriptor (via (AddClientOnOpenFD) */
+	xserver_send_wm(wxs->resource, wxs->wm_fd);
+	close(wxs->wm_fd);
 }
 
 static int
@@ -373,6 +397,7 @@ module_init(struct weston_compositor *compositor)
 				     weston_xserver_handle_event, wxs);
 
 	wl_display_add_global(display, &xserver_interface, wxs, bind_xserver);
+	wl_display_add_global(display, &wm_interface, wxs, bind_wm);
 
 	wxs->destroy_listener.notify = weston_xserver_destroy;
 	wl_signal_add(&compositor->destroy_signal, &wxs->destroy_listener);
diff --git a/src/xwayland/window-manager.c b/src/xwayland/window-manager.c
new file mode 100644
index 0000000..0b582a5
--- /dev/null
+++ b/src/xwayland/window-manager.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright © 2011-2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Tiago Vignatti
+ */
+
+#include <stdlib.h>
+#include "xwayland.h"
+
+#include "../../shared/xwayland-hash.h"
+#include "xserver-server-protocol.h"
+
+struct xserver_window {
+	struct wl_surface *surface;
+	struct weston_xserver *wxs;
+	struct wl_listener surface_destroy_listener;
+	struct shell_surface *shsurf;
+
+	int id;
+	int x, y;
+	int width, height;
+	int flags;
+};
+
+static void
+surface_destroy(struct wl_listener *listener, void *data)
+{
+	struct xserver_window *window = container_of(listener,
+			struct xserver_window, surface_destroy_listener);
+
+	fprintf(stderr, "surface for xid %d destroyed\n", window->id);
+}
+
+static struct xserver_window *
+get_xserver_window(struct weston_surface *surface)
+{
+	struct wl_resource *resource = &surface->surface.resource;
+	struct wl_listener *listener;
+
+	listener = wl_signal_get(&resource->destroy_signal, surface_destroy);
+	if (listener)
+		return container_of(listener, struct xserver_window,
+				    surface_destroy_listener);
+
+	return NULL;
+}
+
+static void
+send_configure(struct weston_surface *surface, uint32_t edges,
+		int32_t width, int32_t height)
+{
+	struct xserver_window *window = get_xserver_window(surface);
+	struct weston_xserver *wxs = window->wxs;
+
+	wm_send_configure(wxs->wm_resource, window->id, edges, width, height);
+}
+
+static const struct weston_shell_client shell_client = {
+	send_configure
+};
+
+static void
+xserver_get_window_surface(struct wl_client *client,
+			   struct wl_resource *resource,
+			   struct wl_resource *surface_resource, uint32_t id)
+
+{
+	struct weston_xserver *wxs = resource->data;
+	struct wl_surface *surface = surface_resource->data;
+	struct weston_surface *weston_surface =
+		(struct weston_surface *) surface;
+	struct xserver_window *window;
+	struct weston_shell_interface *shell_interface =
+		&wxs->compositor->shell_interface;
+
+	window = hash_table_lookup(wxs->window_hash, id);
+	if (window == NULL) {
+		fprintf(stderr, "set_window_id for unknown window %d\n", id);
+		return;
+	}
+
+	fprintf(stderr, "set_window_id %d for surface %p\n", id, surface);
+
+//	weston_wm_window_read_properties(window);
+
+	window->surface = surface;
+	window->surface_destroy_listener.notify = surface_destroy;
+	wl_signal_add(&surface->resource.destroy_signal,
+		      &window->surface_destroy_listener);
+
+//	weston_wm_window_draw_decoration(window);
+
+	window->shsurf =
+		shell_interface->create_shell_surface(shell_interface->shell,
+						      weston_surface,
+						      &shell_client);
+
+	shell_interface->set_toplevel(window->shsurf);
+}
+
+const struct xserver_interface xserver_implementation = {
+	xserver_get_window_surface
+};
+
+static void
+wm_get_window(struct wl_client *client, struct wl_resource *resource,
+		uint32_t id, int x, int y, int width, int height, uint32_t flags)
+{
+	struct weston_xserver *wxs = resource->data;
+	struct xserver_window *w;
+
+	fprintf(stderr, "%s: ", __func__);
+
+	w = hash_table_lookup(wxs->window_hash, id);
+	if (!w) {
+		w = malloc(sizeof *w);
+		if (!w) {
+			weston_log("malloc error\n");
+			return;
+		}
+		hash_table_insert(wxs->window_hash, id, w);
+		w->shsurf = NULL;
+		w->wxs = wxs;
+		w->id = id;
+		fprintf(stderr, "insert: %d, flags: %d\n", id, flags);
+	} else
+		fprintf(stderr, "found: %d, flags: %d\n", id, flags);
+
+	w->x = x;
+	w->y = y;
+	w->width = width;
+	w->height = height;
+	w->flags = flags;
+}
+
+static void
+weston_wm_activate_client(struct wl_listener *listener, void *data)
+{
+	struct weston_surface *surface = data;
+	struct weston_xserver *wxs = container_of(listener,
+			struct weston_xserver, activate_listener);
+
+	struct xserver_window *window = get_xserver_window(surface);
+
+	if (window)
+		wm_send_window_state(wxs->wm_resource,
+				     window->id, WM_STATE_ACTIVATE);
+	else
+		wm_send_window_state(wxs->wm_resource, 0, WM_STATE_DEACTIVATE);
+
+}
+
+static void
+weston_wm_kill_client(struct wl_listener *listener, void *data)
+{
+	struct weston_surface *surface = data;
+	struct weston_xserver *wxs = container_of(listener,
+			struct weston_xserver, kill_listener);
+
+	struct xserver_window *window = get_xserver_window(surface);
+
+	if (window)
+		wm_send_window_state(wxs->wm_resource,
+				window->id, WM_STATE_KILL);
+}
+
+static void
+wm_get_ready(struct wl_client *client, struct wl_resource *resource)
+{
+	struct weston_xserver *wxs = resource->data;
+
+	/* sending now the X display connection together with the actual first
+	 * X client that got connected */
+	xserver_send_client(wxs->resource, wxs->abstract_fd);
+	xserver_send_client(wxs->resource, wxs->unix_fd);
+
+	wxs->window_hash = hash_table_create();
+	if (wxs->window_hash == NULL)
+		return;
+
+	wxs->activate_listener.notify = weston_wm_activate_client;
+	wl_signal_add(&wxs->compositor->activate_signal,
+		      &wxs->activate_listener);
+
+	wxs->kill_listener.notify = weston_wm_kill_client;
+	wl_signal_add(&wxs->compositor->kill_signal,
+		      &wxs->kill_listener);
+}
+
+static struct weston_seat *
+weston_wm_pick_seat(struct weston_xserver *wxs)
+{
+	return container_of(wxs->compositor->seat_list.next,
+			    struct weston_seat, link);
+}
+
+static void
+wm_get_move(struct wl_client *client, struct wl_resource *resource,
+	    uint32_t id)
+{
+	struct weston_xserver *wxs = resource->data;
+	struct weston_shell_interface *shell_interface =
+		&wxs->compositor->shell_interface;
+	struct weston_seat *seat = weston_wm_pick_seat(wxs);
+	struct xserver_window *window;
+
+	window = hash_table_lookup(wxs->window_hash, id);
+	if (!window)
+		return;
+
+        if (seat->seat.pointer->button_count != 1 ||
+            seat->seat.pointer->focus != window->surface)
+                return;
+
+	shell_interface->move(window->shsurf, seat);
+}
+
+static void
+wm_get_resize(struct wl_client *client, struct wl_resource *resource,
+	      uint32_t id, uint32_t location)
+{
+	struct weston_xserver *wxs = resource->data;
+	struct weston_shell_interface *shell_interface =
+		&wxs->compositor->shell_interface;
+	struct weston_seat *seat = weston_wm_pick_seat(wxs);
+	struct xserver_window *window;
+
+	window = hash_table_lookup(wxs->window_hash, id);
+	if (!window)
+		return;
+
+        if (seat->seat.pointer->button_count != 1 ||
+            seat->seat.pointer->focus != window->surface)
+                return;
+
+	shell_interface->resize(window->shsurf, seat, location);
+}
+
+const struct wm_interface wm_implementation = {
+	wm_get_ready,
+	wm_get_window,
+	wm_get_move,
+	wm_get_resize
+};
diff --git a/src/xwayland/xwayland.h b/src/xwayland/xwayland.h
index f7e6216..400cdb7 100644
--- a/src/xwayland/xwayland.h
+++ b/src/xwayland/xwayland.h
@@ -36,13 +36,20 @@ struct weston_xserver {
 	struct wl_resource *resource;
 	struct wl_client *client;
 	struct weston_compositor *compositor;
-	struct weston_wm *wm;
 	struct wl_listener destroy_listener;
+
+	/* window manager related */
+	int wm_fd, wm_xfd;
+	struct {
+		struct weston_process process;
+		struct wl_client *client;
+	} wm_child;
+	struct wl_resource *wm_resource;
+	struct wl_resource *wm_conn_resource;
+	struct hash_table *window_hash;
+	struct wl_listener activate_listener;
+	struct wl_listener kill_listener;
 };
 
 extern const struct xserver_interface xserver_implementation;
-
-struct weston_wm *
-weston_wm_create(struct weston_xserver *wxs);
-void
-weston_wm_destroy(struct weston_wm *wm);
+extern const struct wm_interface wm_implementation;
-- 
1.7.9.5



More information about the wayland-devel mailing list