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
|
@ -7,7 +7,7 @@
|
||||||
#include <wayland-client.h>
|
#include <wayland-client.h>
|
||||||
#include "wlr-foreign-toplevel-management-unstable-v1-client-protocol.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:
|
* Usage:
|
||||||
|
@ -38,11 +38,14 @@ enum toplevel_state_field {
|
||||||
TOPLEVEL_STATE_INVALID = (1 << 4),
|
TOPLEVEL_STATE_INVALID = (1 << 4),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const uint32_t no_parent = (uint32_t)-1;
|
||||||
|
|
||||||
struct toplevel_state {
|
struct toplevel_state {
|
||||||
char *title;
|
char *title;
|
||||||
char *app_id;
|
char *app_id;
|
||||||
|
|
||||||
uint32_t state;
|
uint32_t state;
|
||||||
|
uint32_t parent_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void copy_state(struct toplevel_state *current,
|
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->state = pending->state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
current->parent_id = pending->parent_id;
|
||||||
|
|
||||||
pending->state = TOPLEVEL_STATE_INVALID;
|
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.title ?: "(nil)",
|
||||||
toplevel->current.app_id ?: "(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) {
|
if (print_endl) {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
@ -172,6 +183,28 @@ static void toplevel_handle_state(void *data,
|
||||||
toplevel->pending.state = array_to_state(state);
|
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,
|
static void toplevel_handle_done(void *data,
|
||||||
struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel) {
|
struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel) {
|
||||||
struct toplevel_v1 *toplevel = data;
|
struct toplevel_v1 *toplevel = data;
|
||||||
|
@ -202,11 +235,9 @@ static const struct zwlr_foreign_toplevel_handle_v1_listener toplevel_impl = {
|
||||||
.state = toplevel_handle_state,
|
.state = toplevel_handle_state,
|
||||||
.done = toplevel_handle_done,
|
.done = toplevel_handle_done,
|
||||||
.closed = toplevel_handle_closed,
|
.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,
|
static void toplevel_manager_handle_toplevel(void *data,
|
||||||
struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager,
|
struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager,
|
||||||
struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel) {
|
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->id = global_id++;
|
||||||
toplevel->zwlr_toplevel = zwlr_toplevel;
|
toplevel->zwlr_toplevel = zwlr_toplevel;
|
||||||
|
toplevel->current.parent_id = no_parent;
|
||||||
|
toplevel->pending.parent_id = no_parent;
|
||||||
wl_list_insert(&toplevel_list, &toplevel->link);
|
wl_list_insert(&toplevel_list, &toplevel->link);
|
||||||
|
|
||||||
zwlr_foreign_toplevel_handle_v1_add_listener(zwlr_toplevel, &toplevel_impl,
|
zwlr_foreign_toplevel_handle_v1_add_listener(zwlr_toplevel, &toplevel_impl,
|
||||||
|
|
|
@ -50,6 +50,7 @@ struct wlr_foreign_toplevel_handle_v1 {
|
||||||
|
|
||||||
char *title;
|
char *title;
|
||||||
char *app_id;
|
char *app_id;
|
||||||
|
struct wlr_foreign_toplevel_handle_v1 *parent;
|
||||||
struct wl_list outputs; // wlr_foreign_toplevel_v1_output
|
struct wl_list outputs; // wlr_foreign_toplevel_v1_output
|
||||||
uint32_t state; // wlr_foreign_toplevel_v1_state
|
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_handle_v1 *wlr_foreign_toplevel_handle_v1_create(
|
||||||
struct wlr_foreign_toplevel_manager_v1 *manager);
|
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(
|
void wlr_foreign_toplevel_handle_v1_destroy(
|
||||||
struct wlr_foreign_toplevel_handle_v1 *toplevel);
|
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(
|
void wlr_foreign_toplevel_handle_v1_set_fullscreen(
|
||||||
struct wlr_foreign_toplevel_handle_v1* toplevel, bool 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
|
#endif
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
THIS SOFTWARE.
|
THIS SOFTWARE.
|
||||||
</copyright>
|
</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">
|
<description summary="list and control opened apps">
|
||||||
The purpose of this protocol is to enable the creation of taskbars
|
The purpose of this protocol is to enable the creation of taskbars
|
||||||
and docks by providing them with a list of opened applications and
|
and docks by providing them with a list of opened applications and
|
||||||
|
@ -68,7 +68,7 @@
|
||||||
</event>
|
</event>
|
||||||
</interface>
|
</interface>
|
||||||
|
|
||||||
<interface name="zwlr_foreign_toplevel_handle_v1" version="2">
|
<interface name="zwlr_foreign_toplevel_handle_v1" version="3">
|
||||||
<description summary="an opened toplevel">
|
<description summary="an opened toplevel">
|
||||||
A zwlr_foreign_toplevel_handle_v1 object represents an opened toplevel
|
A zwlr_foreign_toplevel_handle_v1 object represents an opened toplevel
|
||||||
window. Each app may have multiple opened toplevels.
|
window. Each app may have multiple opened toplevels.
|
||||||
|
@ -255,5 +255,16 @@
|
||||||
actually changes, this will be indicated by the state event.
|
actually changes, this will be indicated by the state event.
|
||||||
</description>
|
</description>
|
||||||
</request>
|
</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>
|
</interface>
|
||||||
</protocol>
|
</protocol>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include "util/signal.h"
|
#include "util/signal.h"
|
||||||
#include "wlr-foreign-toplevel-management-unstable-v1-protocol.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;
|
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);
|
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(
|
void wlr_foreign_toplevel_handle_v1_destroy(
|
||||||
struct wlr_foreign_toplevel_handle_v1 *toplevel) {
|
struct wlr_foreign_toplevel_handle_v1 *toplevel) {
|
||||||
if (!toplevel) {
|
if (!toplevel) {
|
||||||
|
@ -432,6 +463,19 @@ void wlr_foreign_toplevel_handle_v1_destroy(
|
||||||
|
|
||||||
wl_list_remove(&toplevel->link);
|
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->title);
|
||||||
free(toplevel->app_id);
|
free(toplevel->app_id);
|
||||||
free(toplevel);
|
free(toplevel);
|
||||||
|
@ -542,6 +586,8 @@ static void toplevel_send_details_to_toplevel_resource(
|
||||||
zwlr_foreign_toplevel_handle_v1_send_state(resource, &states);
|
zwlr_foreign_toplevel_handle_v1_send_state(resource, &states);
|
||||||
wl_array_release(&states);
|
wl_array_release(&states);
|
||||||
|
|
||||||
|
toplevel_resource_send_parent(resource, toplevel->parent);
|
||||||
|
|
||||||
zwlr_foreign_toplevel_handle_v1_send_done(resource);
|
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));
|
wl_list_insert(&manager->resources, wl_resource_get_link(resource));
|
||||||
|
|
||||||
struct wlr_foreign_toplevel_handle_v1 *toplevel, *tmp;
|
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) {
|
wl_list_for_each_safe(toplevel, tmp, &manager->toplevels, link) {
|
||||||
struct wl_resource *toplevel_resource =
|
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_send_details_to_toplevel_resource(toplevel,
|
||||||
toplevel_resource);
|
toplevel_resource);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue