mirror of
				https://gitlab.freedesktop.org/wlroots/wlroots.git
				synced 2025-10-29 05:40:12 -04:00 
			
		
		
		
	foreign-toplevel-management: report parent toplevel
Based on the wlr-protocols PR: https://github.com/swaywm/wlr-protocols/pull/52
This commit is contained in:
		
							parent
							
								
									1ac5257357
								
							
						
					
					
						commit
						36395e5b1c
					
				
					 4 changed files with 123 additions and 8 deletions
				
			
		|  | @ -7,7 +7,7 @@ | |||
| #include <wayland-client.h> | ||||
| #include "wlr-foreign-toplevel-management-unstable-v1-client-protocol.h" | ||||
| 
 | ||||
| #define WLR_FOREIGN_TOPLEVEL_MANAGEMENT_VERSION 2 | ||||
| #define WLR_FOREIGN_TOPLEVEL_MANAGEMENT_VERSION 3 | ||||
| 
 | ||||
| /**
 | ||||
|  * Usage: | ||||
|  | @ -38,11 +38,14 @@ enum toplevel_state_field { | |||
| 	TOPLEVEL_STATE_INVALID = (1 << 4), | ||||
| }; | ||||
| 
 | ||||
| static const uint32_t no_parent = (uint32_t)-1; | ||||
| 
 | ||||
| struct toplevel_state { | ||||
| 	char *title; | ||||
| 	char *app_id; | ||||
| 
 | ||||
| 	uint32_t state; | ||||
| 	uint32_t parent_id; | ||||
| }; | ||||
| 
 | ||||
| static void copy_state(struct toplevel_state *current, | ||||
|  | @ -67,6 +70,8 @@ static void copy_state(struct toplevel_state *current, | |||
| 		current->state = pending->state; | ||||
| 	} | ||||
| 
 | ||||
| 	current->parent_id = pending->parent_id; | ||||
| 
 | ||||
| 	pending->state = TOPLEVEL_STATE_INVALID; | ||||
| } | ||||
| 
 | ||||
|  | @ -84,6 +89,12 @@ static void print_toplevel(struct toplevel_v1 *toplevel, bool print_endl) { | |||
| 			toplevel->current.title ?: "(nil)", | ||||
| 			toplevel->current.app_id ?: "(nil)"); | ||||
| 
 | ||||
| 	if (toplevel->current.parent_id != no_parent) { | ||||
| 		printf(" parent=%u", toplevel->current.parent_id); | ||||
| 	} else { | ||||
| 		printf(" no parent"); | ||||
| 	} | ||||
| 	 | ||||
| 	if (print_endl) { | ||||
| 		printf("\n"); | ||||
| 	} | ||||
|  | @ -172,6 +183,28 @@ static void toplevel_handle_state(void *data, | |||
| 	toplevel->pending.state = array_to_state(state); | ||||
| } | ||||
| 
 | ||||
| static struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager = NULL; | ||||
| static struct wl_list toplevel_list; | ||||
| 
 | ||||
| static void toplevel_handle_parent(void *data, | ||||
| 		struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel, | ||||
| 		struct zwlr_foreign_toplevel_handle_v1 *zwlr_parent) { | ||||
| 	struct toplevel_v1 *toplevel = data; | ||||
| 	toplevel->pending.parent_id = no_parent; | ||||
| 	if (zwlr_parent) { | ||||
| 		struct toplevel_v1 *toplevel_tmp; | ||||
| 		wl_list_for_each(toplevel_tmp, &toplevel_list, link) { | ||||
| 			if (toplevel_tmp->zwlr_toplevel == zwlr_parent) { | ||||
| 				toplevel->pending.parent_id = toplevel_tmp->id; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		if (toplevel->pending.parent_id == no_parent) { | ||||
| 			fprintf(stderr, "Cannot find parent toplevel!\n"); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void toplevel_handle_done(void *data, | ||||
| 		struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel) { | ||||
| 	struct toplevel_v1 *toplevel = data; | ||||
|  | @ -202,11 +235,9 @@ static const struct zwlr_foreign_toplevel_handle_v1_listener toplevel_impl = { | |||
| 	.state = toplevel_handle_state, | ||||
| 	.done = toplevel_handle_done, | ||||
| 	.closed = toplevel_handle_closed, | ||||
| 	.parent = toplevel_handle_parent | ||||
| }; | ||||
| 
 | ||||
| static struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager = NULL; | ||||
| static struct wl_list toplevel_list; | ||||
| 
 | ||||
| static void toplevel_manager_handle_toplevel(void *data, | ||||
| 		struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager, | ||||
| 		struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel) { | ||||
|  | @ -218,6 +249,8 @@ static void toplevel_manager_handle_toplevel(void *data, | |||
| 
 | ||||
| 	toplevel->id = global_id++; | ||||
| 	toplevel->zwlr_toplevel = zwlr_toplevel; | ||||
| 	toplevel->current.parent_id = no_parent; | ||||
| 	toplevel->pending.parent_id = no_parent; | ||||
| 	wl_list_insert(&toplevel_list, &toplevel->link); | ||||
| 
 | ||||
| 	zwlr_foreign_toplevel_handle_v1_add_listener(zwlr_toplevel, &toplevel_impl, | ||||
|  |  | |||
|  | @ -50,6 +50,7 @@ struct wlr_foreign_toplevel_handle_v1 { | |||
| 
 | ||||
| 	char *title; | ||||
| 	char *app_id; | ||||
| 	struct wlr_foreign_toplevel_handle_v1 *parent; | ||||
| 	struct wl_list outputs; // wlr_foreign_toplevel_v1_output
 | ||||
| 	uint32_t state; // wlr_foreign_toplevel_v1_state
 | ||||
| 
 | ||||
|  | @ -104,6 +105,12 @@ struct wlr_foreign_toplevel_manager_v1 *wlr_foreign_toplevel_manager_v1_create( | |||
| 
 | ||||
| struct wlr_foreign_toplevel_handle_v1 *wlr_foreign_toplevel_handle_v1_create( | ||||
| 	struct wlr_foreign_toplevel_manager_v1 *manager); | ||||
| /* Destroy the given toplevel handle, sending the closed event to any
 | ||||
|  * client. Also, if the destroyed toplevel is set as a parent of any | ||||
|  * other valid toplevel, clients still holding a handle to both are | ||||
|  * sent a parent signal with NULL parent. If this is not desired, the | ||||
|  * caller should ensure that any child toplevels are destroyed before | ||||
|  * the parent. */ | ||||
| void wlr_foreign_toplevel_handle_v1_destroy( | ||||
| 	struct wlr_foreign_toplevel_handle_v1 *toplevel); | ||||
| 
 | ||||
