[PATCH weston 09/16] Introduce new XWayland protocol and implementation
Tiago Vignatti
tiago.vignatti at intel.com
Wed Dec 19 11:32:19 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.
There are now three interfaces. 'xserver' and 'wm' interfaces are the global
object for connecting and initializing X and WM respectively. In special 'wm'
has a request wm.create_xwindow for instantiate the third interface,
'wm_xwin'.
A WM client now notifies the compositor about X Windows configuration
(wm_xwin.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
#2 selection support
#3 window positioning
#4 drawing scheduling and window activation
Signed-off-by: Tiago Vignatti <tiago.vignatti at intel.com>
---
clients/Makefile.am | 16 +-
clients/xwm.c | 455 ++++++++++++++++++++---------------------
clients/xwm.h | 8 +-
configure.ac | 2 +-
protocol/xserver.xml | 131 +++++++++++-
src/xwayland/Makefile.am | 5 +-
src/xwayland/launcher.c | 75 ++++---
src/xwayland/window-manager.c | 287 ++++++++++++++++++++++++++
src/xwayland/xwayland.h | 18 +-
9 files changed, 720 insertions(+), 277 deletions(-)
create mode 100644 src/xwayland/window-manager.c
diff --git a/clients/Makefile.am b/clients/Makefile.am
index c1b65ce..022e791 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 = \
@@ -168,6 +171,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 \
@@ -182,7 +192,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..4345d7d 100644
--- a/clients/xwm.c
+++ b/clients/xwm.c
@@ -23,23 +23,49 @@
#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"
+
+struct xwm {
+ struct wl_registry *registry;
+ struct wl_display *wl_display;
+ struct wm *wm;
+ struct wm_xwin *wm_xwin;
+ struct display *display;
+
+ struct weston_wm *weston_wm;
+};
-#include "../../shared/cairo-util.h"
-#include "../../shared/xwayland-hash.h"
-#include "../compositor.h"
-#include "xserver-server-protocol.h"
+struct weston_wm_window {
+ struct weston_wm *wm;
+ xcb_window_t id;
+ xcb_window_t frame_id;
+ struct wm_xwin *xwin;
+ struct wm_xwin *xwin_frame;
+ cairo_surface_t *cairo_surface;
+ int properties_dirty;
+ int pid;
+ char *machine;
+ char *class;
+ char *name;
+ struct weston_wm_window *transient_for;
+ uint32_t protocols;
+ xcb_atom_t type;
+ int width, height;
+ int x, y;
+ int decorate;
+ int override_redirect;
+};
struct motif_wm_hints {
uint32_t flags;
@@ -90,33 +116,6 @@ struct motif_wm_hints {
#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */
#define _NET_WM_MOVERESIZE_CANCEL 11 /* cancel operation */
-
-
-struct weston_wm_window {
- struct weston_wm *wm;
- 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;
- char *class;
- char *name;
- struct weston_wm_window *transient_for;
- uint32_t protocols;
- xcb_atom_t type;
- int width, height;
- int x, y;
- int decorate;
- 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,34 +482,88 @@ 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;
+
+ wm_xwin_set_window(window->xwin, window->x, window->y,
+ configure_notify->width, configure_notify->height,
+ window->override_redirect);
+ wl_display_flush(wm->xwm->wl_display);
+}
+
+static int
+our_resource(struct weston_wm *wm, uint32_t id)
+{
+ const xcb_setup_t *setup;
+
+ setup = xcb_get_setup(wm->conn);
+
+ return (id & ~setup->resource_id_mask) == setup->resource_id_base;
+}
+
+#define ICCCM_WITHDRAWN_STATE 0
+#define ICCCM_NORMAL_STATE 1
+#define ICCCM_ICONIC_STATE 3
+
+static void
+weston_wm_window_set_state(struct weston_wm_window *window, int32_t state)
+{
+ struct weston_wm *wm = window->wm;
+ uint32_t property[2];
+
+ property[0] = state;
+ property[1] = XCB_WINDOW_NONE;
+
+ xcb_change_property(wm->conn,
+ XCB_PROP_MODE_REPLACE,
+ window->id,
+ wm->atom.wm_state,
+ wm->atom.wm_state,
+ 32, /* format */
+ 2, property);
}
static void
-weston_wm_kill_client(struct wl_listener *listener, void *data)
+handle_configure(void *data, struct wm_xwin *xwin, uint32_t edges,
+ int width, int height)
{
- struct weston_surface *surface = data;
- struct weston_wm_window *window = get_wm_window(surface);
- char name[1024];
+ struct weston_wm_window *window = data;
+ struct weston_wm *wm = window->wm;
+ struct theme *t = wm->theme;
+ uint32_t values[2];
- if (!window)
- return;
+ 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;
+ xcb_configure_window(wm->conn,
+ window->id,
+ XCB_CONFIG_WINDOW_WIDTH |
+ XCB_CONFIG_WINDOW_HEIGHT,
+ values);
- gethostname(name, 1024);
+ weston_wm_window_get_frame_size(window, &width, &height);
+ values[0] = width;
+ values[1] = height;
+ xcb_configure_window(wm->conn,
+ window->frame_id,
+ XCB_CONFIG_WINDOW_WIDTH |
+ XCB_CONFIG_WINDOW_HEIGHT,
+ values);
+ xcb_flush(wm->conn);
- /* 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);
+ weston_wm_window_draw_decoration(window);
}
static void
-weston_wm_window_activate(struct wl_listener *listener, void *data)
+set_state_activate(struct xwm *xwm, struct weston_wm_window *window)
{
- 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;
xcb_client_message_event_t client_message;
if (window) {
@@ -541,38 +594,40 @@ weston_wm_window_activate(struct wl_listener *listener, void *data)
weston_wm_window_draw_decoration(wm->focus_window);
}
-static int
-our_resource(struct weston_wm *wm, uint32_t id)
+static void
+set_state_kill(struct weston_wm_window *window)
{
- const xcb_setup_t *setup;
+ char name[1024];
- setup = xcb_get_setup(wm->conn);
+ gethostname(name, 1024);
- return (id & ~setup->resource_id_mask) == setup->resource_id_base;
+ /* 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);
}
-#define ICCCM_WITHDRAWN_STATE 0
-#define ICCCM_NORMAL_STATE 1
-#define ICCCM_ICONIC_STATE 3
-
static void
-weston_wm_window_set_state(struct weston_wm_window *window, int32_t state)
+handle_state(void *data, struct wm_xwin *xwin, enum wm_xwin_state state)
{
- struct weston_wm *wm = window->wm;
- uint32_t property[2];
+ struct weston_wm_window *window = data;
- property[0] = state;
- property[1] = XCB_WINDOW_NONE;
-
- xcb_change_property(wm->conn,
- XCB_PROP_MODE_REPLACE,
- window->id,
- wm->atom.wm_state,
- wm->atom.wm_state,
- 32, /* format */
- 2, property);
+ switch (state) {
+ case WM_XWIN_STATE_ACTIVATE:
+ set_state_activate(window->wm->xwm, window);
+ break;
+ case WM_XWIN_STATE_KILL:
+ set_state_kill(window);
+ break;
+ }
}
+static const struct wm_xwin_listener wm_xwin_listener = {
+ handle_configure,
+ handle_state
+};
+
static void
weston_wm_handle_map_request(struct weston_wm *wm, xcb_generic_event_t *event)
{
@@ -622,6 +677,14 @@ weston_wm_handle_map_request(struct weston_wm *wm, xcb_generic_event_t *event)
XCB_CW_EVENT_MASK, values);
xcb_reparent_window(wm->conn, window->id, window->frame_id, x, y);
+ window->xwin_frame = wm_create_xwindow(wm->xwm->wm, window->frame_id);
+ wm_xwin_add_listener(window->xwin_frame, &wm_xwin_listener, window);
+ hash_table_insert(wm->window_hash, window->frame_id, window);
+ wm_xwin_set_window(window->xwin_frame, window->x, window->y,
+ width, height, 0);
+
+ wl_display_flush(wm->xwm->wl_display);
+
values[0] = 0;
xcb_configure_window(wm->conn, window->id,
XCB_CONFIG_WINDOW_BORDER_WIDTH, values);
@@ -639,8 +702,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 +752,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
@@ -819,7 +878,13 @@ weston_wm_window_create(struct weston_wm *wm,
window->width = width;
window->height = height;
+ window->xwin = wm_create_xwindow(wm->xwm->wm, id);
+ wm_xwin_add_listener(window->xwin, &wm_xwin_listener, window);
hash_table_insert(wm->window_hash, id, window);
+ wm_xwin_set_window(window->xwin, window->x, window->y,
+ width, height, window->override_redirect);
+
+ wl_display_flush(wm->xwm->wl_display);
}
static void
@@ -890,13 +955,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 +969,12 @@ 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_xwin_move(window->xwin_frame);
break;
case _NET_WM_MOVERESIZE_SIZE_TOPLEFT:
case _NET_WM_MOVERESIZE_SIZE_TOP:
@@ -935,7 +984,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_xwin_resize(window->xwin_frame, map[detail]);
break;
case _NET_WM_MOVERESIZE_CANCEL:
break;
@@ -964,7 +1013,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 +1112,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 +1133,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_xwin_move(window->xwin_frame);
break;
case THEME_LOCATION_RESIZING_TOP:
case THEME_LOCATION_RESIZING_BOTTOM:
@@ -1097,8 +1143,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_xwin_resize(window->xwin_frame, location);
break;
default:
break;
@@ -1398,59 +1443,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,147 +1513,99 @@ 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)
+wm_handle_xserver(void *data, struct wm *w, int32_t fd)
{
- struct weston_wm_window *window =
- container_of(listener,
- struct weston_wm_window, surface_destroy_listener);
+ struct xwm *xwm = data;
- fprintf(stderr, "surface for xid %d destroyed\n", window->id);
+ weston_wm_create(xwm, fd);
}
-static struct weston_wm_window *
-get_wm_window(struct weston_surface *surface)
+static void
+wm_handle_state(void *data, struct wm *w, uint32_t state)
{
- struct wl_resource *resource = &surface->surface.resource;
- struct wl_listener *listener;
+ struct xwm *xwm = data;
- listener = wl_signal_get(&resource->destroy_signal, surface_destroy);
- if (listener)
- return container_of(listener, struct weston_wm_window,
- surface_destroy_listener);
-
- return NULL;
+ set_state_activate(xwm, NULL);
}
+static const struct wm_listener wm_listener = {
+ wm_handle_xserver,
+ wm_handle_state
+};
+
static void
-weston_wm_window_configure(struct weston_wm_window *window)
+registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
+ const char *interface, uint32_t version)
{
- struct weston_wm *wm = window->wm;
- uint32_t values[2];
- int width, height;
+ struct xwm *xwm = data;
- values[0] = window->width;
- values[1] = window->height;
- xcb_configure_window(wm->conn,
- window->id,
- XCB_CONFIG_WINDOW_WIDTH |
- XCB_CONFIG_WINDOW_HEIGHT,
- values);
-
- weston_wm_window_get_frame_size(window, &width, &height);
- values[0] = width;
- values[1] = height;
- xcb_configure_window(wm->conn,
- window->frame_id,
- XCB_CONFIG_WINDOW_WIDTH |
- XCB_CONFIG_WINDOW_HEIGHT,
- values);
-
- weston_wm_window_draw_decoration(window);
+ if (!strcmp(interface, "wm")) {
+ xwm->wm = wl_registry_bind(registry, id,
+ &wm_interface, 1);
+ wm_add_listener(xwm->wm, &wm_listener, xwm);
+ }
}
static void
-send_configure(struct weston_surface *surface,
- uint32_t edges, int32_t width, int32_t height)
+sigchild_handler(int s)
{
- 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;
- }
+ int status;
+ pid_t pid;
- weston_wm_window_configure(window);
+ while (pid = waitpid(-1, &status, WNOHANG), pid > 0)
+ fprintf(stderr, "child %d exited\n", pid);
}
-static const struct weston_shell_client shell_client = {
- send_configure
+static const struct wl_registry_listener registry_listener = {
+ registry_handle_global
};
-static void
-xserver_set_window_id(struct wl_client *client, struct wl_resource *resource,
- struct wl_resource *surface_resource, uint32_t id)
+int
+main(int argc, char **argv)
{
- 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;
+ struct xwm xwm = { 0 };
- if (client != wxs->client)
- return;
-
- window = hash_table_lookup(wm->window_hash, id);
- if (window == NULL) {
- fprintf(stderr, "set_window_id for unknown window %d\n", id);
- return;
+ 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);
- fprintf(stderr, "set_window_id %d for surface %p\n", id, surface);
-
- weston_wm_window_read_properties(window);
+ 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);
- window->surface = (struct weston_surface *) surface;
- window->surface_destroy_listener.notify = surface_destroy;
- wl_signal_add(&surface->resource.destroy_signal,
- &window->surface_destroy_listener);
+ signal(SIGCHLD, sigchild_handler);
- weston_wm_window_draw_decoration(window);
+ display_run(xwm.display);
- window->shsurf =
- shell_interface->create_shell_surface(shell_interface->shell,
- window->surface,
- &shell_client);
+ weston_wm_destroy(xwm.weston_wm);
+ display_destroy(xwm.display);
- shell_interface->set_toplevel(window->shsurf);
+ 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..4f89bb1 100644
--- a/protocol/xserver.xml
+++ b/protocol/xserver.xml
@@ -1,18 +1,145 @@
<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"/>
+ <arg name="xid" type="uint"/>
</request>
<event name="client">
+ <description summary="send client fd to X">
+ In principle, this event must be used only once and to send window
+ manager (WM) 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 WM.
+ </description>
<arg name="fd" type="fd"/>
</event>
<event name="listen_socket">
+ <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="create_xwindow">
+ <description summary="instantiates xm_xwin objects">
+ </description>
+ <arg name="id" type="new_id" interface="wm_xwin"/>
+ <arg name="xid" 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>
+
<arg name="fd" type="fd"/>
</event>
+
+ <enum name="state">
+ <description summary="wm states">
+ Describes the wm state the Wayland compositor desires.
+ </description>
+
+ <entry name="deactivate" value="1" summary="deactivate all the windows"/>
+ </enum>
+
+ <event name="state">
+ <description summary="notifies window manager about window state">
+ </description>
+
+ <arg name="state" type="uint"/>
+ </event>
+ </interface>
+
+ <interface name="wm_xwin" version="1">
+ <description summary="">
+ </description>
+
+ <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="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">
+ </request>
+
+ <request name="resize">
+ <arg name="edges" type="uint"/>
+ </request>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy an wm_xwindow">
+ </description>
+ </request>
+
+ <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="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"/>
+ </enum>
+
+ <event name="state">
+ <description summary="notifies window about its state">
+ </description>
+
+ <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..0dec723 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_client(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..fe62ea5
--- /dev/null
+++ b/src/xwayland/window-manager.c
@@ -0,0 +1,287 @@
+/*
+ * 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_resource resource;
+ struct wl_list link;
+
+ struct weston_xserver *wxs;
+ struct wl_surface *surface;
+ struct shell_surface *shsurf;
+ struct wl_listener surface_destroy_listener;
+ struct wl_listener kill_listener;
+
+ uint32_t xid;
+ 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->xid);
+}
+
+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 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
+send_configure(struct weston_surface *surface, uint32_t edges,
+ int32_t width, int32_t height)
+{
+ struct xserver_window *window = get_xserver_window(surface);
+
+ if (window)
+ wm_xwin_send_configure(&window->resource, edges,
+ width, height);
+}
+
+static const struct weston_shell_client shell_client = {
+ send_configure
+};
+
+static void
+xserver_handle_window_surface(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *surface_resource, uint32_t xid)
+{
+ 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;
+
+ wl_list_for_each(window, &wxs->xserver_window_list, link)
+ if (window->xid == xid)
+ break;
+
+ if (window == NULL) {
+ fprintf(stderr, "set_window_id for unknown window %d\n", xid);
+ return;
+ }
+
+ fprintf(stderr, "set_window_id %d for surface %p\n", xid, 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_handle_window_surface
+};
+
+static void
+wm_xwin_handle_set_window(struct wl_client *client,
+ struct wl_resource *resource, int x, int y,
+ int width, int height, uint32_t flags)
+{
+ struct xserver_window *window = resource->data;
+
+ fprintf(stderr, "%s: %d\n", __func__, window->xid);
+ window->x = x;
+ window->y = y;
+ window->width = width;
+ window->height = height;
+ window->flags = flags;
+}
+
+static void
+wm_xwin_handle_move(struct wl_client *client, struct wl_resource *resource)
+{
+ struct xserver_window *window = resource->data;
+ struct weston_xserver *wxs = window->wxs;
+ struct weston_shell_interface *shell_interface =
+ &wxs->compositor->shell_interface;
+ struct weston_seat *seat = weston_wm_pick_seat(wxs);
+
+ if (seat->seat.pointer->button_count != 1 ||
+ seat->seat.pointer->focus != window->surface)
+ return;
+
+ shell_interface->move(window->shsurf, seat);
+}
+
+static void
+wm_xwin_handle_resize(struct wl_client *client,
+ struct wl_resource *resource, uint32_t location)
+{
+ struct xserver_window *window = resource->data;
+ struct weston_xserver *wxs = window->wxs;
+ struct weston_shell_interface *shell_interface =
+ &wxs->compositor->shell_interface;
+ struct weston_seat *seat = weston_wm_pick_seat(wxs);
+
+ if (seat->seat.pointer->button_count != 1 ||
+ seat->seat.pointer->focus != window->surface)
+ return;
+
+ shell_interface->resize(window->shsurf, seat, location);
+}
+
+static void
+wm_destroy_xwin(struct wl_resource *resource)
+{
+ struct xserver_window *window = resource->data;
+
+ wl_list_remove(&window->link);
+ window = NULL;
+ free(window);
+}
+
+static void
+wm_xwin_handle_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+ wm_destroy_xwin(resource);
+}
+
+const struct wm_xwin_interface wm_xwin_implementation = {
+ wm_xwin_handle_set_window,
+ wm_xwin_handle_move,
+ wm_xwin_handle_resize,
+ wm_xwin_handle_destroy
+};
+
+static void
+wm_activate_listener(struct wl_listener *listener, void *data)
+{
+ struct weston_surface *surface = data;
+ struct xserver_window *window = get_xserver_window(surface);
+ struct weston_xserver *wxs = container_of(listener,
+ struct weston_xserver, activate_listener);
+
+ if (window)
+ wm_xwin_send_state(&window->resource, WM_XWIN_STATE_ACTIVATE);
+ else
+ wm_send_state(wxs->wm_resource, WM_STATE_DEACTIVATE);
+}
+
+static void
+window_kill_listener(struct wl_listener *listener, void *data)
+{
+ struct weston_surface *surface = data;
+ struct xserver_window *window = get_xserver_window(surface);
+
+ if (window)
+ wm_xwin_send_state(&window->resource, WM_XWIN_STATE_KILL);
+}
+
+
+static void
+wm_handle_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_listen_socket(wxs->resource, wxs->abstract_fd);
+ xserver_send_listen_socket(wxs->resource, wxs->unix_fd);
+
+ wl_list_init(&wxs->xserver_window_list);
+
+ wxs->activate_listener.notify = wm_activate_listener;
+ wl_signal_add(&wxs->compositor->activate_signal,
+ &wxs->activate_listener);
+}
+
+static void
+wm_handle_create_xwindow(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id, uint32_t xid)
+{
+ struct weston_xserver *wxs = resource->data;
+ struct xserver_window *window;
+
+ fprintf(stderr, "%s: xid: %d\n", __func__, xid);
+ window = malloc(sizeof *window);
+ if (!window) {
+ wl_resource_post_no_memory(resource);
+ return;
+ }
+
+ window->shsurf = NULL;
+ window->wxs = wxs;
+ window->xid = xid;
+
+ window->resource.destroy = wm_destroy_xwin;
+ window->resource.object.id = id;
+ window->resource.object.interface = &wm_xwin_interface;
+ window->resource.object.implementation =
+ (void (**)(void)) &wm_xwin_implementation;
+ window->resource.data = window;
+ wl_client_add_resource(client, &window->resource);
+
+ window->kill_listener.notify = window_kill_listener;
+ wl_signal_add(&wxs->compositor->kill_signal, &window->kill_listener);
+
+ wl_list_insert(&wxs->xserver_window_list, &window->link);
+}
+
+const struct wm_interface wm_implementation = {
+ wm_handle_ready,
+ wm_handle_create_xwindow
+};
+
diff --git a/src/xwayland/xwayland.h b/src/xwayland/xwayland.h
index f7e6216..65ecf15 100644
--- a/src/xwayland/xwayland.h
+++ b/src/xwayland/xwayland.h
@@ -36,13 +36,19 @@ 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 wl_listener activate_listener;
+ struct wl_list xserver_window_list;
};
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