[PATCH weston 13/17] Introduce new XWayland protocol and implementation
Tiago Vignatti
tiago.vignatti at intel.com
Fri Nov 30 11:20:08 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 | 348 ++++++++++++++++++++---------------------
clients/xwm.h | 8 +-
configure.ac | 2 +-
protocol/xserver.xml | 104 +++++++++++-
src/xwayland/Makefile.am | 5 +-
src/xwayland/launcher.c | 75 ++++++---
src/xwayland/window-manager.c | 259 ++++++++++++++++++++++++++++++
src/xwayland/xwayland.h | 19 ++-
9 files changed, 610 insertions(+), 226 deletions(-)
create mode 100644 src/xwayland/window-manager.c
diff --git a/clients/Makefile.am b/clients/Makefile.am
index fd83a29..d7e172d 100644
--- a/clients/Makefile.am
+++ b/clients/Makefile.am
@@ -1,6 +1,7 @@
bin_PROGRAMS = \
weston-info \
- $(terminal)
+ $(terminal) \
+ $(xwm)
noinst_PROGRAMS = \
$(clients_programs) \
@@ -77,6 +78,8 @@ endif
screenshooter = weston-screenshooter
+xwm = weston-xwm
+
noinst_LIBRARIES = libtoytoolkit.a
libtoytoolkit_a_SOURCES = \
@@ -162,6 +165,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 \
@@ -176,7 +186,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..0d0a413 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,43 @@ 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_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 +641,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 +664,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 +714,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 +841,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 +914,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 +928,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 +944,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 +973,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 +1072,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 +1093,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 +1103,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 +1403,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 +1473,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 +1531,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, ®istry_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 7329c06..d1ca660 100644
--- a/configure.ac
+++ b/configure.ac
@@ -202,7 +202,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])
CLIENT_CFLAGS="$CLIENT_CFLAGS $IMAGE_CFLAGS"
diff --git a/protocol/xserver.xml b/protocol/xserver.xml
index 9e25f5c..907c882 100644
--- a/protocol/xserver.xml
+++ b/protocol/xserver.xml
@@ -1,18 +1,118 @@
<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="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">
+ </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 eb4b9e8..32ab1dd 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
@@ -15,7 +13,6 @@ xwayland_la_LIBADD = \
xwayland_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_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 59154a3..f420065 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
@@ -370,6 +394,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..4ffa533
--- /dev/null
+++ b/src/xwayland/window-manager.c
@@ -0,0 +1,259 @@
+/*
+ * 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);
+}
+
+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