mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2025-10-28 05:40:11 -04:00
xdg-toplevel-icon-v1: add implementation
This commit is contained in:
parent
061aa1bd15
commit
bcf8e467db
4 changed files with 375 additions and 0 deletions
80
include/wlr/types/wlr_xdg_toplevel_icon_v1.h
Normal file
80
include/wlr/types/wlr_xdg_toplevel_icon_v1.h
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* This an unstable interface of wlroots. No guarantees are made regarding the
|
||||
* future consistency of this API.
|
||||
*/
|
||||
#ifndef WLR_USE_UNSTABLE
|
||||
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
|
||||
#endif
|
||||
|
||||
#ifndef WLR_TYPES_WLR_XDG_TOPLEVEL_ICON_V1_H
|
||||
#define WLR_TYPES_WLR_XDG_TOPLEVEL_ICON_V1_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
|
||||
#include <wlr/util/addon.h>
|
||||
|
||||
struct wlr_xdg_toplevel_icon_manager_v1 {
|
||||
struct wl_global *global;
|
||||
|
||||
struct wl_list resources;
|
||||
|
||||
int *sizes;
|
||||
size_t n_sizes;
|
||||
|
||||
struct {
|
||||
struct wl_signal set_icon; // struct wlr_xdg_toplevel_icon_manager_v1_set_icon_event
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_xdg_toplevel_icon_manager_v1_set_icon_event {
|
||||
struct wlr_xdg_toplevel *toplevel;
|
||||
|
||||
// Must be referenced to be used after the event is emitted
|
||||
struct wlr_xdg_toplevel_icon_v1 *icon; // May be NULL
|
||||
};
|
||||
|
||||
struct wlr_xdg_toplevel_icon_v1_buffer {
|
||||
struct wlr_buffer *buffer;
|
||||
int scale;
|
||||
|
||||
struct wl_list link; // wlr_xdg_toplevel_icon_v1.buffers
|
||||
};
|
||||
|
||||
struct wlr_xdg_toplevel_icon_v1 {
|
||||
char *name; // May be NULL
|
||||
struct wl_list buffers; // wlr_xdg_toplevel_icon_v1_buffer.link
|
||||
|
||||
struct {
|
||||
int n_refs;
|
||||
bool immutable;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_xdg_toplevel_icon_manager_v1 *wlr_xdg_toplevel_icon_manager_v1_create(
|
||||
struct wl_display *display, uint32_t version);
|
||||
|
||||
/**
|
||||
* Set icon size preferences.
|
||||
*
|
||||
* The list may be empty.
|
||||
*/
|
||||
void wlr_xdg_toplevel_icon_manager_v1_set_sizes(struct wlr_xdg_toplevel_icon_manager_v1 *manager,
|
||||
int *sizes, size_t n_sizes);
|
||||
|
||||
/**
|
||||
* Reference an icon.
|
||||
*/
|
||||
struct wlr_xdg_toplevel_icon_v1 *wlr_xdg_toplevel_icon_v1_ref(
|
||||
struct wlr_xdg_toplevel_icon_v1 *icon);
|
||||
|
||||
/**
|
||||
* Unreference an icon. When the icon reference count reaches 0, it is destroyed.
|
||||
*/
|
||||
void wlr_xdg_toplevel_icon_v1_unref(struct wlr_xdg_toplevel_icon_v1 *icon);
|
||||
|
||||
#endif
|
||||
|
|
@ -39,6 +39,7 @@ protocols = {
|
|||
'xdg-activation-v1': wl_protocol_dir / 'staging/xdg-activation/xdg-activation-v1.xml',
|
||||
'xdg-dialog-v1': wl_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml',
|
||||
'xdg-system-bell-v1': wl_protocol_dir / 'staging/xdg-system-bell/xdg-system-bell-v1.xml',
|
||||
'xdg-toplevel-icon-v1': wl_protocol_dir / 'staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml',
|
||||
'xwayland-shell-v1': wl_protocol_dir / 'staging/xwayland-shell/xwayland-shell-v1.xml',
|
||||
'tearing-control-v1': wl_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml',
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ wlr_files += files(
|
|||
'wlr_xdg_foreign_v2.c',
|
||||
'wlr_xdg_foreign_registry.c',
|
||||
'wlr_xdg_output_v1.c',
|
||||
'wlr_xdg_toplevel_icon_v1.c',
|
||||
)
|
||||
|
||||
if features.get('drm-backend')
|
||||
|
|
|
|||
293
types/wlr_xdg_toplevel_icon_v1.c
Normal file
293
types/wlr_xdg_toplevel_icon_v1.c
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <wayland-server-protocol.h>
|
||||
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/types/wlr_xdg_toplevel_icon_v1.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
#include "xdg-toplevel-icon-v1-protocol.h"
|
||||
|
||||
#define MANAGER_VERSION 1
|
||||
|
||||
static const struct xdg_toplevel_icon_v1_interface icon_impl;
|
||||
|
||||
static struct wlr_xdg_toplevel_icon_v1 *icon_from_resource(struct wl_resource *resource) {
|
||||
assert(wl_resource_instance_of(resource, &xdg_toplevel_icon_v1_interface, &icon_impl));
|
||||
return wl_resource_get_user_data(resource);
|
||||
}
|
||||
|
||||
static void icon_destroy(struct wlr_xdg_toplevel_icon_v1 *icon) {
|
||||
struct wlr_xdg_toplevel_icon_v1_buffer *icon_buffer, *tmp;
|
||||
wl_list_for_each_safe(icon_buffer, tmp, &icon->buffers, link) {
|
||||
wlr_buffer_unlock(icon_buffer->buffer);
|
||||
wl_list_remove(&icon_buffer->link);
|
||||
free(icon_buffer);
|
||||
}
|
||||
|
||||
free(icon->name);
|
||||
free(icon);
|
||||
}
|
||||
|
||||
static void icon_handle_destroy(struct wl_client *client, struct wl_resource *resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void icon_handle_set_name(struct wl_client *client, struct wl_resource *resource,
|
||||
const char *name) {
|
||||
struct wlr_xdg_toplevel_icon_v1 *icon = icon_from_resource(resource);
|
||||
if (icon->immutable) {
|
||||
wl_resource_post_error(resource, XDG_TOPLEVEL_ICON_V1_ERROR_IMMUTABLE,
|
||||
"the icon has already been assigned to a toplevel and must not be changed");
|
||||
return;
|
||||
}
|
||||
|
||||
char *dup = strdup(name);
|
||||
if (dup == NULL) {
|
||||
wl_resource_post_no_memory(resource);
|
||||
return;
|
||||
}
|
||||
|
||||
free(icon->name);
|
||||
icon->name = dup;
|
||||
}
|
||||
|
||||
static void icon_handle_add_buffer(struct wl_client *client, struct wl_resource *resource,
|
||||
struct wl_resource *buffer_resource, int32_t scale) {
|
||||
struct wlr_xdg_toplevel_icon_v1 *icon = icon_from_resource(resource);
|
||||
if (icon->immutable) {
|
||||
wl_resource_post_error(resource, XDG_TOPLEVEL_ICON_V1_ERROR_IMMUTABLE,
|
||||
"the icon has already been assigned to a toplevel and must not be changed");
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_buffer *buffer = wlr_buffer_try_from_resource(buffer_resource);
|
||||
|
||||
const char *bad_buffer_msg = NULL;
|
||||
|
||||
struct wlr_shm_attributes shm_attribs;
|
||||
if (!wlr_buffer_get_shm(buffer, &shm_attribs)) {
|
||||
bad_buffer_msg = "not backed by wl_shm";
|
||||
} else if (buffer->width != buffer->height) {
|
||||
bad_buffer_msg = "not square";
|
||||
}
|
||||
|
||||
if (bad_buffer_msg != NULL) {
|
||||
wl_resource_post_error(resource, XDG_TOPLEVEL_ICON_V1_ERROR_INVALID_BUFFER,
|
||||
"the provided buffer does not satisfy requirements: %s", bad_buffer_msg);
|
||||
wlr_buffer_unlock(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_xdg_toplevel_icon_v1_buffer *icon_buffer;
|
||||
wl_list_for_each(icon_buffer, &icon->buffers, link) {
|
||||
if (icon_buffer->buffer->width == buffer->width && icon_buffer->scale == scale) {
|
||||
wlr_buffer_unlock(icon_buffer->buffer);
|
||||
icon_buffer->buffer = buffer;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
icon_buffer = calloc(1, sizeof(*icon_buffer));
|
||||
if (icon_buffer == NULL) {
|
||||
wl_resource_post_no_memory(resource);
|
||||
}
|
||||
|
||||
icon_buffer->buffer = buffer;
|
||||
icon_buffer->scale = scale;
|
||||
|
||||
wl_list_insert(&icon->buffers, &icon_buffer->link);
|
||||
}
|
||||
|
||||
static const struct xdg_toplevel_icon_v1_interface icon_impl = {
|
||||
.destroy = icon_handle_destroy,
|
||||
.set_name = icon_handle_set_name,
|
||||
.add_buffer = icon_handle_add_buffer,
|
||||
};
|
||||
|
||||
static void icon_handle_resource_destroy(struct wl_resource *resource) {
|
||||
wlr_xdg_toplevel_icon_v1_unref(icon_from_resource(resource));
|
||||
}
|
||||
|
||||
struct wlr_xdg_toplevel_icon_v1 *wlr_xdg_toplevel_icon_v1_ref(
|
||||
struct wlr_xdg_toplevel_icon_v1 *icon) {
|
||||
++icon->n_refs;
|
||||
return icon;
|
||||
}
|
||||
|
||||
void wlr_xdg_toplevel_icon_v1_unref(struct wlr_xdg_toplevel_icon_v1 *icon) {
|
||||
if (icon == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(icon->n_refs > 0);
|
||||
--icon->n_refs;
|
||||
if (icon->n_refs == 0) {
|
||||
icon_destroy(icon);
|
||||
};
|
||||
}
|
||||
|
||||
static const struct xdg_toplevel_icon_manager_v1_interface manager_impl;
|
||||
|
||||
static struct wlr_xdg_toplevel_icon_manager_v1 *manager_from_resource(
|
||||
struct wl_resource *resource) {
|
||||
assert(wl_resource_instance_of(resource, &xdg_toplevel_icon_manager_v1_interface,
|
||||
&manager_impl));
|
||||
return wl_resource_get_user_data(resource);
|
||||
}
|
||||
|
||||
static void manager_handle_destroy(struct wl_client *client, struct wl_resource *resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void manager_handle_create_icon(struct wl_client *client, struct wl_resource *resource,
|
||||
uint32_t id) {
|
||||
struct wlr_xdg_toplevel_icon_v1 *icon = calloc(1, sizeof(*icon));
|
||||
if (icon == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
|
||||
struct wl_resource *icon_resource = wl_resource_create(client,
|
||||
&xdg_toplevel_icon_v1_interface, wl_resource_get_version(resource), id);
|
||||
if (resource == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
free(icon);
|
||||
return;
|
||||
}
|
||||
|
||||
wl_list_init(&icon->buffers);
|
||||
icon->n_refs = 1;
|
||||
|
||||
wl_resource_set_implementation(icon_resource, &icon_impl, icon, icon_handle_resource_destroy);
|
||||
}
|
||||
|
||||
static void manager_handle_set_icon(struct wl_client *client, struct wl_resource *resource,
|
||||
struct wl_resource *toplevel_resource, struct wl_resource *icon_resource) {
|
||||
struct wlr_xdg_toplevel_icon_manager_v1 *manager = manager_from_resource(resource);
|
||||
struct wlr_xdg_toplevel *toplevel = wlr_xdg_toplevel_from_resource(toplevel_resource);
|
||||
|
||||
struct wlr_xdg_toplevel_icon_v1 *icon = NULL;
|
||||
if (icon_resource != NULL) {
|
||||
icon = icon_from_resource(icon_resource);
|
||||
icon->immutable = true;
|
||||
|
||||
if (icon->name == NULL && wl_list_empty(&icon->buffers)) {
|
||||
// Same as supplying null icon
|
||||
icon = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct wlr_xdg_toplevel_icon_manager_v1_set_icon_event event = {
|
||||
.toplevel = toplevel,
|
||||
.icon = icon,
|
||||
};
|
||||
|
||||
wl_signal_emit_mutable(&manager->events.set_icon, &event);
|
||||
}
|
||||
|
||||
static const struct xdg_toplevel_icon_manager_v1_interface manager_impl = {
|
||||
.destroy = manager_handle_destroy,
|
||||
.create_icon = manager_handle_create_icon,
|
||||
.set_icon = manager_handle_set_icon,
|
||||
};
|
||||
|
||||
static void manager_send_sizes(struct wlr_xdg_toplevel_icon_manager_v1 *manager,
|
||||
struct wl_resource *resource) {
|
||||
for (size_t i = 0; i < manager->n_sizes; i++) {
|
||||
xdg_toplevel_icon_manager_v1_send_icon_size(resource, manager->sizes[i]);
|
||||
}
|
||||
xdg_toplevel_icon_manager_v1_send_done(resource);
|
||||
}
|
||||
|
||||
static void manager_handle_resource_destroy(struct wl_resource *resource) {
|
||||
wl_list_remove(wl_resource_get_link(resource));
|
||||
}
|
||||
|
||||
static void manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) {
|
||||
struct wlr_xdg_toplevel_icon_manager_v1 *manager = data;
|
||||
|
||||
struct wl_resource *resource = wl_resource_create(client,
|
||||
&xdg_toplevel_icon_manager_v1_interface, version, id);
|
||||
if (resource == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(resource, &manager_impl, manager, manager_handle_resource_destroy);
|
||||
|
||||
wl_list_insert(&manager->resources, wl_resource_get_link(resource));
|
||||
|
||||
manager_send_sizes(manager, resource);
|
||||
}
|
||||
|
||||
static void manager_handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_xdg_toplevel_icon_manager_v1 *manager =
|
||||
wl_container_of(listener, manager, display_destroy);
|
||||
|
||||
wl_signal_emit_mutable(&manager->events.destroy, NULL);
|
||||
|
||||
wl_list_remove(&manager->display_destroy.link);
|
||||
wl_global_destroy(manager->global);
|
||||
|
||||
wl_list_remove(&manager->resources);
|
||||
|
||||
free(manager->sizes);
|
||||
free(manager);
|
||||
}
|
||||
|
||||
void wlr_xdg_toplevel_icon_manager_v1_set_sizes(struct wlr_xdg_toplevel_icon_manager_v1 *manager,
|
||||
int *sizes, size_t n_sizes) {
|
||||
if (n_sizes != manager->n_sizes) {
|
||||
int *dup_sizes = NULL;
|
||||
if (n_sizes > 0) {
|
||||
dup_sizes = calloc(n_sizes, sizeof(*dup_sizes));
|
||||
if (dup_sizes == NULL) {
|
||||
wlr_log(WLR_ERROR, "Allocation failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
free(manager->sizes);
|
||||
manager->sizes = dup_sizes;
|
||||
manager->n_sizes = n_sizes;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < n_sizes; i++) {
|
||||
manager->sizes[i] = sizes[i];
|
||||
}
|
||||
|
||||
struct wl_resource *resource;
|
||||
wl_resource_for_each(resource, &manager->resources) {
|
||||
manager_send_sizes(manager, resource);
|
||||
}
|
||||
}
|
||||
|
||||
struct wlr_xdg_toplevel_icon_manager_v1 *wlr_xdg_toplevel_icon_manager_v1_create(
|
||||
struct wl_display *display, uint32_t version) {
|
||||
assert(version <= MANAGER_VERSION);
|
||||
|
||||
struct wlr_xdg_toplevel_icon_manager_v1 *manager = calloc(1, sizeof(*manager));
|
||||
if (manager == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
manager->global = wl_global_create(display, &xdg_toplevel_icon_manager_v1_interface,
|
||||
version, manager, manager_bind);
|
||||
if (manager->global == NULL) {
|
||||
free(manager);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wl_signal_init(&manager->events.set_icon);
|
||||
wl_signal_init(&manager->events.destroy);
|
||||
|
||||
wl_list_init(&manager->resources);
|
||||
|
||||
manager->display_destroy.notify = manager_handle_display_destroy;
|
||||
wl_display_add_destroy_listener(display, &manager->display_destroy);
|
||||
|
||||
return manager;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue