[PATCH weston 6/6] stacking: manage stacking lists, implement present()

Manuel Bachmann manuel.bachmann at open.eurogiciel.org
Thu Apr 9 09:25:51 PDT 2015


Due to the absence of a clever close handler, closing one
window among multiple ones used to quit the application.
We now keep track of our children windows, and close only
these ones.

If the user tries to create a new window and we already
have a child, present() the child instead. The user will
then be able to raise and find the child by interacting
with the notification.

Signed-off-by: Manuel Bachmann <manuel.bachmann at open.eurogiciel.org>
---
 clients/stacking.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 70 insertions(+), 11 deletions(-)

diff --git a/clients/stacking.c b/clients/stacking.c
index ea6101d..c9e38d3 100644
--- a/clients/stacking.c
+++ b/clients/stacking.c
@@ -33,9 +33,15 @@
 
 #include "window.h"
 
+struct stacked_window {
+	struct window *window;
+	struct stacked_window *child_window;
+	struct stacking *stacking;
+};
+
 struct stacking {
 	struct display *display;
-	struct window *root_window;
+	struct stacked_window *root_window;
 };
 
 static void
@@ -55,17 +61,33 @@ static void
 fullscreen_handler(struct window *window, void *data);
 static void
 redraw_handler(struct widget *widget, void *data);
+static void
+close_handler(void *data);
 
 /* Iff parent_window is set, the new window will be transient. */
 static struct window *
 new_window(struct stacking *stacking, struct window *parent_window)
 {
+	struct stacked_window *current_window;
 	struct window *new_window;
 	struct widget *new_widget;
 
 	new_window = window_create(stacking->display);
 	window_set_parent(new_window, parent_window);
 
+	/* iterate through stackings, and stop once we find
+	 * the last window */
+	current_window = stacking->root_window;
+	while (current_window->child_window) {
+		current_window = current_window->child_window;
+	}
+	/* we create the new child */
+	current_window->child_window = xzalloc(sizeof *current_window);
+	current_window = current_window->child_window;
+	current_window->stacking = stacking;
+	current_window->window = new_window;
+	current_window->child_window = NULL;
+
 	new_widget = window_frame_create(new_window, new_window);
 
 	window_set_title(new_window, "Stacking Test");
@@ -74,7 +96,8 @@ new_window(struct stacking *stacking, struct window *parent_window)
 	window_set_fullscreen_handler(new_window, fullscreen_handler);
 	widget_set_button_handler(new_widget, button_handler);
 	widget_set_redraw_handler(new_widget, redraw_handler);
-	window_set_user_data(new_window, stacking);
+	window_set_close_handler(new_window, close_handler);
+	window_set_user_data(new_window, current_window);
 
 	window_schedule_resize(new_window, 300, 300);
 
@@ -108,12 +131,12 @@ button_handler(struct widget *widget,
                uint32_t button,
                enum wl_pointer_button_state state, void *data)
 {
-	struct stacking *stacking = data;
+	struct stacked_window *current_window = data;
 
 	switch (button) {
 	case BTN_RIGHT:
 		if (state == WL_POINTER_BUTTON_STATE_PRESSED)
-			show_popup(stacking, input, time,
+			show_popup(current_window->stacking, input, time,
 			           widget_get_user_data(widget));
 		break;
 
@@ -129,7 +152,7 @@ key_handler(struct window *window,
             uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
             void *data)
 {
-	struct stacking *stacking = data;
+	struct stacked_window *current_window = data;
 
 	if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
 		return;
@@ -144,12 +167,16 @@ key_handler(struct window *window,
 		break;
 
 	case XKB_KEY_n:
-		/* New top-level window. */
-		new_window(stacking, NULL);
+		/* If this window has no child, create a new top-level one.
+		 * Otherwise, present the existing child to the user. */
+		if (!current_window->child_window)
+			new_window(current_window->stacking, NULL);
+		else
+			window_present(current_window->child_window->window);
 		break;
 
 	case XKB_KEY_p:
-		show_popup(stacking, input, time, window);
+		show_popup(current_window->stacking, input, time, window);
 		break;
 
 	case XKB_KEY_q:
@@ -158,7 +185,7 @@ key_handler(struct window *window,
 
 	case XKB_KEY_t:
 		/* New transient window. */
-		new_window(stacking, window);
+		new_window(current_window->stacking, window);
 		break;
 
 	default:
@@ -281,6 +308,34 @@ redraw_handler(struct widget *widget, void *data)
 	cairo_destroy(cr);
 }
 
+static void
+close_handler(void *data)
+{
+	struct stacked_window *current_window = data;
+	struct stacked_window *parent_window;
+
+	/* we first re-iterate from the root window to the current
+	 * one to find the direct parent, and unreference it */
+	parent_window = current_window->stacking->root_window;
+	while (parent_window) {
+		if (parent_window->child_window == current_window) {
+			parent_window->child_window = NULL;
+			break;
+		}
+		parent_window = parent_window->child_window;
+	}
+
+	/* we can now unreference and free all the children */
+	while (current_window) {
+		window_destroy(current_window->window);
+		free(current_window);
+
+		parent_window = current_window;
+		current_window = current_window->child_window;
+		parent_window->child_window = NULL;
+	}
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -288,6 +343,10 @@ main(int argc, char *argv[])
 
 	memset(&stacking, 0, sizeof stacking);
 
+	stacking.root_window = xzalloc(sizeof stacking.root_window);
+	stacking.root_window->stacking = &stacking;
+	stacking.root_window->child_window = NULL;
+
 #ifdef HAVE_PANGO
 	g_type_init();
 #endif
@@ -300,11 +359,11 @@ main(int argc, char *argv[])
 
 	display_set_user_data(stacking.display, &stacking);
 
-	stacking.root_window = new_window(&stacking, NULL);
+	stacking.root_window->window = new_window(&stacking, NULL);
 
 	display_run(stacking.display);
 
-	window_destroy(stacking.root_window);
+	window_destroy(stacking.root_window->window);
 	display_destroy(stacking.display);
 
 	return 0;
-- 
1.8.3.1



More information about the wayland-devel mailing list