[PATCH weston 17/17] xwayland: Fix window positioning

Tiago Vignatti tiago.vignatti at intel.com
Fri Nov 30 11:20:16 PST 2012


This patch solves the window positioning problem through forwarding its global
coordinates to X. A change in desktop-shell protocol is needed for doing so
and to add a new type of surface, the xwayland (description and details of it
are on the previous commit and also in the protocol).

The approach used here shows a weakness of the Weston WM-as-client
architecture: one cannot guarantee that the X11 stream needed to create
windows with its right position will happen before Weston maps the surface,
via Wayland. IOW we'd like always ConfigureNotify with the coordinates coming
and only then Wayland compositor could map the surface:

    1. xwm: gets XCB_CREATE_NOTIFY (via X11)
    2. xwm: gets XCB_CONFIGURE_NOTIFY (via X11)
    3. weston: gets correct position (wm_get_window, via Wayland)
    4. weston: maps the surface (xserver_get_window_surface, via X11)

but it was happening:

    1. xwm: gets XCB_CREATE_NOTIFY (via X11)
    2. weston: maps w/ wrong position (xserver_get_window_surface, via X11)
    3. xwm: gets XCB_CONFIGURE_NOTIFY (via X11)
    4. weston: gets outdated position (wm_get_window, via Wayland)

The problem now is that we have to control the order of two different stream
in one process only. We haven't faced this before with a single Weston + XWM
process because that was controlled by the time the event was touching the fd.

In order to solve that, we introduce a new request (wm.map) telling the moment
WM is ready for mapping (MapNotify arrived) and a new event (xserver.send_map)
to forward it to X, which in turn will reply back to the compositor with the
actual mapping request (xserver.set_window_surface). Therefore doing so all
the mapping is managed and ordered via Wayland stream.

