xwayland: Forward global position to X

xeyes works as expected now. subwindows are popped also as expected. This
patch should fix the following:

https://bugs.freedesktop.org/show_bug.cgi?id=59983

Signed-off-by: Tiago Vignatti <tiago.vignatti@intel.com>
diff --git a/src/compositor.c b/src/compositor.c
index 42011f5..d44ffaa 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -728,6 +728,8 @@
 	weston_surface_damage_below(surface);
 
 	weston_surface_assign_output(surface);
+
+	wl_signal_emit(&surface->compositor->transform_signal, surface);
 }
 
 WL_EXPORT void
@@ -2778,6 +2780,7 @@
 	ec->wl_display = display;
 	wl_signal_init(&ec->destroy_signal);
 	wl_signal_init(&ec->activate_signal);
+	wl_signal_init(&ec->transform_signal);
 	wl_signal_init(&ec->kill_signal);
 	wl_signal_init(&ec->idle_signal);
 	wl_signal_init(&ec->wake_signal);
diff --git a/src/compositor.h b/src/compositor.h
index c87d9f1..865b01c 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -94,6 +94,8 @@
 			       uint32_t method,
 			       uint32_t framerate,
 			       struct weston_output *output);
+	void (*set_xwayland)(struct shell_surface *shsurf,
+			       int x, int y, uint32_t flags);
 	int (*move)(struct shell_surface *shsurf, struct weston_seat *ws);
 	int (*resize)(struct shell_surface *shsurf,
 		      struct weston_seat *ws, uint32_t edges);
@@ -502,7 +504,10 @@
 	struct weston_shell_interface shell_interface;
 	struct weston_config *config;
 
+	/* surface signals */
 	struct wl_signal activate_signal;
+	struct wl_signal transform_signal;
+
 	struct wl_signal kill_signal;
 	struct wl_signal idle_signal;
 	struct wl_signal wake_signal;
diff --git a/src/shell.c b/src/shell.c
index 57dbb0a..cfdb19c 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -171,7 +171,8 @@
 	SHELL_SURFACE_TRANSIENT,
 	SHELL_SURFACE_FULLSCREEN,
 	SHELL_SURFACE_MAXIMIZED,
-	SHELL_SURFACE_POPUP
+	SHELL_SURFACE_POPUP,
+	SHELL_SURFACE_XWAYLAND
 };
 
 struct ping_timer {
@@ -1581,6 +1582,7 @@
 	case SHELL_SURFACE_TOPLEVEL:
 	case SHELL_SURFACE_TRANSIENT:
 	case SHELL_SURFACE_POPUP:
+	case SHELL_SURFACE_XWAYLAND:
 		break;
 	}
 
@@ -1622,6 +1624,11 @@
 		}
 		break;
 
+	case SHELL_SURFACE_XWAYLAND:
+		weston_surface_set_position(surface, shsurf->transient.x,
+					    shsurf->transient.y);
+		break;
+
 	default:
 		break;
 	}
@@ -1925,6 +1932,16 @@
 	set_fullscreen(shsurf, method, framerate, output);
 }
 
+static void
+set_xwayland(struct shell_surface *shsurf, int x, int y, uint32_t flags)
+{
+	/* XXX: using the same fields for transient type */
+	shsurf->transient.x = x;
+	shsurf->transient.y = y;
+	shsurf->transient.flags = flags;
+	shsurf->next_type = SHELL_SURFACE_XWAYLAND;
+}
+
 static const struct weston_pointer_grab_interface popup_grab_interface;
 
 static void
@@ -3398,6 +3415,7 @@
 	case SHELL_SURFACE_FULLSCREEN:
 	case SHELL_SURFACE_NONE:
 		break;
+	case SHELL_SURFACE_XWAYLAND:
 	default:
 		ws = get_current_workspace(shell);
 		wl_list_insert(&ws->layer.surface_list, &surface->layer_link);
