[PATCH weston 07/11] XWayland: Draw decorations on Expose

Daniel Stone daniel at fooishbar.org
Tue Nov 6 22:51:41 PST 2012


Instead of issuing draw commands immediately after we map or
reconfigure, wait for the server to send us an Expose event, thus making
sure our drawing doesn't get lost.

Signed-off-by: Daniel Stone <daniel at fooishbar.org>
---
 src/xwayland/window-manager.c |  218 +++++++++++++++++++++--------------------
 1 file changed, 112 insertions(+), 106 deletions(-)

diff --git a/src/xwayland/window-manager.c b/src/xwayland/window-manager.c
index 4d44527..3ceff63 100644
--- a/src/xwayland/window-manager.c
+++ b/src/xwayland/window-manager.c
@@ -99,7 +99,6 @@ struct weston_wm_window {
 	struct weston_surface *surface;
 	struct shell_surface *shsurf;
 	struct wl_listener surface_destroy_listener;
-	struct wl_event_source *repaint_source;
 	struct wl_event_source *configure_source;
 	int properties_dirty;
 	int pid;
@@ -118,9 +117,6 @@ struct weston_wm_window {
 static struct weston_wm_window *
 get_wm_window(struct weston_surface *surface);
 
-static void
-weston_wm_window_schedule_repaint(struct weston_wm_window *window);
-
 const char *
 get_atom_name(xcb_connection_t *c, xcb_atom_t atom)
 {
@@ -412,6 +408,81 @@ weston_wm_window_get_child_position(struct weston_wm_window *window,
 }
 
 static void
+weston_wm_window_draw_decoration(void *data)
+{
+	struct weston_wm_window *window = data;
+	struct weston_wm *wm = window->wm;
+	struct theme *t = wm->theme;
+	cairo_t *cr;
+	int x, y, width, height;
+	const char *title;
+	uint32_t flags = 0;
+	struct pixman_region32 region;
+
+	weston_wm_window_read_properties(window);
+
+	if (window->frame_id == XCB_WINDOW_NONE) {
+		if (window->surface != NULL) {
+			pixman_region32_fini(&window->surface->pending.opaque);
+			pixman_region32_init_rect(&window->surface->pending.opaque,
+						  0, 0,
+						  window->width, window->height);
+			window->surface->geometry.dirty = 1;
+			weston_surface_schedule_repaint(window->surface);
+		}
+		return;
+	}
+
+	if (window->decorate) {
+		weston_wm_window_get_frame_size(window, &width, &height);
+		weston_wm_window_get_child_position(window, &x, &y);
+
+		cairo_xcb_surface_set_size(window->cairo_surface, width, height);
+
+		cr = cairo_create(window->cairo_surface);
+		if (wm->focus_window == window)
+			flags |= THEME_FRAME_ACTIVE;
+
+		if (window->name)
+			title = window->name;
+		else
+			title = "untitled";
+
+		theme_render_frame(t, cr, width, height, title, flags);
+		cairo_destroy(cr);
+	}
+
+	xcb_flush(wm->conn);
+
+	if (!window->surface)
+		return;
+
+	/* We leave an extra pixel around the X window area to
+	 * make sure we don't sample from the undefined alpha
+	 * channel when filtering. */
+	pixman_region32_init_rect(&region, x - 1, y - 1,
+				  window->width + 2,
+				  window->height + 2);
+	if (!pixman_region32_equal(&region,
+				   &window->surface->pending.opaque)) {
+		pixman_region32_copy(&window->surface->pending.opaque, &region);
+		pixman_region32_copy(&window->surface->opaque,
+				     &window->surface->pending.opaque);
+		pixman_region32_fini(&window->surface->pending.input);
+		pixman_region32_init_rect(&window->surface->pending.input,
+					  t->margin, t->margin,
+					  width - 2 * t->margin,
+					  height - 2 * t->margin);
+		pixman_region32_intersect_rect(&window->surface->pending.opaque,
+					       &window->surface->pending.opaque,
+					       x - 1, y - 1,
+					       window->width + 2,
+					       window->height + 2);
+	}
+	pixman_region32_fini(&region);
+}
+
+static void
 weston_wm_handle_configure_request(struct weston_wm *wm, xcb_generic_event_t *event)
 {
 	xcb_configure_request_event_t *configure_request = 
@@ -458,7 +529,7 @@ weston_wm_handle_configure_request(struct weston_wm *wm, xcb_generic_event_t *ev
 	mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
 	xcb_configure_window(wm->conn, window->frame_id, mask, values);
 
-	weston_wm_window_schedule_repaint(window);
+	weston_wm_window_draw_decoration(window);
 }
 
 static void
@@ -509,9 +580,10 @@ static void
 weston_wm_window_activate(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, activate_listener);
+	struct weston_wm_window *window = get_wm_window(surface);
+	struct weston_wm_window *old_focus = wm->focus_window;
 	xcb_client_message_event_t client_message;
 
 	if (window) {
@@ -535,13 +607,16 @@ weston_wm_window_activate(struct wl_listener *listener, void *data)
 				     XCB_TIME_CURRENT_TIME);
 	}
 
-	if (wm->focus_window)
-		weston_wm_window_schedule_repaint(wm->focus_window);
+	if (wm->focus_window == window)
+		return;
+
 	wm->focus_window = window;
 	if (window)
 		wm->focus_latest = window;
 	if (wm->focus_window)
-		weston_wm_window_schedule_repaint(wm->focus_window);
+		weston_wm_window_draw_decoration(wm->focus_window);
+	if (old_focus)
+		weston_wm_window_draw_decoration(old_focus);
 }
 
 static int
@@ -610,7 +685,8 @@ weston_wm_handle_map_request(struct weston_wm *wm, xcb_generic_event_t *event)
 		XCB_EVENT_MASK_ENTER_WINDOW |
 		XCB_EVENT_MASK_LEAVE_WINDOW |
 		XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
-		XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT;
+		XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
+		XCB_EVENT_MASK_EXPOSURE;
 
 	window->frame_id = xcb_generate_id(wm->conn);
 	xcb_create_window(wm->conn,
@@ -650,6 +726,7 @@ static void
 weston_wm_handle_map_notify(struct weston_wm *wm, xcb_generic_event_t *event)
 {
 	xcb_map_notify_event_t *map_notify = (xcb_map_notify_event_t *) event;
+	struct weston_wm_window *window;
 
 	if (our_resource(wm, map_notify->window)) {
 			weston_log("XCB_MAP_NOTIFY (window %d, ours)\n",
@@ -657,10 +734,27 @@ weston_wm_handle_map_notify(struct weston_wm *wm, xcb_generic_event_t *event)
 			return;
 	}
 
+	window = hash_table_lookup(wm->window_hash, map_notify->window);
+	if (window && window->override_redirect)
+		weston_wm_window_draw_decoration(window);
+
 	weston_log("XCB_MAP_NOTIFY (window %d)\n", map_notify->window);
 }
 
 static void
+weston_wm_handle_expose(struct weston_wm *wm, xcb_generic_event_t *event)
+{
+	xcb_expose_event_t *expose = (xcb_expose_event_t *) event;
+	struct weston_wm_window *window;
+
+	window = hash_table_lookup(wm->window_hash, expose->window);
+	if (window && expose->window == window->frame_id)
+		weston_wm_window_draw_decoration(window);
+
+	weston_log("XCB_EXPOSE (window %d)\n", expose->window);
+}
+
+static void
 weston_wm_handle_unmap_notify(struct weston_wm *wm, xcb_generic_event_t *event)
 {
 	xcb_unmap_notify_event_t *unmap_notify =
@@ -681,8 +775,6 @@ weston_wm_handle_unmap_notify(struct weston_wm *wm, xcb_generic_event_t *event)
 		return;
 
 	window = hash_table_lookup(wm->window_hash, unmap_notify->window);
-	if (window->repaint_source)
-		wl_event_source_remove(window->repaint_source);
 	if (window->cairo_surface)
 		cairo_surface_destroy(window->cairo_surface);
 
@@ -702,97 +794,6 @@ weston_wm_handle_unmap_notify(struct weston_wm *wm, xcb_generic_event_t *event)
 }
 
 static void
-weston_wm_window_draw_decoration(void *data)
-{
-	struct weston_wm_window *window = data;
-	struct weston_wm *wm = window->wm;
-	struct theme *t = wm->theme;
-	cairo_t *cr;
-	int x, y, width, height;
-	const char *title;
-	uint32_t flags = 0;
-
-	weston_wm_window_read_properties(window);
-
-	window->repaint_source = NULL;
-
-	weston_wm_window_get_frame_size(window, &width, &height);
-	weston_wm_window_get_child_position(window, &x, &y);
-
-	cairo_xcb_surface_set_size(window->cairo_surface, width, height);
-	cr = cairo_create(window->cairo_surface);
-
-	if (window->decorate) {
-		if (wm->focus_window == window)
-			flags |= THEME_FRAME_ACTIVE;
-
-		if (window->name)
-			title = window->name;
-		else
-			title = "untitled";
-
-		theme_render_frame(t, cr, width, height, title, flags);
-	} else {
-		cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
-		cairo_set_source_rgba(cr, 0, 0, 0, 0);
-		cairo_paint(cr);
-
-		cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
-		cairo_set_source_rgba(cr, 0, 0, 0, 0.45);
-		tile_mask(cr, t->shadow, 2, 2, width + 8, height + 8, 64, 64);
-	}
-
-	cairo_destroy(cr);
-
-	if (window->surface) {
-		pixman_region32_fini(&window->surface->opaque);
-		pixman_region32_init_rect(&window->surface->opaque, 0, 0,
-					  width, height);
-
-		/* We leave an extra pixel around the X window area to
-		 * make sure we don't sample from the undefined alpha
-		 * channel when filtering. */
-		pixman_region32_intersect_rect(&window->surface->opaque,
-					       &window->surface->opaque,
-					       x - 1, y - 1,
-					       window->width + 2,
-					       window->height + 2);
-		window->surface->geometry.dirty = 1;
-
-		pixman_region32_init_rect(&window->surface->input,
-					  t->margin, t->margin,
-					  width - 2 * t->margin,
-					  height - 2 * t->margin);
-	}
-}
-
-static void
-weston_wm_window_schedule_repaint(struct weston_wm_window *window)
-{
-	struct weston_wm *wm = window->wm;
-	int width, height;
-
-	if (window->frame_id == XCB_WINDOW_NONE) {
-		if (window->surface != NULL) {
-			weston_wm_window_get_frame_size(window, &width, &height);
-			pixman_region32_fini(&window->surface->opaque);
-			pixman_region32_init_rect(&window->surface->opaque, 0, 0,
-						  width, height);
-			window->surface->geometry.dirty = 1;
-		}
-		return;
-	}
-
-	if (window->repaint_source)
-		return;
-
-	window->repaint_source =
-		wl_event_loop_add_idle(wm->server->loop,
-				       weston_wm_window_draw_decoration,
-				       window);
-}
-
-static void
 weston_wm_handle_property_notify(struct weston_wm *wm, xcb_generic_event_t *event)
 {
 	xcb_property_notify_event_t *property_notify =
@@ -814,7 +815,7 @@ weston_wm_handle_property_notify(struct weston_wm *wm, xcb_generic_event_t *even
 	if (window &&
 	    (property_notify->atom == wm->atom.net_wm_name ||
 	     property_notify->atom == XCB_ATOM_WM_NAME))
-		weston_wm_window_schedule_repaint(window);
+		weston_wm_window_draw_decoration(window);
 }
 
 static void
@@ -1240,6 +1241,11 @@ weston_wm_handle_event(int fd, uint32_t mask, void *data)
 		case XCB_CLIENT_MESSAGE:
 			weston_wm_handle_client_message(wm, event);
 			break;
+		case XCB_EXPOSE:
+			weston_wm_handle_expose(wm, event);
+			break;
+		default:
+			break;
 		}
 
 		free(event);
@@ -1580,7 +1586,7 @@ weston_wm_window_configure(void *data)
 
 	window->configure_source = NULL;
 
-	weston_wm_window_schedule_repaint(window);
+	weston_wm_window_draw_decoration(window);
 }
 
 static void
@@ -1685,7 +1691,7 @@ xserver_set_window_id(struct wl_client *client, struct wl_resource *resource,
 	wl_signal_add(&surface->resource.destroy_signal,
 		      &window->surface_destroy_listener);
 
-	weston_wm_window_schedule_repaint(window);
+	weston_wm_window_draw_decoration(window);
 	xserver_map_shell_surface(wm, window);
 }
 
-- 
1.7.10.4



More information about the wayland-devel mailing list