This patch brings back a feature we removed previously (#3 window positioning,
2aee1248) and also put the X Windows in their global position (for instance,
now xeyes works like expected and also menu windows are shifted correctly
regarding output's dimensions).

Signed-off-by: Tiago Vignatti <tiago.vignatti at intel.com>
---
 clients/xwm.c                 |   10 +++++++---
 protocol/xserver.xml          |   33 +++++++++++++++++++++++++++++++
 src/compositor.c              |    1 +
 src/compositor.h              |    1 +
 src/shell.c                   |    7 +++++++
 src/xwayland/window-manager.c |   43 ++++++++++++++++++++++++++++++++++++++++-
 src/xwayland/xwayland.h       |    1 +
 7 files changed, 92 insertions(+), 4 deletions(-)

diff --git a/clients/xwm.c b/clients/xwm.c
index c421380..0331439 100644
--- a/clients/xwm.c
+++ b/clients/xwm.c
@@ -697,13 +697,17 @@ static void
 xwm_handle_map_notify(struct xwm_wm *wm, xcb_generic_event_t *event)
 {
 	xcb_map_notify_event_t *map_notify = (xcb_map_notify_event_t *) event;
+	struct xwm_window *window;
 
+	window = hash_table_lookup(wm->window_hash, map_notify->window);
 	if (our_resource(wm, map_notify->window)) {
-			fprintf(stderr, "XCB_MAP_NOTIFY (window %d, ours)\n",
-				map_notify->window);
-			return;
+		wm_map(wm->xwm->wm, window->frame_id);
+		fprintf(stderr, "XCB_MAP_NOTIFY (window %d, ours)\n",
+			map_notify->window);
+		return;
 	}
 
+	wm_map(wm->xwm->wm, window->id);
 	fprintf(stderr, "XCB_MAP_NOTIFY (window %d)\n", map_notify->window);
 }
 
diff --git a/protocol/xserver.xml b/protocol/xserver.xml
index 907c882..3779d1a 100644
--- a/protocol/xserver.xml
+++ b/protocol/xserver.xml
@@ -34,6 +34,29 @@
       </description>
       <arg name="fd" type="fd"/>
     </event>
+
+    <event name="map">
+      <description summary="notify X when window can be mapped">
+	Notify X that Window 'id' is ready to be mapped. Effectively this
+	happens after compositor receiving wm.map from WM.
+      </description>
+
+       <arg name="id" type="uint"/>
+    </event>
+
+    <event name="configure">
+      <description summary="notify X about new window configuration">
+	Worth to note that coordinates 'x' and 'y' are global.
+      </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="edges" type="uint"/>
+    </event>
+
   </interface>
 
   <interface name="wm" version="1">
@@ -45,6 +68,16 @@
       </description>
     </request>
 
+    <request name="map">
+      <description summary="notify compositor when window can be mapped">
+	Notify compositor that Window 'id' is ready to be mapped via X.
+	Effectively this happens after a MapNotify hits the window manager and
+	the compositor in principle would proceed notifying X via xserver.map.
+      </description>
+
+      <arg name="id" type="uint"/>
+    </request>
+
     <request name="set_window">
       <description summary="specify window id, geometries and positioning">
 	Notifies the compositor about X Window id and its configuration
diff --git a/src/compositor.c b/src/compositor.c
index a965fc2..f750193 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -2859,6 +2859,7 @@ weston_compositor_init(struct weston_compositor *ec,
 	ec->wl_display = display;
 	wl_signal_init(&ec->destroy_signal);
 	wl_signal_init(&ec->activate_signal);
+	wl_signal_init(&ec->position_signal);
 	wl_signal_init(&ec->kill_signal);
 	wl_signal_init(&ec->lock_signal);
 	wl_signal_init(&ec->unlock_signal);
diff --git a/src/compositor.h b/src/compositor.h
index a96eb0b..64b92e1 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -281,6 +281,7 @@ struct weston_compositor {
 	struct weston_shell_interface shell_interface;
 
 	struct wl_signal activate_signal;
+	struct wl_signal position_signal;
 	struct wl_signal kill_signal;
 	struct wl_signal lock_signal;
 	struct wl_signal unlock_signal;
diff --git a/src/shell.c b/src/shell.c
index 56432fb..020df76 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -303,9 +303,13 @@ shell_grab_start(struct shell_grab *grab,
 static void
 shell_grab_end(struct shell_grab *grab)
 {
+	struct weston_compositor *compositor =
+		grab->shsurf->surface->compositor;
+
 	if (grab->shsurf)
 		wl_list_remove(&grab->shsurf_destroy_listener.link);
 
+	wl_signal_emit(&compositor->position_signal, grab->shsurf->surface);
 	wl_pointer_end_grab(grab->pointer);
 }
 
@@ -3067,6 +3071,7 @@ shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
 {
 	struct shell_surface *shsurf = get_shell_surface(es);
 	struct desktop_shell *shell = shsurf->shell;
+	struct weston_compositor *compositor = shsurf->surface->compositor;
 	int32_t width = weston_surface_buffer_width(es);
 	int32_t height = weston_surface_buffer_height(es);
 	int type_changed = 0;
@@ -3092,6 +3097,8 @@ shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
 			  es->geometry.y + to_y - from_y,
 			  width, height);
 	}
+
+	wl_signal_emit(&compositor->position_signal, shsurf->surface);
 }
 
 static void launch_desktop_shell_process(void *data);
diff --git a/src/xwayland/window-manager.c b/src/xwayland/window-manager.c
index 39bac18..63e5029 100644
--- a/src/xwayland/window-manager.c
+++ b/src/xwayland/window-manager.c
@@ -107,7 +107,12 @@ xserver_get_window_surface(struct wl_client *client,
 						      weston_surface,
 						      &shell_client);
 
-	shell_interface->set_toplevel(window->shsurf);
+	if (!window->flags)
+		shell_interface->set_toplevel(window->shsurf);
+	else
+		shell_interface->set_xwayland(window->shsurf,
+				window->x + 32, window->y + 32,
+				WL_SHELL_SURFACE_XWAYLAND_INACTIVE);
 }
 
 const struct xserver_interface xserver_implementation = {
@@ -156,6 +161,29 @@ weston_wm_activate_client(struct wl_listener *listener, void *data)
 }
 
 static void
+weston_wm_position_client(struct wl_listener *listener, void *data)
+{
+	struct weston_surface *surface = data;
+	struct weston_xserver *wxs = container_of(listener,
+			struct weston_xserver, position_listener);
+	struct xserver_window *window = get_xserver_window(surface);
+	struct weston_output *output = surface->output;
+	float sxf, syf;
+
+	if (!window || !weston_surface_is_mapped(surface))
+		return;
+
+	weston_surface_to_global_float(surface,
+				       output->x, output->y,
+				       &sxf, &syf);
+
+	xserver_send_configure(wxs->resource, window->id,
+			       (int) sxf, (int) syf,
+			       window->width, window->height,
+			       WL_SHELL_SURFACE_RESIZE_NONE);
+}
+
+static void
 weston_wm_kill_client(struct wl_listener *listener, void *data)
 {
 	struct weston_surface *surface = data;
@@ -187,11 +215,23 @@ wm_get_ready(struct wl_client *client, struct wl_resource *resource)
 	wl_signal_add(&wxs->compositor->activate_signal,
 		      &wxs->activate_listener);
 
+	wxs->position_listener.notify = weston_wm_position_client;
+	wl_signal_add(&wxs->compositor->position_signal,
+		      &wxs->position_listener);
+
 	wxs->kill_listener.notify = weston_wm_kill_client;
 	wl_signal_add(&wxs->compositor->kill_signal,
 		      &wxs->kill_listener);
 }
 
+static void
+wm_get_map(struct wl_client *client, struct wl_resource *resource, uint32_t id)
+{
+	struct weston_xserver *wxs = resource->data;
+
+	xserver_send_map(wxs->resource, id);
+}
+
 static struct weston_seat *
 weston_wm_pick_seat(struct weston_xserver *wxs)
 {
@@ -243,6 +283,7 @@ wm_get_resize(struct wl_client *client, struct wl_resource *resource,
 
 const struct wm_interface wm_implementation = {
 	wm_get_ready,
+	wm_get_map,
 	wm_get_window,
 	wm_get_move,
 	wm_get_resize
diff --git a/src/xwayland/xwayland.h b/src/xwayland/xwayland.h
index 400cdb7..1ddb51a 100644
--- a/src/xwayland/xwayland.h
+++ b/src/xwayland/xwayland.h
@@ -48,6 +48,7 @@ struct weston_xserver {
 	struct wl_resource *wm_conn_resource;
 	struct hash_table *window_hash;
 	struct wl_listener activate_listener;
+	struct wl_listener position_listener;
 	struct wl_listener kill_listener;
 };
 
-- 
1.7.9.5



More information about the wayland-devel mailing list