@@ -3411,6 +3429,8 @@
 	}
 
 	switch (surface_type) {
+	/* XXX: xwayland's using the same fields for transient type */
+	case SHELL_SURFACE_XWAYLAND:
 	case SHELL_SURFACE_TRANSIENT:
 		if (shsurf->transient.flags ==
 				WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
@@ -3489,6 +3509,7 @@
 {
 	struct shell_surface *shsurf = get_shell_surface(es);
 	struct desktop_shell *shell = shsurf->shell;
+	struct weston_compositor *compositor = shsurf->surface->compositor;
 
 	int type_changed = 0;
 
@@ -4433,6 +4454,7 @@
 	ec->shell_interface.set_toplevel = set_toplevel;
 	ec->shell_interface.set_transient = set_transient;
 	ec->shell_interface.set_fullscreen = set_fullscreen;
+	ec->shell_interface.set_xwayland = set_xwayland;
 	ec->shell_interface.move = surface_move;
 	ec->shell_interface.resize = surface_resize;
 
diff --git a/src/xwayland/window-manager.c b/src/xwayland/window-manager.c
index 3fc5633..6b9e38b 100644
--- a/src/xwayland/window-manager.c
+++ b/src/xwayland/window-manager.c
@@ -593,12 +593,49 @@
 	if (wm->focus_window)
 		weston_wm_window_schedule_repaint(wm->focus_window);
 	wm->focus_window = window;
-	if (window)
-		wm->focus_latest = window;
 	if (wm->focus_window)
 		weston_wm_window_schedule_repaint(wm->focus_window);
 }
 
+static void
+weston_wm_window_transform(struct wl_listener *listener, void *data)
+{
+	struct weston_surface *surface = data;
+	struct weston_wm_window *window = get_wm_window(surface);
+	struct weston_wm *wm =
+		container_of(listener, struct weston_wm, transform_listener);
+	struct weston_output *output = surface->output;
+	uint32_t mask, values[2];
+	float sxf, syf;
+	int sx, sy;
+	static int old_sx = -1, old_sy = -1;
+
+	if (!window || !wm)
+		return;
+
+	if (!weston_surface_is_mapped(surface))
+		return;
+
+	weston_surface_to_global_float(surface, output->x, output->y,
+				       &sxf, &syf);
+
+	sx = (int) sxf;
+	sy = (int) syf;
+
+	if (old_sx == sx && old_sy == sy)
+		return;
+
+	values[0] = sx;
+	values[1] = sy;
+	mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y;
+
+	xcb_configure_window(wm->conn, window->frame_id, mask, values);
+	xcb_flush(wm->conn);
+
+	old_sx = sx;
+	old_sy = sy;
+}
+
 static int
 our_resource(struct weston_wm *wm, uint32_t id)
 {
@@ -1684,6 +1721,9 @@
 	wm->activate_listener.notify = weston_wm_window_activate;
 	wl_signal_add(&wxs->compositor->activate_signal,
 		      &wm->activate_listener);
+	wm->transform_listener.notify = weston_wm_window_transform;
+	wl_signal_add(&wxs->compositor->transform_signal,
+		      &wm->transform_listener);
 	wm->kill_listener.notify = weston_wm_kill_client;
 	wl_signal_add(&wxs->compositor->kill_signal,
 		      &wm->kill_listener);
@@ -1807,9 +1847,7 @@
 {
 	struct weston_shell_interface *shell_interface =
 		&wm->server->compositor->shell_interface;
-	struct weston_wm_window *parent;
 	struct theme *t = window->wm->theme;
-	int parent_id, x = 0, y = 0;
 
 	if (!shell_interface->create_shell_surface)
 		return;
@@ -1827,31 +1865,14 @@
 						0, NULL);
 		return;
 	} else if (!window->override_redirect) {
-		/* ICCCM 4.1.1 */
 		shell_interface->set_toplevel(window->shsurf);
 		return;
+	} else {
+		shell_interface->set_xwayland(window->shsurf,
+					      window->x + t->margin,
+					      window->y + t->margin,
+					      WL_SHELL_SURFACE_TRANSIENT_INACTIVE);
 	}
-
-	/* not all non-toplevel has transient_for set. So we need this
-	 * workaround to guess a parent that will determine the relative
-	 * position of the transient surface */
-	if (!window->transient_for)
-		parent_id = wm->focus_latest->id;
-	else
-		parent_id = window->transient_for->id;
-
-	parent = hash_table_lookup(wm->window_hash, parent_id);
-
-	/* non-decorated and non-toplevel windows, e.g. sub-menus */
-	if (!parent->decorate && parent->override_redirect) {
-		x = parent->x + t->margin;
-		y = parent->y + t->margin;
-	}
-
-	shell_interface->set_transient(window->shsurf, parent->surface,
-				       window->x + t->margin - x,
-				       window->y + t->margin - y,
-				       WL_SHELL_SURFACE_TRANSIENT_INACTIVE);
 }
 
 static void
diff --git a/src/xwayland/xwayland.h b/src/xwayland/xwayland.h
index 9151cce..c68a517 100644
--- a/src/xwayland/xwayland.h
+++ b/src/xwayland/xwayland.h
@@ -53,7 +53,6 @@
 	struct weston_xserver *server;
 	xcb_window_t wm_window;
 	struct weston_wm_window *focus_window;
-	struct weston_wm_window *focus_latest;
 	struct theme *theme;
 	xcb_cursor_t *cursors;
 	int last_cursor;
@@ -61,6 +60,7 @@
 	xcb_visualid_t visual_id;
 	xcb_colormap_t colormap;
 	struct wl_listener activate_listener;
+	struct wl_listener transform_listener;
 	struct wl_listener kill_listener;
 
 	xcb_window_t selection_window;