summaryrefslogtreecommitdiff
path: root/libdecor/src/libdecor.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdecor/src/libdecor.c')
-rw-r--r--libdecor/src/libdecor.c1871
1 files changed, 0 insertions, 1871 deletions
diff --git a/libdecor/src/libdecor.c b/libdecor/src/libdecor.c
deleted file mode 100644
index 39886c80f..000000000
--- a/libdecor/src/libdecor.c
+++ /dev/null
@@ -1,1871 +0,0 @@
-/*
- * Copyright © 2017-2018 Red Hat Inc.
- * Copyright © 2018 Jonas Ådahl
- * Copyright © 2019 Christian Rauch
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <errno.h>
-#include <dirent.h>
-#include <dlfcn.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include "libdecor.h"
-#include "libdecor-fallback.h"
-#include "libdecor-plugin.h"
-#include "utils.h"
-
-#include "xdg-shell-client-protocol.h"
-#include "xdg-decoration-client-protocol.h"
-
-struct libdecor {
- int ref_count;
-
- const struct libdecor_interface *iface;
- void *user_data;
-
- struct libdecor_plugin *plugin;
- bool plugin_ready;
-
- struct wl_display *wl_display;
- struct wl_registry *wl_registry;
- struct xdg_wm_base *xdg_wm_base;
- struct zxdg_decoration_manager_v1 *decoration_manager;
-
- struct wl_callback *init_callback;
- bool init_done;
- bool has_error;
-
- struct wl_list frames;
-};
-
-struct libdecor_state {
- enum libdecor_window_state window_state;
-
- int content_width;
- int content_height;
-};
-
-struct libdecor_limits {
- int min_width;
- int min_height;
- int max_width;
- int max_height;
-};
-
-struct libdecor_configuration {
- uint32_t serial;
-
- bool has_window_state;
- enum libdecor_window_state window_state;
-
- bool has_size;
- int window_width;
- int window_height;
-};
-
-struct libdecor_frame_private {
- int ref_count;
-
- struct libdecor *context;
-
- struct wl_surface *wl_surface;
-
- const struct libdecor_frame_interface *iface;
- void *user_data;
-
- struct xdg_surface *xdg_surface;
- struct xdg_toplevel *xdg_toplevel;
- struct zxdg_toplevel_decoration_v1 *toplevel_decoration;
-
- bool pending_map;
-
- struct {
- char *app_id;
- char *title;
- struct libdecor_limits content_limits;
- struct xdg_toplevel *parent;
- } state;
-
- struct libdecor_configuration *pending_configuration;
-
- int content_width;
- int content_height;
-
- enum libdecor_window_state window_state;
-
- bool has_decoration_mode;
- enum zxdg_toplevel_decoration_v1_mode decoration_mode;
-
- enum libdecor_capabilities capabilities;
-
- enum libdecor_wm_capabilities wm_capabilities;
-
- /* original limits for interactive resize */
- struct libdecor_limits interactive_limits;
-
- bool visible;
-};
-
-struct libdecor_plugin_private {
- struct libdecor_plugin_interface *iface;
-};
-
-/* gather all states at which a window is non-floating */
-static const enum libdecor_window_state states_non_floating =
- LIBDECOR_WINDOW_STATE_MAXIMIZED | LIBDECOR_WINDOW_STATE_FULLSCREEN |
- LIBDECOR_WINDOW_STATE_TILED_LEFT | LIBDECOR_WINDOW_STATE_TILED_RIGHT |
- LIBDECOR_WINDOW_STATE_TILED_TOP | LIBDECOR_WINDOW_STATE_TILED_BOTTOM;
-
-static bool
-streql(const char *str1, const char *str2)
-{
- return (str1 && str2) && (strcmp(str1, str2) == 0);
-}
-
-
-static void
-do_map(struct libdecor_frame *frame);
-
-static bool
-state_is_floating(enum libdecor_window_state window_state)
-{
- return !(window_state & states_non_floating);
-}
-
-static void
-constrain_content_size(const struct libdecor_frame *frame,
- int *width,
- int *height)
-{
- const struct libdecor_limits lim = frame->priv->state.content_limits;
-
- if (lim.min_width > 0)
- *width = MAX(lim.min_width, *width);
- if (lim.max_width > 0)
- *width = MIN(*width, lim.max_width);
-
- if (lim.min_height > 0)
- *height = MAX(lim.min_height, *height);
- if (lim.max_height > 0)
- *height = MIN(*height, lim.max_height);
-}
-
-static bool
-frame_has_visible_client_side_decoration(struct libdecor_frame *frame)
-{
- /* visibility by client configuration */
- const bool vis_client = frame->priv->visible;
- /* visibility by compositor configuration */
- const bool vis_server = (frame->priv->decoration_mode ==
- ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE);
-
- return vis_client && vis_server;
-}
-
-LIBDECOR_EXPORT int
-libdecor_state_get_content_width(struct libdecor_state *state)
-{
- return state->content_width;
-}
-
-LIBDECOR_EXPORT int
-libdecor_state_get_content_height(struct libdecor_state *state)
-{
- return state->content_height;
-}
-
-LIBDECOR_EXPORT enum libdecor_window_state
-libdecor_state_get_window_state(struct libdecor_state *state)
-{
- return state->window_state;
-}
-
-LIBDECOR_EXPORT struct libdecor_state *
-libdecor_state_new(int width,
- int height)
-{
- struct libdecor_state *state;
-
- state = zalloc(sizeof *state);
- state->content_width = width;
- state->content_height = height;
-
- return state;
-}
-
-LIBDECOR_EXPORT void
-libdecor_state_free(struct libdecor_state *state)
-{
- free(state);
-}
-
-static struct libdecor_configuration *
-libdecor_configuration_new(void)
-{
- struct libdecor_configuration *configuration;
-
- configuration = zalloc(sizeof *configuration);
-
- return configuration;
-}
-
-static void
-libdecor_configuration_free(struct libdecor_configuration *configuration)
-{
- free(configuration);
-}
-
-static bool
-frame_get_window_size_for(struct libdecor_frame *frame,
- struct libdecor_state *state,
- int *window_width,
- int *window_height)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
- struct libdecor *context = frame_priv->context;
- struct libdecor_plugin *plugin = context->plugin;
-
- *window_width = state->content_width;
- *window_height = state->content_height;
-
- if (frame_has_visible_client_side_decoration(frame) &&
- plugin->priv->iface->frame_get_border_size) {
- int left, right, top, bottom;
- if (!plugin->priv->iface->frame_get_border_size(
- plugin, frame, NULL, &left, &right, &top, &bottom))
- return false;
- *window_width += left + right;
- *window_height += top + bottom;
- }
-
- return true;
-}
-
-static void
-frame_set_window_geometry(struct libdecor_frame *frame,
- int32_t content_width, int32_t content_height)
-{
- struct libdecor_plugin *plugin = frame->priv->context->plugin;
- int x, y, width, height;
- int left, right, top, bottom;
-
- plugin->priv->iface->frame_get_border_size(plugin, frame, NULL,
- &left, &right, &top, &bottom);
- x = -left;
- y = -top;
- width = content_width + left + right;
- height = content_height + top + bottom;
- xdg_surface_set_window_geometry(frame->priv->xdg_surface, x, y, width, height);
-}
-
-LIBDECOR_EXPORT bool
-libdecor_configuration_get_content_size(struct libdecor_configuration *configuration,
- struct libdecor_frame *frame,
- int *width,
- int *height)
-{
- struct libdecor_plugin *plugin = frame->priv->context->plugin;
-
- /* get configured toplevel dimensions */
- if (!configuration->has_size)
- return false;
-
- if (configuration->window_width == 0 || configuration->window_height == 0)
- return false;
-
- *width = configuration->window_width;
- *height = configuration->window_height;
-
- /* remove plugin-specific border size */
- if (frame_has_visible_client_side_decoration(frame) &&
- plugin->priv->iface->frame_get_border_size) {
- int left, right, top, bottom;
-
- /* Update window state for correct border size calculation */
- frame->priv->window_state = configuration->window_state;
- if (!plugin->priv->iface->frame_get_border_size(
- plugin, frame, configuration, &left, &right, &top, &bottom))
- return false;
-
- *width -= (left + right);
- *height -= (top + bottom);
- }
-
- /* constrain content dimensions manually */
- if (state_is_floating(configuration->window_state)) {
- constrain_content_size(frame, width, height);
- }
-
- return true;
-}
-
-LIBDECOR_EXPORT bool
-libdecor_configuration_get_window_state(struct libdecor_configuration *configuration,
- enum libdecor_window_state *window_state)
-{
- if (!configuration->has_window_state)
- return false;
-
- *window_state = configuration->window_state;
- return true;
-}
-
-static void
-xdg_surface_configure(void *user_data,
- struct xdg_surface *xdg_surface,
- uint32_t serial)
-{
- struct libdecor_frame *frame = user_data;
- struct libdecor_frame_private *frame_priv = frame->priv;
- struct libdecor_configuration *configuration;
-
- configuration = frame_priv->pending_configuration;
- frame_priv->pending_configuration = NULL;
-
- if (!configuration)
- configuration = libdecor_configuration_new();
-
- configuration->serial = serial;
-
- frame_priv->iface->configure(frame,
- configuration,
- frame_priv->user_data);
-
- libdecor_configuration_free(configuration);
-}
-
-static const struct xdg_surface_listener xdg_surface_listener = {
- xdg_surface_configure,
-};
-
-static enum libdecor_window_state
-parse_states(struct wl_array *states)
-{
- enum libdecor_window_state pending_state = LIBDECOR_WINDOW_STATE_NONE;
- uint32_t *p;
-
- wl_array_for_each(p, states) {
- enum xdg_toplevel_state state = *p;
-
- switch (state) {
- case XDG_TOPLEVEL_STATE_FULLSCREEN:
- pending_state |= LIBDECOR_WINDOW_STATE_FULLSCREEN;
- break;
- case XDG_TOPLEVEL_STATE_MAXIMIZED:
- pending_state |= LIBDECOR_WINDOW_STATE_MAXIMIZED;
- break;
- case XDG_TOPLEVEL_STATE_ACTIVATED:
- pending_state |= LIBDECOR_WINDOW_STATE_ACTIVE;
- break;
- case XDG_TOPLEVEL_STATE_TILED_LEFT:
- pending_state |= LIBDECOR_WINDOW_STATE_TILED_LEFT;
- break;
- case XDG_TOPLEVEL_STATE_TILED_RIGHT:
- pending_state |= LIBDECOR_WINDOW_STATE_TILED_RIGHT;
- break;
- case XDG_TOPLEVEL_STATE_TILED_TOP:
- pending_state |= LIBDECOR_WINDOW_STATE_TILED_TOP;
- break;
- case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
- pending_state |= LIBDECOR_WINDOW_STATE_TILED_BOTTOM;
- break;
- case XDG_TOPLEVEL_STATE_RESIZING:
- pending_state |= LIBDECOR_WINDOW_STATE_RESIZING;
- break;
-#ifdef XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION
- case XDG_TOPLEVEL_STATE_SUSPENDED:
- pending_state |= LIBDECOR_WINDOW_STATE_SUSPENDED;
- break;
-#endif
-#ifdef XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT_SINCE_VERSION
- case XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT:
- pending_state |= LIBDECOR_WINDOW_STATE_CONSTRAINED_LEFT;
- break;
- case XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT:
- pending_state |= LIBDECOR_WINDOW_STATE_CONSTRAINED_RIGHT;
- break;
- case XDG_TOPLEVEL_STATE_CONSTRAINED_TOP:
- pending_state |= LIBDECOR_WINDOW_STATE_CONSTRAINED_TOP;
- break;
- case XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM:
- pending_state |= LIBDECOR_WINDOW_STATE_CONSTRAINED_BOTTOM;
- break;
-#endif
- default:
- break;
- }
- }
-
- return pending_state;
-}
-
-static void
-xdg_toplevel_configure(void *user_data,
- struct xdg_toplevel *xdg_toplevel,
- int32_t width,
- int32_t height,
- struct wl_array *states)
-{
- struct libdecor_frame *frame = user_data;
- struct libdecor_frame_private *frame_priv = frame->priv;
- enum libdecor_window_state window_state;
-
- window_state = parse_states(states);
-
- frame_priv->pending_configuration = libdecor_configuration_new();
-
- frame_priv->pending_configuration->has_size = true;
- frame_priv->pending_configuration->window_width = width;
- frame_priv->pending_configuration->window_height = height;
-
- frame_priv->pending_configuration->has_window_state = true;
- frame_priv->pending_configuration->window_state = window_state;
-}
-
-static void
-xdg_toplevel_close(void *user_data,
- struct xdg_toplevel *xdg_toplevel)
-{
- struct libdecor_frame *frame = user_data;
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- frame_priv->iface->close(frame, frame_priv->user_data);
-}
-
-#ifdef XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION
-static void
-xdg_toplevel_configure_bounds(void *user_data,
- struct xdg_toplevel *xdg_toplevel,
- int32_t width,
- int32_t height)
-{
- struct libdecor_frame *frame = user_data;
- struct libdecor_frame_private *frame_priv = frame->priv;
- struct libdecor *context = frame_priv->context;
- struct libdecor_plugin *plugin = context->plugin;
- int left = 0, top = 0, right = 0, bottom = 0;
-
- if (frame_has_visible_client_side_decoration(frame) &&
- plugin->priv->iface->frame_get_border_size) {
- plugin->priv->iface->frame_get_border_size(plugin, frame, NULL,
- &left, &right, &top, &bottom);
- }
-
- width -= left + right;
- height -= top + bottom;
- if (frame_priv->iface->bounds) {
- frame_priv->iface->bounds(frame, width, height, frame_priv->user_data);
- }
-}
-#endif
-
-#ifdef XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION
-static void
-xdg_toplevel_wm_capabilities(void *user_data,
- struct xdg_toplevel *xdg_toplevel,
- struct wl_array *capabilities)
-{
- struct libdecor_frame *frame = user_data;
- struct libdecor_frame_private *frame_priv = frame->priv;
- enum xdg_toplevel_wm_capabilities *wm_cap;
-
- frame_priv->wm_capabilities = 0;
-
- wl_array_for_each(wm_cap, capabilities) {
- switch (*wm_cap) {
- case XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU:
- frame_priv->wm_capabilities |= LIBDECOR_WM_CAPABILITIES_WINDOW_MENU;
- break;
- case XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE:
- frame_priv->wm_capabilities |= LIBDECOR_WM_CAPABILITIES_MAXIMIZE;
- break;
- case XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN:
- frame_priv->wm_capabilities |= LIBDECOR_WM_CAPABILITIES_FULLSCREEN;
- break;
- case XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE:
- frame_priv->wm_capabilities |= LIBDECOR_WM_CAPABILITIES_MINIMIZE;
- break;
- default:
- break;
- }
- }
-}
-#endif
-
-static const struct xdg_toplevel_listener xdg_toplevel_listener = {
- xdg_toplevel_configure,
- xdg_toplevel_close,
-#ifdef XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION
- xdg_toplevel_configure_bounds,
-#endif
-#ifdef XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION
- xdg_toplevel_wm_capabilities,
-#endif
-};
-
-static void
-toplevel_decoration_configure(
- void *data,
- struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1,
- uint32_t mode)
-{
- struct libdecor_frame_private *frame_priv = (struct libdecor_frame_private *)data;
- /* Ignore any _configure calls after the first, they will be
- * from our set_mode call. */
- if (!frame_priv->has_decoration_mode) {
- frame_priv->has_decoration_mode = true;
- frame_priv->decoration_mode = mode;
- }
-}
-
-static const struct zxdg_toplevel_decoration_v1_listener
- xdg_toplevel_decoration_listener = {
- toplevel_decoration_configure,
-};
-
-void
-libdecor_frame_create_xdg_decoration(struct libdecor_frame_private *frame_priv)
-{
- if (!frame_priv->context->decoration_manager)
- return;
-
- frame_priv->toplevel_decoration =
- zxdg_decoration_manager_v1_get_toplevel_decoration(
- frame_priv->context->decoration_manager,
- frame_priv->xdg_toplevel);
-
- zxdg_toplevel_decoration_v1_add_listener(
- frame_priv->toplevel_decoration,
- &xdg_toplevel_decoration_listener,
- frame_priv);
-}
-
-static void
-init_shell_surface(struct libdecor_frame *frame)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
- struct libdecor *context = frame_priv->context;
-
- if (frame_priv->xdg_surface)
- return;
-
- frame_priv->xdg_surface =
- xdg_wm_base_get_xdg_surface(context->xdg_wm_base,
- frame_priv->wl_surface);
- xdg_surface_add_listener(frame_priv->xdg_surface,
- &xdg_surface_listener,
- frame);
-
- frame_priv->xdg_toplevel =
- xdg_surface_get_toplevel(frame_priv->xdg_surface);
- xdg_toplevel_add_listener(frame_priv->xdg_toplevel,
- &xdg_toplevel_listener,
- frame);
-
- frame_priv->decoration_mode =
- ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
- frame_priv->toplevel_decoration = NULL;
- libdecor_frame_create_xdg_decoration(frame_priv);
-
- if (frame_priv->state.parent) {
- xdg_toplevel_set_parent(frame_priv->xdg_toplevel,
- frame_priv->state.parent);
- }
- if (frame_priv->state.title) {
- xdg_toplevel_set_title(frame_priv->xdg_toplevel,
- frame_priv->state.title);
- }
- if (frame_priv->state.app_id) {
- xdg_toplevel_set_app_id(frame_priv->xdg_toplevel,
- frame_priv->state.app_id);
- }
-
- if (frame_priv->pending_map)
- do_map(frame);
-}
-
-LIBDECOR_EXPORT struct libdecor_frame *
-libdecor_decorate(struct libdecor *context,
- struct wl_surface *wl_surface,
- const struct libdecor_frame_interface *iface,
- void *user_data)
-{
- struct libdecor_plugin *plugin = context->plugin;
- struct libdecor_frame *frame;
- struct libdecor_frame_private *frame_priv;
-
- if (context->has_error)
- return NULL;
-
- frame = plugin->priv->iface->frame_new(plugin);
- if (!frame)
- return NULL;
-
- frame_priv = zalloc(sizeof *frame_priv);
- frame->priv = frame_priv;
-
- frame_priv->ref_count = 1;
- frame_priv->context = context;
-
- frame_priv->wl_surface = wl_surface;
- frame_priv->iface = iface;
- frame_priv->user_data = user_data;
- frame_priv->wm_capabilities = LIBDECOR_WM_CAPABILITIES_WINDOW_MENU |
- LIBDECOR_WM_CAPABILITIES_MAXIMIZE |
- LIBDECOR_WM_CAPABILITIES_FULLSCREEN |
- LIBDECOR_WM_CAPABILITIES_MINIMIZE;
-
- wl_list_insert(&context->frames, &frame->link);
-
- libdecor_frame_set_capabilities(frame,
- LIBDECOR_ACTION_MOVE |
- LIBDECOR_ACTION_RESIZE |
- LIBDECOR_ACTION_MINIMIZE |
- LIBDECOR_ACTION_FULLSCREEN |
- LIBDECOR_ACTION_CLOSE);
-
- frame_priv->visible = true;
-
- if (context->init_done)
- init_shell_surface(frame);
-
- return frame;
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_ref(struct libdecor_frame *frame)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- frame_priv->ref_count++;
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_unref(struct libdecor_frame *frame)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- frame_priv->ref_count--;
- if (frame_priv->ref_count == 0) {
- struct libdecor *context = frame_priv->context;
- struct libdecor_plugin *plugin = context->plugin;
-
- if (context->decoration_manager && frame_priv->toplevel_decoration) {
- zxdg_toplevel_decoration_v1_destroy(frame_priv->toplevel_decoration);
- frame_priv->toplevel_decoration = NULL;
- }
-
- wl_list_remove(&frame->link);
-
- if (frame_priv->xdg_toplevel)
- xdg_toplevel_destroy(frame_priv->xdg_toplevel);
- if (frame_priv->xdg_surface)
- xdg_surface_destroy(frame_priv->xdg_surface);
-
- plugin->priv->iface->frame_free(plugin, frame);
-
- free(frame_priv->state.title);
- free(frame_priv->state.app_id);
-
- free(frame_priv);
-
- free(frame);
- }
-}
-
-LIBDECOR_EXPORT void *
-libdecor_frame_get_user_data(struct libdecor_frame *frame)
-{
- return frame->priv->user_data;
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_set_user_data(struct libdecor_frame *frame, void *user_data)
-{
- frame->priv->user_data = user_data;
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_set_visibility(struct libdecor_frame *frame,
- bool visible)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
- struct libdecor *context = frame_priv->context;
- struct libdecor_plugin *plugin = context->plugin;
-
- frame_priv->visible = visible;
-
- /* enable/disable decorations that are managed by the compositor.
- * Note that, as of xdg_decoration v1, this is just a hint and there is
- * no reliable way of disabling all decorations. In practice this should
- * work but per spec this is not guaranteed.
- *
- * See also: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/17
- */
- if (context->decoration_manager &&
- frame_priv->toplevel_decoration &&
- frame_priv->has_decoration_mode &&
- frame_priv->decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE) {
- zxdg_toplevel_decoration_v1_set_mode(frame_priv->toplevel_decoration,
- frame->priv->visible
- ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE
- : ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE);
- }
-
- if (frame_priv->content_width <= 0 ||
- frame_priv->content_height <= 0)
- return;
-
- /* enable/disable decorations that are managed by a plugin */
- if (frame_has_visible_client_side_decoration(frame)) {
- /* show client-side decorations */
- plugin->priv->iface->frame_commit(plugin, frame, NULL, NULL);
- } else {
- /* destroy client-side decorations */
- plugin->priv->iface->frame_free(plugin, frame);
- }
-
- frame_set_window_geometry(frame,
- frame_priv->content_width,
- frame_priv->content_height);
-
- libdecor_frame_toplevel_commit(frame);
-}
-
-LIBDECOR_EXPORT bool
-libdecor_frame_is_visible(struct libdecor_frame *frame)
-{
- return frame->priv->visible;
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_set_parent(struct libdecor_frame *frame,
- struct libdecor_frame *parent)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- if (!frame_priv->xdg_toplevel)
- return;
-
- frame_priv->state.parent = parent ? parent->priv->xdg_toplevel : NULL;
-
- xdg_toplevel_set_parent(frame_priv->xdg_toplevel,
- frame_priv->state.parent);
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_set_title(struct libdecor_frame *frame,
- const char *title)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
- struct libdecor_plugin *plugin = frame_priv->context->plugin;
-
- if (!streql(frame_priv->state.title, title)) {
- free(frame_priv->state.title);
- frame_priv->state.title = strdup(title);
-
- if (!frame_priv->xdg_toplevel)
- return;
-
- xdg_toplevel_set_title(frame_priv->xdg_toplevel, title);
-
- plugin->priv->iface->frame_property_changed(plugin, frame);
- }
-}
-
-LIBDECOR_EXPORT const char *
-libdecor_frame_get_title(struct libdecor_frame *frame)
-{
- return frame->priv->state.title;
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_set_app_id(struct libdecor_frame *frame,
- const char *app_id)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- free(frame_priv->state.app_id);
- frame_priv->state.app_id = strdup(app_id);
-
- if (!frame_priv->xdg_toplevel)
- return;
-
- xdg_toplevel_set_app_id(frame_priv->xdg_toplevel, app_id);
-}
-
-static void
-notify_on_capability_change(struct libdecor_frame *frame,
- const enum libdecor_capabilities old_capabilities)
-{
- struct libdecor_plugin *plugin = frame->priv->context->plugin;
- struct libdecor_state *state;
-
- if (frame->priv->capabilities == old_capabilities)
- return;
-
- if (frame->priv->content_width == 0 ||
- frame->priv->content_height == 0)
- return;
-
- plugin->priv->iface->frame_property_changed(plugin, frame);
-
- if (!libdecor_frame_has_capability(frame, LIBDECOR_ACTION_RESIZE)) {
- frame->priv->interactive_limits = frame->priv->state.content_limits;
- /* set fixed window size */
- libdecor_frame_set_min_content_size(frame,
- frame->priv->content_width,
- frame->priv->content_height);
- libdecor_frame_set_max_content_size(frame,
- frame->priv->content_width,
- frame->priv->content_height);
- } else {
- /* restore old limits */
- frame->priv->state.content_limits = frame->priv->interactive_limits;
- }
-
- state = libdecor_state_new(frame->priv->content_width,
- frame->priv->content_height);
- libdecor_frame_commit(frame, state, NULL);
- libdecor_state_free(state);
-
- libdecor_frame_toplevel_commit(frame);
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_set_capabilities(struct libdecor_frame *frame,
- enum libdecor_capabilities capabilities)
-{
- const enum libdecor_capabilities old_capabilities =
- frame->priv->capabilities;
-
- frame->priv->capabilities |= capabilities;
-
- notify_on_capability_change(frame, old_capabilities);
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_unset_capabilities(struct libdecor_frame *frame,
- enum libdecor_capabilities capabilities)
-{
- const enum libdecor_capabilities old_capabilities =
- frame->priv->capabilities;
-
- frame->priv->capabilities &= ~capabilities;
-
- notify_on_capability_change(frame, old_capabilities);
-}
-
-LIBDECOR_EXPORT bool
-libdecor_frame_has_capability(struct libdecor_frame *frame,
- enum libdecor_capabilities capability)
-{
- return frame->priv->capabilities & capability;
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_popup_grab(struct libdecor_frame *frame,
- const char *seat_name)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
- struct libdecor *context = frame_priv->context;
- struct libdecor_plugin *plugin = context->plugin;
-
- plugin->priv->iface->frame_popup_grab(plugin, frame, seat_name);
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_popup_ungrab(struct libdecor_frame *frame,
- const char *seat_name)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
- struct libdecor *context = frame_priv->context;
- struct libdecor_plugin *plugin = context->plugin;
-
- plugin->priv->iface->frame_popup_ungrab(plugin, frame, seat_name);
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_dismiss_popup(struct libdecor_frame *frame,
- const char *seat_name)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- frame_priv->iface->dismiss_popup(frame, seat_name, frame_priv->user_data);
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_show_window_menu(struct libdecor_frame *frame,
- struct wl_seat *wl_seat,
- uint32_t serial,
- int x,
- int y)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- if (!frame_priv->xdg_toplevel) {
- fprintf(stderr, "Can't show window menu before being mapped\n");
- return;
- }
-
- xdg_toplevel_show_window_menu(frame_priv->xdg_toplevel,
- wl_seat, serial,
- x, y);
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_translate_coordinate(struct libdecor_frame *frame,
- int content_x,
- int content_y,
- int *frame_x,
- int *frame_y)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
- struct libdecor *context = frame_priv->context;
- struct libdecor_plugin *plugin = context->plugin;
-
- *frame_x = content_x;
- *frame_y = content_y;
-
- if (frame_has_visible_client_side_decoration(frame) &&
- plugin->priv->iface->frame_get_border_size) {
- int left, top;
- plugin->priv->iface->frame_get_border_size(plugin, frame, NULL,
- &left, NULL, &top, NULL);
- *frame_x += left;
- *frame_y += top;
- }
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_set_min_content_size(struct libdecor_frame *frame,
- int content_width,
- int content_height)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- frame_priv->state.content_limits.min_width = content_width;
- frame_priv->state.content_limits.min_height = content_height;
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_set_max_content_size(struct libdecor_frame *frame,
- int content_width,
- int content_height)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- frame_priv->state.content_limits.max_width = content_width;
- frame_priv->state.content_limits.max_height = content_height;
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_get_min_content_size(const struct libdecor_frame *frame,
- int *content_width,
- int *content_height)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- *content_width = frame_priv->state.content_limits.min_width;
- *content_height = frame_priv->state.content_limits.min_height;
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_get_max_content_size(const struct libdecor_frame *frame,
- int *content_width,
- int *content_height)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- *content_width = frame_priv->state.content_limits.max_width;
- *content_height = frame_priv->state.content_limits.max_height;
-}
-
-LIBDECOR_EXPORT enum libdecor_capabilities
-libdecor_frame_get_capabilities(const struct libdecor_frame *frame)
-{
- return frame->priv->capabilities;
-}
-
-enum xdg_toplevel_resize_edge
-edge_to_xdg_edge(enum libdecor_resize_edge edge)
-{
- switch (edge) {
- case LIBDECOR_RESIZE_EDGE_NONE:
- return XDG_TOPLEVEL_RESIZE_EDGE_NONE;
- case LIBDECOR_RESIZE_EDGE_TOP:
- return XDG_TOPLEVEL_RESIZE_EDGE_TOP;
- case LIBDECOR_RESIZE_EDGE_BOTTOM:
- return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
- case LIBDECOR_RESIZE_EDGE_LEFT:
- return XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
- case LIBDECOR_RESIZE_EDGE_TOP_LEFT:
- return XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
- case LIBDECOR_RESIZE_EDGE_BOTTOM_LEFT:
- return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
- case LIBDECOR_RESIZE_EDGE_RIGHT:
- return XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
- case LIBDECOR_RESIZE_EDGE_TOP_RIGHT:
- return XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
- case LIBDECOR_RESIZE_EDGE_BOTTOM_RIGHT:
- return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
- }
-
- abort();
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_resize(struct libdecor_frame *frame,
- struct wl_seat *wl_seat,
- uint32_t serial,
- enum libdecor_resize_edge edge)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
- enum xdg_toplevel_resize_edge xdg_edge;
-
- xdg_edge = edge_to_xdg_edge(edge);
- xdg_toplevel_resize(frame_priv->xdg_toplevel,
- wl_seat, serial, xdg_edge);
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_move(struct libdecor_frame *frame,
- struct wl_seat *wl_seat,
- uint32_t serial)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- xdg_toplevel_move(frame_priv->xdg_toplevel, wl_seat, serial);
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_set_minimized(struct libdecor_frame *frame)
-{
- xdg_toplevel_set_minimized(frame->priv->xdg_toplevel);
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_set_maximized(struct libdecor_frame *frame)
-{
- xdg_toplevel_set_maximized(frame->priv->xdg_toplevel);
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_unset_maximized(struct libdecor_frame *frame)
-{
- xdg_toplevel_unset_maximized(frame->priv->xdg_toplevel);
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_set_fullscreen(struct libdecor_frame *frame,
- struct wl_output *output)
-{
- xdg_toplevel_set_fullscreen(frame->priv->xdg_toplevel, output);
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_unset_fullscreen(struct libdecor_frame *frame)
-{
- xdg_toplevel_unset_fullscreen(frame->priv->xdg_toplevel);
-}
-
-LIBDECOR_EXPORT bool
-libdecor_frame_is_floating(struct libdecor_frame *frame)
-{
- return state_is_floating(frame->priv->window_state);
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_close(struct libdecor_frame *frame)
-{
- xdg_toplevel_close(frame, frame->priv->xdg_toplevel);
-}
-
-bool
-valid_limits(struct libdecor_frame_private *frame_priv)
-{
- if (frame_priv->state.content_limits.min_width > 0 &&
- frame_priv->state.content_limits.max_width > 0 &&
- frame_priv->state.content_limits.min_width >
- frame_priv->state.content_limits.max_width)
- return false;
-
- if (frame_priv->state.content_limits.min_height > 0 &&
- frame_priv->state.content_limits.max_height > 0 &&
- frame_priv->state.content_limits.min_height >
- frame_priv->state.content_limits.max_height)
- return false;
-
- return true;
-}
-
-static void
-libdecor_frame_apply_limits(struct libdecor_frame *frame,
- enum libdecor_window_state window_state)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- if (!valid_limits(frame_priv)) {
- libdecor_notify_plugin_error(
- frame_priv->context,
- LIBDECOR_ERROR_INVALID_FRAME_CONFIGURATION,
- "minimum size (%i,%i) must be smaller than maximum size (%i,%i)",
- frame_priv->state.content_limits.min_width,
- frame_priv->state.content_limits.min_height,
- frame_priv->state.content_limits.max_width,
- frame_priv->state.content_limits.max_height);
- }
-
- /* If the frame is configured as non-resizable before the first
- * configure event is received, we have to manually set the min/max
- * limits with the configured content size afterwards. */
- if (!libdecor_frame_has_capability(frame, LIBDECOR_ACTION_RESIZE)) {
- frame_priv->state.content_limits.min_width =
- frame_priv->content_width;
- frame_priv->state.content_limits.max_width =
- frame_priv->content_width;
-
- frame_priv->state.content_limits.min_height =
- frame_priv->content_height;
- frame_priv->state.content_limits.max_height =
- frame_priv->content_height;
- }
-
- if (frame_priv->state.content_limits.min_width > 0 &&
- frame_priv->state.content_limits.min_height > 0) {
- struct libdecor_state state_min;
- int win_min_width, win_min_height;
-
- state_min.content_width = frame_priv->state.content_limits.min_width;
- state_min.content_height = frame_priv->state.content_limits.min_height;
- state_min.window_state = window_state;
-
- frame_get_window_size_for(frame, &state_min,
- &win_min_width, &win_min_height);
- xdg_toplevel_set_min_size(frame_priv->xdg_toplevel,
- win_min_width, win_min_height);
- } else {
- xdg_toplevel_set_min_size(frame_priv->xdg_toplevel, 0, 0);
- }
-
- if (frame_priv->state.content_limits.max_width > 0 &&
- frame_priv->state.content_limits.max_height > 0) {
- struct libdecor_state state_max;
- int win_max_width, win_max_height;
-
- state_max.content_width = frame_priv->state.content_limits.max_width;
- state_max.content_height = frame_priv->state.content_limits.max_height;
- state_max.window_state = window_state;
-
- frame_get_window_size_for(frame, &state_max,
- &win_max_width, &win_max_height);
- xdg_toplevel_set_max_size(frame_priv->xdg_toplevel,
- win_max_width, win_max_height);
- } else {
- xdg_toplevel_set_max_size(frame_priv->xdg_toplevel, 0, 0);
- }
-}
-
-static void
-libdecor_frame_apply_state(struct libdecor_frame *frame,
- struct libdecor_state *state)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- frame_priv->content_width = state->content_width;
- frame_priv->content_height = state->content_height;
-
- /* do not set limits in non-floating states */
- if (state_is_floating(state->window_state)) {
- libdecor_frame_apply_limits(frame, state->window_state);
- }
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_toplevel_commit(struct libdecor_frame *frame)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- frame_priv->iface->commit(frame, frame_priv->user_data);
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_commit(struct libdecor_frame *frame,
- struct libdecor_state *state,
- struct libdecor_configuration *configuration)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
- struct libdecor *context = frame_priv->context;
- struct libdecor_plugin *plugin = context->plugin;
-
- if (configuration && configuration->has_window_state) {
- frame_priv->window_state = configuration->window_state;
- state->window_state = configuration->window_state;
- } else {
- state->window_state = frame_priv->window_state;
- }
-
- libdecor_frame_apply_state(frame, state);
-
- /* switch between decoration modes */
- if (frame_has_visible_client_side_decoration(frame)) {
- plugin->priv->iface->frame_commit(plugin, frame, state,
- configuration);
- } else {
- plugin->priv->iface->frame_free(plugin, frame);
- }
-
- frame_set_window_geometry(frame,
- frame_priv->content_width,
- frame_priv->content_height);
-
- if (configuration) {
- xdg_surface_ack_configure(frame_priv->xdg_surface,
- configuration->serial);
- }
-}
-
-static void
-do_map(struct libdecor_frame *frame)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- frame_priv->pending_map = false;
- wl_surface_commit(frame_priv->wl_surface);
-}
-
-LIBDECOR_EXPORT void
-libdecor_frame_map(struct libdecor_frame *frame)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- if (!frame_priv->xdg_surface) {
- frame_priv->pending_map = true;
- return;
- }
-
- do_map(frame);
-}
-
-LIBDECOR_EXPORT struct wl_surface *
-libdecor_frame_get_wl_surface(struct libdecor_frame *frame)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- return frame_priv->wl_surface;
-}
-
-LIBDECOR_EXPORT struct xdg_surface *
-libdecor_frame_get_xdg_surface(struct libdecor_frame *frame)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- return frame_priv->xdg_surface;
-}
-
-LIBDECOR_EXPORT struct xdg_toplevel *
-libdecor_frame_get_xdg_toplevel(struct libdecor_frame *frame)
-{
- return frame->priv->xdg_toplevel;
-}
-
-LIBDECOR_EXPORT void
-libdecor_set_handle_application_cursor(struct libdecor *context,
- bool handle_cursor)
-{
- struct libdecor_plugin *plugin = context->plugin;
-
- plugin->priv->iface->set_handle_application_cursor(plugin,
- handle_cursor);
-}
-
-LIBDECOR_EXPORT int
-libdecor_frame_get_content_width(struct libdecor_frame *frame)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- return frame_priv->content_width;
-}
-
-LIBDECOR_EXPORT int
-libdecor_frame_get_content_height(struct libdecor_frame *frame)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- return frame_priv->content_height;
-}
-
-LIBDECOR_EXPORT enum libdecor_window_state
-libdecor_frame_get_window_state(struct libdecor_frame *frame)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- return frame_priv->window_state;
-}
-
-LIBDECOR_EXPORT enum libdecor_wm_capabilities
-libdecor_frame_get_wm_capabilities(struct libdecor_frame *frame)
-{
- struct libdecor_frame_private *frame_priv = frame->priv;
-
- return frame_priv->wm_capabilities;
-}
-
-LIBDECOR_EXPORT int
-libdecor_plugin_init(struct libdecor_plugin *plugin,
- struct libdecor *context,
- struct libdecor_plugin_interface *iface)
-{
- plugin->priv = zalloc(sizeof (struct libdecor_plugin_private));
- if (!plugin->priv)
- return -1;
-
- plugin->priv->iface = iface;
-
- return 0;
-}
-
-LIBDECOR_EXPORT void
-libdecor_plugin_release(struct libdecor_plugin *plugin)
-{
- free(plugin->priv);
-}
-
-static void
-xdg_wm_base_ping(void *user_data,
- struct xdg_wm_base *xdg_wm_base,
- uint32_t serial)
-{
- xdg_wm_base_pong(xdg_wm_base, serial);
-}
-
-static const struct xdg_wm_base_listener xdg_wm_base_listener = {
- xdg_wm_base_ping,
-};
-
-static void
-init_xdg_wm_base(struct libdecor *context,
- uint32_t id,
- uint32_t version)
-{
- uint32_t desired_version = 2;
-
- /* Find the required version for the available features. */
-#ifdef XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT_SINCE_VERSION
- desired_version = MAX(desired_version, XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT_SINCE_VERSION);
-#endif
-#ifdef XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION
- desired_version = MAX(desired_version, XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION);
-#endif
-#ifdef XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION
- desired_version = MAX(desired_version, XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION);
-#endif
-#ifdef XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION
- desired_version = MAX(desired_version, XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION);
-#endif
-
- context->xdg_wm_base = wl_registry_bind(context->wl_registry,
- id,
- &xdg_wm_base_interface,
- MIN(version, desired_version));
- xdg_wm_base_add_listener(context->xdg_wm_base,
- &xdg_wm_base_listener,
- context);
-}
-
-static void
-registry_handle_global(void *user_data,
- struct wl_registry *wl_registry,
- uint32_t id,
- const char *interface,
- uint32_t version)
-{
- struct libdecor *context = user_data;
-
- if (!strcmp(interface, xdg_wm_base_interface.name)) {
- init_xdg_wm_base(context, id, version);
- } else if (!strcmp(interface, zxdg_decoration_manager_v1_interface.name)) {
- const char *force_csd = getenv("LIBDECOR_FORCE_CSD");
-
- if (force_csd && atoi(force_csd)) {
- return;
- }
-
- context->decoration_manager = wl_registry_bind(
- context->wl_registry, id,
- &zxdg_decoration_manager_v1_interface,
- MIN(version,2));
- }
-}
-
-static void
-registry_handle_global_remove(void *user_data,
- struct wl_registry *wl_registry,
- uint32_t name)
-{
-}
-
-static const struct wl_registry_listener registry_listener = {
- registry_handle_global,
- registry_handle_global_remove
-};
-
-static bool
-is_compositor_compatible(struct libdecor *context)
-{
- if (!context->xdg_wm_base)
- return false;
-
- return true;
-}
-
-static void
-notify_error(struct libdecor *context,
- enum libdecor_error error,
- const char *message)
-{
- context->has_error = true;
- context->iface->error(context, error, message);
- context->plugin->priv->iface->destroy(context->plugin);
-}
-
-static void
-finish_init(struct libdecor *context)
-{
- struct libdecor_frame *frame;
-
- wl_list_for_each(frame, &context->frames, link)
- init_shell_surface(frame);
-}
-
-static void
-init_wl_display_callback(void *user_data,
- struct wl_callback *callback,
- uint32_t time)
-{
- struct libdecor *context = user_data;
-
- context->init_done = true;
-
- wl_callback_destroy(callback);
- context->init_callback = NULL;
-
- if (!is_compositor_compatible(context)) {
- notify_error(context,
- LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE,
- "Compositor is missing required interfaces");
- }
-
- if (context->plugin_ready) {
- finish_init(context);
- }
-}
-
-static const struct wl_callback_listener init_wl_display_callback_listener = {
- init_wl_display_callback
-};
-
-struct plugin_loader {
- struct wl_list link;
- void *lib;
- const struct libdecor_plugin_description *description;
- int priority;
- char *name;
-};
-
-static int
-calculate_priority(const struct libdecor_plugin_description *plugin_description)
-{
- const char *current_desktop;
- int i;
-
- if (!plugin_description->priorities)
- return -1;
-
- current_desktop = getenv("XDG_CURRENT_DESKTOP");
-
- i = 0;
- while (true) {
- struct libdecor_plugin_priority priority =
- plugin_description->priorities[i];
-
- i++;
-
- if (priority.desktop) {
- char *tokens;
- char *saveptr;
- char *token;
-
- if (!current_desktop)
- continue;
-
- tokens = strdup(current_desktop);
- token = strtok_r(tokens, ":", &saveptr);
- while (token) {
- if (strcmp(priority.desktop, token) == 0) {
- free(tokens);
- return priority.priority;
- }
- token = strtok_r(NULL, ":", &saveptr);
- }
- free(tokens);
- } else {
- return priority.priority;
- }
- }
-
- return -1;
-}
-
-static bool
-check_symbol_conflicts(const struct libdecor_plugin_description *plugin_description, void *lib)
-{
- char * const *symbol;
-
- symbol = plugin_description->conflicting_symbols;
- while (*symbol) {
- dlerror();
- void *sym = dlsym(RTLD_DEFAULT, *symbol);
- if (!dlerror()) {
- void *libsym = dlsym(lib, *symbol);
- if (!dlerror() && libsym != sym) {
- fprintf(stderr, "Plugin \"%s\" uses conflicting symbol \"%s\".\n",
- plugin_description->description, *symbol);
- return false;
- }
- }
-
- symbol++;
- }
-
- return true;
-}
-
-static struct plugin_loader *
-load_plugin_loader(struct libdecor *context,
- const char *path,
- const char *name)
-{
- char *ext;
- char *filename;
- void *lib;
- const struct libdecor_plugin_description *plugin_description;
- int priority;
- struct plugin_loader *plugin_loader;
-
- ext = strrchr(name, '.');
- if (ext == NULL || strcmp(ext, ".so") != 0)
- return NULL;
-
- if (asprintf(&filename, "%s/%s", path, name) == -1)
- return NULL;
-
- lib = dlopen(filename, RTLD_NOW | RTLD_LAZY);
- free(filename);
- if (!lib) {
- fprintf(stderr, "Failed to load plugin: '%s'\n", dlerror());
- return NULL;
- }
-
- plugin_description = dlsym(lib, "libdecor_plugin_description");
- if (!plugin_description) {
- fprintf(stderr,
- "Failed to load plugin '%s': no plugin description symbol\n",
- name);
- dlclose(lib);
- return NULL;
- }
-
- if (plugin_description->api_version != LIBDECOR_PLUGIN_API_VERSION) {
- fprintf(stderr,
- "Plugin '%s' found, but it's incompatible "
- "(expected API version %d, but got %d)\n",
- name,
- LIBDECOR_PLUGIN_API_VERSION,
- plugin_description->api_version);
- dlclose(lib);
- return NULL;
- }
-
- if (!(plugin_description->capabilities & LIBDECOR_PLUGIN_CAPABILITY_BASE)) {
- dlclose(lib);
- return NULL;
- }
-
- if (!check_symbol_conflicts(plugin_description, lib)) {
- dlclose(lib);
- return NULL;
- }
-
- priority = calculate_priority(plugin_description);
- if (priority == -1) {
- fprintf(stderr,
- "Plugin '%s' found, but has an invalid description\n",
- name);
- dlclose(lib);
- return NULL;
- }
-
- plugin_loader = zalloc(sizeof *plugin_loader);
- plugin_loader->description = plugin_description;
- plugin_loader->lib = lib;
- plugin_loader->priority = priority;
- plugin_loader->name = strdup(name);
-
- return plugin_loader;
-}
-
-static bool
-plugin_loader_higher_priority(struct plugin_loader *plugin_loader,
- struct plugin_loader *best_plugin_loader)
-{
- return plugin_loader->priority > best_plugin_loader->priority;
-}
-
-static int
-init_plugins(struct libdecor *context)
-{
- const char *plugin_dir_env;
- char *all_plugin_dirs;
- char *plugin_dir;
- char *saveptr;
- DIR *dir;
- struct wl_list plugin_loaders;
- struct plugin_loader *plugin_loader, *tmp;
- struct plugin_loader *best_plugin_loader;
- struct libdecor_plugin *plugin;
-
- plugin_dir_env = getenv("LIBDECOR_PLUGIN_DIR");
- if (!plugin_dir_env) {
- plugin_dir_env = LIBDECOR_PLUGIN_DIR;
- }
- all_plugin_dirs = strdup(plugin_dir_env);
-
- wl_list_init(&plugin_loaders);
- plugin_dir = strtok_r(all_plugin_dirs, ":", &saveptr);
- while (plugin_dir) {
- dir = opendir(plugin_dir);
- if (!dir) {
- fprintf(stderr, "Couldn't open plugin directory: %s\n",
- strerror(errno));
- } else {
-
- while (true) {
- struct dirent *de;
-
- de = readdir(dir);
- if (!de)
- break;
-
- plugin_loader = load_plugin_loader(context,
- plugin_dir,
- de->d_name);
- if (!plugin_loader)
- continue;
-
- wl_list_insert(plugin_loaders.prev, &plugin_loader->link);
- }
-
- closedir(dir);
- }
- plugin_dir = strtok_r(NULL, ":", &saveptr);
- }
- free(all_plugin_dirs);
-
-retry_next:
- best_plugin_loader = NULL;
- wl_list_for_each(plugin_loader, &plugin_loaders, link) {
- if (!best_plugin_loader) {
- best_plugin_loader = plugin_loader;
- continue;
- }
-
- if (plugin_loader_higher_priority(plugin_loader,
- best_plugin_loader))
- best_plugin_loader = plugin_loader;
- }
-
- if (!best_plugin_loader)
- return -1;
-
- plugin_loader = best_plugin_loader;
- plugin = plugin_loader->description->constructor(context);
- if (!plugin) {
- fprintf(stderr,
- "Failed to load plugin '%s': failed to init\n",
- plugin_loader->name);
- dlclose(plugin_loader->lib);
- wl_list_remove(&plugin_loader->link);
- free(plugin_loader->name);
- free(plugin_loader);
- goto retry_next;
- }
-
- context->plugin = plugin;
-
- wl_list_remove(&plugin_loader->link);
- free(plugin_loader->name);
- free(plugin_loader);
-
- wl_list_for_each_safe(plugin_loader, tmp, &plugin_loaders, link) {
- dlclose(plugin_loader->lib);
- free(plugin_loader->name);
- free(plugin_loader);
- }
-
- return 0;
-}
-
-LIBDECOR_EXPORT void *
-libdecor_get_user_data(struct libdecor *context)
-{
- return context->user_data;
-}
-
-LIBDECOR_EXPORT void
-libdecor_set_user_data(struct libdecor *context, void *user_data)
-{
- context->user_data = user_data;
-}
-
-LIBDECOR_EXPORT int
-libdecor_get_fd(struct libdecor *context)
-{
- struct libdecor_plugin *plugin = context->plugin;
-
- return plugin->priv->iface->get_fd(plugin);
-}
-
-LIBDECOR_EXPORT int
-libdecor_dispatch(struct libdecor *context,
- int timeout)
-{
- struct libdecor_plugin *plugin = context->plugin;
-
- return plugin->priv->iface->dispatch(plugin, timeout);
-}
-
-LIBDECOR_EXPORT struct wl_display *
-libdecor_get_wl_display(struct libdecor *context)
-{
- return context->wl_display;
-}
-
-LIBDECOR_EXPORT void
-libdecor_notify_plugin_ready(struct libdecor *context)
-{
- context->plugin_ready = true;
-
- if (context->init_done)
- finish_init(context);
-}
-
-LIBDECOR_EXPORT void
-libdecor_notify_plugin_error(struct libdecor *context,
- enum libdecor_error error,
- const char *__restrict fmt,
- ...)
-{
- char *msg = NULL;
- int nbytes = 0;
- va_list argp;
-
- if (context->has_error)
- return;
-
- va_start(argp, fmt);
- nbytes = vasprintf(&msg, fmt, argp);
- va_end(argp);
-
- if (nbytes>0)
- notify_error(context, error, msg);
-
- if (msg)
- free(msg);
-}
-
-LIBDECOR_EXPORT void
-libdecor_unref(struct libdecor *context)
-{
- context->ref_count--;
- if (context->ref_count == 0) {
- if (context->plugin)
- context->plugin->priv->iface->destroy(context->plugin);
- if (context->init_callback)
- wl_callback_destroy(context->init_callback);
- wl_registry_destroy(context->wl_registry);
- if (context->xdg_wm_base)
- xdg_wm_base_destroy(context->xdg_wm_base);
- if (context->decoration_manager)
- zxdg_decoration_manager_v1_destroy(
- context->decoration_manager);
- free(context);
- }
-}
-
-LIBDECOR_EXPORT struct libdecor *
-libdecor_new(struct wl_display *wl_display,
- const struct libdecor_interface *iface)
-{
- return libdecor_new_with_user_data(wl_display, iface, NULL);
-}
-
-LIBDECOR_EXPORT struct libdecor *
-libdecor_new_with_user_data(struct wl_display *wl_display,
- const struct libdecor_interface *iface,
- void *user_data)
-{
- struct libdecor *context;
-
- context = zalloc(sizeof *context);
-
- context->ref_count = 1;
- context->iface = iface;
- context->user_data = user_data;
- context->wl_display = wl_display;
- context->wl_registry = wl_display_get_registry(wl_display);
- wl_registry_add_listener(context->wl_registry,
- &registry_listener,
- context);
- context->init_callback = wl_display_sync(context->wl_display);
- wl_callback_add_listener(context->init_callback,
- &init_wl_display_callback_listener,
- context);
-
- wl_list_init(&context->frames);
-
- if (init_plugins(context) != 0) {
- fprintf(stderr,
- "No plugins found, falling back on no decorations\n");
- context->plugin = libdecor_fallback_plugin_new(context);
- }
-
- wl_display_flush(wl_display);
-
- return context;
-}