[PATCH weston 13/16] xwayland: Fix window positioning

Tiago Vignatti tiago.vignatti at intel.com
Wed Dec 19 11:32:23 PST 2012


This patch solves the window positioning problem through forwarding its global
coordinates to X. A new type of shell surface is need for doing so, 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_xwin.map) telling the
moment X Window 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)
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                 |   11 ++++++++---
 protocol/xserver.xml          |   31 +++++++++++++++++++++++++++++
 src/compositor.c              |    1 +
 src/compositor.h              |    1 +
 src/shell.c                   |    7 +++++++
 src/xwayland/window-manager.c |   43 ++++++++++++++++++++++++++++++++++++++---
 6 files changed, 88 insertions(+), 6 deletions(-)

diff --git a/clients/xwm.c b/clients/xwm.c
index 7185434..a4ab816 100644
--- a/clients/xwm.c
+++ b/clients/xwm.c
@@ -736,13 +736,18 @@ 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_xwin_map(window->xwin_frame);
+
+		fprintf(stderr, "XCB_MAP_NOTIFY (window %d, ours)\n",
+			map_notify->window);
+		return;
 	}
 
+	wm_xwin_map(window->xwin);
 	fprintf(stderr, "XCB_MAP_NOTIFY (window %d)\n", map_notify->window);
 }
 
diff --git a/protocol/xserver.xml b/protocol/xserver.xml
index 4f89bb1..a5dbebd 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 'xid' is ready to be mapped. Effectively this
+	happens after compositor receiving wm_xwin.map from WM.
+      </description>
+
+      <arg name="xid" 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="xid" 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">
@@ -81,6 +104,14 @@
     <description summary="">
     </description>
 
+    <request name="map">
+      <description summary="notify compositor when window can be mapped">
+	Notify compositor that the current window is ready to be mapped by X.
+	Effectively this happens after a MapNotify hits the window manager and
+	the compositor in principle would proceed notifying X via xserver.map.
+      </description>
+    </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 e556766..02dd649 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -2955,6 +2955,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 5f5e47e..eb8efed 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -309,6 +309,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 7a0e24c..dcefd9c 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);
 }
 
@@ -3058,6 +3062,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;
@@ -3083,6 +3088,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 97765a0..7fb7379 100644
--- a/src/xwayland/window-manager.c
+++ b/src/xwayland/window-manager.c
@@ -36,6 +36,7 @@ struct xserver_window {
 	struct wl_surface *surface;
 	struct shell_surface *shsurf;
 	struct wl_listener surface_destroy_listener;
+	struct wl_listener position_listener;
 	struct wl_listener kill_listener;
 
 	uint32_t xid;
@@ -120,8 +121,12 @@ xserver_handle_window_surface(struct wl_client *client,
 		shell_interface->create_shell_surface(shell_interface->shell,
 						      weston_surface,
 						      &shell_client);
-
-	shell_interface->set_toplevel(window->shsurf);
+	if (!window->flags)
+		shell_interface->set_toplevel(window->shsurf);
+	else
+		shell_interface->set_transient_xwayland(window->shsurf,
+				window->x + 32, window->y + 32,
+				XWAYLAND_INACTIVE);
 }
 
 const struct xserver_interface xserver_implementation = {
@@ -129,6 +134,14 @@ const struct xserver_interface xserver_implementation = {
 };
 
 static void
+wm_xwin_handle_map(struct wl_client *client, struct wl_resource *resource)
+{
+	struct xserver_window *window = resource->data;
+
+	xserver_send_map(window->wxs->resource, window->xid);
+}
+
+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)
@@ -192,6 +205,7 @@ wm_xwin_handle_destroy(struct wl_client *client, struct wl_resource *resource)
 }
 
 const struct wm_xwin_interface wm_xwin_implementation = {
+	wm_xwin_handle_map,
 	wm_xwin_handle_set_window,
 	wm_xwin_handle_move,
 	wm_xwin_handle_resize,
@@ -213,6 +227,26 @@ wm_activate_listener(struct wl_listener *listener, void *data)
 }
 
 static void
+window_position_listener(struct wl_listener *listener, void *data)
+{
+	struct weston_surface *surface = data;
+	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(window->wxs->resource, window->xid,
+			       (int) sxf, (int) syf,
+			       window->width, window->height,
+			       WL_SHELL_SURFACE_RESIZE_NONE);
+}
+
+static void
 window_kill_listener(struct wl_listener *listener, void *data)
 {
 	struct weston_surface *surface = data;
@@ -222,7 +256,6 @@ window_kill_listener(struct wl_listener *listener, void *data)
 		wm_xwin_send_state(&window->resource, WM_XWIN_STATE_KILL);
 }
 
-
 static void
 wm_handle_ready(struct wl_client *client, struct wl_resource *resource)
 {
@@ -269,6 +302,10 @@ wm_handle_create_xwindow(struct wl_client *client,
 	window->kill_listener.notify = window_kill_listener;
 	wl_signal_add(&wxs->compositor->kill_signal, &window->kill_listener);
 
+	window->position_listener.notify = window_position_listener;
+	wl_signal_add(&wxs->compositor->position_signal,
+		      &window->position_listener);
+
 	wl_list_insert(&wxs->xserver_window_list, &window->link);
 }
 
-- 
1.7.9.5



More information about the wayland-devel mailing list