|  | @ -126,4 +133,14 @@ void wlr_foreign_toplevel_handle_v1_set_activated( | |||
| void wlr_foreign_toplevel_handle_v1_set_fullscreen( | ||||
| 	struct wlr_foreign_toplevel_handle_v1* toplevel, bool fullscreen); | ||||
| 
 | ||||
| /* Set the parent of a toplevel. If the parent changed from its previous
 | ||||
|  * value, also sends a parent event to all clients that hold handles to | ||||
|  * both toplevel and parent (no message is sent to clients that have | ||||
|  * previously destroyed their parent handle). NULL is allowed as the | ||||
|  * parent, meaning no parent exists. */ | ||||
| void wlr_foreign_toplevel_handle_v1_set_parent( | ||||
| 	struct wlr_foreign_toplevel_handle_v1 *toplevel, | ||||
| 	struct wlr_foreign_toplevel_handle_v1 *parent); | ||||
| 
 | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -25,7 +25,7 @@ | |||
|     THIS SOFTWARE. | ||||
|   </copyright> | ||||
| 
 | ||||
|   <interface name="zwlr_foreign_toplevel_manager_v1" version="2"> | ||||
|   <interface name="zwlr_foreign_toplevel_manager_v1" version="3"> | ||||
|     <description summary="list and control opened apps"> | ||||
|       The purpose of this protocol is to enable the creation of taskbars | ||||
|       and docks by providing them with a list of opened applications and | ||||
|  | @ -68,7 +68,7 @@ | |||
|     </event> | ||||
|   </interface> | ||||
| 
 | ||||
|   <interface name="zwlr_foreign_toplevel_handle_v1" version="2"> | ||||
|   <interface name="zwlr_foreign_toplevel_handle_v1" version="3"> | ||||
|     <description summary="an opened toplevel"> | ||||
|       A zwlr_foreign_toplevel_handle_v1 object represents an opened toplevel | ||||
|       window. Each app may have multiple opened toplevels. | ||||
|  | @ -255,5 +255,16 @@ | |||
|         actually changes, this will be indicated by the state event. | ||||
|       </description> | ||||
|     </request> | ||||
| 
 | ||||
|     <!-- Version 3 additions --> | ||||
| 
 | ||||
|     <event name="parent" since="3"> | ||||
|       <description summary="parent change"> | ||||
|         This event is emitted whenever the parent of the toplevel changes. | ||||
|          | ||||
|         No event is emitted when the parent handle is destroyed by the client. | ||||
|       </description> | ||||
|       <arg name="parent" type="object" interface="zwlr_foreign_toplevel_handle_v1" allow-null="true"/> | ||||
|     </event> | ||||
|   </interface> | ||||
| </protocol> | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ | |||
| #include "util/signal.h" | ||||
| #include "wlr-foreign-toplevel-management-unstable-v1-protocol.h" | ||||
| 
 | ||||
| #define FOREIGN_TOPLEVEL_MANAGEMENT_V1_VERSION 2 | ||||
| #define FOREIGN_TOPLEVEL_MANAGEMENT_V1_VERSION 3 | ||||
| 
 | ||||
| static const struct zwlr_foreign_toplevel_handle_v1_interface toplevel_handle_impl; | ||||
| 
 | ||||
|  | @ -405,6 +405,37 @@ void wlr_foreign_toplevel_handle_v1_set_fullscreen( | |||
| 	toplevel_send_state(toplevel); | ||||
| } | ||||
| 
 | ||||
| static void toplevel_resource_send_parent( | ||||
| 		struct wl_resource *toplevel_resource, | ||||
| 		struct wlr_foreign_toplevel_handle_v1 *parent) { | ||||
| 	struct wl_client *client = wl_resource_get_client(toplevel_resource); | ||||
| 	struct wl_resource *parent_resource = NULL; | ||||
| 	if (parent) { | ||||
| 		parent_resource = wl_resource_find_for_client(&parent->resources, client); | ||||
| 		if (!parent_resource) { | ||||
| 			/* don't send an event if this client destroyed the parent handle */ | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| 	zwlr_foreign_toplevel_handle_v1_send_parent(toplevel_resource, | ||||
| 		parent_resource); | ||||
| } | ||||
| 
 | ||||
| void wlr_foreign_toplevel_handle_v1_set_parent( | ||||
| 		struct wlr_foreign_toplevel_handle_v1 *toplevel, | ||||
| 		struct wlr_foreign_toplevel_handle_v1 *parent) { | ||||
| 	if (parent == toplevel->parent) { | ||||
| 		/* only send parent event to the clients if there was a change */ | ||||
| 		return; | ||||
| 	} | ||||
| 	struct wl_resource *toplevel_resource, *tmp; | ||||
| 	wl_resource_for_each_safe(toplevel_resource, tmp, &toplevel->resources) { | ||||
| 		toplevel_resource_send_parent(toplevel_resource, parent); | ||||
| 	} | ||||
| 	toplevel->parent = parent; | ||||
| 	toplevel_update_idle_source(toplevel); | ||||
| } | ||||
| 
 | ||||
| void wlr_foreign_toplevel_handle_v1_destroy( | ||||
| 		struct wlr_foreign_toplevel_handle_v1 *toplevel) { | ||||
| 	if (!toplevel) { | ||||
|  | @ -432,6 +463,19 @@ void wlr_foreign_toplevel_handle_v1_destroy( | |||
| 
 | ||||
| 	wl_list_remove(&toplevel->link); | ||||
| 
 | ||||
| 	/* need to ensure no other toplevels hold a pointer to this one as
 | ||||
| 	 * a parent, so that a later call to foreign_toplevel_manager_bind() | ||||
| 	 * will not result in a segfault */ | ||||
| 	struct wlr_foreign_toplevel_handle_v1 *tl, *tmp3; | ||||
| 	wl_list_for_each_safe(tl, tmp3, &toplevel->manager->toplevels, link) { | ||||
| 		if (tl->parent == toplevel) { | ||||
| 			/* Note: we send a parent signal to all clients in this case;
 | ||||
| 			 * the caller should first destroy the child handles if it | ||||
| 			 * wishes to avoid this behavior. */ | ||||
| 			wlr_foreign_toplevel_handle_v1_set_parent(tl, NULL); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	free(toplevel->title); | ||||
| 	free(toplevel->app_id); | ||||
| 	free(toplevel); | ||||
|  | @ -542,6 +586,8 @@ static void toplevel_send_details_to_toplevel_resource( | |||
| 	zwlr_foreign_toplevel_handle_v1_send_state(resource, &states); | ||||
| 	wl_array_release(&states); | ||||
| 
 | ||||
| 	toplevel_resource_send_parent(resource, toplevel->parent); | ||||
| 
 | ||||
| 	zwlr_foreign_toplevel_handle_v1_send_done(resource); | ||||
| } | ||||
| 
 | ||||
|  | @ -560,9 +606,17 @@ static void foreign_toplevel_manager_bind(struct wl_client *client, void *data, | |||
| 	wl_list_insert(&manager->resources, wl_resource_get_link(resource)); | ||||
| 
 | ||||
| 	struct wlr_foreign_toplevel_handle_v1 *toplevel, *tmp; | ||||
| 	/* First loop: create a handle for all toplevels for all clients.
 | ||||
| 	 * Separation into two loops avoid the case where a child handle | ||||
| 	 * is created before a parent handle, so the parent relationship | ||||
| 	 * could not be sent to a client. */ | ||||
| 	wl_list_for_each_safe(toplevel, tmp, &manager->toplevels, link) { | ||||
| 		create_toplevel_resource_for_resource(toplevel, resource); | ||||
| 	} | ||||
| 	/* Second loop: send details about each toplevel. */ | ||||
| 	wl_list_for_each_safe(toplevel, tmp, &manager->toplevels, link) { | ||||
| 		struct wl_resource *toplevel_resource = | ||||
| 			create_toplevel_resource_for_resource(toplevel, resource); | ||||
| 			wl_resource_find_for_client(&toplevel->resources, client); | ||||
| 		toplevel_send_details_to_toplevel_resource(toplevel, | ||||
| 			toplevel_resource); | ||||
| 	} | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Daniel Kondor
						Daniel Kondor