summaryrefslogtreecommitdiff
path: root/libdecor
diff options
context:
space:
mode:
Diffstat (limited to 'libdecor')
-rw-r--r--libdecor/LICENSE19
-rw-r--r--libdecor/README.md86
-rw-r--r--libdecor/build/fl_libdecor-plugins.c311
-rw-r--r--libdecor/build/fl_libdecor.c145
-rw-r--r--libdecor/build/fl_libdecor.h93
-rw-r--r--libdecor/build/gtk-shell.xml109
-rw-r--r--libdecor/src/desktop-settings.c213
-rw-r--r--libdecor/src/desktop-settings.h41
-rw-r--r--libdecor/src/libdecor-fallback.c190
-rw-r--r--libdecor/src/libdecor-fallback.h35
-rw-r--r--libdecor/src/libdecor-plugin.h186
-rw-r--r--libdecor/src/libdecor.c1871
-rw-r--r--libdecor/src/libdecor.h605
-rw-r--r--libdecor/src/os-compatibility.c198
-rw-r--r--libdecor/src/os-compatibility.h34
-rw-r--r--libdecor/src/plugins/cairo/libdecor-cairo.c2796
-rw-r--r--libdecor/src/plugins/common/libdecor-cairo-blur.c255
-rw-r--r--libdecor/src/plugins/common/libdecor-cairo-blur.h10
-rw-r--r--libdecor/src/plugins/dummy/libdecor-dummy.c141
-rw-r--r--libdecor/src/plugins/gtk/libdecor-gtk.c3028
-rw-r--r--libdecor/src/utils.h48
21 files changed, 0 insertions, 10414 deletions
diff --git a/libdecor/LICENSE b/libdecor/LICENSE
deleted file mode 100644
index 9cf106272..000000000
--- a/libdecor/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-MIT License
-
-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 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.
diff --git a/libdecor/README.md b/libdecor/README.md
deleted file mode 100644
index 83234c7ee..000000000
--- a/libdecor/README.md
+++ /dev/null
@@ -1,86 +0,0 @@
-# libdecor - A client-side decorations library for Wayland client
-
-libdecor is a library that can help Wayland clients draw window
-decorations for them. It aims to provide multiple backends that implements the
-decoration drawing.
-
-
-## Dependencies
-
-Required:
-- `meson` >= 0.47
-- `ninja`
-- `wayland-client` >= 1.18
-- `wayland-protocols` >= 1.15
-- `wayland-cursor`
-- `cairo`
-- `pangocairo`
-
-Recommended:
-- `dbus-1` (to query current cursor theme)
-
-Optional
-- `egl` (to build EGL example)
-- `opengl`
-- `xkbcommon` (to build cairo demo)
-
-Install via apt:
-`sudo apt install meson libwayland-dev wayland-protocols libpango1.0-dev libdbus-1-dev libegl-dev libopengl-dev libxkbcommon-dev`
-
-Install via dnf:
-`sudo dnf install meson wayland-devel wayland-protocols-devel pango-devel dbus-devel mesa-libEGL-devel libglvnd-devel libxkbcommon-devel`
-
-Newer meson versions can be installed via pip: `pip3 install -U meson`.
-
-## Build & Install
-
-### Quick Start
-
-To build and run the example program:
-1. `meson build -Dinstall_demo=true && meson compile -C build`
-2. `meson devenv -C build libdecor-demo`
-
-### Release Builds
-
-The library and default plugins can be built and installed via:
-1. `meson build --buildtype release`
-2. `meson install -C build`
-
-where `build` is the build directory that will be created during this process.
-
-This will install by default to `/usr/local/`. To change this set the `prefix` during built, e.g. `meson build --buildtype release -Dprefix=$HOME/.local/`.
-
-Plugins will be installed into the same directory and from thereon will be selected automatically depending on their precedence. This behaviour can be overridden at runtime by setting the environment variable `LIBDECOR_PLUGIN_DIR` and pointing it to a directory with a valid plugin.
-
-### Debug and Development Builds
-
-During development and when debugging, it is recommended to enable the AddressSanitizer and increase the warning level:
-1. `meson build -Dinstall_demo=true -Db_sanitize=address -Dwarning_level=3`
-2. `meson compile -C build`
-
-You may have to install `libasan6` (apt) or `libasan` (dnf). Otherwise linking will fail.
-
-By default `libdecor` will look for plugins in the target directory of the installation. Therefore, when running the demos directly from the `build` directory, no plugins will be found and the fallback plugin without any decorations will be used.
-
-On Meson 0.58.0 and above, this can be corrected using `devenv`, i.e., to run the demo:
-
-`meson devenv -C build libdecor-demo`
-
-On older Meson versions, the search path for plugins can be overridden by the environment variable `LIBDECOR_PLUGIN_DIR`. To use the `cairo` plugin, point to the plugin directory:
-
-`export LIBDECOR_PLUGIN_DIR=build/src/plugins/cairo/`
-
-and run the demo:
-
-`./build/demo/libdecor-demo`.
-
-
-### Code of Conduct
-
-libdecor follows the Contributor Covenant, found at:
-https://www.freedesktop.org/wiki/CodeOfConduct
-
-Please conduct yourself in a respectful and civilised manner when interacting
-with community members on mailing lists, IRC, or bug trackers. The community
-represents the project as a whole, and abusive or bullying behaviour is not
-tolerated by the project.
diff --git a/libdecor/build/fl_libdecor-plugins.c b/libdecor/build/fl_libdecor-plugins.c
deleted file mode 100644
index 4197ea8f0..000000000
--- a/libdecor/build/fl_libdecor-plugins.c
+++ /dev/null
@@ -1,311 +0,0 @@
-//
-// Interface with the libdecor library for the Fast Light Tool Kit (FLTK).
-//
-// Copyright 2022-2024 by Bill Spitzak and others.
-//
-// This library is free software. Distribution and use rights are outlined in
-// the file "COPYING" which should have been included with this file. If this
-// file is missing or damaged, see the license at:
-//
-// https://www.fltk.org/COPYING.php
-//
-// Please see the following page on how to report bugs and issues:
-//
-// https://www.fltk.org/bugs.php
-//
-
-/* Support of interactions between FLTK and libdecor plugins, either dynamically
- loaded by dlopen() or built-in FLTK.
-
- Under USE_SYSTEM_LIBDECOR, the plugin can only be dynamically loaded.
- Under ! USE_SYSTEM_LIBDECOR, it can be dynamically loaded from a directory
- given in environment variable LIBDECOR_PLUGIN_DIR, or the built-in one is used.
- */
-
-#include <dlfcn.h>
-#include <string.h>
-#include "fl_libdecor.h"
-#include <pango/pangocairo.h>
-#include <dlfcn.h>
-
-#ifndef HAVE_GTK
-# define HAVE_GTK 0
-#endif
-
-enum plugin_kind { UNKNOWN, SSD, CAIRO, GTK3 };
-
-#if USE_SYSTEM_LIBDECOR
-# include "../src/libdecor-plugin.h"
-
-enum component {NONE}; /* details are not necessary*/
-enum decoration_type {DECORATION_TYPE_NONE}; /* details are not necessary*/
-
-struct buffer { // identical in libdecor-cairo.c and libdecor-gtk.c
- struct wl_buffer *wl_buffer;
- bool in_use;
- bool is_detached;
-
- void *data;
- size_t data_size;
- int width;
- int height;
- int scale;
- int buffer_width;
- int buffer_height;
-};
-
-#else // !USE_SYSTEM_LIBDECOR
-
-const struct libdecor_plugin_description *fl_libdecor_plugin_description = NULL;
-
-# if HAVE_GTK
-# include "../src/plugins/gtk/libdecor-gtk.c"
-# else
-# include "../src/plugins/cairo/libdecor-cairo.c"
-# endif // HAVE_GTK
-
-#endif // USE_SYSTEM_LIBDECOR
-
-
-#if USE_SYSTEM_LIBDECOR || HAVE_GTK
-/* these definitions derive from libdecor/src/plugins/cairo/libdecor-cairo.c */
-
-enum composite_mode {COMPOSITE_SERVER}; /* details are not necessary*/
-
-struct border_component_cairo {
- enum component type;
-
- bool is_hidden;
- bool opaque;
-
- enum composite_mode composite_mode;
- struct {
- struct wl_surface *wl_surface;
- struct wl_subsurface *wl_subsurface;
- struct buffer *buffer;
- struct wl_list output_list;
- int scale;
- } server;
- struct {
- cairo_surface_t *image;
- struct border_component_cairo *parent_component;
- } client;
-
- struct wl_list child_components; /* border_component::link */
- struct wl_list link; /* border_component::child_components */
-};
-
-struct libdecor_frame_cairo {
- struct libdecor_frame frame;
-
- struct libdecor_plugin_cairo *plugin_cairo;
-
- int content_width;
- int content_height;
-
- enum decoration_type decoration_type;
-
- enum libdecor_window_state window_state;
-
- char *title;
-
- enum libdecor_capabilities capabilities;
-
- struct border_component_cairo *focus;
- struct border_component_cairo *active;
- struct border_component_cairo *grab;
-
- bool shadow_showing;
- struct border_component_cairo shadow;
-
- struct {
- bool is_showing;
- struct border_component_cairo title;
- struct border_component_cairo min;
- struct border_component_cairo max;
- struct border_component_cairo close;
- } title_bar;
-
- /* store pre-processed shadow tile */
- cairo_surface_t *shadow_blur;
-
- struct wl_list link;
-};
-#endif // USE_SYSTEM_LIBDECOR || HAVE_GTK
-
-
-#if USE_SYSTEM_LIBDECOR || !HAVE_GTK
-
-/* Definitions derived from libdecor-gtk.c */
-
-typedef struct _GtkWidget GtkWidget;
-enum header_element { HEADER_NONE }; /* details are not needed */
-
-typedef enum { GTK_STATE_FLAG_NORMAL = 0 } GtkStateFlags;
-
-struct border_component_gtk {
- enum component type;
- struct wl_surface *wl_surface;
- struct wl_subsurface *wl_subsurface;
- struct buffer *buffer;
- bool opaque;
- struct wl_list output_list;
- int scale;
- struct wl_list child_components; /* border_component::link */
- struct wl_list link; /* border_component::child_components */
-};
-
-struct header_element_data {
- const char* name;
- enum header_element type;
- GtkWidget *widget;
- GtkStateFlags state;
-};
-
-struct libdecor_frame_gtk {
- struct libdecor_frame frame;
- struct libdecor_plugin_gtk *plugin_gtk;
- int content_width;
- int content_height;
- enum libdecor_window_state window_state;
- enum decoration_type decoration_type;
- char *title;
- enum libdecor_capabilities capabilities;
- struct border_component_gtk *active;
- struct border_component_gtk *touch_active;
- struct border_component_gtk *focus;
- struct border_component_gtk *grab;
- bool shadow_showing;
- struct border_component_gtk shadow;
- GtkWidget *window; /* offscreen window for rendering */
- GtkWidget *header; /* header bar with widgets */
- struct border_component_gtk headerbar;
- struct header_element_data hdr_focus;
- cairo_surface_t *shadow_blur;
- struct wl_list link;
- struct {
- enum titlebar_gesture_state {TITLEBAR_GESTURE_STATE_INIT} state;
- int button_pressed_count;
- uint32_t first_pressed_button;
- uint32_t first_pressed_time;
- double pressed_x;
- double pressed_y;
- uint32_t pressed_serial;
- } titlebar_gesture;
-};
-
-#endif // USE_SYSTEM_LIBDECOR || !HAVE_GTK
-
-
-static unsigned char *gtk_titlebar_buffer(struct libdecor_frame *frame,
- int *width, int *height, int *stride)
-{
- struct libdecor_frame_gtk *lfg = (struct libdecor_frame_gtk *)frame;
- struct buffer *buffer = lfg->headerbar.buffer;
- *width = buffer->buffer_width;
- *height = buffer->buffer_height;
- *stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, buffer->buffer_width);
- return (unsigned char*)buffer->data;
-}
-
-
-static unsigned char *cairo_titlebar_buffer(struct libdecor_frame *frame,
- int *width, int *height, int *stride)
-{
- struct libdecor_frame_cairo *lfc = (struct libdecor_frame_cairo *)frame;
- struct buffer *buffer = lfc->title_bar.title.server.buffer;
- *width = buffer->buffer_width;
- *height = buffer->buffer_height;
- *stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, buffer->buffer_width);
- return (unsigned char*)buffer->data;
-}
-
-
-/*
- Although each plugin declares an exported global variable
- LIBDECOR_EXPORT const struct libdecor_plugin_description libdecor_plugin_description;
- these plugins are dlopen()'ed in libdecor.c without the RTLD_GLOBAL flag.
- Consequently their symbols are not discovered by dlsym(RTLD_DEFAULT, "symbol-name").
-
- Under USE_SYSTEM_LIBDECOR, we repeat the dlopen() for the same plugin
- then dlsym() will report the address of libdecor_plugin_description.
-
- Under !USE_SYSTEM_LIBDECOR, we compile fl_libdecor.c which modifies the dlopen()
- to call dlsym(ld, "libdecor_plugin_description") just after the dlopen and memorizes
- this address.
-
- A plugin is loaded also if SSD.
- KWin has its own size limit, similar to that of GDK plugin
- */
-static const char *get_libdecor_plugin_description() {
- static const struct libdecor_plugin_description *plugin_description = NULL;
- if (!plugin_description) {
-#if USE_SYSTEM_LIBDECOR
- char fname[PATH_MAX];
- const char *dir = getenv("LIBDECOR_PLUGIN_DIR");
- if (!dir) dir = LIBDECOR_PLUGIN_DIR;
- snprintf(fname, PATH_MAX, "%s/libdecor-gtk.so", dir);
- void *dl = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
- if (!dl) {
- snprintf(fname, PATH_MAX, "%s/libdecor-cairo.so", dir);
- dl = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
- }
- if (dl) plugin_description = (const struct libdecor_plugin_description*)dlsym(dl, "libdecor_plugin_description");
-#else
- plugin_description = fl_libdecor_plugin_description;
- extern const struct libdecor_plugin_description libdecor_plugin_description;
- if (!plugin_description) plugin_description = &libdecor_plugin_description;
-#endif
- //if (plugin_description) puts(plugin_description->description);
- }
- return plugin_description ? plugin_description->description : NULL;
-}
-
-
-static enum plugin_kind get_plugin_kind(struct libdecor_frame *frame) {
- static enum plugin_kind kind = UNKNOWN;
- if (kind == UNKNOWN) {
- if (frame) {
- int X, Y = 0;
- libdecor_frame_translate_coordinate(frame, 0, 0, &X, &Y);
- if (Y == 0) {
- return SSD;
- }
- }
- const char *name = get_libdecor_plugin_description();
- if (name && !strcmp(name, "GTK3 plugin")) kind = GTK3;
- else if (name && !strcmp(name, "libdecor plugin using Cairo")) kind = CAIRO;
- }
- return kind;
-}
-
-/*
- FLTK-added utility function to give access to the pixel array representing
- the titlebar of a window decorated by the cairo plugin of libdecor.
- frame: a libdecor-defined pointer given by fl_xid(win)->frame (with Fl_Window *win);
- *width, *height: returned assigned to the width and height in pixels of the titlebar;
- *stride: returned assigned to the number of bytes per line of the pixel array;
- return value: start of the pixel array, which is in BGRA order, or NULL.
- */
-unsigned char *fl_libdecor_titlebar_buffer(struct libdecor_frame *frame,
- int *width, int *height, int *stride)
-{
- enum plugin_kind kind = get_plugin_kind(frame);
- if (kind == GTK3) {
- return gtk_titlebar_buffer(frame, width, height, stride);
- }
- else if (kind == CAIRO) {
- return cairo_titlebar_buffer(frame, width, height, stride);
- }
- return NULL;
-}
-
-
-/* Returns whether surface is the libdecor-created GTK-titlebar of frame */
-bool fl_is_surface_from_GTK_titlebar (struct wl_surface *surface, struct libdecor_frame *frame,
- bool *using_GTK) {
- *using_GTK = (get_plugin_kind(NULL) == GTK3);
- if (!*using_GTK) return false;
- struct libdecor_frame_gtk *frame_gtk = (struct libdecor_frame_gtk*)frame;
- return (frame_gtk->headerbar.wl_surface == surface);
-}
diff --git a/libdecor/build/fl_libdecor.c b/libdecor/build/fl_libdecor.c
deleted file mode 100644
index c7105bd85..000000000
--- a/libdecor/build/fl_libdecor.c
+++ /dev/null
@@ -1,145 +0,0 @@
-//
-// Interface with the libdecor library for the Fast Light Tool Kit (FLTK).
-//
-// Copyright 2022-2024 by Bill Spitzak and others.
-//
-// This library is free software. Distribution and use rights are outlined in
-// the file "COPYING" which should have been included with this file. If this
-// file is missing or damaged, see the license at:
-//
-// https://www.fltk.org/COPYING.php
-//
-// Please see the following page on how to report bugs and issues:
-//
-// https://www.fltk.org/bugs.php
-//
-
-/* Improvements to libdecor.c without modifying libdecor.c itself */
-#if ! USE_SYSTEM_LIBDECOR
-
-#include <dlfcn.h>
-#include <stdlib.h>
-static void *dlopen_corrected(const char *, int);
-#define dlopen(A, B) dlopen_corrected(A, B)
-#include "fl_libdecor.h"
-#undef libdecor_new
-#define libdecor_new libdecor_new_orig
-#undef libdecor_frame_set_minimized
-#define libdecor_frame_set_minimized libdecor_frame_set_minimized_orig
-#include "../src/libdecor.c"
-#undef dlopen
-#undef libdecor_frame_set_minimized
-#undef libdecor_new
-#define libdecor_new fl_libdecor_new
-#define libdecor_frame_set_minimized fl_libdecor_frame_set_minimized
-
-extern bool fl_libdecor_using_weston(void);
-extern const struct libdecor_plugin_description *fl_libdecor_plugin_description;
-//#include <stdio.h>
-
-// we have a built-in plugin so don't need a fallback one
-struct libdecor_plugin *libdecor_fallback_plugin_new(struct libdecor *context) {
- return NULL;
-}
-
-// see get_libdecor_plugin_description() explaining why this is useful
-static void *dlopen_corrected(const char *filename, int flags) {
- static int best_priority = -1;
- void *retval = dlopen(filename, flags);
- if (retval) {
- const struct libdecor_plugin_description *description =
- (const struct libdecor_plugin_description*)dlsym(retval, "libdecor_plugin_description");
- if (description && description->priorities->priority > best_priority) {
- fl_libdecor_plugin_description = description;
- best_priority = description->priorities->priority;
- }
- }
- return retval;
-}
-
-
-void fl_libdecor_frame_set_minimized(struct libdecor_frame *frame)
-{
- static bool done = false;
- static bool using_weston = false;
- if (!done) {
- typedef bool (*ext_f)(void);
- volatile ext_f ext = fl_libdecor_using_weston;
- done = true;
- if (ext) using_weston = fl_libdecor_using_weston();
-//fprintf(stderr, "fl_libdecor_using_weston=%p using_weston=%d\n", fl_libdecor_using_weston, using_weston);
- if (using_weston) { // determine the version of the running Weston compositor
- FILE *pipe = popen("weston --version", "r");
- if (pipe) {
- char line[50], *p;
- int version = 0;
- p = fgets(line, sizeof(line), pipe);
- pclose(pipe);
- if (p) p = strchr(line, ' ');
- if (p) {
- sscanf(p, "%d", &version);
- // Weston version 10 has fixed the bug handled here
- if (version >= 10) using_weston = false;
- }
- }
- }
- }
- if (using_weston) libdecor_frame_set_visibility(frame, false);
- libdecor_frame_set_minimized_orig(frame);
-}
-
-
-/*
- By default, FLTK modifies libdecor's libdecor_new() function to determine the plugin as follows :
- 1) the directory pointed by environment variable LIBDECOR_PLUGIN_DIR or, in absence of this variable,
- by -DLIBDECOR_PLUGIN_DIR=xxx at build time is searched for a libdecor plugin;
- 2) if this directory does not exist or contains no plugin, the built-in plugin is used.
- * if FLTK was built with package libgtk-3-dev, the GTK plugin is used
- * if FLTK was built without package libgtk-3-dev, the Cairo plugin is used
-
- If FLTK was built with FLTK_USE_SYSTEM_LIBDECOR turned ON, the present modification
- isn't compiled, so the plugin-searching algorithm of libdecor_new() in libdecor-0.so is used.
- This corresponds to step 1) above and to use no titlebar is no plugin is found.
-
- N.B.: only the system package is built with a meaningful value of -DLIBDECOR_PLUGIN_DIR=
- so a plugin may be loaded that way only if FLTK was built with FLTK_USE_SYSTEM_LIBDECOR turned ON.
-
- */
-struct libdecor *fl_libdecor_new(struct wl_display *wl_display, const struct libdecor_interface *iface)
-{
- struct libdecor *context;
- context = zalloc(sizeof *context);
- context->ref_count = 1;
- context->iface = iface;
- 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);
- // attempt to dynamically load a libdecor plugin with dlopen()
- if (init_plugins(context) != 0) { // attempt to load plugin by dlopen()
- // no plug-in was found by dlopen(), use built-in plugin instead
- // defined in the source code of the built-in plugin: libdecor-cairo.c or libdecor-gtk.c
- extern const struct libdecor_plugin_description libdecor_plugin_description;
-#if HAVE_GTK
- bool gdk_caution = false;
- if (getenv("GDK_BACKEND") && strcmp(getenv("GDK_BACKEND"), "x11") == 0) {
- // Environment variable GDK_BACKEND=x11 makes the .constructor below fail
- // for the built-in GTK plugin and then FLTK crashes (#1029).
- // Temporarily unset GDK_BACKEND to prevent that.
- gdk_caution = true;
- unsetenv("GDK_BACKEND");
- }
-#endif
- context->plugin = libdecor_plugin_description.constructor(context);
-#if HAVE_GTK
- if (gdk_caution) putenv("GDK_BACKEND=x11");
-#endif
- }
-
- wl_display_flush(wl_display);
- return context;
-}
-
-#endif //! USE_SYSTEM_LIBDECOR
diff --git a/libdecor/build/fl_libdecor.h b/libdecor/build/fl_libdecor.h
deleted file mode 100644
index 97041c885..000000000
--- a/libdecor/build/fl_libdecor.h
+++ /dev/null
@@ -1,93 +0,0 @@
-//
-// Interface with the libdecor library for the Fast Light Tool Kit (FLTK).
-//
-// Copyright 2024 by Bill Spitzak and others.
-//
-// This library is free software. Distribution and use rights are outlined in
-// the file "COPYING" which should have been included with this file. If this
-// file is missing or damaged, see the license at:
-//
-// https://www.fltk.org/COPYING.php
-//
-// Please see the following page on how to report bugs and issues:
-//
-// https://www.fltk.org/bugs.php
-//
-
-#ifndef FL_LIBDECOR_H
-#define FL_LIBDECOR_H
-
-#if ! USE_SYSTEM_LIBDECOR
-
-// add "fl_" prefix to libdecor.h symbols
-#define libdecor_unref fl_libdecor_unref
-#define libdecor_new fl_libdecor_new
-#define libdecor_new_with_user_data fl_libdecor_new_with_user_data
-#define libdecor_get_user_data fl_libdecor_get_user_data
-#define libdecor_set_user_data fl_libdecor_set_user_data
-#define libdecor_get_fd fl_libdecor_get_fd
-#define libdecor_dispatch fl_libdecor_dispatch
-#define libdecor_decorate fl_libdecor_decorate
-#define libdecor_frame_ref fl_libdecor_frame_ref
-#define libdecor_frame_unref fl_libdecor_frame_unref
-#define libdecor_frame_get_user_data fl_libdecor_frame_get_user_data
-#define libdecor_frame_set_user_data fl_libdecor_frame_set_user_data
-#define libdecor_frame_set_visibility fl_libdecor_frame_set_visibility
-#define libdecor_frame_is_visible fl_libdecor_frame_is_visible
-#define libdecor_frame_set_parent fl_libdecor_frame_set_parent
-#define libdecor_frame_set_title fl_libdecor_frame_set_title
-#define libdecor_frame_get_title fl_libdecor_frame_get_title
-#define libdecor_frame_set_app_id fl_libdecor_frame_set_app_id
-#define libdecor_frame_set_capabilities fl_libdecor_frame_set_capabilities
-#define libdecor_frame_unset_capabilities fl_libdecor_frame_unset_capabilitiesf
-#define libdecor_frame_has_capability fl_libdecor_frame_has_capability
-#define libdecor_frame_show_window_menu fl_libdecor_frame_show_window_menu
-#define libdecor_frame_popup_grab fl_libdecor_frame_popup_grab
-#define libdecor_frame_popup_ungrab fl_libdecor_frame_popup_ungrab
-#define libdecor_frame_translate_coordinate fl_libdecor_frame_translate_coordinate
-#define libdecor_frame_set_min_content_size fl_libdecor_frame_set_min_content_size
-#define libdecor_frame_set_max_content_size fl_libdecor_frame_set_max_content_size
-#define libdecor_frame_get_min_content_size fl_libdecor_frame_get_min_content_size
-#define libdecor_frame_get_max_content_size fl_libdecor_frame_get_max_content_size
-#define libdecor_frame_resize fl_libdecor_frame_resize
-#define libdecor_frame_move fl_libdecor_frame_move
-#define libdecor_frame_commit fl_libdecor_frame_commit
-#define libdecor_frame_set_minimized fl_libdecor_frame_set_minimized
-#define libdecor_frame_set_maximized fl_libdecor_frame_set_maximized
-#define libdecor_frame_unset_maximized fl_libdecor_frame_unset_maximized
-#define libdecor_frame_set_fullscreen fl_libdecor_frame_set_fullscreen
-#define libdecor_frame_unset_fullscreen fl_libdecor_frame_unset_fullscreen
-#define libdecor_frame_is_floating fl_libdecor_frame_is_floating
-#define libdecor_frame_close fl_libdecor_frame_close
-#define libdecor_frame_map fl_libdecor_frame_map
-#define libdecor_frame_get_xdg_surface fl_libdecor_frame_get_xdg_surface
-#define libdecor_frame_get_xdg_toplevel fl_libdecor_frame_get_xdg_toplevel
-#define libdecor_frame_get_wm_capabilities fl_libdecor_frame_get_wm_capabilities
-#define libdecor_set_handle_application_cursor fl_libdecor_set_handle_application_cursor
-#define libdecor_state_new fl_libdecor_state_new
-#define libdecor_state_free fl_libdecor_state_free
-#define libdecor_configuration_get_content_size fl_libdecor_configuration_get_content_size
-#define libdecor_configuration_get_window_state fl_libdecor_configuration_get_window_state
-
-// add "fl_" prefix to libdecor-plugin.h symbols
-#define libdecor_frame_get_wl_surface fl_libdecor_frame_get_wl_surface
-#define libdecor_frame_get_content_width fl_libdecor_frame_get_content_width
-#define libdecor_frame_get_content_height fl_libdecor_frame_get_content_height
-#define libdecor_frame_get_window_state fl_libdecor_frame_get_window_state
-#define libdecor_frame_get_capabilities fl_libdecor_frame_get_capabilities
-#define libdecor_frame_dismiss_popup fl_libdecor_frame_dismiss_popup
-#define libdecor_frame_toplevel_commit fl_libdecor_frame_toplevel_commit
-#define libdecor_get_wl_display fl_libdecor_get_wl_display
-#define libdecor_notify_plugin_ready fl_libdecor_notify_plugin_ready
-#define libdecor_notify_plugin_error fl_libdecor_notify_plugin_error
-#define libdecor_state_get_content_width fl_libdecor_state_get_content_width
-#define libdecor_state_get_content_height fl_libdecor_state_get_content_height
-#define libdecor_state_get_window_state fl_libdecor_state_get_window_state
-#define libdecor_plugin_init fl_libdecor_plugin_init
-#define libdecor_plugin_release fl_libdecor_plugin_release
-
-#endif // ! USE_SYSTEM_LIBDECOR
-
-#include "../src/libdecor.h"
-
-#endif // ! FL_LIBDECOR_H
diff --git a/libdecor/build/gtk-shell.xml b/libdecor/build/gtk-shell.xml
deleted file mode 100644
index f00684679..000000000
--- a/libdecor/build/gtk-shell.xml
+++ /dev/null
@@ -1,109 +0,0 @@
-<!-- found at: https://gitlab.gnome.org/GNOME/gtk/-/blob/main/gdk/wayland/protocol/gtk-shell.xml -->
-<protocol name="gtk">
-
- <interface name="gtk_shell1" version="5">
- <description summary="gtk specific extensions">
- gtk_shell is a protocol extension providing additional features for
- clients implementing it.
- </description>
-
- <enum name="capability">
- <entry name="global_app_menu" value="1"/>
- <entry name="global_menu_bar" value="2"/>
- <entry name="desktop_icons" value="3"/>
- </enum>
-
- <event name="capabilities">
- <arg name="capabilities" type="uint"/>
- </event>
-
- <request name="get_gtk_surface">
- <arg name="gtk_surface" type="new_id" interface="gtk_surface1"/>
- <arg name="surface" type="object" interface="wl_surface"/>
- </request>
-
- <request name="set_startup_id">
- <arg name="startup_id" type="string" allow-null="true"/>
- </request>
-
- <request name="system_bell">
- <arg name="surface" type="object" interface="gtk_surface1" allow-null="true"/>
- </request>
-
- <!-- Version 3 additions -->
- <request name="notify_launch" since="3">
- <arg name="startup_id" type="string"/>
- </request>
- </interface>
-
- <interface name="gtk_surface1" version="5">
- <request name="set_dbus_properties">
- <arg name="application_id" type="string" allow-null="true"/>
- <arg name="app_menu_path" type="string" allow-null="true"/>
- <arg name="menubar_path" type="string" allow-null="true"/>
- <arg name="window_object_path" type="string" allow-null="true"/>
- <arg name="application_object_path" type="string" allow-null="true"/>
- <arg name="unique_bus_name" type="string" allow-null="true"/>
- </request>
-
- <request name="set_modal"/>
- <request name="unset_modal"/>
-
- <request name="present">
- <arg name="time" type="uint"/>
- </request>
-
- <!-- Version 2 additions -->
-
- <enum name="state">
- <entry name="tiled" value="1"/>
-
- <entry name="tiled_top" value="2" since="2" />
- <entry name="tiled_right" value="3" since="2" />
- <entry name="tiled_bottom" value="4" since="2" />
- <entry name="tiled_left" value="5" since="2" />
- </enum>
-
- <enum name="edge_constraint" since="2">
- <entry name="resizable_top" value="1"/>
- <entry name="resizable_right" value="2"/>
- <entry name="resizable_bottom" value="3"/>
- <entry name="resizable_left" value="4"/>
- </enum>
-
- <event name="configure">
- <arg name="states" type="array"/>
- </event>
-
- <event name="configure_edges" since="2">
- <arg name="constraints" type="array"/>
- </event>
-
- <!-- Version 3 additions -->
- <request name="request_focus" since="3">
- <arg name="startup_id" type="string" allow-null="true"/>
- </request>
-
- <!-- Version 4 additions -->
- <request name="release" type="destructor" since="4"/>
-
- <!-- Version 5 additions -->
- <enum name="gesture" since="5">
- <entry name="double_click" value="1"/>
- <entry name="right_click" value="2"/>
- <entry name="middle_click" value="3"/>
- </enum>
-
- <enum name="error" since="5">
- <entry name="invalid_gesture" value="0"/>
- </enum>
-
- <request name="titlebar_gesture" since="5">
- <arg name="serial" type="uint"/>
- <arg name="seat" type="object" interface="wl_seat"/>
- <arg name="gesture" type="uint" enum="gesture"/>
- </request>
- </interface>
-
-</protocol>
-
diff --git a/libdecor/src/desktop-settings.c b/libdecor/src/desktop-settings.c
deleted file mode 100644
index 28067ac3e..000000000
--- a/libdecor/src/desktop-settings.c
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright © 2019 Christian Rauch
- * Copyright © 2024 Colin Kinloch
- *
- * 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 "desktop-settings.h"
-#include <stdlib.h>
-#include <string.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include "config.h"
-
-static bool
-get_cursor_settings_from_env(char **theme, int *size)
-{
- char *env_xtheme;
- char *env_xsize;
-
- env_xtheme = getenv("XCURSOR_THEME");
- if (env_xtheme != NULL)
- *theme = strdup(env_xtheme);
-
- env_xsize = getenv("XCURSOR_SIZE");
- if (env_xsize != NULL)
- *size = atoi(env_xsize);
-
- return env_xtheme != NULL && env_xsize != NULL;
-}
-
-#ifdef HAS_DBUS
-#include <dbus/dbus.h>
-
-static DBusMessage *
-get_setting_sync(DBusConnection *const connection,
- const char *key,
- const char *value)
-{
- DBusError error;
- dbus_bool_t success;
- DBusMessage *message;
- DBusMessage *reply;
-
- message = dbus_message_new_method_call(
- "org.freedesktop.portal.Desktop",
- "/org/freedesktop/portal/desktop",
- "org.freedesktop.portal.Settings",
- "Read");
-
- success = dbus_message_append_args(message,
- DBUS_TYPE_STRING, &key,
- DBUS_TYPE_STRING, &value,
- DBUS_TYPE_INVALID);
-
- if (!success)
- return NULL;
-
- dbus_error_init(&error);
-
- reply = dbus_connection_send_with_reply_and_block(
- connection,
- message,
- DBUS_TIMEOUT_USE_DEFAULT,
- &error);
-
- dbus_message_unref(message);
-
- if (dbus_error_is_set(&error)) {
- dbus_error_free(&error);
- return NULL;
- }
-
- dbus_error_free(&error);
- return reply;
-}
-
-static bool
-parse_type(DBusMessage *const reply,
- const int type,
- void *value)
-{
- DBusMessageIter iter[3];
-
- dbus_message_iter_init(reply, &iter[0]);
- if (dbus_message_iter_get_arg_type(&iter[0]) != DBUS_TYPE_VARIANT)
- return false;
-
- dbus_message_iter_recurse(&iter[0], &iter[1]);
- if (dbus_message_iter_get_arg_type(&iter[1]) != DBUS_TYPE_VARIANT)
- return false;
-
- dbus_message_iter_recurse(&iter[1], &iter[2]);
- if (dbus_message_iter_get_arg_type(&iter[2]) != type)
- return false;
-
- dbus_message_iter_get_basic(&iter[2], value);
-
- return true;
-}
-
-bool
-libdecor_get_cursor_settings(char **theme, int *size)
-{
- static const char name[] = "org.gnome.desktop.interface";
- static const char key_theme[] = "cursor-theme";
- static const char key_size[] = "cursor-size";
-
- DBusError error;
- DBusConnection *connection;
- DBusMessage *reply;
- const char *value_theme = NULL;
-
- dbus_error_init(&error);
-
- connection = dbus_bus_get(DBUS_BUS_SESSION, &error);
-
- if (dbus_error_is_set(&error))
- goto fallback;
-
- reply = get_setting_sync(connection, name, key_theme);
- if (!reply)
- goto fallback;
-
- if (!parse_type(reply, DBUS_TYPE_STRING, &value_theme)) {
- dbus_message_unref(reply);
- goto fallback;
- }
-
- *theme = strdup(value_theme);
-
- dbus_message_unref(reply);
-
- reply = get_setting_sync(connection, name, key_size);
- if (!reply)
- goto fallback;
-
- if (!parse_type(reply, DBUS_TYPE_INT32, size)) {
- dbus_message_unref(reply);
- goto fallback;
- }
-
- dbus_message_unref(reply);
-
- return true;
-
-fallback:
- return get_cursor_settings_from_env(theme, size);
-}
-
-enum libdecor_color_scheme
-libdecor_get_color_scheme()
-{
- static const char name[] = "org.freedesktop.appearance";
- static const char key_color_scheme[] = "color-scheme";
- uint32_t color = 0;
-
- DBusError error;
- DBusConnection *connection;
- DBusMessage *reply;
-
- dbus_error_init(&error);
-
- connection = dbus_bus_get(DBUS_BUS_SESSION, &error);
-
- if (dbus_error_is_set(&error))
- return 0;
-
- reply = get_setting_sync(connection, name, key_color_scheme);
- if (!reply)
- return 0;
-
- if (!parse_type(reply, DBUS_TYPE_UINT32, &color)) {
- dbus_message_unref(reply);
- return 0;
- }
-
- dbus_message_unref(reply);
-
- return color;
-}
-#else
-bool
-libdecor_get_cursor_settings(char **theme, int *size)
-{
- return get_cursor_settings_from_env(theme, size);
-}
-
-uint32_t
-libdecor_get_color_scheme()
-{
- return LIBDECOR_COLOR_SCHEME_DEFAULT;
-}
-#endif
diff --git a/libdecor/src/desktop-settings.h b/libdecor/src/desktop-settings.h
deleted file mode 100644
index 5747d3168..000000000
--- a/libdecor/src/desktop-settings.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright © 2019 Christian Rauch
- * Copyright © 2024 Colin Kinloch
- *
- * 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.
- */
-
-#pragma once
-
-#include <stdbool.h>
-
-enum libdecor_color_scheme {
- LIBDECOR_COLOR_SCHEME_DEFAULT,
- LIBDECOR_COLOR_SCHEME_PREFER_DARK,
- LIBDECOR_COLOR_SCHEME_PREFER_LIGHT,
-};
-
-bool
-libdecor_get_cursor_settings(char **theme, int *size);
-
-enum libdecor_color_scheme
-libdecor_get_color_scheme();
diff --git a/libdecor/src/libdecor-fallback.c b/libdecor/src/libdecor-fallback.c
deleted file mode 100644
index ea0d35b03..000000000
--- a/libdecor/src/libdecor-fallback.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright © 2019 Jonas Ådahl
- *
- * 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 "libdecor-fallback.h"
-
-#include <poll.h>
-#include <errno.h>
-
-#include "utils.h"
-
-struct libdecor_plugin_fallback {
- struct libdecor_plugin plugin;
- struct libdecor *context;
-};
-
-static void
-libdecor_plugin_fallback_destroy(struct libdecor_plugin *plugin)
-{
- libdecor_plugin_release(plugin);
- free(plugin);
-}
-
-static int
-libdecor_plugin_fallback_get_fd(struct libdecor_plugin *plugin)
-{
- struct libdecor_plugin_fallback *plugin_fallback =
- (struct libdecor_plugin_fallback *) plugin;
- struct wl_display *wl_display =
- libdecor_get_wl_display(plugin_fallback->context);
-
- return wl_display_get_fd(wl_display);
-}
-
-static int
-libdecor_plugin_fallback_dispatch(struct libdecor_plugin *plugin,
- int timeout)
-{
- struct libdecor_plugin_fallback *plugin_fallback =
- (struct libdecor_plugin_fallback *) plugin;
- struct wl_display *wl_display =
- libdecor_get_wl_display(plugin_fallback->context);
- struct pollfd fds[1];
- int ret;
- int dispatch_count = 0;
-
- while (wl_display_prepare_read(wl_display) != 0)
- dispatch_count += wl_display_dispatch_pending(wl_display);
-
- if (wl_display_flush(wl_display) < 0 &&
- errno != EAGAIN) {
- wl_display_cancel_read(wl_display);
- return -errno;
- }
-
- fds[0] = (struct pollfd) { wl_display_get_fd(wl_display), POLLIN };
-
- ret = poll(fds, ARRAY_SIZE (fds), timeout);
- if (ret > 0) {
- if (fds[0].revents & POLLIN) {
- wl_display_read_events(wl_display);
- dispatch_count += wl_display_dispatch_pending(wl_display);
- return dispatch_count;
- } else {
- wl_display_cancel_read(wl_display);
- return dispatch_count;
- }
- } else if (ret == 0) {
- wl_display_cancel_read(wl_display);
- return dispatch_count;
- } else {
- wl_display_cancel_read(wl_display);
- return -errno;
- }
-}
-
-static struct libdecor_frame *
-libdecor_plugin_fallback_frame_new(struct libdecor_plugin *plugin)
-{
- struct libdecor_frame *frame;
-
- frame = zalloc(sizeof *frame);
-
- return frame;
-}
-
-static void
-libdecor_plugin_fallback_frame_free(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame)
-{
-}
-
-static void
-libdecor_plugin_fallback_frame_commit(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame,
- struct libdecor_state *state,
- struct libdecor_configuration *configuration)
-{
-}
-
-static void
-libdecor_plugin_fallback_frame_property_changed(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame)
-{
-}
-
-static void
-libdecor_plugin_fallback_frame_popup_grab(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame,
- const char *seat_name)
-{
-}
-
-static void
-libdecor_plugin_fallback_frame_popup_ungrab(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame,
- const char *seat_name)
-{
-}
-
-static bool
-libdecor_plugin_fallback_frame_get_border_size(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame,
- struct libdecor_configuration *configuration,
- int *left,
- int *right,
- int *top,
- int *bottom)
-{
- if (left)
- *left = 0;
- if (right)
- *right = 0;
- if (top)
- *top = 0;
- if (bottom)
- *bottom = 0;
-
- return true;
-}
-
-static struct libdecor_plugin_interface fallback_plugin_iface = {
- .destroy = libdecor_plugin_fallback_destroy,
- .get_fd = libdecor_plugin_fallback_get_fd,
- .dispatch = libdecor_plugin_fallback_dispatch,
- .frame_new = libdecor_plugin_fallback_frame_new,
- .frame_free = libdecor_plugin_fallback_frame_free,
- .frame_commit = libdecor_plugin_fallback_frame_commit,
- .frame_property_changed = libdecor_plugin_fallback_frame_property_changed,
- .frame_popup_grab = libdecor_plugin_fallback_frame_popup_grab,
- .frame_popup_ungrab = libdecor_plugin_fallback_frame_popup_ungrab,
- .frame_get_border_size = libdecor_plugin_fallback_frame_get_border_size,
-};
-
-struct libdecor_plugin *
-libdecor_fallback_plugin_new(struct libdecor *context)
-{
- struct libdecor_plugin_fallback *plugin;
-
- plugin = zalloc(sizeof *plugin);
- libdecor_plugin_init(&plugin->plugin, context, &fallback_plugin_iface);
- plugin->context = context;
-
- libdecor_notify_plugin_ready(context);
-
- return &plugin->plugin;
-}
diff --git a/libdecor/src/libdecor-fallback.h b/libdecor/src/libdecor-fallback.h
deleted file mode 100644
index 40a5c51d2..000000000
--- a/libdecor/src/libdecor-fallback.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright © 2019 Jonas Ådahl
- *
- * 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.
- */
-
-#ifndef LIBDECOR_FALLBACK_H
-#define LIBDECOR_FALLBACK_H
-
-#include "libdecor.h"
-#include "libdecor-plugin.h"
-
-struct libdecor_plugin *
-libdecor_fallback_plugin_new(struct libdecor *context);
-
-#endif /* LIBDECOR_FALLBACK_H */
diff --git a/libdecor/src/libdecor-plugin.h b/libdecor/src/libdecor-plugin.h
deleted file mode 100644
index d57430e9c..000000000
--- a/libdecor/src/libdecor-plugin.h
+++ /dev/null
@@ -1,186 +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.
- */
-
-#ifndef LIBDECOR_PLUGIN_H
-#define LIBDECOR_PLUGIN_H
-
-#include "libdecor.h"
-
-struct libdecor_frame_private;
-
-struct libdecor_frame {
- struct libdecor_frame_private *priv;
- struct wl_list link;
-};
-
-struct libdecor_plugin_private;
-
-struct libdecor_plugin {
- struct libdecor_plugin_private *priv;
-};
-
-typedef struct libdecor_plugin * (* libdecor_plugin_constructor)(struct libdecor *context);
-
-#define LIBDECOR_PLUGIN_PRIORITY_HIGH 1000
-#define LIBDECOR_PLUGIN_PRIORITY_MEDIUM 100
-#define LIBDECOR_PLUGIN_PRIORITY_LOW 0
-
-struct libdecor_plugin_priority {
- const char *desktop;
- int priority;
-};
-
-enum libdecor_plugin_capabilities {
- LIBDECOR_PLUGIN_CAPABILITY_BASE = 1 << 0,
-};
-
-struct libdecor_plugin_description {
- /* API version the plugin is compatible with. */
- int api_version;
-
- /* Human readable string describing the plugin. */
- char *description;
-
- /* A plugin has a bitmask of capabilities. The plugin loader can use this
- * to load a plugin with the right capabilities. */
- enum libdecor_plugin_capabilities capabilities;
-
- /*
- * The priorities field points to a list of per desktop priorities.
- * properties[i].desktop is matched against XDG_CURRENT_DESKTOP when
- * determining what plugin to use. The last entry in the list MUST have
- * the priorities[i].desktop pointer set to NULL as a default
- * priority.
- */
- const struct libdecor_plugin_priority *priorities;
-
- /* Vfunc used for constructing a plugin instance. */
- libdecor_plugin_constructor constructor;
-
- /* NULL terminated list of incompatible symbols. */
- char *conflicting_symbols[1024];
-};
-
-struct libdecor_plugin_interface {
- void (* destroy)(struct libdecor_plugin *plugin);
-
- int (* get_fd)(struct libdecor_plugin *plugin);
- int (* dispatch)(struct libdecor_plugin *plugin,
- int timeout);
-
- void (* set_handle_application_cursor)(struct libdecor_plugin *plugin,
- bool handle_cursor);
-
- struct libdecor_frame * (* frame_new)(struct libdecor_plugin *plugin);
- void (* frame_free)(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame);
- void (* frame_commit)(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame,
- struct libdecor_state *state,
- struct libdecor_configuration *configuration);
- void (*frame_property_changed)(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame);
- void (* frame_popup_grab)(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame,
- const char *seat_name);
- void (* frame_popup_ungrab)(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame,
- const char *seat_name);
-
- bool (* frame_get_border_size)(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame,
- struct libdecor_configuration *configuration,
- int *left,
- int *right,
- int *top,
- int *bottom);
-
- /* Reserved */
- void (* reserved0)(void);
- void (* reserved1)(void);
- void (* reserved2)(void);
- void (* reserved3)(void);
- void (* reserved4)(void);
- void (* reserved5)(void);
- void (* reserved6)(void);
- void (* reserved7)(void);
- void (* reserved8)(void);
- void (* reserved9)(void);
-};
-
-struct wl_surface *
-libdecor_frame_get_wl_surface(struct libdecor_frame *frame);
-
-int
-libdecor_frame_get_content_width(struct libdecor_frame *frame);
-
-int
-libdecor_frame_get_content_height(struct libdecor_frame *frame);
-
-enum libdecor_window_state
-libdecor_frame_get_window_state(struct libdecor_frame *frame);
-
-enum libdecor_capabilities
-libdecor_frame_get_capabilities(const struct libdecor_frame *frame);
-
-void
-libdecor_frame_dismiss_popup(struct libdecor_frame *frame,
- const char *seat_name);
-
-void
-libdecor_frame_toplevel_commit(struct libdecor_frame *frame);
-
-struct wl_display *
-libdecor_get_wl_display(struct libdecor *context);
-
-void
-libdecor_notify_plugin_ready(struct libdecor *context);
-
-void
-libdecor_notify_plugin_error(struct libdecor *context,
- enum libdecor_error error,
- const char *__restrict fmt,
- ...);
-
-int
-libdecor_state_get_content_width(struct libdecor_state *state);
-
-int
-libdecor_state_get_content_height(struct libdecor_state *state);
-
-enum libdecor_window_state
-libdecor_state_get_window_state(struct libdecor_state *state);
-
-int
-libdecor_plugin_init(struct libdecor_plugin *plugin,
- struct libdecor *context,
- struct libdecor_plugin_interface *iface);
-
-void
-libdecor_plugin_release(struct libdecor_plugin *plugin);
-
-#endif /* LIBDECOR_PLUGIN_H */
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;
-}
diff --git a/libdecor/src/libdecor.h b/libdecor/src/libdecor.h
deleted file mode 100644
index 71c9d7660..000000000
--- a/libdecor/src/libdecor.h
+++ /dev/null
@@ -1,605 +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.
- */
-
-#ifndef LIBDECOR_H
-#define LIBDECOR_H
-
-#include <stdbool.h>
-#include <wayland-client.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if defined(__GNUC__) && __GNUC__ >= 4
-#define LIBDECOR_EXPORT __attribute__ ((visibility("default")))
-#else
-#define LIBDECOR_EXPORT
-#endif
-
-struct xdg_toplevel;
-
-/** \class libdecor
- *
- * \brief A libdecor context instance.
- */
-struct libdecor;
-
-/** \class libdecor_frame
- *
- * \brief A frame used for decorating a Wayland surface.
- */
-struct libdecor_frame;
-
-/** \class libdecor_configuration
- *
- * \brief An object representing a toplevel window configuration.
- */
-struct libdecor_configuration;
-
-/** \class libdecor_state
- *
- * \brief An object corresponding to a configured content state.
- */
-struct libdecor_state;
-
-enum libdecor_error {
- LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE,
- LIBDECOR_ERROR_INVALID_FRAME_CONFIGURATION,
-};
-
-enum libdecor_window_state {
- LIBDECOR_WINDOW_STATE_NONE = 0,
- LIBDECOR_WINDOW_STATE_ACTIVE = 1 << 0,
- LIBDECOR_WINDOW_STATE_MAXIMIZED = 1 << 1,
- LIBDECOR_WINDOW_STATE_FULLSCREEN = 1 << 2,
- LIBDECOR_WINDOW_STATE_TILED_LEFT = 1 << 3,
- LIBDECOR_WINDOW_STATE_TILED_RIGHT = 1 << 4,
- LIBDECOR_WINDOW_STATE_TILED_TOP = 1 << 5,
- LIBDECOR_WINDOW_STATE_TILED_BOTTOM = 1 << 6,
- LIBDECOR_WINDOW_STATE_SUSPENDED = 1 << 7,
- LIBDECOR_WINDOW_STATE_RESIZING = 1 << 8,
- LIBDECOR_WINDOW_STATE_CONSTRAINED_LEFT = 1 << 9,
- LIBDECOR_WINDOW_STATE_CONSTRAINED_RIGHT = 1 << 10,
- LIBDECOR_WINDOW_STATE_CONSTRAINED_TOP = 1 << 11,
- LIBDECOR_WINDOW_STATE_CONSTRAINED_BOTTOM = 1 << 12,
-};
-
-enum libdecor_resize_edge {
- LIBDECOR_RESIZE_EDGE_NONE,
- LIBDECOR_RESIZE_EDGE_TOP,
- LIBDECOR_RESIZE_EDGE_BOTTOM,
- LIBDECOR_RESIZE_EDGE_LEFT,
- LIBDECOR_RESIZE_EDGE_TOP_LEFT,
- LIBDECOR_RESIZE_EDGE_BOTTOM_LEFT,
- LIBDECOR_RESIZE_EDGE_RIGHT,
- LIBDECOR_RESIZE_EDGE_TOP_RIGHT,
- LIBDECOR_RESIZE_EDGE_BOTTOM_RIGHT,
-};
-
-enum libdecor_capabilities {
- LIBDECOR_ACTION_MOVE = 1 << 0,
- LIBDECOR_ACTION_RESIZE = 1 << 1,
- LIBDECOR_ACTION_MINIMIZE = 1 << 2,
- LIBDECOR_ACTION_FULLSCREEN = 1 << 3,
- LIBDECOR_ACTION_CLOSE = 1 << 4,
-};
-
-enum libdecor_wm_capabilities {
- LIBDECOR_WM_CAPABILITIES_WINDOW_MENU = 1 << 0,
- LIBDECOR_WM_CAPABILITIES_MAXIMIZE = 1 << 1,
- LIBDECOR_WM_CAPABILITIES_FULLSCREEN = 1 << 2,
- LIBDECOR_WM_CAPABILITIES_MINIMIZE = 1 << 3
-};
-
-struct libdecor_interface {
- /**
- * An error event
- */
- void (* error)(struct libdecor *context,
- enum libdecor_error error,
- const char *message);
-
- /* Reserved */
- void (* reserved0)(void);
- void (* reserved1)(void);
- void (* reserved2)(void);
- void (* reserved3)(void);
- void (* reserved4)(void);
- void (* reserved5)(void);
- void (* reserved6)(void);
- void (* reserved7)(void);
- void (* reserved8)(void);
- void (* reserved9)(void);
-};
-
-/**
- * Interface for integrating a Wayland surface with libdecor.
- */
-struct libdecor_frame_interface {
- /**
- * A new configuration was received. An application should respond to
- * this by creating a suitable libdecor_state, and apply it using
- * libdecor_frame_commit.
- */
- void (* configure)(struct libdecor_frame *frame,
- struct libdecor_configuration *configuration,
- void *user_data);
-
- /**
- * The window was requested to be closed by the compositor.
- */
- void (* close)(struct libdecor_frame *frame,
- void *user_data);
-
- /**
- * The window decoration asked to have the main surface to be
- * committed. This is required when the decoration is implemented using
- * synchronous subsurfaces.
- */
- void (* commit)(struct libdecor_frame *frame,
- void *user_data);
-
- /**
- * Any mapped popup that has a grab on the given seat should be
- * dismissed.
- */
- void (* dismiss_popup)(struct libdecor_frame *frame,
- const char *seat_name,
- void *user_data);
-
- /**
- * The recommended client region bounds for the window.
- * This will be followed by a configure event.
- */
- void (* bounds)(struct libdecor_frame *frame,
- int width,
- int height,
- void *user_data);
-
- /* Reserved */
- void (* reserved0)(void);
- void (* reserved1)(void);
- void (* reserved2)(void);
- void (* reserved3)(void);
- void (* reserved4)(void);
- void (* reserved5)(void);
- void (* reserved6)(void);
- void (* reserved7)(void);
- void (* reserved8)(void);
-};
-
-/**
- * Remove a reference to the libdecor instance. When the reference count
- * reaches zero, it is freed.
- */
-void
-libdecor_unref(struct libdecor *context);
-
-/**
- * Create a new libdecor context for the given wl_display.
- */
-struct libdecor *
-libdecor_new(struct wl_display *display,
- const struct libdecor_interface *iface);
-
-/**
- * Create a new libdecor context for the given wl_display and attach user data.
- */
-struct libdecor *
-libdecor_new_with_user_data(struct wl_display *display,
- const struct libdecor_interface *iface,
- void *user_data);
-
-/**
- * Get the user data associated with this libdecor context.
- */
-void *
-libdecor_get_user_data(struct libdecor *context);
-
-/**
- * Set the user data associated with this libdecor context.
- */
-void
-libdecor_set_user_data(struct libdecor *context, void *user_data);
-
-/**
- * Get the file descriptor used by libdecor. This is similar to
- * wl_display_get_fd(), thus should be polled, and when data is available,
- * libdecor_dispatch() should be called.
- */
-int
-libdecor_get_fd(struct libdecor *context);
-
-/**
- * Dispatch events. This function should be called when data is available on
- * the file descriptor returned by libdecor_get_fd(). If timeout is zero, this
- * function will never block.
- */
-int
-libdecor_dispatch(struct libdecor *context,
- int timeout);
-
-/**
- * Decorate the given content wl_surface.
- *
- * This will create an xdg_surface and an xdg_toplevel, and integrate it
- * properly with the windowing system, including creating appropriate
- * decorations when needed, as well as handle windowing integration events such
- * as resizing, moving, maximizing, etc.
- *
- * The passed wl_surface should only contain actual application content,
- * without any window decoration.
- */
-struct libdecor_frame *
-libdecor_decorate(struct libdecor *context,
- struct wl_surface *surface,
- const struct libdecor_frame_interface *iface,
- void *user_data);
-
-/**
- * Add a reference to the frame object.
- */
-void
-libdecor_frame_ref(struct libdecor_frame *frame);
-
-/**
- * Remove a reference to the frame object. When the reference count reaches
- * zero, the frame object is destroyed.
- */
-void
-libdecor_frame_unref(struct libdecor_frame *frame);
-
-/**
- * Get the user data associated with this libdecor frame.
- */
-void *
-libdecor_frame_get_user_data(struct libdecor_frame *frame);
-
-/**
- * Set the user data associated with this libdecor frame.
- */
-void
-libdecor_frame_set_user_data(struct libdecor_frame *frame, void *user_data);
-
-/**
- * Set the visibility of the frame.
- *
- * If an application wants to be borderless, it can set the frame visibility to
- * false.
- */
-void
-libdecor_frame_set_visibility(struct libdecor_frame *frame,
- bool visible);
-
-/**
- * Get the visibility of the frame.
- */
-bool
-libdecor_frame_is_visible(struct libdecor_frame *frame);
-
-
-/**
- * Set the parent of the window.
- *
- * This can be used to stack multiple toplevel windows above or under each
- * other.
- */
-void
-libdecor_frame_set_parent(struct libdecor_frame *frame,
- struct libdecor_frame *parent);
-
-/**
- * Set the title of the window.
- */
-void
-libdecor_frame_set_title(struct libdecor_frame *frame,
- const char *title);
-
-/**
- * Get the title of the window.
- */
-const char *
-libdecor_frame_get_title(struct libdecor_frame *frame);
-
-/**
- * Set the application ID of the window.
- */
-void
-libdecor_frame_set_app_id(struct libdecor_frame *frame,
- const char *app_id);
-
-/**
- * Set new capabilities of the window.
- *
- * This determines whether e.g. a window decoration should show a maximize
- * button, etc.
- *
- * Setting a capability does not implicitly unset any other.
- */
-void
-libdecor_frame_set_capabilities(struct libdecor_frame *frame,
- enum libdecor_capabilities capabilities);
-
-/**
- * Unset capabilities of the window.
- *
- * The opposite of libdecor_frame_set_capabilities.
- */
-void
-libdecor_frame_unset_capabilities(struct libdecor_frame *frame,
- enum libdecor_capabilities capabilities);
-
-/**
- * Check whether the window has any of the given capabilities.
- */
-bool
-libdecor_frame_has_capability(struct libdecor_frame *frame,
- enum libdecor_capabilities capability);
-
-/**
- * Show the window menu.
- */
-void
-libdecor_frame_show_window_menu(struct libdecor_frame *frame,
- struct wl_seat *wl_seat,
- uint32_t serial,
- int x,
- int y);
-
-/**
- * Issue a popup grab on the window. Call this when a xdg_popup is mapped, so
- * that it can be properly dismissed by the decorations.
- */
-void
-libdecor_frame_popup_grab(struct libdecor_frame *frame,
- const char *seat_name);
-
-/**
- * Release the popup grab. Call this when you unmap a popup.
- */
-void
-libdecor_frame_popup_ungrab(struct libdecor_frame *frame,
- const char *seat_name);
-
-/**
- * Translate content surface local coordinates to toplevel window local
- * coordinates.
- *
- * This can be used to translate surface coordinates to coordinates useful for
- * e.g. showing the window menu, or positioning a popup.
- */
-void
-libdecor_frame_translate_coordinate(struct libdecor_frame *frame,
- int surface_x,
- int surface_y,
- int *frame_x,
- int *frame_y);
-
-/**
- * Set the min content size.
- *
- * This translates roughly to xdg_toplevel_set_min_size().
- */
-void
-libdecor_frame_set_min_content_size(struct libdecor_frame *frame,
- int content_width,
- int content_height);
-
-/**
- * Set the max content size.
- *
- * This translates roughly to xdg_toplevel_set_max_size().
- */
-void
-libdecor_frame_set_max_content_size(struct libdecor_frame *frame,
- int content_width,
- int content_height);
-
-/**
- * Get the min content size.
- */
-void
-libdecor_frame_get_min_content_size(const struct libdecor_frame *frame,
- int *content_width,
- int *content_height);
-
-/**
- * Get the max content size.
- */
-void
-libdecor_frame_get_max_content_size(const struct libdecor_frame *frame,
- int *content_width,
- int *content_height);
-
-/**
- * Initiate an interactive resize.
- *
- * This roughly translates to xdg_toplevel_resize().
- */
-void
-libdecor_frame_resize(struct libdecor_frame *frame,
- struct wl_seat *wl_seat,
- uint32_t serial,
- enum libdecor_resize_edge edge);
-
-/**
- * Initiate an interactive move.
- *
- * This roughly translates to xdg_toplevel_move().
- */
-void
-libdecor_frame_move(struct libdecor_frame *frame,
- struct wl_seat *wl_seat,
- uint32_t serial);
-
-/**
- * Commit a new window state. This can be called on application driven resizes
- * when the window is floating, or in response to received configurations, i.e.
- * from e.g. interactive resizes or state changes.
- */
-void
-libdecor_frame_commit(struct libdecor_frame *frame,
- struct libdecor_state *state,
- struct libdecor_configuration *configuration);
-
-/**
- * Minimize the window.
- *
- * Roughly translates to xdg_toplevel_set_minimized().
- */
-void
-libdecor_frame_set_minimized(struct libdecor_frame *frame);
-
-/**
- * Maximize the window.
- *
- * Roughly translates to xdg_toplevel_set_maximized().
- */
-void
-libdecor_frame_set_maximized(struct libdecor_frame *frame);
-
-/**
- * Unmaximize the window.
- *
- * Roughly translates to xdg_toplevel_unset_maximized().
- */
-void
-libdecor_frame_unset_maximized(struct libdecor_frame *frame);
-
-/**
- * Fullscreen the window.
- *
- * Roughly translates to xdg_toplevel_set_fullscreen().
- */
-void
-libdecor_frame_set_fullscreen(struct libdecor_frame *frame,
- struct wl_output *output);
-
-/**
- * Unfullscreen the window.
- *
- * Roughly translates to xdg_toplevel_unset_unfullscreen().
- */
-void
-libdecor_frame_unset_fullscreen(struct libdecor_frame *frame);
-
-/**
- * Return true if the window is floating.
- *
- * A window is floating when it's not maximized, tiled, fullscreen, or in any
- * similar way with a fixed size and state.
- * Note that this function uses the "applied" configuration. If this function
- * is used in the 'configure' callback, the provided configuration has to be
- * applied via 'libdecor_frame_commit' first, before it will reflect the current
- * window state from the provided configuration.
- */
-bool
-libdecor_frame_is_floating(struct libdecor_frame *frame);
-
-/**
- * Close the window.
- *
- * Roughly translates to xdg_toplevel_close().
- */
-void
-libdecor_frame_close(struct libdecor_frame *frame);
-
-/**
- * Map the window.
- *
- * This will eventually result in the initial configure event.
- */
-void
-libdecor_frame_map(struct libdecor_frame *frame);
-
-/**
- * Get the associated xdg_surface for content wl_surface.
- */
-struct xdg_surface *
-libdecor_frame_get_xdg_surface(struct libdecor_frame *frame);
-
-/**
- * Get the associated xdg_toplevel for the content wl_surface.
- */
-struct xdg_toplevel *
-libdecor_frame_get_xdg_toplevel(struct libdecor_frame *frame);
-
-/**
- * Get the supported window manager capabilities for the window.
- */
-enum libdecor_wm_capabilities
-libdecor_frame_get_wm_capabilities(struct libdecor_frame *frame);
-
-/**
- * Tell libdecor to set the default pointer cursor when the pointer is over an
- * application surface. The default false.
- */
-void
-libdecor_set_handle_application_cursor(struct libdecor *context,
- bool handle_cursor);
-
-/**
- * Create a new content surface state.
- */
-struct libdecor_state *
-libdecor_state_new(int width,
- int height);
-
-/**
- * Free a content surface state.
- */
-void
-libdecor_state_free(struct libdecor_state *state);
-
-/**
- * Get the expected size of the content for this configuration.
- *
- * If the configuration doesn't contain a size, false is returned.
- */
-bool
-libdecor_configuration_get_content_size(struct libdecor_configuration *configuration,
- struct libdecor_frame *frame,
- int *width,
- int *height);
-
-/**
- * Get the window state for this configuration.
- *
- * If the configuration doesn't contain any associated window state, false is
- * returned, and the application should assume the window state remains
- * unchanged.
- */
-bool
-libdecor_configuration_get_window_state(struct libdecor_configuration *configuration,
- enum libdecor_window_state *window_state);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBDECOR_H */
diff --git a/libdecor/src/os-compatibility.c b/libdecor/src/os-compatibility.c
deleted file mode 100644
index 23766473d..000000000
--- a/libdecor/src/os-compatibility.c
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright © 2012 Collabora, Ltd.
- *
- * 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 <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <signal.h>
-#include <string.h>
-#include <stdlib.h>
-
-#ifdef HAVE_MEMFD_CREATE
-#include <sys/mman.h>
-#endif
-
-#include "os-compatibility.h"
-
-#ifndef HAVE_MKOSTEMP
-static int
-set_cloexec_or_close(int fd)
-{
- long flags;
-
- if (fd == -1)
- return -1;
-
- flags = fcntl(fd, F_GETFD);
- if (flags == -1)
- goto err;
-
- if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
- goto err;
-
- return fd;
-
-err:
- close(fd);
- return -1;
-}
-#endif
-
-static int
-create_tmpfile_cloexec(char *tmpname)
-{
- int fd;
-
-#ifdef HAVE_MKOSTEMP
- fd = mkostemp(tmpname, O_CLOEXEC);
- if (fd >= 0)
- unlink(tmpname);
-#else
- fd = mkstemp(tmpname);
- if (fd >= 0) {
- fd = set_cloexec_or_close(fd);
- unlink(tmpname);
- }
-#endif
-
- return fd;
-}
-
-static int
-os_resize_anonymous_file(int fd, off_t size)
-{
-#ifdef HAVE_POSIX_FALLOCATE
- sigset_t mask;
- sigset_t old_mask;
-
- /* posix_fallocate() might be interrupted, so we need to check
- * for EINTR and retry in that case.
- * However, in the presence of an alarm, the interrupt may trigger
- * repeatedly and prevent a large posix_fallocate() to ever complete
- * successfully, so we need to first block SIGALRM to prevent
- * this.
- */
- sigemptyset(&mask);
- sigaddset(&mask, SIGALRM);
- sigprocmask(SIG_BLOCK, &mask, &old_mask);
- /*
- * Filesystems that do not support fallocate will return EINVAL or
- * EOPNOTSUPP. In this case we need to fall back to ftruncate
- */
- do {
- errno = posix_fallocate(fd, 0, size);
- } while (errno == EINTR);
- sigprocmask(SIG_SETMASK, &old_mask, NULL);
- if (errno == 0)
- return 0;
- else if (errno != EINVAL && errno != EOPNOTSUPP)
- return -1;
-#endif
- if (ftruncate(fd, size) < 0)
- return -1;
-
- return 0;
-}
-
-/*
- * Create a new, unique, anonymous file of the given size, and
- * return the file descriptor for it. The file descriptor is set
- * CLOEXEC. The file is immediately suitable for mmap()'ing
- * the given size at offset zero.
- *
- * The file should not have a permanent backing store like a disk,
- * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
- *
- * The file name is deleted from the file system.
- *
- * The file is suitable for buffer sharing between processes by
- * transmitting the file descriptor over Unix sockets using the
- * SCM_RIGHTS methods.
- *
- * If the C library implements posix_fallocate(), it is used to
- * guarantee that disk space is available for the file at the
- * given size. If disk space is insufficient, errno is set to ENOSPC.
- * If posix_fallocate() is not supported, program may receive
- * SIGBUS on accessing mmap()'ed file contents instead.
- *
- * If the C library implements memfd_create(), it is used to create the
- * file purely in memory, without any backing file name on the file
- * system, and then sealing off the possibility of shrinking it. This
- * can then be checked before accessing mmap()'ed file contents, to
- * make sure SIGBUS can't happen. It also avoids requiring
- * XDG_RUNTIME_DIR.
- */
-int
-libdecor_os_create_anonymous_file(off_t size)
-{
- static const char template[] = "/libdecor-shared-XXXXXX";
- const char *path;
- char *name;
- int fd;
-
-#ifdef HAVE_MEMFD_CREATE
- fd = memfd_create("libdecor", MFD_CLOEXEC | MFD_ALLOW_SEALING);
- if (fd >= 0) {
- /* We can add this seal before calling posix_fallocate(), as
- * the file is currently zero-sized anyway.
- *
- * There is also no need to check for the return value, we
- * couldn't do anything with it anyway.
- */
- fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
- } else
-#endif
- {
- path = getenv("XDG_RUNTIME_DIR");
- if (!path) {
- errno = ENOENT;
- return -1;
- }
-
- name = malloc(strlen(path) + sizeof(template));
- if (!name)
- return -1;
-
- strcpy(name, path);
- strcat(name, template);
-
- fd = create_tmpfile_cloexec(name);
-
- free(name);
-
- if (fd < 0)
- return -1;
- }
-
- if (os_resize_anonymous_file(fd, size) < 0) {
- close(fd);
- return -1;
- }
-
- return fd;
-}
diff --git a/libdecor/src/os-compatibility.h b/libdecor/src/os-compatibility.h
deleted file mode 100644
index 6ce49d01c..000000000
--- a/libdecor/src/os-compatibility.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright © 2012 Collabora, Ltd.
- *
- * 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.
- */
-
-#ifndef OS_COMPATIBILITY_H
-#define OS_COMPATIBILITY_H
-
-#include <sys/types.h>
-
-int
-libdecor_os_create_anonymous_file(off_t size);
-
-#endif /* OS_COMPATIBILITY_H */
diff --git a/libdecor/src/plugins/cairo/libdecor-cairo.c b/libdecor/src/plugins/cairo/libdecor-cairo.c
deleted file mode 100644
index d8854bc8e..000000000
--- a/libdecor/src/plugins/cairo/libdecor-cairo.c
+++ /dev/null
@@ -1,2796 +0,0 @@
-/*
- * 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 <linux/input.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-#include <limits.h>
-#include <wayland-cursor.h>
-
-#include "libdecor-plugin.h"
-#include "utils.h"
-#include "desktop-settings.h"
-#include "os-compatibility.h"
-
-#include <cairo/cairo.h>
-#include <pango/pangocairo.h>
-
-#include "common/libdecor-cairo-blur.h"
-
-static const size_t SHADOW_MARGIN = 24; /* graspable part of the border */
-static const size_t TITLE_HEIGHT = 24;
-static const size_t BUTTON_WIDTH = 32;
-static const size_t SYM_DIM = 14;
-
-static const uint32_t COL_TITLE = 0xFF080706;
-static const uint32_t COL_TITLE_INACT = 0xFF303030;
-static const uint32_t COL_BUTTON_MIN = 0xFFFFBB00;
-static const uint32_t COL_BUTTON_MAX = 0xFF238823;
-static const uint32_t COL_BUTTON_CLOSE = 0xFFFB6542;
-static const uint32_t COL_BUTTON_INACT = 0xFF404040;
-static const uint32_t COL_SYM = 0xFFF4F4EF;
-static const uint32_t COL_SYM_ACT = 0xFF20322A;
-static const uint32_t COL_SYM_INACT = 0xFF909090;
-
-static const uint32_t DOUBLE_CLICK_TIME_MS = 400;
-
-static const char *cursor_names[] = {
- "top_side",
- "bottom_side",
- "left_side",
- "top_left_corner",
- "bottom_left_corner",
- "right_side",
- "top_right_corner",
- "bottom_right_corner"
-};
-
-
-/* color conversion function from 32bit integer to double components */
-
-double
-red(const uint32_t *const col) {
- return ((const uint8_t*)(col))[2] / (double)(255);
-}
-
-double
-green(const uint32_t *const col) {
- return ((const uint8_t*)(col))[1] / (double)(255);
-}
-
-double
-blue(const uint32_t *const col) {
- return ((const uint8_t*)(col))[0] / (double)(255);
-}
-
-double
-alpha(const uint32_t *const col) {
- return ((const uint8_t*)(col))[3] / (double)(255);
-}
-
-void
-cairo_set_rgba32(cairo_t *cr, const uint32_t *const c) {
- cairo_set_source_rgba(cr, red(c), green(c), blue(c), alpha(c));
-}
-
-static bool
-streql(const char *str1, const char *str2)
-{
- return (str1 && str2) && (strcmp(str1, str2) == 0);
-}
-
-enum decoration_type {
- DECORATION_TYPE_NONE,
- DECORATION_TYPE_ALL,
- DECORATION_TYPE_MAXIMIZED,
- DECORATION_TYPE_TILED
-};
-
-enum component {
- NONE = 0,
- SHADOW,
- TITLE,
- BUTTON_MIN,
- BUTTON_MAX,
- BUTTON_CLOSE,
-};
-
-enum composite_mode {
- COMPOSITE_SERVER,
- COMPOSITE_CLIENT,
-};
-
-struct seat {
- struct libdecor_plugin_cairo *plugin_cairo;
-
- char *name;
-
- struct wl_seat *wl_seat;
- struct wl_pointer *wl_pointer;
-
- struct wl_surface *cursor_surface;
- struct wl_cursor *current_cursor;
- int cursor_scale;
- struct wl_list cursor_outputs;
-
- struct wl_cursor_theme *cursor_theme;
- /* cursors for resize edges and corners */
- struct wl_cursor *cursors[ARRAY_LENGTH(cursor_names)];
- struct wl_cursor *cursor_left_ptr;
-
- struct wl_surface *pointer_focus;
- struct libdecor_frame_cairo *pointer_focus_frame;
-
- int pointer_x, pointer_y;
-
- uint32_t pointer_button_time_stamp;
-
- uint32_t serial;
-
- bool grabbed;
-
- struct wl_list link;
-};
-
-struct output {
- struct libdecor_plugin_cairo *plugin_cairo;
-
- struct wl_output *wl_output;
- uint32_t id;
- int scale;
-
- struct wl_list link;
-};
-
-struct buffer {
- struct wl_buffer *wl_buffer;
- bool in_use;
- bool is_detached;
-
- void *data;
- size_t data_size;
- int width;
- int height;
- int scale;
- int buffer_width;
- int buffer_height;
-};
-
-struct border_component {
- enum component type;
-
- bool is_hidden;
- bool opaque;
-
- enum composite_mode composite_mode;
- struct {
- struct wl_surface *wl_surface;
- struct wl_subsurface *wl_subsurface;
- struct buffer *buffer;
- struct wl_list output_list;
- int scale;
- } server;
- struct {
- cairo_surface_t *image;
- struct border_component *parent_component;
- } client;
-
- struct wl_list child_components; /* border_component::link */
- struct wl_list link; /* border_component::child_components */
-};
-
-struct surface_output {
- struct output *output;
- struct wl_list link;
-};
-
-struct cursor_output {
- struct output *output;
- struct wl_list link;
-};
-
-struct libdecor_frame_cairo {
- struct libdecor_frame frame;
-
- struct libdecor_plugin_cairo *plugin_cairo;
-
- int content_width;
- int content_height;
-
- enum decoration_type decoration_type;
-
- enum libdecor_window_state window_state;
-
- char *title;
-
- enum libdecor_capabilities capabilities;
-
- struct border_component *focus;
- struct border_component *active;
- struct border_component *grab;
-
- bool shadow_showing;
- struct border_component shadow;
-
- struct {
- bool is_showing;
- struct border_component title;
- struct border_component min;
- struct border_component max;
- struct border_component close;
- } title_bar;
-
- /* store pre-processed shadow tile */
- cairo_surface_t *shadow_blur;
-
- struct wl_list link;
-};
-
-struct libdecor_plugin_cairo {
- struct libdecor_plugin plugin;
-
- struct wl_callback *globals_callback;
- struct wl_callback *globals_callback_shm;
-
- struct libdecor *context;
-
- struct wl_registry *wl_registry;
- struct wl_subcompositor *wl_subcompositor;
- struct wl_compositor *wl_compositor;
-
- struct wl_shm *wl_shm;
- struct wl_callback *shm_callback;
- bool has_argb;
-
- struct wl_list visible_frame_list;
- struct wl_list seat_list;
- struct wl_list output_list;
-
- char *cursor_theme_name;
- int cursor_size;
-
- PangoFontDescription *font;
-
- bool handle_cursor;
-};
-
-static const char *libdecor_cairo_proxy_tag = "libdecor-cairo";
-
-static void
-sync_active_component(struct libdecor_frame_cairo *frame_cairo,
- struct seat *seat);
-
-static void
-synthesize_pointer_enter(struct seat *seat);
-
-static void
-synthesize_pointer_leave(struct seat *seat);
-
-static bool
-own_proxy(struct wl_proxy *proxy)
-{
- if (!proxy)
- return false;
-
- return (wl_proxy_get_tag(proxy) == &libdecor_cairo_proxy_tag);
-}
-
-static bool
-own_surface(struct wl_surface *surface)
-{
- return own_proxy((struct wl_proxy *) surface);
-}
-
-static bool
-own_output(struct wl_output *output)
-{
- return own_proxy((struct wl_proxy *) output);
-}
-
-static bool
-moveable(struct libdecor_frame_cairo *frame_cairo) {
- return libdecor_frame_has_capability(&frame_cairo->frame,
- LIBDECOR_ACTION_MOVE);
-}
-
-static bool
-resizable(struct libdecor_frame_cairo *frame_cairo) {
- return libdecor_frame_has_capability(&frame_cairo->frame,
- LIBDECOR_ACTION_RESIZE);
-}
-
-static bool
-minimizable(struct libdecor_frame_cairo *frame_cairo) {
- return libdecor_frame_has_capability(&frame_cairo->frame,
- LIBDECOR_ACTION_MINIMIZE);
-}
-
-static bool
-closeable(struct libdecor_frame_cairo *frame_cairo) {
- return libdecor_frame_has_capability(&frame_cairo->frame,
- LIBDECOR_ACTION_CLOSE);
-}
-
-static void
-buffer_free(struct buffer *buffer);
-
-static void
-draw_border_component(struct libdecor_frame_cairo *frame_cairo,
- struct border_component *border_component);
-
-static void
-send_cursor(struct seat *seat);
-
-static bool
-update_local_cursor(struct seat *seat);
-
-static void
-libdecor_plugin_cairo_destroy(struct libdecor_plugin *plugin)
-{
- struct libdecor_plugin_cairo *plugin_cairo =
- (struct libdecor_plugin_cairo *) plugin;
- struct seat *seat, *seat_tmp;
- struct output *output, *output_tmp;
- struct libdecor_frame_cairo *frame, *frame_tmp;
-
- if (plugin_cairo->globals_callback)
- wl_callback_destroy(plugin_cairo->globals_callback);
- if (plugin_cairo->globals_callback_shm)
- wl_callback_destroy(plugin_cairo->globals_callback_shm);
- if (plugin_cairo->shm_callback)
- wl_callback_destroy(plugin_cairo->shm_callback);
- wl_registry_destroy(plugin_cairo->wl_registry);
-
- wl_list_for_each_safe(seat, seat_tmp, &plugin_cairo->seat_list, link) {
- struct cursor_output *cursor_output, *tmp;
-
- if (seat->wl_pointer)
- wl_pointer_destroy(seat->wl_pointer);
- if (seat->cursor_surface)
- wl_surface_destroy(seat->cursor_surface);
- wl_seat_destroy(seat->wl_seat);
- if (seat->cursor_theme)
- wl_cursor_theme_destroy(seat->cursor_theme);
-
- wl_list_for_each_safe(cursor_output, tmp, &seat->cursor_outputs, link) {
- wl_list_remove(&cursor_output->link);
- free(cursor_output);
- }
- free(seat->name);
-
- free(seat);
- }
-
- wl_list_for_each_safe(output, output_tmp,
- &plugin_cairo->output_list, link) {
- if (wl_output_get_version (output->wl_output) >=
- WL_OUTPUT_RELEASE_SINCE_VERSION)
- wl_output_release(output->wl_output);
- else
- wl_output_destroy(output->wl_output);
- free(output);
- }
-
- wl_list_for_each_safe(frame, frame_tmp,
- &plugin_cairo->visible_frame_list, link) {
- wl_list_remove(&frame->link);
- }
-
- free(plugin_cairo->cursor_theme_name);
-
- if (plugin_cairo->wl_shm)
- wl_shm_destroy(plugin_cairo->wl_shm);
-
- pango_font_description_free(plugin_cairo->font);
-
- if (plugin_cairo->wl_compositor)
- wl_compositor_destroy(plugin_cairo->wl_compositor);
- if (plugin_cairo->wl_subcompositor)
- wl_subcompositor_destroy(plugin_cairo->wl_subcompositor);
-
- libdecor_plugin_release(&plugin_cairo->plugin);
- free(plugin_cairo);
-}
-
-static void
-init_server_component(struct border_component *border_component,
- enum component type)
-{
- border_component->composite_mode = COMPOSITE_SERVER;
- wl_list_init(&border_component->child_components);
- border_component->type = type;
-}
-
-static void
-init_client_component(struct border_component *border_component,
- struct border_component *parent,
- enum component type)
-{
- border_component->composite_mode = COMPOSITE_CLIENT;
- wl_list_init(&border_component->child_components);
- wl_list_insert(parent->child_components.prev, &border_component->link);
- border_component->client.parent_component = parent;
- border_component->type = type;
-}
-
-static void
-init_components(struct libdecor_frame_cairo *frame_cairo)
-{
- init_server_component(&frame_cairo->title_bar.title,
- TITLE);
- init_client_component(&frame_cairo->title_bar.min,
- &frame_cairo->title_bar.title,
- BUTTON_MIN);
- init_client_component(&frame_cairo->title_bar.max,
- &frame_cairo->title_bar.title,
- BUTTON_MAX);
- init_client_component(&frame_cairo->title_bar.close,
- &frame_cairo->title_bar.title,
- BUTTON_CLOSE);
- init_server_component(&frame_cairo->shadow,
- SHADOW);
-}
-
-static struct libdecor_frame_cairo *
-libdecor_frame_cairo_new(struct libdecor_plugin_cairo *plugin_cairo)
-{
- struct libdecor_frame_cairo *frame_cairo = zalloc(sizeof *frame_cairo);
- cairo_t *cr;
-
- static const int size = 128;
- static const int boundary = 32;
-
- frame_cairo->plugin_cairo = plugin_cairo;
- frame_cairo->shadow_blur = cairo_image_surface_create(
- CAIRO_FORMAT_ARGB32, size, size);
- wl_list_insert(&plugin_cairo->visible_frame_list, &frame_cairo->link);
-
- init_components(frame_cairo);
-
- cr = cairo_create(frame_cairo->shadow_blur);
- cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
- cairo_set_source_rgba(cr, 0, 0, 0, 1);
- cairo_rectangle(cr, boundary, boundary, size-2*boundary, size-2*boundary);
- cairo_fill(cr);
- cairo_destroy(cr);
- blur_surface(frame_cairo->shadow_blur, 64);
-
- return frame_cairo;
-}
-
-static int
-libdecor_plugin_cairo_get_fd(struct libdecor_plugin *plugin)
-{
- struct libdecor_plugin_cairo *plugin_cairo =
- (struct libdecor_plugin_cairo *) plugin;
- struct wl_display *wl_display =
- libdecor_get_wl_display(plugin_cairo->context);
-
- return wl_display_get_fd(wl_display);
-}
-
-static int
-libdecor_plugin_cairo_dispatch(struct libdecor_plugin *plugin,
- int timeout)
-{
- struct libdecor_plugin_cairo *plugin_cairo =
- (struct libdecor_plugin_cairo *) plugin;
- struct wl_display *wl_display =
- libdecor_get_wl_display(plugin_cairo->context);
- struct pollfd fds[1];
- int ret;
- int dispatch_count = 0;
-
- while (wl_display_prepare_read(wl_display) != 0)
- dispatch_count += wl_display_dispatch_pending(wl_display);
-
- if (wl_display_flush(wl_display) < 0 &&
- errno != EAGAIN) {
- wl_display_cancel_read(wl_display);
- return -errno;
- }
-
- fds[0] = (struct pollfd) { wl_display_get_fd(wl_display), POLLIN };
-
- ret = poll(fds, ARRAY_SIZE (fds), timeout);
- if (ret > 0) {
- if (fds[0].revents & POLLIN) {
- wl_display_read_events(wl_display);
- dispatch_count += wl_display_dispatch_pending(wl_display);
- return dispatch_count;
- } else {
- wl_display_cancel_read(wl_display);
- return dispatch_count;
- }
- } else if (ret == 0) {
- wl_display_cancel_read(wl_display);
- return dispatch_count;
- } else {
- wl_display_cancel_read(wl_display);
- return -errno;
- }
-}
-
-static void
-libdecor_plugin_cairo_set_handle_application_cursor(struct libdecor_plugin *plugin,
- bool handle_cursor)
-{
- struct libdecor_plugin_cairo *plugin_cairo =
- (struct libdecor_plugin_cairo *) plugin;
-
- plugin_cairo->handle_cursor = handle_cursor;
-}
-
-static struct libdecor_frame *
-libdecor_plugin_cairo_frame_new(struct libdecor_plugin *plugin)
-{
- struct libdecor_plugin_cairo *plugin_cairo =
- (struct libdecor_plugin_cairo *) plugin;
- struct libdecor_frame_cairo *frame_cairo;
-
- frame_cairo = libdecor_frame_cairo_new(plugin_cairo);
-
- return &frame_cairo->frame;
-}
-
-static void
-toggle_maximized(struct libdecor_frame *const frame)
-{
- if (!resizable((struct libdecor_frame_cairo *)frame))
- return;
-
- if (!(libdecor_frame_get_window_state(frame) &
- LIBDECOR_WINDOW_STATE_MAXIMIZED))
- libdecor_frame_set_maximized(frame);
- else
- libdecor_frame_unset_maximized(frame);
-}
-
-static void
-buffer_release(void *user_data,
- struct wl_buffer *wl_buffer)
-{
- struct buffer *buffer = user_data;
-
- if (buffer->is_detached)
- buffer_free(buffer);
- else
- buffer->in_use = false;
-}
-
-static const struct wl_buffer_listener buffer_listener = {
- buffer_release
-};
-
-static struct buffer *
-create_shm_buffer(struct libdecor_plugin_cairo *plugin_cairo,
- int width,
- int height,
- bool opaque,
- int scale)
-{
- struct wl_shm_pool *pool;
- int fd, size, buffer_width, buffer_height, stride;
- void *data;
- struct buffer *buffer;
- enum wl_shm_format buf_fmt;
-
- buffer_width = width * scale;
- buffer_height = height * scale;
- stride = buffer_width * 4;
- size = stride * buffer_height;
-
- fd = libdecor_os_create_anonymous_file(size);
- if (fd < 0) {
- fprintf(stderr, "creating a buffer file for %d B failed: %s\n",
- size, strerror(errno));
- return NULL;
- }
-
- data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if (data == MAP_FAILED) {
- fprintf(stderr, "mmap failed: %s\n", strerror(errno));
- close(fd);
- return NULL;
- }
-
- buf_fmt = opaque ? WL_SHM_FORMAT_XRGB8888 : WL_SHM_FORMAT_ARGB8888;
-
- pool = wl_shm_create_pool(plugin_cairo->wl_shm, fd, size);
- buffer = zalloc(sizeof *buffer);
- buffer->wl_buffer = wl_shm_pool_create_buffer(pool, 0,
- buffer_width, buffer_height,
- stride,
- buf_fmt);
- wl_buffer_add_listener(buffer->wl_buffer, &buffer_listener, buffer);
- wl_shm_pool_destroy(pool);
- close(fd);
-
- buffer->data = data;
- buffer->data_size = size;
- buffer->width = width;
- buffer->height = height;
- buffer->scale = scale;
- buffer->buffer_width = buffer_width;
- buffer->buffer_height = buffer_height;
-
- return buffer;
-}
-
-static void
-buffer_free(struct buffer *buffer)
-{
- if (buffer->wl_buffer) {
- wl_buffer_destroy(buffer->wl_buffer);
- munmap(buffer->data, buffer->data_size);
- buffer->wl_buffer = NULL;
- buffer->in_use = false;
- }
- free(buffer);
-}
-
-static void
-free_border_component(struct border_component *border_component)
-{
- struct surface_output *surface_output, *surface_output_tmp;
-
- if (border_component->server.wl_surface) {
- wl_subsurface_destroy(border_component->server.wl_subsurface);
- border_component->server.wl_subsurface = NULL;
- wl_surface_destroy(border_component->server.wl_surface);
- border_component->server.wl_surface = NULL;
- }
- if (border_component->server.buffer) {
- buffer_free(border_component->server.buffer);
- border_component->server.buffer = NULL;
- }
- if (border_component->client.image) {
- cairo_surface_destroy(border_component->client.image);
- border_component->client.image = NULL;
- }
- if (border_component->server.output_list.next != NULL) {
- wl_list_for_each_safe(surface_output, surface_output_tmp,
- &border_component->server.output_list, link) {
- wl_list_remove(&surface_output->link);
- free(surface_output);
- }
- }
-}
-
-static void
-libdecor_plugin_cairo_frame_free(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame)
-{
- struct libdecor_plugin_cairo *plugin_cairo =
- (struct libdecor_plugin_cairo *) plugin;
- struct libdecor_frame_cairo *frame_cairo =
- (struct libdecor_frame_cairo *) frame;
- struct seat *seat;
-
- wl_list_for_each(seat, &plugin_cairo->seat_list, link) {
- if (seat->pointer_focus) {
- if (wl_surface_get_user_data(seat->pointer_focus) == frame_cairo)
- seat->pointer_focus = NULL;
- if (seat->pointer_focus_frame == frame_cairo)
- seat->pointer_focus_frame = NULL;
- }
- }
-
- free_border_component(&frame_cairo->title_bar.title);
- free_border_component(&frame_cairo->title_bar.min);
- free_border_component(&frame_cairo->title_bar.max);
- free_border_component(&frame_cairo->title_bar.close);
- frame_cairo->title_bar.is_showing = false;
- free_border_component(&frame_cairo->shadow);
- frame_cairo->shadow_showing = false;
- if (frame_cairo->shadow_blur != NULL) {
- cairo_surface_destroy(frame_cairo->shadow_blur);
- frame_cairo->shadow_blur = NULL;
- }
-
- free(frame_cairo->title);
- frame_cairo->title = NULL;
-
- frame_cairo->decoration_type = DECORATION_TYPE_NONE;
-
- if (frame_cairo->link.next != NULL)
- wl_list_remove(&frame_cairo->link);
-}
-
-static bool
-is_border_surfaces_showing(struct libdecor_frame_cairo *frame_cairo)
-{
- return frame_cairo->shadow_showing;
-}
-
-static bool
-is_title_bar_surfaces_showing(struct libdecor_frame_cairo *frame_cairo)
-{
- return frame_cairo->title_bar.is_showing;
-}
-
-static struct border_component *
-get_server_component(struct border_component *border_component)
-{
- switch (border_component->composite_mode) {
- case COMPOSITE_SERVER:
- return border_component;
- case COMPOSITE_CLIENT:
- return get_server_component(border_component->client.parent_component);
- }
- return NULL;
-}
-
-static void
-redraw_border_component(struct libdecor_frame_cairo *frame_cairo,
- struct border_component *border_component)
-{
- struct border_component *server_component;
-
- server_component = get_server_component(border_component);
- draw_border_component(frame_cairo, server_component);
-}
-
-static void
-hide_border_component(struct libdecor_frame_cairo *frame_cairo,
- struct border_component *border_component)
-{
- border_component->is_hidden = true;
-
- switch (border_component->composite_mode) {
- case COMPOSITE_SERVER:
- if (!border_component->server.wl_surface)
- return;
-
- wl_surface_attach(border_component->server.wl_surface,
- NULL, 0, 0);
- wl_surface_commit(border_component->server.wl_surface);
- break;
- case COMPOSITE_CLIENT:
- redraw_border_component(frame_cairo, border_component);
- break;
- }
-}
-
-static void
-hide_border_surfaces(struct libdecor_frame_cairo *frame_cairo)
-{
- hide_border_component(frame_cairo, &frame_cairo->shadow);
- frame_cairo->shadow_showing = false;
-}
-
-static void
-hide_title_bar_surfaces(struct libdecor_frame_cairo *frame_cairo)
-{
- hide_border_component(frame_cairo, &frame_cairo->title_bar.title);
- hide_border_component(frame_cairo, &frame_cairo->title_bar.min);
- hide_border_component(frame_cairo, &frame_cairo->title_bar.max);
- hide_border_component(frame_cairo, &frame_cairo->title_bar.close);
- frame_cairo->title_bar.is_showing = false;
-}
-
-static struct border_component *
-get_component_for_surface(struct libdecor_frame_cairo *frame_cairo,
- struct wl_surface *surface)
-{
- if (frame_cairo->shadow.server.wl_surface == surface)
- return &frame_cairo->shadow;
- if (frame_cairo->title_bar.title.server.wl_surface == surface)
- return &frame_cairo->title_bar.title;
- return NULL;
-}
-
-static void
-calculate_component_size(struct libdecor_frame_cairo *frame_cairo,
- enum component component,
- int *component_x,
- int *component_y,
- int *component_width,
- int *component_height);
-
-static void
-update_component_focus(struct libdecor_frame_cairo *frame_cairo,
- struct wl_surface *surface,
- struct seat *seat)
-{
- static struct border_component *border_component;
- static struct border_component *child_component;
- static struct border_component *focus_component;
-
- border_component = get_component_for_surface(frame_cairo, surface);
- if (!border_component) {
- focus_component = NULL;
- goto out;
- }
-
- focus_component = border_component;
- wl_list_for_each(child_component, &border_component->child_components, link) {
- int component_x = 0, component_y = 0;
- int component_width = 0, component_height = 0;
-
- calculate_component_size(frame_cairo, child_component->type,
- &component_x, &component_y,
- &component_width, &component_height);
- if (seat->pointer_x >= component_x &&
- seat->pointer_x < component_x + component_width &&
- seat->pointer_y >= component_y &&
- seat->pointer_y < component_y + component_height) {
- focus_component = child_component;
- break;
- }
- }
-
-out:
- if (frame_cairo->grab)
- frame_cairo->active = frame_cairo->grab;
- else
- frame_cairo->active = focus_component;
- frame_cairo->focus = focus_component;
-
-}
-
-static void
-ensure_component(struct libdecor_frame_cairo *frame_cairo,
- struct border_component *cmpnt);
-
-static bool
-redraw_scale(struct libdecor_frame_cairo *frame_cairo,
- struct border_component *cmpnt)
-{
- struct surface_output *surface_output;
- int scale = 1;
-
- if (cmpnt->is_hidden)
- return false;
-
- ensure_component(frame_cairo, cmpnt);
-
- wl_list_for_each(surface_output, &cmpnt->server.output_list, link) {
- scale = MAX(scale, surface_output->output->scale);
- }
- if (scale != cmpnt->server.scale) {
- cmpnt->server.scale = scale;
- if ((cmpnt->type != SHADOW) || is_border_surfaces_showing(frame_cairo)) {
- draw_border_component(frame_cairo, cmpnt);
- return true;
- }
- }
- return false;
-}
-
-static bool
-add_surface_output(struct libdecor_plugin_cairo *plugin_cairo,
- struct wl_output *wl_output,
- struct wl_list *list)
-{
- struct output *output;
- struct surface_output *surface_output;
-
- if (!own_output(wl_output))
- return false;
-
- output = wl_output_get_user_data(wl_output);
-
- if (output == NULL)
- return false;
-
- surface_output = zalloc(sizeof *surface_output);
- surface_output->output = output;
- wl_list_insert(list, &surface_output->link);
- return true;
-}
-
-static void
-surface_enter(void *data,
- struct wl_surface *wl_surface,
- struct wl_output *wl_output)
-{
- struct libdecor_frame_cairo *frame_cairo = data;
- struct border_component *cmpnt;
-
- if (!(own_surface(wl_surface) && own_output(wl_output)))
- return;
-
- cmpnt = get_component_for_surface(frame_cairo, wl_surface);
- if (cmpnt == NULL)
- return;
-
- if (!add_surface_output(frame_cairo->plugin_cairo, wl_output,
- &cmpnt->server.output_list))
- return;
-
- if (redraw_scale(frame_cairo, cmpnt))
- libdecor_frame_toplevel_commit(&frame_cairo->frame);
-}
-
-static bool
-remove_surface_output(struct wl_list *list, struct wl_output *wl_output)
-{
- struct surface_output *surface_output;
- wl_list_for_each(surface_output, list, link) {
- if (surface_output->output->wl_output == wl_output) {
- wl_list_remove(&surface_output->link);
- free(surface_output);
- return true;
- }
- }
- return false;
-}
-
-static void
-surface_leave(void *data,
- struct wl_surface *wl_surface,
- struct wl_output *wl_output)
-{
- struct libdecor_frame_cairo *frame_cairo = data;
- struct border_component *cmpnt;
-
- if (!(own_surface(wl_surface) && own_output(wl_output)))
- return;
-
- cmpnt = get_component_for_surface(frame_cairo, wl_surface);
- if (cmpnt == NULL)
- return;
-
- if (!remove_surface_output(&cmpnt->server.output_list, wl_output))
- return;
-
- if (redraw_scale(frame_cairo, cmpnt))
- libdecor_frame_toplevel_commit(&frame_cairo->frame);
-}
-
-static struct wl_surface_listener surface_listener = {
- surface_enter,
- surface_leave,
-};
-
-static void
-create_surface_subsurface_pair(struct libdecor_frame_cairo *frame_cairo,
- struct wl_surface **out_wl_surface,
- struct wl_subsurface **out_wl_subsurface)
-{
- struct libdecor_plugin_cairo *plugin_cairo = frame_cairo->plugin_cairo;
- struct libdecor_frame *frame = &frame_cairo->frame;
- struct wl_compositor *wl_compositor = plugin_cairo->wl_compositor;
- struct wl_subcompositor *wl_subcompositor = plugin_cairo->wl_subcompositor;
- struct wl_surface *wl_surface;
- struct wl_surface *parent;
- struct wl_subsurface *wl_subsurface;
-
- wl_surface = wl_compositor_create_surface(wl_compositor);
- wl_proxy_set_tag((struct wl_proxy *) wl_surface,
- &libdecor_cairo_proxy_tag);
-
- parent = libdecor_frame_get_wl_surface(frame);
- wl_subsurface = wl_subcompositor_get_subsurface(wl_subcompositor,
- wl_surface,
- parent);
-
- *out_wl_surface = wl_surface;
- *out_wl_subsurface = wl_subsurface;
-}
-
-static void
-ensure_component(struct libdecor_frame_cairo *frame_cairo,
- struct border_component *cmpnt)
-{
- switch (cmpnt->composite_mode) {
- case COMPOSITE_SERVER:
- if (!cmpnt->server.wl_surface) {
- wl_list_init(&cmpnt->server.output_list);
- cmpnt->server.scale = 1;
- create_surface_subsurface_pair(frame_cairo,
- &cmpnt->server.wl_surface,
- &cmpnt->server.wl_subsurface);
- wl_surface_add_listener(cmpnt->server.wl_surface,
- &surface_listener,
- frame_cairo);
- }
- break;
- case COMPOSITE_CLIENT:
- wl_list_init(&cmpnt->server.output_list);
- break;
- }
-
- cmpnt->is_hidden = false;
-}
-
-static void
-ensure_border_surfaces(struct libdecor_frame_cairo *frame_cairo)
-{
- int min_width, min_height, current_max_w, current_max_h;
-
- frame_cairo->shadow.opaque = false;
- ensure_component(frame_cairo, &frame_cairo->shadow);
-
- libdecor_frame_get_min_content_size(&frame_cairo->frame,
- &min_width, &min_height);
- min_width = MAX(min_width, (int)MAX(56, 4 * BUTTON_WIDTH));
- min_height = MAX(min_height, (int)MAX(56, TITLE_HEIGHT + 1));
- libdecor_frame_set_min_content_size(&frame_cairo->frame, min_width, min_height);
- libdecor_frame_get_max_content_size(&frame_cairo->frame, &current_max_w,
- &current_max_h);
- if (current_max_w && current_max_w < min_width) current_max_w = min_width;
- if (current_max_h && current_max_h < min_height) current_max_h = min_height;
- libdecor_frame_set_max_content_size(&frame_cairo->frame, current_max_w,
- current_max_h);
-}
-
-
-static void
-ensure_title_bar_surfaces(struct libdecor_frame_cairo *frame_cairo)
-{
- frame_cairo->title_bar.title.opaque = true;
- ensure_component(frame_cairo, &frame_cairo->title_bar.title);
-
- frame_cairo->title_bar.min.opaque = true;
- ensure_component(frame_cairo, &frame_cairo->title_bar.min);
-
- frame_cairo->title_bar.max.opaque = true;
- ensure_component(frame_cairo, &frame_cairo->title_bar.max);
-
- frame_cairo->title_bar.close.opaque = true;
- ensure_component(frame_cairo, &frame_cairo->title_bar.close);
-}
-
-static void
-calculate_component_size(struct libdecor_frame_cairo *frame_cairo,
- enum component component,
- int *component_x,
- int *component_y,
- int *component_width,
- int *component_height)
-{
- struct libdecor_frame *frame = &frame_cairo->frame;
- int content_width, content_height;
-
- content_width = libdecor_frame_get_content_width(frame);
- content_height = libdecor_frame_get_content_height(frame);
-
- switch (component) {
- case NONE:
- *component_width = 0;
- *component_height = 0;
- return;
- case SHADOW:
- *component_x = -(int)SHADOW_MARGIN;
- *component_y = -(int)(SHADOW_MARGIN+TITLE_HEIGHT);
- *component_width = content_width + 2 * SHADOW_MARGIN;
- *component_height = content_height
- + 2 * SHADOW_MARGIN
- + TITLE_HEIGHT;
- return;
- case TITLE:
- *component_x = 0;
- *component_y = -(int)TITLE_HEIGHT;
- *component_width = content_width;
- *component_height = TITLE_HEIGHT;
- return;
- case BUTTON_MIN:
- *component_x = content_width - 3 * BUTTON_WIDTH;
- *component_y = 0;
- *component_width = BUTTON_WIDTH;
- *component_height = TITLE_HEIGHT;
- return;
- case BUTTON_MAX:
- *component_x = content_width - 2 * BUTTON_WIDTH;
- *component_y = 0;
- *component_width = BUTTON_WIDTH;
- *component_height = TITLE_HEIGHT;
- return;
- case BUTTON_CLOSE:
- *component_x = content_width - BUTTON_WIDTH;
- *component_y = 0;
- *component_width = BUTTON_WIDTH;
- *component_height = TITLE_HEIGHT;
- return;
- }
-
- abort();
-}
-
-static int
-border_component_get_scale(struct border_component *border_component)
-{
- switch (border_component->composite_mode) {
- case COMPOSITE_SERVER:
- return border_component->server.scale;
- case COMPOSITE_CLIENT:
- return border_component_get_scale(
- border_component->client.parent_component);
- }
- return 0;
-}
-
-static void
-draw_title_text(struct libdecor_frame_cairo *frame_cairo,
- cairo_t *cr,
- const int *title_width,
- bool active)
-{
- const uint32_t col_title = active ? COL_TITLE : COL_TITLE_INACT;
- const uint32_t col_title_text = active ? COL_SYM : COL_SYM_INACT;
-
- PangoLayout *layout;
-
- /* title fade out at buttons */
- const int fade_width = 5 * BUTTON_WIDTH;
- int fade_start;
- cairo_pattern_t *fade;
-
- /* text position and dimensions */
- int text_extents_width, text_extents_height;
- double text_x, text_y;
- double text_width, text_height;
-
- const char *title;
-
- title = libdecor_frame_get_title((struct libdecor_frame*) frame_cairo);
- if (!title)
- return;
-
- layout = pango_cairo_create_layout(cr);
-
- pango_layout_set_text(layout,
- title,
- -1);
- pango_layout_set_font_description(layout, frame_cairo->plugin_cairo->font);
- pango_layout_get_size(layout, &text_extents_width, &text_extents_height);
-
- /* set text position and dimensions */
- text_width = text_extents_width / PANGO_SCALE;
- text_height = text_extents_height / PANGO_SCALE;
- text_x = *title_width / 2.0 - text_width / 2.0;
- text_x += MIN(0.0, ((*title_width - fade_width) - (text_x + text_width)));
- text_x = MAX(text_x, BUTTON_WIDTH);
- text_y = TITLE_HEIGHT / 2.0 - text_height / 2.0;
-
- /* draw title text */
- cairo_move_to(cr, text_x, text_y);
- cairo_set_rgba32(cr, &col_title_text);
- pango_cairo_show_layout(cr, layout);
-
- /* draw fade-out from title text to buttons */
- fade_start = *title_width - fade_width;
- fade = cairo_pattern_create_linear(fade_start, 0,
- fade_start + 2 * BUTTON_WIDTH, 0);
- cairo_pattern_add_color_stop_rgba(fade, 0,
- red(&col_title),
- green(&col_title),
- blue(&col_title),
- 0);
- cairo_pattern_add_color_stop_rgb(fade, 1,
- red(&col_title),
- green(&col_title),
- blue(&col_title));
- cairo_rectangle(cr, fade_start, 0, fade_width, TITLE_HEIGHT);
- cairo_set_source(cr, fade);
- cairo_fill(cr);
-
- cairo_pattern_destroy(fade);
- g_object_unref(layout);
-}
-
-static void
-draw_component_content(struct libdecor_frame_cairo *frame_cairo,
- struct border_component *border_component,
- int component_width,
- int component_height,
- enum component component)
-{
- struct buffer *buffer;
- cairo_surface_t *surface = NULL;
- int width = 0, height = 0;
- int scale;
- cairo_t *cr;
-
- /* button symbol origin */
- const double x = BUTTON_WIDTH / 2 - SYM_DIM / 2 + 0.5;
- const double y = TITLE_HEIGHT / 2 - SYM_DIM / 2 + 0.5;
-
- enum libdecor_window_state state;
-
- bool active;
-
- uint32_t col_title;
-
- bool cap_min, cap_max, cap_close;
-
- /* capabilities of decorations */
- cap_min = minimizable(frame_cairo);
- cap_max = resizable(frame_cairo);
- cap_close = closeable(frame_cairo);
-
- scale = border_component_get_scale(border_component);
-
- state = libdecor_frame_get_window_state((struct libdecor_frame *) frame_cairo);
-
- active = state & LIBDECOR_WINDOW_STATE_ACTIVE;
-
- col_title = active ? COL_TITLE : COL_TITLE_INACT;
-
- /* clear buffer */
- switch (border_component->composite_mode) {
- case COMPOSITE_SERVER:
- buffer = border_component->server.buffer;
-
- surface = cairo_image_surface_create_for_data(
- buffer->data, CAIRO_FORMAT_ARGB32,
- buffer->buffer_width, buffer->buffer_height,
- cairo_format_stride_for_width(
- CAIRO_FORMAT_ARGB32,
- buffer->buffer_width)
- );
- cairo_surface_set_device_scale(surface, scale, scale);
- width = buffer->width;
- height = buffer->height;
- break;
- case COMPOSITE_CLIENT:
- surface = cairo_surface_reference(border_component->client.image);
- width = cairo_image_surface_get_width(surface);
- height = cairo_image_surface_get_height(surface);
- break;
- }
-
- cr = cairo_create(surface);
- cairo_save(cr);
- cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
- cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
- cairo_paint(cr);
- cairo_restore(cr);
-
- /* background */
- switch (component) {
- case NONE:
- break;
- case SHADOW:
- if (frame_cairo->decoration_type != DECORATION_TYPE_TILED)
- render_shadow(cr,
- frame_cairo->shadow_blur,
- -(int)SHADOW_MARGIN/2,
- -(int)SHADOW_MARGIN/2,
- width + SHADOW_MARGIN,
- height + SHADOW_MARGIN,
- 64,
- 64);
- break;
- case TITLE:
- cairo_set_rgba32(cr, &col_title);
- cairo_paint(cr);
- break;
- case BUTTON_MIN:
- if (cap_min && frame_cairo->active == &frame_cairo->title_bar.min)
- cairo_set_rgba32(cr, active ? &COL_BUTTON_MIN : &COL_BUTTON_INACT);
- else
- cairo_set_rgba32(cr, &col_title);
- cairo_paint(cr);
- break;
- case BUTTON_MAX:
- if (cap_max && frame_cairo->active == &frame_cairo->title_bar.max)
- cairo_set_rgba32(cr, active ? &COL_BUTTON_MAX : &COL_BUTTON_INACT);
- else
- cairo_set_rgba32(cr, &col_title);
- cairo_paint(cr);
- break;
- case BUTTON_CLOSE:
- if (cap_close && frame_cairo->active == &frame_cairo->title_bar.close)
- cairo_set_rgba32(cr, active ? &COL_BUTTON_CLOSE : &COL_BUTTON_INACT);
- else
- cairo_set_rgba32(cr, &col_title);
- cairo_paint(cr);
- break;
- }
-
- /* button symbols */
- /* https://www.cairographics.org/FAQ/#sharp_lines */
- cairo_set_line_width(cr, 1);
-
- switch (component) {
- case TITLE:
- draw_title_text(frame_cairo,cr, &component_width, active);
- break;
- case BUTTON_MIN:
- if (!active) {
- /* inactive: use single desaturated color */
- cairo_set_rgba32(cr, &COL_SYM_INACT);
- } else {
- if (!cap_min ||
- frame_cairo->active == &frame_cairo->title_bar.min) {
- /* active (a.k.a. prelight) */
- cairo_set_rgba32(cr, &COL_SYM_ACT);
- } else {
- /* normal */
- cairo_set_rgba32(cr, &COL_SYM);
- }
- }
- cairo_move_to(cr, x, y + SYM_DIM - 1);
- cairo_rel_line_to(cr, SYM_DIM - 1, 0);
- cairo_stroke(cr);
- break;
- case BUTTON_MAX:
- if (!active) {
- /* inactive: use single desaturated color */
- cairo_set_rgba32(cr, &COL_SYM_INACT);
- } else {
- if (!cap_max ||
- frame_cairo->active == &frame_cairo->title_bar.max) {
- /* active (a.k.a. prelight) */
- cairo_set_rgba32(cr, &COL_SYM_ACT);
- } else {
- /* normal */
- cairo_set_rgba32(cr, &COL_SYM);
- }
- }
-
- if (state & LIBDECOR_WINDOW_STATE_MAXIMIZED) {
- const size_t small = 12;
- cairo_rectangle(cr,
- x,
- y + SYM_DIM - small,
- small - 1,
- small - 1);
- cairo_move_to(cr,
- x + SYM_DIM - small,
- y + SYM_DIM - small);
- cairo_line_to(cr, x + SYM_DIM - small, y);
- cairo_rel_line_to(cr, small - 1, 0);
- cairo_rel_line_to(cr, 0, small - 1);
- cairo_line_to(cr, x + small - 1, y + small - 1);
- } else {
- cairo_rectangle(cr, x, y, SYM_DIM - 1, SYM_DIM - 1);
- }
- cairo_stroke(cr);
- break;
- case BUTTON_CLOSE:
- if (!active) {
- /* inactive: use single desaturated color */
- cairo_set_rgba32(cr, &COL_SYM_INACT);
- } else {
- if (!cap_close ||
- frame_cairo->active == &frame_cairo->title_bar.close) {
- /* active (a.k.a. prelight) */
- cairo_set_rgba32(cr, &COL_SYM_ACT);
- } else {
- /* normal */
- cairo_set_rgba32(cr, &COL_SYM);
- }
- }
- cairo_move_to(cr, x, y);
- cairo_rel_line_to(cr, SYM_DIM - 1, SYM_DIM - 1);
- cairo_move_to(cr, x + SYM_DIM - 1, y);
- cairo_line_to(cr, x, y + SYM_DIM - 1);
- cairo_stroke(cr);
- break;
- default:
- break;
- }
-
- /* mask the toplevel surface */
- if (component == SHADOW) {
- int component_x, component_y, component_width, component_height;
- calculate_component_size(frame_cairo, component,
- &component_x, &component_y,
- &component_width, &component_height);
- cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
- cairo_rectangle(cr, -component_x, -component_y,
- libdecor_frame_get_content_width(
- &frame_cairo->frame),
- libdecor_frame_get_content_height(
- &frame_cairo->frame));
- cairo_fill(cr);
- }
-
- cairo_destroy(cr);
- cairo_surface_destroy(surface);
-}
-
-static void
-set_component_input_region(struct libdecor_frame_cairo *frame_cairo,
- struct border_component *border_component)
-{
- if (border_component->type == SHADOW && frame_cairo->shadow_showing) {
- struct wl_region *input_region;
- int component_x;
- int component_y;
- int component_width;
- int component_height;
-
- calculate_component_size(frame_cairo, border_component->type,
- &component_x, &component_y,
- &component_width, &component_height);
-
- /*
- * the input region is the outer surface size minus the inner
- * content size
- */
- input_region = wl_compositor_create_region(
- frame_cairo->plugin_cairo->wl_compositor);
- wl_region_add(input_region, 0, 0,
- component_width, component_height);
- wl_region_subtract(input_region, -component_x, -component_y,
- libdecor_frame_get_content_width(&frame_cairo->frame),
- libdecor_frame_get_content_height(&frame_cairo->frame));
- wl_surface_set_input_region(border_component->server.wl_surface,
- input_region);
- wl_region_destroy(input_region);
- }
-}
-
-static void
-ensure_component_realized_server(struct libdecor_frame_cairo *frame_cairo,
- struct border_component *border_component,
- int component_width,
- int component_height,
- int scale)
-{
- struct buffer *old_buffer;
- struct buffer *buffer = NULL;
-
- old_buffer = border_component->server.buffer;
- if (old_buffer) {
- if (!old_buffer->in_use &&
- old_buffer->buffer_width == component_width * scale &&
- old_buffer->buffer_height == component_height * scale) {
- buffer = old_buffer;
- } else {
- buffer_free(old_buffer);
- border_component->server.buffer = NULL;
- }
- }
-
- if (!buffer)
- buffer = create_shm_buffer(frame_cairo->plugin_cairo,
- component_width,
- component_height,
- border_component->opaque,
- border_component->server.scale);
-
- border_component->server.buffer = buffer;
-}
-
-static void
-ensure_component_realized_client(struct libdecor_frame_cairo *frame_cairo,
- struct border_component *border_component,
- int component_width,
- int component_height,
- int scale)
-{
- cairo_surface_t *old_image;
-
- old_image = border_component->client.image;
- if (old_image) {
- int cairo_buffer_width;
- int cairo_buffer_height;
- double x_scale;
- double y_scale;
-
- cairo_surface_get_device_scale(old_image, &x_scale, &y_scale);
- cairo_buffer_width =
- (int) round(cairo_image_surface_get_width(old_image) *
- x_scale);
- cairo_buffer_height =
- (int) round(cairo_image_surface_get_height(old_image) *
- y_scale);
-
- if (cairo_buffer_width != component_width * scale ||
- cairo_buffer_height != component_height * scale) {
- cairo_surface_destroy(old_image);
- border_component->client.image = NULL;
- }
- }
-
- if (!border_component->client.image) {
- cairo_surface_t *new_image;
-
- new_image =
- cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
- component_width * scale,
- component_height * scale);
- cairo_surface_set_device_scale(new_image, scale, scale);
- border_component->client.image = new_image;
- }
-
-}
-
-static void
-ensure_component_realized(struct libdecor_frame_cairo *frame_cairo,
- struct border_component *border_component,
- int component_width,
- int component_height,
- int scale)
-{
- switch (border_component->composite_mode) {
- case COMPOSITE_SERVER:
- ensure_component_realized_server(frame_cairo, border_component,
- component_width,
- component_height,
- scale);
- break;
- case COMPOSITE_CLIENT:
- ensure_component_realized_client(frame_cairo, border_component,
- component_width,
- component_height,
- scale);
- break;
- }
-}
-
-static cairo_t *
-create_cairo_for_parent(struct border_component *border_component)
-{
- struct border_component *parent =
- border_component->client.parent_component;
- struct buffer *buffer;
- struct border_component *server_component;
- cairo_surface_t *parent_surface;
- cairo_t *cr;
-
- switch (parent->composite_mode) {
- case COMPOSITE_SERVER:
- buffer = parent->server.buffer;
- parent_surface = cairo_image_surface_create_for_data(
- buffer->data, CAIRO_FORMAT_ARGB32,
- buffer->buffer_width, buffer->buffer_height,
- cairo_format_stride_for_width(
- CAIRO_FORMAT_ARGB32,
- buffer->buffer_width)
- );
- cr = cairo_create(parent_surface);
- cairo_surface_destroy(parent_surface);
- cairo_scale(cr, buffer->scale, buffer->scale);
- return cr;
- case COMPOSITE_CLIENT:
- cr = cairo_create(parent->client.image);
- server_component = get_server_component(border_component);
- cairo_scale(cr,
- server_component->server.scale,
- server_component->server.scale);
- return cr;
- }
- return NULL;
-}
-
-static void
-draw_border_component(struct libdecor_frame_cairo *frame_cairo,
- struct border_component *border_component)
-{
- enum component component = border_component->type;
- struct buffer *buffer;
- cairo_t *cr;
- int component_x;
- int component_y;
- int component_width;
- int component_height;
- int scale;
- struct border_component *child_component;
-
- if (border_component->is_hidden)
- return;
-
- calculate_component_size(frame_cairo, component,
- &component_x, &component_y,
- &component_width, &component_height);
-
- set_component_input_region(frame_cairo, border_component);
-
- scale = border_component_get_scale(border_component);
- ensure_component_realized(frame_cairo, border_component,
- component_width,
- component_height,
- scale);
-
- draw_component_content(frame_cairo,
- border_component,
- component_width, component_height,
- component);
-
- switch(border_component->composite_mode) {
- case COMPOSITE_SERVER:
- buffer = border_component->server.buffer;
- wl_surface_attach(border_component->server.wl_surface,
- buffer->wl_buffer,
- 0, 0);
- wl_surface_set_buffer_scale(border_component->server.wl_surface,
- buffer->scale);
- buffer->in_use = true;
- wl_surface_commit(border_component->server.wl_surface);
- wl_surface_damage_buffer(border_component->server.wl_surface, 0, 0,
- component_width * scale,
- component_height * scale);
- wl_subsurface_set_position(border_component->server.wl_subsurface,
- component_x, component_y);
- break;
- case COMPOSITE_CLIENT:
- cr = create_cairo_for_parent(border_component);
- cairo_set_source_surface(cr,
- border_component->client.image,
- component_x, component_y);
- cairo_paint(cr);
- cairo_destroy(cr);
- break;
- }
-
- wl_list_for_each(child_component, &border_component->child_components, link)
- draw_border_component(frame_cairo, child_component);
-}
-
-static void
-draw_border(struct libdecor_frame_cairo *frame_cairo)
-{
- draw_border_component(frame_cairo, &frame_cairo->shadow);
- frame_cairo->shadow_showing = true;
-}
-
-static void
-draw_title_bar(struct libdecor_frame_cairo *frame_cairo)
-{
- draw_border_component(frame_cairo, &frame_cairo->title_bar.title);
- frame_cairo->title_bar.is_showing = true;
-}
-
-static void
-draw_decoration(struct libdecor_frame_cairo *frame_cairo)
-{
- switch (frame_cairo->decoration_type) {
- case DECORATION_TYPE_NONE:
- if (frame_cairo->link.next != NULL)
- wl_list_remove(&frame_cairo->link);
- if (is_border_surfaces_showing(frame_cairo))
- hide_border_surfaces(frame_cairo);
- if (is_title_bar_surfaces_showing(frame_cairo))
- hide_title_bar_surfaces(frame_cairo);
- break;
- case DECORATION_TYPE_TILED:
- case DECORATION_TYPE_ALL:
- /* show borders */
- ensure_border_surfaces(frame_cairo);
- draw_border(frame_cairo);
- /* show title bar */
- ensure_title_bar_surfaces(frame_cairo);
- draw_title_bar(frame_cairo);
- /* link frame */
- if (frame_cairo->link.next == NULL)
- wl_list_insert(
- &frame_cairo->plugin_cairo->visible_frame_list,
- &frame_cairo->link);
- break;
- case DECORATION_TYPE_MAXIMIZED:
- /* hide borders */
- if (is_border_surfaces_showing(frame_cairo))
- hide_border_surfaces(frame_cairo);
- /* show title bar */
- ensure_title_bar_surfaces(frame_cairo);
- draw_title_bar(frame_cairo);
- /* link frame */
- if (frame_cairo->link.next == NULL)
- wl_list_insert(
- &frame_cairo->plugin_cairo->visible_frame_list,
- &frame_cairo->link);
- break;
- }
-}
-
-static enum decoration_type
-window_state_to_decoration_type(enum libdecor_window_state window_state)
-{
- if (window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN)
- return DECORATION_TYPE_NONE;
- else if (window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED)
- /* title bar, no shadows */
- return DECORATION_TYPE_MAXIMIZED;
- else if (window_state & LIBDECOR_WINDOW_STATE_TILED_LEFT ||
- window_state & LIBDECOR_WINDOW_STATE_TILED_RIGHT ||
- window_state & LIBDECOR_WINDOW_STATE_TILED_TOP ||
- window_state & LIBDECOR_WINDOW_STATE_TILED_BOTTOM)
- /* title bar, invisible shadows */
- return DECORATION_TYPE_TILED;
- else
- /* title bar, shadows */
- return DECORATION_TYPE_ALL;
-}
-
-static void
-libdecor_plugin_cairo_frame_commit(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame,
- struct libdecor_state *state,
- struct libdecor_configuration *configuration)
-{
- struct libdecor_frame_cairo *frame_cairo =
- (struct libdecor_frame_cairo *) frame;
- enum libdecor_window_state old_window_state;
- enum libdecor_window_state new_window_state;
- int old_content_width, old_content_height;
- int new_content_width, new_content_height;
- enum decoration_type old_decoration_type;
- enum decoration_type new_decoration_type;
-
- old_window_state = frame_cairo->window_state;
- new_window_state = libdecor_frame_get_window_state(frame);
-
- old_content_width = frame_cairo->content_width;
- old_content_height = frame_cairo->content_height;
- new_content_width = libdecor_frame_get_content_width(frame);
- new_content_height = libdecor_frame_get_content_height(frame);
-
- old_decoration_type = frame_cairo->decoration_type;
- new_decoration_type = window_state_to_decoration_type(new_window_state);
-
- if (old_decoration_type == new_decoration_type &&
- old_content_width == new_content_width &&
- old_content_height == new_content_height &&
- old_window_state == new_window_state)
- return;
-
- frame_cairo->content_width = new_content_width;
- frame_cairo->content_height = new_content_height;
- frame_cairo->decoration_type = new_decoration_type;
- frame_cairo->window_state = new_window_state;
-
- draw_decoration(frame_cairo);
-}
-
-static void
-libdecor_plugin_cairo_frame_property_changed(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame)
-{
- struct libdecor_frame_cairo *frame_cairo =
- (struct libdecor_frame_cairo *) frame;
- bool redraw_needed = false;
- const char *new_title;
-
- new_title = libdecor_frame_get_title(frame);
- if (frame_cairo->title_bar.is_showing) {
- if (!streql(frame_cairo->title, new_title))
- redraw_needed = true;
- }
-
- if (frame_cairo->title) {
- free(frame_cairo->title);
- frame_cairo->title = NULL;
- }
-
- if (new_title) {
- frame_cairo->title = strdup(new_title);
- }
-
- if (frame_cairo->capabilities != libdecor_frame_get_capabilities(frame)) {
- frame_cairo->capabilities = libdecor_frame_get_capabilities(frame);
- redraw_needed = true;
- }
-
- if (redraw_needed) {
- draw_decoration(frame_cairo);
- libdecor_frame_toplevel_commit(frame);
- }
-}
-
-static bool
-streq(const char *str1,
- const char *str2)
-{
- if (!str1 && !str2)
- return true;
-
- if (str1 && str2)
- return strcmp(str1, str2) == 0;
-
- return false;
-}
-
-static void
-libdecor_plugin_cairo_frame_popup_grab(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame,
- const char *seat_name)
-{
- struct libdecor_frame_cairo *frame_cairo =
- (struct libdecor_frame_cairo *) frame;
- struct libdecor_plugin_cairo *plugin_cairo = frame_cairo->plugin_cairo;
- struct seat *seat;
-
- wl_list_for_each(seat, &plugin_cairo->seat_list, link) {
- if (streq(seat->name, seat_name)) {
- if (seat->grabbed) {
- fprintf(stderr, "libdecor-WARNING: Application "
- "tried to grab seat twice\n");
- }
- synthesize_pointer_leave(seat);
- seat->grabbed = true;
- return;
- }
- }
-
- fprintf(stderr,
- "libdecor-WARNING: Application tried to grab unknown seat\n");
-}
-
-static void
-libdecor_plugin_cairo_frame_popup_ungrab(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame,
- const char *seat_name)
-{
- struct libdecor_frame_cairo *frame_cairo =
- (struct libdecor_frame_cairo *) frame;
- struct libdecor_plugin_cairo *plugin_cairo = frame_cairo->plugin_cairo;
- struct seat *seat;
-
- wl_list_for_each(seat, &plugin_cairo->seat_list, link) {
- if (streq(seat->name, seat_name)) {
- if (!seat->grabbed) {
- fprintf(stderr, "libdecor-WARNING: Application "
- "tried to ungrab seat twice\n");
- }
- seat->grabbed = false;
- synthesize_pointer_enter(seat);
- sync_active_component(frame_cairo, seat);
- return;
- }
- }
-
- fprintf(stderr,
- "libdecor-WARNING: Application tried to ungrab unknown seat\n");
-}
-
-static bool
-libdecor_plugin_cairo_frame_get_border_size(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame,
- struct libdecor_configuration *configuration,
- int *left,
- int *right,
- int *top,
- int *bottom)
-{
- enum libdecor_window_state window_state;
-
- if (configuration) {
- if (!libdecor_configuration_get_window_state(
- configuration, &window_state))
- return false;
- } else {
- window_state = libdecor_frame_get_window_state(frame);
- }
-
- if (left)
- *left = 0;
- if (right)
- *right = 0;
- if (bottom)
- *bottom = 0;
- if (top) {
- enum decoration_type type = window_state_to_decoration_type(window_state);
-
- if (((struct libdecor_frame_cairo *)frame)->title_bar.is_showing &&
- (type != DECORATION_TYPE_NONE))
- *top = TITLE_HEIGHT;
- else
- *top = 0;
- }
-
- return true;
-}
-
-static struct libdecor_plugin_interface cairo_plugin_iface = {
- .destroy = libdecor_plugin_cairo_destroy,
- .get_fd = libdecor_plugin_cairo_get_fd,
- .dispatch = libdecor_plugin_cairo_dispatch,
-
- .set_handle_application_cursor = libdecor_plugin_cairo_set_handle_application_cursor,
-
- .frame_new = libdecor_plugin_cairo_frame_new,
- .frame_free = libdecor_plugin_cairo_frame_free,
- .frame_commit = libdecor_plugin_cairo_frame_commit,
- .frame_property_changed = libdecor_plugin_cairo_frame_property_changed,
- .frame_popup_grab = libdecor_plugin_cairo_frame_popup_grab,
- .frame_popup_ungrab = libdecor_plugin_cairo_frame_popup_ungrab,
- .frame_get_border_size = libdecor_plugin_cairo_frame_get_border_size,
-};
-
-static void
-init_wl_compositor(struct libdecor_plugin_cairo *plugin_cairo,
- uint32_t id,
- uint32_t version)
-{
- plugin_cairo->wl_compositor =
- wl_registry_bind(plugin_cairo->wl_registry,
- id, &wl_compositor_interface,
- MIN(version, 4));
-}
-
-static void
-init_wl_subcompositor(struct libdecor_plugin_cairo *plugin_cairo,
- uint32_t id,
- uint32_t version)
-{
- plugin_cairo->wl_subcompositor =
- wl_registry_bind(plugin_cairo->wl_registry,
- id, &wl_subcompositor_interface, 1);
-}
-
-static void
-shm_format(void *user_data,
- struct wl_shm *wl_shm,
- uint32_t format)
-{
- struct libdecor_plugin_cairo *plugin_cairo = user_data;
-
- if (format == WL_SHM_FORMAT_ARGB8888)
- plugin_cairo->has_argb = true;
-}
-
-struct wl_shm_listener shm_listener = {
- shm_format
-};
-
-static void
-shm_callback(void *user_data,
- struct wl_callback *callback,
- uint32_t time)
-{
- struct libdecor_plugin_cairo *plugin_cairo = user_data;
- struct libdecor *context = plugin_cairo->context;
-
- wl_callback_destroy(callback);
- plugin_cairo->globals_callback_shm = NULL;
-
- if (!plugin_cairo->has_argb) {
- libdecor_notify_plugin_error(
- context,
- LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE,
- "Compositor is missing required shm format");
- return;
- }
-
- libdecor_notify_plugin_ready(context);
-}
-
-static const struct wl_callback_listener shm_callback_listener = {
- shm_callback
-};
-
-static void
-init_wl_shm(struct libdecor_plugin_cairo *plugin_cairo,
- uint32_t id,
- uint32_t version)
-{
- struct libdecor *context = plugin_cairo->context;
- struct wl_display *wl_display = libdecor_get_wl_display(context);
-
- plugin_cairo->wl_shm =
- wl_registry_bind(plugin_cairo->wl_registry,
- id, &wl_shm_interface, 1);
- wl_shm_add_listener(plugin_cairo->wl_shm, &shm_listener, plugin_cairo);
-
- plugin_cairo->globals_callback_shm = wl_display_sync(wl_display);
- wl_callback_add_listener(plugin_cairo->globals_callback_shm,
- &shm_callback_listener,
- plugin_cairo);
-}
-
-static void
-cursor_surface_enter(void *data,
- struct wl_surface *wl_surface,
- struct wl_output *wl_output)
-{
- struct seat *seat = data;
-
- if(own_output(wl_output)) {
- struct cursor_output *cursor_output;
- cursor_output = zalloc(sizeof *cursor_output);
- cursor_output->output = wl_output_get_user_data(wl_output);
- wl_list_insert(&seat->cursor_outputs, &cursor_output->link);
- if (update_local_cursor(seat))
- send_cursor(seat);
- }
-}
-
-static void
-cursor_surface_leave(void *data,
- struct wl_surface *wl_surface,
- struct wl_output *wl_output)
-{
- struct seat *seat = data;
-
- if(own_output(wl_output)) {
- struct cursor_output *cursor_output, *tmp;
- wl_list_for_each_safe(cursor_output, tmp, &seat->cursor_outputs, link) {
- if (cursor_output->output->wl_output == wl_output) {
- wl_list_remove(&cursor_output->link);
- free(cursor_output);
- }
- }
-
- if (update_local_cursor(seat))
- send_cursor(seat);
- }
-}
-
-static struct wl_surface_listener cursor_surface_listener = {
- cursor_surface_enter,
- cursor_surface_leave,
-};
-
-static void
-ensure_cursor_surface(struct seat *seat)
-{
- struct wl_compositor *wl_compositor = seat->plugin_cairo->wl_compositor;
-
- if (seat->cursor_surface)
- return;
-
- seat->cursor_surface = wl_compositor_create_surface(wl_compositor);
- wl_surface_add_listener(seat->cursor_surface,
- &cursor_surface_listener, seat);
-}
-
-static bool
-ensure_cursor_theme(struct seat *seat)
-{
- struct libdecor_plugin_cairo *plugin_cairo = seat->plugin_cairo;
- int scale = 1;
- struct wl_cursor_theme *theme;
- struct cursor_output *cursor_output;
-
- wl_list_for_each(cursor_output, &seat->cursor_outputs, link) {
- scale = MAX(scale, cursor_output->output->scale);
- }
-
- if (seat->cursor_theme && seat->cursor_scale == scale)
- return false;
-
- seat->cursor_scale = scale;
- theme = wl_cursor_theme_load(plugin_cairo->cursor_theme_name,
- plugin_cairo->cursor_size * scale,
- plugin_cairo->wl_shm);
- if (theme == NULL)
- return false;
-
- if (seat->cursor_theme)
- wl_cursor_theme_destroy(seat->cursor_theme);
-
- seat->cursor_theme = theme;
-
- for (unsigned int i = 0; i < ARRAY_LENGTH(cursor_names); i++) {
- seat->cursors[i] = wl_cursor_theme_get_cursor(
- seat->cursor_theme,
- cursor_names[i]);
- }
-
- seat->cursor_left_ptr = wl_cursor_theme_get_cursor(seat->cursor_theme,
- "left_ptr");
- seat->current_cursor = seat->cursor_left_ptr;
-
- return true;
-}
-
-enum libdecor_resize_edge
-component_edge(const struct border_component *cmpnt,
- const int pointer_x,
- const int pointer_y,
- const int margin)
-{
- const bool top = pointer_y < margin * 2;
- const bool bottom = pointer_y > (cmpnt->server.buffer->height - margin * 2);
- const bool left = pointer_x < margin * 2;
- const bool right = pointer_x > (cmpnt->server.buffer->width - margin * 2);
-
- if (top)
- if (left)
- return LIBDECOR_RESIZE_EDGE_TOP_LEFT;
- else if (right)
- return LIBDECOR_RESIZE_EDGE_TOP_RIGHT;
- else
- return LIBDECOR_RESIZE_EDGE_TOP;
- else if (bottom)
- if (left)
- return LIBDECOR_RESIZE_EDGE_BOTTOM_LEFT;
- else if (right)
- return LIBDECOR_RESIZE_EDGE_BOTTOM_RIGHT;
- else
- return LIBDECOR_RESIZE_EDGE_BOTTOM;
- else if (left)
- return LIBDECOR_RESIZE_EDGE_LEFT;
- else if (right)
- return LIBDECOR_RESIZE_EDGE_RIGHT;
- else
- return LIBDECOR_RESIZE_EDGE_NONE;
-}
-
-static bool
-update_local_cursor(struct seat *seat)
-{
- if (!seat->pointer_focus) {
- seat->current_cursor = seat->cursor_left_ptr;
- return false;
- }
-
- if (!own_surface(seat->pointer_focus)) {
- if (seat->plugin_cairo->handle_cursor) {
- seat->current_cursor = seat->cursor_left_ptr;
- return true;
- } else {
- return false;
- }
- }
-
- struct libdecor_frame_cairo *frame_cairo =
- wl_surface_get_user_data(seat->pointer_focus);
- struct wl_cursor *wl_cursor = NULL;
-
- if (!frame_cairo || !frame_cairo->active) {
- seat->current_cursor = seat->cursor_left_ptr;
- return false;
- }
-
- bool theme_updated = ensure_cursor_theme(seat);
-
- if (frame_cairo->active->type == SHADOW &&
- is_border_surfaces_showing(frame_cairo) &&
- resizable(frame_cairo)) {
- enum libdecor_resize_edge edge;
- edge = component_edge(frame_cairo->active,
- seat->pointer_x,
- seat->pointer_y, SHADOW_MARGIN);
-
- if (edge != LIBDECOR_RESIZE_EDGE_NONE)
- wl_cursor = seat->cursors[edge - 1];
- } else {
- wl_cursor = seat->cursor_left_ptr;
- }
-
- if (seat->current_cursor != wl_cursor) {
- seat->current_cursor = wl_cursor;
- return true;
- }
-
- return theme_updated;
-}
-
-static void
-send_cursor(struct seat *seat)
-{
- struct wl_cursor_image *image;
- struct wl_buffer *buffer;
-
- if (seat->pointer_focus == NULL || seat->current_cursor == NULL)
- return;
-
- image = seat->current_cursor->images[0];
- buffer = wl_cursor_image_get_buffer(image);
- wl_surface_attach(seat->cursor_surface, buffer, 0, 0);
- wl_surface_set_buffer_scale(seat->cursor_surface, seat->cursor_scale);
- wl_surface_damage_buffer(seat->cursor_surface, 0, 0,
- image->width * seat->cursor_scale,
- image->height * seat->cursor_scale);
- wl_surface_commit(seat->cursor_surface);
- wl_pointer_set_cursor(seat->wl_pointer, seat->serial,
- seat->cursor_surface,
- image->hotspot_x / seat->cursor_scale,
- image->hotspot_y / seat->cursor_scale);
-}
-
-static void
-sync_active_component(struct libdecor_frame_cairo *frame_cairo,
- struct seat *seat)
-{
- struct border_component *old_active;
-
- if (!seat->pointer_focus)
- return;
-
- old_active = frame_cairo->active;
- update_component_focus(frame_cairo, seat->pointer_focus, seat);
- if (old_active != frame_cairo->active) {
- draw_decoration(frame_cairo);
- libdecor_frame_toplevel_commit(&frame_cairo->frame);
- }
-
- if (update_local_cursor(seat))
- send_cursor(seat);
-}
-
-static void
-synthesize_pointer_enter(struct seat *seat)
-{
- struct wl_surface *surface;
- struct libdecor_frame_cairo *frame_cairo;
-
- surface = seat->pointer_focus;
- if (!surface || !own_surface(surface))
- return;
-
- frame_cairo = wl_surface_get_user_data(surface);
- if (!frame_cairo)
- return;
-
- update_component_focus(frame_cairo, seat->pointer_focus, seat);
- frame_cairo->grab = NULL;
-
- /* update decorations */
- if (frame_cairo->active) {
- draw_decoration(frame_cairo);
- libdecor_frame_toplevel_commit(&frame_cairo->frame);
- }
-
- update_local_cursor(seat);
- send_cursor(seat);
-}
-
-static void
-synthesize_pointer_leave(struct seat *seat)
-{
- struct wl_surface *surface;
- struct libdecor_frame_cairo *frame_cairo;
-
- surface = seat->pointer_focus;
- if (!surface || !own_surface(surface))
- return;
-
- frame_cairo = wl_surface_get_user_data(surface);
- if (!frame_cairo)
- return;
-
- if (!frame_cairo->active)
- return;
-
- frame_cairo->active = NULL;
- draw_decoration(frame_cairo);
- libdecor_frame_toplevel_commit(&frame_cairo->frame);
- update_local_cursor(seat);
-}
-
-static void
-pointer_enter(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t serial,
- struct wl_surface *surface,
- wl_fixed_t surface_x,
- wl_fixed_t surface_y)
-{
- struct seat *seat = data;
- struct libdecor_frame_cairo *frame_cairo = NULL;
-
- if (!surface)
- return;
-
- if (!own_surface(surface)) {
- struct seat *seat = wl_pointer_get_user_data(wl_pointer);
- struct libdecor_plugin_cairo *plugin_cairo = seat->plugin_cairo;
-
- if (!plugin_cairo->handle_cursor)
- return;
- } else {
- frame_cairo = wl_surface_get_user_data(surface);
- }
-
- ensure_cursor_surface(seat);
-
- seat->pointer_x = wl_fixed_to_int(surface_x);
- seat->pointer_y = wl_fixed_to_int(surface_y);
- seat->serial = serial;
- seat->pointer_focus = surface;
- seat->pointer_focus_frame = frame_cairo;
-
- if (seat->grabbed)
- return;
-
- synthesize_pointer_enter(seat);
-}
-
-static void
-pointer_leave(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t serial,
- struct wl_surface *surface)
-{
- struct seat *seat = data;
-
- if (!surface)
- return;
-
- if (!own_surface(surface))
- return;
-
- synthesize_pointer_leave(seat);
- seat->pointer_focus = NULL;
- seat->pointer_focus_frame = NULL;
-}
-
-static void
-pointer_motion(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t time,
- wl_fixed_t surface_x,
- wl_fixed_t surface_y)
-{
- struct seat *seat = data;
-
- seat->pointer_x = wl_fixed_to_int(surface_x);
- seat->pointer_y = wl_fixed_to_int(surface_y);
-
- if (seat->grabbed)
- return;
-
- if (!seat->pointer_focus_frame)
- return;
-
- sync_active_component(seat->pointer_focus_frame, seat);
-}
-
-static void
-pointer_button(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t serial,
- uint32_t time,
- uint32_t button,
- uint32_t state)
-{
- struct seat *seat = data;
- struct libdecor_frame_cairo *frame_cairo;
-
- if (!seat->pointer_focus || !own_surface(seat->pointer_focus))
- return;
-
- frame_cairo = wl_surface_get_user_data(seat->pointer_focus);
- if (!frame_cairo)
- return;
-
- if (seat->grabbed) {
- libdecor_frame_dismiss_popup(&frame_cairo->frame, seat->name);
- return;
- }
-
- if (!frame_cairo->active)
- return;
-
- if (button == BTN_LEFT) {
- if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
- enum libdecor_resize_edge edge =
- LIBDECOR_RESIZE_EDGE_NONE;
-
- frame_cairo->grab = NULL;
-
- switch (frame_cairo->active->type) {
- case SHADOW:
- edge = component_edge(frame_cairo->active,
- seat->pointer_x,
- seat->pointer_y,
- SHADOW_MARGIN);
- break;
- case TITLE:
- if (time-seat->pointer_button_time_stamp <
- DOUBLE_CLICK_TIME_MS) {
- toggle_maximized(&frame_cairo->frame);
- }
- else if (moveable(frame_cairo)) {
- seat->pointer_button_time_stamp = time;
- libdecor_frame_move(&frame_cairo->frame,
- seat->wl_seat,
- serial);
- }
- break;
- case BUTTON_MIN:
- case BUTTON_MAX:
- case BUTTON_CLOSE:
- frame_cairo->grab = frame_cairo->active;
- break;
- default:
- break;
- }
-
- if (edge != LIBDECOR_RESIZE_EDGE_NONE &&
- resizable(frame_cairo)) {
- libdecor_frame_resize(
- &frame_cairo->frame,
- seat->wl_seat,
- serial,
- edge);
- }
- }
- else if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
- frame_cairo->grab) {
- libdecor_frame_ref(&frame_cairo->frame);
- if (frame_cairo->grab == frame_cairo->focus) {
- switch (frame_cairo->active->type) {
- case BUTTON_MIN:
- if (minimizable(frame_cairo))
- libdecor_frame_set_minimized(
- &frame_cairo->frame);
- break;
- case BUTTON_MAX:
- toggle_maximized(&frame_cairo->frame);
- break;
- case BUTTON_CLOSE:
- if (closeable(frame_cairo))
- libdecor_frame_close(&frame_cairo->frame);
- break;
- default:
- break;
- }
- }
- frame_cairo->grab = NULL;
- sync_active_component(frame_cairo, seat);
- libdecor_frame_unref(&frame_cairo->frame);
- }
- }
- else if (button == BTN_RIGHT &&
- state == WL_POINTER_BUTTON_STATE_PRESSED &&
- seat->pointer_focus == frame_cairo->title_bar.title.server.wl_surface) {
- libdecor_frame_show_window_menu(&frame_cairo->frame,
- seat->wl_seat,
- serial,
- seat->pointer_x,
- seat->pointer_y - TITLE_HEIGHT);
- }
-}
-
-static void
-pointer_axis(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t time,
- uint32_t axis,
- wl_fixed_t value)
-{
-}
-
-static struct wl_pointer_listener pointer_listener = {
- pointer_enter,
- pointer_leave,
- pointer_motion,
- pointer_button,
- pointer_axis
-};
-
-static void
-seat_capabilities(void *data,
- struct wl_seat *wl_seat,
- uint32_t capabilities)
-{
- struct seat *seat = data;
-
- if ((capabilities & WL_SEAT_CAPABILITY_POINTER) &&
- !seat->wl_pointer) {
- seat->wl_pointer = wl_seat_get_pointer(wl_seat);
- wl_pointer_add_listener(seat->wl_pointer,
- &pointer_listener, seat);
- } else if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) &&
- seat->wl_pointer) {
- wl_pointer_release(seat->wl_pointer);
- seat->wl_pointer = NULL;
- }
-}
-
-static void
-seat_name(void *data,
- struct wl_seat *wl_seat,
- const char *name)
-{
- struct seat *seat = data;
-
- seat->name = strdup(name);
-}
-
-static struct wl_seat_listener seat_listener = {
- seat_capabilities,
- seat_name
-};
-
-static void
-init_wl_seat(struct libdecor_plugin_cairo *plugin_cairo,
- uint32_t id,
- uint32_t version)
-{
- struct seat *seat;
-
- if (version < 3) {
- libdecor_notify_plugin_error(
- plugin_cairo->context,
- LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE,
- "%s version 3 required but only version %i is available\n",
- wl_seat_interface.name, version);
- }
-
- seat = zalloc(sizeof *seat);
- seat->cursor_scale = 1;
- seat->plugin_cairo = plugin_cairo;
- wl_list_init(&seat->cursor_outputs);
- wl_list_insert(&plugin_cairo->seat_list, &seat->link);
- seat->wl_seat =
- wl_registry_bind(plugin_cairo->wl_registry,
- id, &wl_seat_interface, 3);
- wl_seat_add_listener(seat->wl_seat, &seat_listener, seat);
-}
-
-static void
-output_geometry(void *data,
- struct wl_output *wl_output,
- int32_t x,
- int32_t y,
- int32_t physical_width,
- int32_t physical_height,
- int32_t subpixel,
- const char *make,
- const char *model,
- int32_t transform)
-{
-}
-
-static void
-output_mode(void *data,
- struct wl_output *wl_output,
- uint32_t flags,
- int32_t width,
- int32_t height,
- int32_t refresh)
-{
-}
-
-static void
-output_done(void *data,
- struct wl_output *wl_output)
-{
- struct output *output = data;
- struct libdecor_frame_cairo *frame_cairo;
- struct seat *seat;
-
- wl_list_for_each(frame_cairo,
- &output->plugin_cairo->visible_frame_list, link) {
- bool updated = false;
- updated |= redraw_scale(frame_cairo, &frame_cairo->shadow);
- updated |= redraw_scale(frame_cairo, &frame_cairo->title_bar.title);
- if (updated)
- libdecor_frame_toplevel_commit(&frame_cairo->frame);
- }
- wl_list_for_each(seat, &output->plugin_cairo->seat_list, link) {
- if (update_local_cursor(seat))
- send_cursor(seat);
- }
-}
-
-static void
-output_scale(void *data,
- struct wl_output *wl_output,
- int32_t factor)
-{
- struct output *output = data;
-
- output->scale = factor;
-}
-
-static struct wl_output_listener output_listener = {
- output_geometry,
- output_mode,
- output_done,
- output_scale
-};
-
-static void
-init_wl_output(struct libdecor_plugin_cairo *plugin_cairo,
- uint32_t id,
- uint32_t version)
-{
- struct output *output;
-
- if (version < 2) {
- libdecor_notify_plugin_error(
- plugin_cairo->context,
- LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE,
- "%s version 2 required but only version %i is available\n",
- wl_output_interface.name, version);
- }
-
- output = zalloc(sizeof *output);
- output->plugin_cairo = plugin_cairo;
- wl_list_insert(&plugin_cairo->output_list, &output->link);
- output->id = id;
- output->wl_output =
- wl_registry_bind(plugin_cairo->wl_registry,
- id, &wl_output_interface,
- MIN (version, 3));
- wl_proxy_set_tag((struct wl_proxy *) output->wl_output,
- &libdecor_cairo_proxy_tag);
- wl_output_add_listener(output->wl_output, &output_listener, output);
-}
-
-static void
-registry_handle_global(void *user_data,
- struct wl_registry *wl_registry,
- uint32_t id,
- const char *interface,
- uint32_t version)
-{
- struct libdecor_plugin_cairo *plugin_cairo = user_data;
-
- if (strcmp(interface, "wl_compositor") == 0)
- init_wl_compositor(plugin_cairo, id, version);
- else if (strcmp(interface, "wl_subcompositor") == 0)
- init_wl_subcompositor(plugin_cairo, id, version);
- else if (strcmp(interface, "wl_shm") == 0)
- init_wl_shm(plugin_cairo, id, version);
- else if (strcmp(interface, "wl_seat") == 0)
- init_wl_seat(plugin_cairo, id, version);
- else if (strcmp(interface, "wl_output") == 0)
- init_wl_output(plugin_cairo, id, version);
-}
-
-static void
-remove_surface_outputs(struct border_component *cmpnt, struct output *output)
-{
- struct surface_output *surface_output;
- wl_list_for_each(surface_output, &cmpnt->server.output_list, link) {
- if (surface_output->output == output) {
- wl_list_remove(&surface_output->link);
- free(surface_output);
- break;
- }
- }
-}
-
-static void
-output_removed(struct libdecor_plugin_cairo *plugin_cairo,
- struct output *output)
-{
- struct libdecor_frame_cairo *frame_cairo;
- struct seat *seat;
-
- wl_list_for_each(frame_cairo, &plugin_cairo->visible_frame_list, link) {
- remove_surface_outputs(&frame_cairo->shadow, output);
- remove_surface_outputs(&frame_cairo->title_bar.title, output);
- remove_surface_outputs(&frame_cairo->title_bar.min, output);
- remove_surface_outputs(&frame_cairo->title_bar.max, output);
- remove_surface_outputs(&frame_cairo->title_bar.close, output);
- }
- wl_list_for_each(seat, &plugin_cairo->seat_list, link) {
- struct cursor_output *cursor_output, *tmp;
- wl_list_for_each_safe(cursor_output, tmp, &seat->cursor_outputs, link) {
- if (cursor_output->output == output) {
- wl_list_remove(&cursor_output->link);
- free(cursor_output);
- }
- }
- }
-
- wl_list_remove(&output->link);
- wl_output_destroy(output->wl_output);
- free(output);
-}
-
-static void
-registry_handle_global_remove(void *user_data,
- struct wl_registry *wl_registry,
- uint32_t name)
-{
- struct libdecor_plugin_cairo *plugin_cairo = user_data;
- struct output *output;
-
- wl_list_for_each(output, &plugin_cairo->output_list, link) {
- if (output->id == name) {
- output_removed(plugin_cairo, output);
- break;
- }
- }
-}
-
-static const struct wl_registry_listener registry_listener = {
- registry_handle_global,
- registry_handle_global_remove
-};
-
-static bool
-has_required_globals(struct libdecor_plugin_cairo *plugin_cairo)
-{
- if (!plugin_cairo->wl_compositor)
- return false;
- if (!plugin_cairo->wl_subcompositor)
- return false;
- if (!plugin_cairo->wl_shm)
- return false;
-
- return true;
-}
-
-static void
-globals_callback(void *user_data,
- struct wl_callback *callback,
- uint32_t time)
-{
- struct libdecor_plugin_cairo *plugin_cairo = user_data;
-
- wl_callback_destroy(callback);
- plugin_cairo->globals_callback = NULL;
-}
-
-static const struct wl_callback_listener globals_callback_listener = {
- globals_callback
-};
-
-static struct libdecor_plugin *
-libdecor_plugin_new(struct libdecor *context)
-{
- struct libdecor_plugin_cairo *plugin_cairo;
- struct wl_display *wl_display;
-
- plugin_cairo = zalloc(sizeof *plugin_cairo);
- libdecor_plugin_init(&plugin_cairo->plugin,
- context,
- &cairo_plugin_iface);
- plugin_cairo->context = context;
-
- wl_list_init(&plugin_cairo->visible_frame_list);
- wl_list_init(&plugin_cairo->seat_list);
- wl_list_init(&plugin_cairo->output_list);
-
- /* fetch cursor theme and size*/
- if (!libdecor_get_cursor_settings(&plugin_cairo->cursor_theme_name,
- &plugin_cairo->cursor_size)) {
- plugin_cairo->cursor_theme_name = NULL;
- plugin_cairo->cursor_size = 24;
- }
-
- /* define a sens-serif bold font at symbol size */
- plugin_cairo->font = pango_font_description_new();
- pango_font_description_set_family(plugin_cairo->font, "sans");
- pango_font_description_set_weight(plugin_cairo->font, PANGO_WEIGHT_BOLD);
- pango_font_description_set_absolute_size(plugin_cairo->font, SYM_DIM * PANGO_SCALE);
-
- wl_display = libdecor_get_wl_display(context);
- plugin_cairo->wl_registry = wl_display_get_registry(wl_display);
- wl_registry_add_listener(plugin_cairo->wl_registry,
- &registry_listener,
- plugin_cairo);
-
- plugin_cairo->globals_callback = wl_display_sync(wl_display);
- wl_callback_add_listener(plugin_cairo->globals_callback,
- &globals_callback_listener,
- plugin_cairo);
- wl_display_roundtrip(wl_display);
-
- if (!has_required_globals(plugin_cairo)) {
- fprintf(stderr, "libdecor-cairo-WARNING: Could not get required globals\n");
- libdecor_plugin_cairo_destroy(&plugin_cairo->plugin);
- return NULL;
- }
-
- return &plugin_cairo->plugin;
-}
-
-static struct libdecor_plugin_priority priorities[] = {
- { NULL, LIBDECOR_PLUGIN_PRIORITY_MEDIUM }
-};
-
-LIBDECOR_EXPORT const struct libdecor_plugin_description
-libdecor_plugin_description = {
- .api_version = LIBDECOR_PLUGIN_API_VERSION,
- .capabilities = LIBDECOR_PLUGIN_CAPABILITY_BASE,
- .description = "libdecor plugin using Cairo",
- .priorities = priorities,
- .constructor = libdecor_plugin_new,
-};
diff --git a/libdecor/src/plugins/common/libdecor-cairo-blur.c b/libdecor/src/plugins/common/libdecor-cairo-blur.c
deleted file mode 100644
index 2cddc7a23..000000000
--- a/libdecor/src/plugins/common/libdecor-cairo-blur.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright © 2008 Kristian Høgsberg
- * Copyright © 2012 Intel Corporation
- *
- * 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.
- */
-
-/*
- * functions 'blur_surface' and 'render_shadow' from weston project:
- * https://gitlab.freedesktop.org/wayland/weston/raw/master/shared/cairo-util.c
- */
-
-#include "libdecor-cairo-blur.h"
-#include <stdint.h>
-#include <stdlib.h>
-#include <math.h>
-
-/**
- * Compile-time computation of number of items in a hardcoded array.
- *
- * @param a the array being measured.
- * @return the number of items hardcoded into the array.
- */
-#ifndef ARRAY_LENGTH
-#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
-#endif
-
-int
-blur_surface(cairo_surface_t *surface, int margin)
-{
- int32_t width, height, stride, x, y, z, w;
- uint8_t *src, *dst;
- uint32_t *s, *d, a, p;
- int i, j, k, size, half;
- uint32_t kernel[71];
- double f;
-
- size = ARRAY_LENGTH(kernel);
- width = cairo_image_surface_get_width(surface);
- height = cairo_image_surface_get_height(surface);
- stride = cairo_image_surface_get_stride(surface);
- src = cairo_image_surface_get_data(surface);
-
- dst = malloc(height * stride);
- if (dst == NULL)
- return -1;
-
- half = size / 2;
- a = 0;
- for (i = 0; i < size; i++) {
- f = (i - half);
- kernel[i] = exp(- f * f / ARRAY_LENGTH(kernel)) * 10000;
- a += kernel[i];
- }
-
- for (i = 0; i < height; i++) {
- s = (uint32_t *) (src + i * stride);
- d = (uint32_t *) (dst + i * stride);
- for (j = 0; j < width; j++) {
- if (margin < j && j < width - margin) {
- d[j] = s[j];
- continue;
- }
-
- x = 0;
- y = 0;
- z = 0;
- w = 0;
- for (k = 0; k < size; k++) {
- if (j - half + k < 0 || j - half + k >= width)
- continue;
- p = s[j - half + k];
-
- x += (p >> 24) * kernel[k];
- y += ((p >> 16) & 0xff) * kernel[k];
- z += ((p >> 8) & 0xff) * kernel[k];
- w += (p & 0xff) * kernel[k];
- }
- d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a;
- }
- }
-
- for (i = 0; i < height; i++) {
- s = (uint32_t *) (dst + i * stride);
- d = (uint32_t *) (src + i * stride);
- for (j = 0; j < width; j++) {
- if (margin <= i && i < height - margin) {
- d[j] = s[j];
- continue;
- }
-
- x = 0;
- y = 0;
- z = 0;
- w = 0;
- for (k = 0; k < size; k++) {
- if (i - half + k < 0 || i - half + k >= height)
- continue;
- s = (uint32_t *) (dst + (i - half + k) * stride);
- p = s[j];
-
- x += (p >> 24) * kernel[k];
- y += ((p >> 16) & 0xff) * kernel[k];
- z += ((p >> 8) & 0xff) * kernel[k];
- w += (p & 0xff) * kernel[k];
- }
- d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a;
- }
- }
-
- free(dst);
- cairo_surface_mark_dirty(surface);
-
- return 0;
-}
-
-void
-render_shadow(cairo_t *cr, cairo_surface_t *surface,
- int x, int y, int width, int height, int margin, int top_margin)
-{
- cairo_pattern_t *pattern;
- cairo_matrix_t matrix;
- int i, fx, fy, shadow_height, shadow_width;
-
- cairo_set_source_rgba(cr, 0, 0, 0, 0.45);
- cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
- pattern = cairo_pattern_create_for_surface (surface);
- cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST);
-
- for (i = 0; i < 4; i++) {
- /* when fy is set, then we are working with lower corners,
- * when fx is set, then we are working with right corners
- *
- * 00 ------- 01
- * | |
- * | |
- * 10 ------- 11
- */
- fx = i & 1;
- fy = i >> 1;
-
- cairo_matrix_init_translate(&matrix,
- -x + fx * (128 - width),
- -y + fy * (128 - height));
- cairo_pattern_set_matrix(pattern, &matrix);
-
- shadow_width = margin;
- shadow_height = fy ? margin : top_margin;
-
- /* if the shadows together are greater than the surface, we need
- * to fix it - set the shadow size to the half of
- * the size of surface. Also handle the case when the size is
- * not divisible by 2. In that case we need one part of the
- * shadow to be one pixel greater. !fy or !fx, respectively,
- * will do the work.
- */
- if (height < 2 * shadow_height)
- shadow_height = (height + !fy) / 2;
-
- if (width < 2 * shadow_width)
- shadow_width = (width + !fx) / 2;
-
- cairo_reset_clip(cr);
- cairo_rectangle(cr,
- x + fx * (width - shadow_width),
- y + fy * (height - shadow_height),
- shadow_width, shadow_height);
- cairo_clip (cr);
- cairo_mask(cr, pattern);
- }
-
-
- shadow_width = width - 2 * margin;
- shadow_height = top_margin;
- if (height < 2 * shadow_height)
- shadow_height = height / 2;
-
- if (shadow_width > 0 && shadow_height) {
- /* Top stretch */
- cairo_matrix_init_translate(&matrix, 60, 0);
- cairo_matrix_scale(&matrix, 8.0 / width, 1);
- cairo_matrix_translate(&matrix, -x - width / 2, -y);
- cairo_pattern_set_matrix(pattern, &matrix);
- cairo_rectangle(cr, x + margin, y, shadow_width, shadow_height);
-
- cairo_reset_clip(cr);
- cairo_rectangle(cr,
- x + margin, y,
- shadow_width, shadow_height);
- cairo_clip (cr);
- cairo_mask(cr, pattern);
-
- /* Bottom stretch */
- cairo_matrix_translate(&matrix, 0, -height + 128);
- cairo_pattern_set_matrix(pattern, &matrix);
-
- cairo_reset_clip(cr);
- cairo_rectangle(cr, x + margin, y + height - margin,
- shadow_width, margin);
- cairo_clip (cr);
- cairo_mask(cr, pattern);
- }
-
- shadow_width = margin;
- if (width < 2 * shadow_width)
- shadow_width = width / 2;
-
- shadow_height = height - margin - top_margin;
-
- /* if height is smaller than sum of margins,
- * then the shadow is already done by the corners */
- if (shadow_height > 0 && shadow_width) {
- /* Left stretch */
- cairo_matrix_init_translate(&matrix, 0, 60);
- cairo_matrix_scale(&matrix, 1, 8.0 / height);
- cairo_matrix_translate(&matrix, -x, -y - height / 2);
- cairo_pattern_set_matrix(pattern, &matrix);
- cairo_reset_clip(cr);
- cairo_rectangle(cr, x, y + top_margin,
- shadow_width, shadow_height);
- cairo_clip (cr);
- cairo_mask(cr, pattern);
-
- /* Right stretch */
- cairo_matrix_translate(&matrix, -width + 128, 0);
- cairo_pattern_set_matrix(pattern, &matrix);
- cairo_rectangle(cr, x + width - shadow_width, y + top_margin,
- shadow_width, shadow_height);
- cairo_reset_clip(cr);
- cairo_clip (cr);
- cairo_mask(cr, pattern);
- }
-
- cairo_pattern_destroy(pattern);
- cairo_reset_clip(cr);
-}
diff --git a/libdecor/src/plugins/common/libdecor-cairo-blur.h b/libdecor/src/plugins/common/libdecor-cairo-blur.h
deleted file mode 100644
index d48e9dd3d..000000000
--- a/libdecor/src/plugins/common/libdecor-cairo-blur.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-
-#include <cairo/cairo.h>
-
-int
-blur_surface(cairo_surface_t *surface, int margin);
-
-void
-render_shadow(cairo_t *cr, cairo_surface_t *surface,
- int x, int y, int width, int height, int margin, int top_margin);
diff --git a/libdecor/src/plugins/dummy/libdecor-dummy.c b/libdecor/src/plugins/dummy/libdecor-dummy.c
deleted file mode 100644
index 621dd027f..000000000
--- a/libdecor/src/plugins/dummy/libdecor-dummy.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright © 2021 Jonas Ådahl
- *
- * 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 "libdecor-plugin.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <stdlib.h>
-#include <wayland-cursor.h>
-
-#include "utils.h"
-
-struct libdecor_plugin_dummy {
- struct libdecor_plugin plugin;
- struct libdecor *context;
-};
-
-static void
-libdecor_plugin_dummy_destroy(struct libdecor_plugin *plugin)
-{
- struct libdecor_plugin_dummy *plugin_dummy =
- (struct libdecor_plugin_dummy *) plugin;
-
- libdecor_plugin_release(plugin);
- free(plugin_dummy);
-}
-
-static struct libdecor_frame *
-libdecor_plugin_dummy_frame_new(struct libdecor_plugin *plugin)
-{
- struct libdecor_frame *frame;
-
- frame = zalloc(sizeof *frame);
-
- return frame;
-}
-
-static void
-libdecor_plugin_dummy_set_handle_application_cursor(struct libdecor_plugin *plugin,
- bool handle_cursor)
-{
-}
-
-static void
-libdecor_plugin_dummy_frame_free(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame)
-{
-}
-
-static void
-libdecor_plugin_dummy_frame_commit(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame,
- struct libdecor_state *state,
- struct libdecor_configuration *configuration)
-{
-}
-
-static void
-libdecor_plugin_dummy_frame_property_changed(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame)
-{
-}
-
-static void
-libdecor_plugin_dummy_frame_popup_grab(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame,
- const char *seat_name)
-{
-}
-
-static void
-libdecor_plugin_dummy_frame_popup_ungrab(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame,
- const char *seat_name)
-{
-}
-
-static struct libdecor_plugin_interface dummy_plugin_iface = {
- .destroy = libdecor_plugin_dummy_destroy,
-
- .set_handle_application_cursor = libdecor_plugin_dummy_set_handle_application_cursor,
-
- .frame_new = libdecor_plugin_dummy_frame_new,
- .frame_free = libdecor_plugin_dummy_frame_free,
- .frame_commit = libdecor_plugin_dummy_frame_commit,
- .frame_property_changed = libdecor_plugin_dummy_frame_property_changed,
- .frame_popup_grab = libdecor_plugin_dummy_frame_popup_grab,
- .frame_popup_ungrab = libdecor_plugin_dummy_frame_popup_ungrab,
-};
-
-static struct libdecor_plugin *
-libdecor_plugin_new(struct libdecor *context)
-{
- struct libdecor_plugin_dummy *plugin_dummy;
-
- plugin_dummy = zalloc(sizeof *plugin_dummy);
- libdecor_plugin_init(&plugin_dummy->plugin, context, &dummy_plugin_iface);
- plugin_dummy->context = context;
-
- libdecor_notify_plugin_ready(context);
-
- return &plugin_dummy->plugin;
-}
-
-static struct libdecor_plugin_priority priorities[] = {
- { NULL, LIBDECOR_PLUGIN_PRIORITY_LOW }
-};
-
-LIBDECOR_EXPORT const struct libdecor_plugin_description
-libdecor_plugin_description = {
- .api_version = LIBDECOR_PLUGIN_API_VERSION,
- .capabilities = LIBDECOR_PLUGIN_CAPABILITY_BASE,
- .description = "dummy libdecor plugin",
- .priorities = priorities,
- .constructor = libdecor_plugin_new,
-};
diff --git a/libdecor/src/plugins/gtk/libdecor-gtk.c b/libdecor/src/plugins/gtk/libdecor-gtk.c
deleted file mode 100644
index bc5b0fa61..000000000
--- a/libdecor/src/plugins/gtk/libdecor-gtk.c
+++ /dev/null
@@ -1,3028 +0,0 @@
-/*
- * Copyright © 2018 Jonas Ådahl
- * Copyright © 2021 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 <linux/input.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-#include <wayland-client-core.h>
-#include <wayland-cursor.h>
-
-#include "libdecor-plugin.h"
-#include "utils.h"
-#include "desktop-settings.h"
-#include "os-compatibility.h"
-
-#include <cairo/cairo.h>
-
-#include "common/libdecor-cairo-blur.h"
-#include <poll.h>
-
-#include <gtk/gtk.h>
-
-static const size_t SHADOW_MARGIN = 24; /* grabbable part of the border */
-
-static const char *cursor_names[] = {
- "top_side",
- "bottom_side",
- "left_side",
- "top_left_corner",
- "bottom_left_corner",
- "right_side",
- "top_right_corner",
- "bottom_right_corner"
-};
-
-enum header_element {
- HEADER_NONE,
- HEADER_FULL, /* entire header bar */
- HEADER_TITLE, /* label */
- HEADER_MIN,
- HEADER_MAX,
- HEADER_CLOSE,
-};
-
-enum titlebar_gesture_state {
- TITLEBAR_GESTURE_STATE_INIT,
- TITLEBAR_GESTURE_STATE_BUTTON_PRESSED,
- TITLEBAR_GESTURE_STATE_CONSUMED,
- TITLEBAR_GESTURE_STATE_DISCARDED,
-};
-
-struct header_element_data {
- const char *name;
- enum header_element type;
- /* pointer to button or NULL if not found*/
- GtkWidget *widget;
- GtkStateFlags state;
-};
-
-static void
-find_widget_by_name(GtkWidget *widget, void *data)
-{
- if (GTK_IS_WIDGET(widget)) {
- char *style_ctx = gtk_style_context_to_string(
- gtk_widget_get_style_context(widget),
- GTK_STYLE_CONTEXT_PRINT_SHOW_STYLE);
- if (strstr(style_ctx, ((struct header_element_data *)data)->name)) {
- ((struct header_element_data *)data)->widget = widget;
- free(style_ctx);
- return;
- }
- free(style_ctx);
- }
-
- if (GTK_IS_CONTAINER(widget)) {
- /* recursively traverse container */
- gtk_container_forall(GTK_CONTAINER(widget), &find_widget_by_name, data);
- }
-}
-
-static struct header_element_data
-find_widget_by_type(GtkWidget *widget, enum header_element type)
-{
- char* name = NULL;
- switch (type) {
- case HEADER_FULL:
- name = "headerbar.titlebar:";
- break;
- case HEADER_TITLE:
- name = "label.title:";
- break;
- case HEADER_MIN:
- name = ".minimize";
- break;
- case HEADER_MAX:
- name = ".maximize";
- break;
- case HEADER_CLOSE:
- name = ".close";
- break;
- default:
- break;
- }
-
- struct header_element_data data = {.name = name, .type = type, .widget = NULL};
- find_widget_by_name(widget, &data);
- return data;
-}
-
-static bool
-in_region(const cairo_rectangle_int_t *rect, const int *x, const int *y)
-{
- return (*x>=rect->x) & (*y>=rect->y) &
- (*x<(rect->x+rect->width)) & (*y<(rect->y+rect->height));
-}
-
-static struct header_element_data
-get_header_focus(const GtkHeaderBar *header_bar, const int x, const int y)
-{
- /* we have to check child widgets (buttons, title) before the 'HDR_HDR' root widget */
- static const enum header_element elems[] =
- {HEADER_TITLE, HEADER_MIN, HEADER_MAX, HEADER_CLOSE};
-
- for (size_t i = 0; i < ARRAY_SIZE(elems); i++) {
- struct header_element_data elem =
- find_widget_by_type(GTK_WIDGET(header_bar), elems[i]);
- if (elem.widget) {
- GtkAllocation allocation;
- gtk_widget_get_allocation(GTK_WIDGET(elem.widget), &allocation);
- if (in_region(&allocation, &x, &y))
- return elem;
- }
- }
-
- struct header_element_data elem_none = { .widget=NULL};
- return elem_none;
-}
-
-static bool
-streq(const char *str1,
- const char *str2)
-{
- if (!str1 && !str2)
- return true;
-
- if (str1 && str2)
- return strcmp(str1, str2) == 0;
-
- return false;
-}
-
-enum decoration_type {
- DECORATION_TYPE_NONE,
- DECORATION_TYPE_ALL,
- DECORATION_TYPE_TITLE_ONLY
-};
-
-enum component {
- NONE = 0,
- SHADOW,
- HEADER,
-};
-
-struct seat {
- struct libdecor_plugin_gtk *plugin_gtk;
-
- char *name;
-
- struct wl_seat *wl_seat;
- struct wl_pointer *wl_pointer;
- struct wl_touch *wl_touch;
-
- struct wl_surface *cursor_surface;
- struct wl_cursor *current_cursor;
- int cursor_scale;
- struct wl_list cursor_outputs;
-
- struct wl_cursor_theme *cursor_theme;
- /* cursors for resize edges and corners */
- struct wl_cursor *cursors[ARRAY_LENGTH(cursor_names)];
- struct wl_cursor *cursor_left_ptr;
-
- struct wl_surface *pointer_focus;
- struct wl_surface *touch_focus;
-
- int pointer_x, pointer_y;
-
- uint32_t touch_down_time_stamp;
-
- uint32_t serial;
-
- bool grabbed;
-
- struct wl_list link;
-};
-
-struct output {
- struct libdecor_plugin_gtk *plugin_gtk;
-
- struct wl_output *wl_output;
- uint32_t id;
- int scale;
-
- struct wl_list link;
-};
-
-struct buffer {
- struct wl_buffer *wl_buffer;
- bool in_use;
- bool is_detached;
-
- void *data;
- size_t data_size;
- int width;
- int height;
- int scale;
- int buffer_width;
- int buffer_height;
-};
-
-struct border_component {
- enum component type;
- struct wl_surface *wl_surface;
- struct wl_subsurface *wl_subsurface;
- struct buffer *buffer;
- bool opaque;
- struct wl_list output_list;
- int scale;
-
- struct wl_list child_components; /* border_component::link */
- struct wl_list link; /* border_component::child_components */
-};
-
-struct surface_output {
- struct output *output;
- struct wl_list link;
-};
-
-struct cursor_output {
- struct output *output;
- struct wl_list link;
-};
-
-struct libdecor_frame_gtk {
- struct libdecor_frame frame;
-
- struct libdecor_plugin_gtk *plugin_gtk;
-
- int content_width;
- int content_height;
-
- enum libdecor_window_state window_state;
-
- enum decoration_type decoration_type;
-
- char *title;
-
- enum libdecor_capabilities capabilities;
-
- struct border_component *active;
- struct border_component *touch_active;
-
- struct border_component *focus;
- struct border_component *grab;
-
- bool shadow_showing;
- struct border_component shadow;
-
- GtkWidget *window; /* offscreen window for rendering */
- GtkWidget *header; /* header bar with widgets */
- struct border_component headerbar;
- struct header_element_data hdr_focus;
-
- /* store pre-processed shadow tile */
- cairo_surface_t *shadow_blur;
-
- struct wl_list link;
-
- struct {
- enum titlebar_gesture_state state;
- int button_pressed_count;
- uint32_t first_pressed_button;
- uint32_t first_pressed_time;
- double pressed_x;
- double pressed_y;
- uint32_t pressed_serial;
- } titlebar_gesture;
-};
-
-struct libdecor_plugin_gtk {
- struct libdecor_plugin plugin;
-
- struct wl_callback *globals_callback;
- struct wl_callback *globals_callback_shm;
-
- struct libdecor *context;
-
- struct wl_registry *wl_registry;
- struct wl_subcompositor *wl_subcompositor;
- struct wl_compositor *wl_compositor;
-
- struct wl_shm *wl_shm;
- struct wl_callback *shm_callback;
- bool has_argb;
-
- struct wl_list visible_frame_list;
- struct wl_list seat_list;
- struct wl_list output_list;
-
- char *cursor_theme_name;
- int cursor_size;
-
- uint32_t color_scheme_setting;
-
- int double_click_time_ms;
- int drag_threshold;
-
- bool handle_cursor;
-};
-
-static const char *libdecor_gtk_proxy_tag = "libdecor-gtk";
-
-static bool
-own_proxy(struct wl_proxy *proxy)
-{
- if (!proxy)
- return false;
-
- return (wl_proxy_get_tag(proxy) == &libdecor_gtk_proxy_tag);
-}
-
-static bool
-own_surface(struct wl_surface *surface)
-{
- return own_proxy((struct wl_proxy *) surface);
-}
-
-static bool
-own_output(struct wl_output *output)
-{
- return own_proxy((struct wl_proxy *) output);
-}
-
-static bool
-moveable(struct libdecor_frame_gtk *frame_gtk) {
- return libdecor_frame_has_capability(&frame_gtk->frame,
- LIBDECOR_ACTION_MOVE);
-}
-
-static bool
-resizable(struct libdecor_frame_gtk *frame_gtk) {
- return libdecor_frame_has_capability(&frame_gtk->frame,
- LIBDECOR_ACTION_RESIZE);
-}
-
-static bool
-minimizable(struct libdecor_frame_gtk *frame_gtk) {
- return libdecor_frame_has_capability(&frame_gtk->frame,
- LIBDECOR_ACTION_MINIMIZE);
-}
-
-static bool
-closeable(struct libdecor_frame_gtk *frame_gtk) {
- return libdecor_frame_has_capability(&frame_gtk->frame,
- LIBDECOR_ACTION_CLOSE);
-}
-
-static void
-buffer_free(struct buffer *buffer);
-
-static void
-draw_border_component(struct libdecor_frame_gtk *frame_gtk,
- struct border_component *border_component,
- enum component component);
-
-static void
-send_cursor(struct seat *seat);
-
-static bool
-update_local_cursor(struct seat *seat);
-
-static void
-libdecor_plugin_gtk_destroy(struct libdecor_plugin *plugin)
-{
- struct libdecor_plugin_gtk *plugin_gtk =
- (struct libdecor_plugin_gtk *) plugin;
- struct seat *seat, *seat_tmp;
- struct output *output, *output_tmp;
- struct libdecor_frame_gtk *frame, *frame_tmp;
-
- if (plugin_gtk->globals_callback)
- wl_callback_destroy(plugin_gtk->globals_callback);
- if (plugin_gtk->globals_callback_shm)
- wl_callback_destroy(plugin_gtk->globals_callback_shm);
- if (plugin_gtk->shm_callback)
- wl_callback_destroy(plugin_gtk->shm_callback);
- wl_registry_destroy(plugin_gtk->wl_registry);
-
- wl_list_for_each_safe(seat, seat_tmp, &plugin_gtk->seat_list, link) {
- struct cursor_output *cursor_output, *tmp;
-
- if (seat->wl_pointer)
- wl_pointer_destroy(seat->wl_pointer);
- if (seat->wl_touch)
- wl_touch_destroy(seat->wl_touch);
- if (seat->cursor_surface)
- wl_surface_destroy(seat->cursor_surface);
- wl_seat_destroy(seat->wl_seat);
- if (seat->cursor_theme)
- wl_cursor_theme_destroy(seat->cursor_theme);
-
- wl_list_for_each_safe(cursor_output, tmp, &seat->cursor_outputs, link) {
- wl_list_remove(&cursor_output->link);
- free(cursor_output);
- }
-
- free(seat->name);
- free(seat);
- }
-
- wl_list_for_each_safe(output, output_tmp,
- &plugin_gtk->output_list, link) {
- if (wl_output_get_version (output->wl_output) >=
- WL_OUTPUT_RELEASE_SINCE_VERSION)
- wl_output_release(output->wl_output);
- else
- wl_output_destroy(output->wl_output);
- free(output);
- }
-
- wl_list_for_each_safe(frame, frame_tmp,
- &plugin_gtk->visible_frame_list, link) {
- wl_list_remove(&frame->link);
- }
-
- free(plugin_gtk->cursor_theme_name);
-
- if (plugin_gtk->wl_shm)
- wl_shm_destroy(plugin_gtk->wl_shm);
-
- if (plugin_gtk->wl_compositor)
- wl_compositor_destroy(plugin_gtk->wl_compositor);
- if (plugin_gtk->wl_subcompositor)
- wl_subcompositor_destroy(plugin_gtk->wl_subcompositor);
-
- libdecor_plugin_release(&plugin_gtk->plugin);
- free(plugin_gtk);
-}
-
-static struct libdecor_frame_gtk *
-libdecor_frame_gtk_new(struct libdecor_plugin_gtk *plugin_gtk)
-{
- struct libdecor_frame_gtk *frame_gtk = zalloc(sizeof *frame_gtk);
- cairo_t *cr;
-
- static const int size = 128;
- static const int boundary = 32;
-
- frame_gtk->plugin_gtk = plugin_gtk;
- frame_gtk->shadow_blur = cairo_image_surface_create(
- CAIRO_FORMAT_ARGB32, size, size);
- wl_list_insert(&plugin_gtk->visible_frame_list, &frame_gtk->link);
-
- cr = cairo_create(frame_gtk->shadow_blur);
- cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
- cairo_set_source_rgba(cr, 0, 0, 0, 1);
- cairo_rectangle(cr, boundary, boundary,
- size - 2 * boundary,
- size - 2 * boundary);
- cairo_fill(cr);
- cairo_destroy(cr);
- blur_surface(frame_gtk->shadow_blur, 64);
-
- return frame_gtk;
-}
-
-static int
-libdecor_plugin_gtk_get_fd(struct libdecor_plugin *plugin)
-{
- struct libdecor_plugin_gtk *plugin_gtk =
- (struct libdecor_plugin_gtk *) plugin;
- struct wl_display *wl_display =
- libdecor_get_wl_display(plugin_gtk->context);
-
- return wl_display_get_fd(wl_display);
-}
-
-static int
-libdecor_plugin_gtk_dispatch(struct libdecor_plugin *plugin,
- int timeout)
-{
- struct libdecor_plugin_gtk *plugin_gtk =
- (struct libdecor_plugin_gtk *) plugin;
- struct wl_display *wl_display =
- libdecor_get_wl_display(plugin_gtk->context);
- struct pollfd fds[1];
- int ret;
- int dispatch_count = 0;
-
- while (g_main_context_iteration(NULL, FALSE));
-
- while (wl_display_prepare_read(wl_display) != 0)
- dispatch_count += wl_display_dispatch_pending(wl_display);
-
- if (wl_display_flush(wl_display) < 0 &&
- errno != EAGAIN) {
- wl_display_cancel_read(wl_display);
- return -errno;
- }
-
- fds[0] = (struct pollfd) { wl_display_get_fd(wl_display), POLLIN };
-
- ret = poll(fds, ARRAY_SIZE (fds), timeout);
- if (ret > 0) {
- if (fds[0].revents & POLLIN) {
- wl_display_read_events(wl_display);
- dispatch_count += wl_display_dispatch_pending(wl_display);
- return dispatch_count;
- } else {
- wl_display_cancel_read(wl_display);
- return dispatch_count;
- }
- } else if (ret == 0) {
- wl_display_cancel_read(wl_display);
- return dispatch_count;
- } else {
- wl_display_cancel_read(wl_display);
- return -errno;
- }
-}
-
-static void
-libdecor_plugin_gtk_set_handle_application_cursor(struct libdecor_plugin *plugin,
- bool handle_cursor)
-{
- struct libdecor_plugin_gtk *plugin_gtk =
- (struct libdecor_plugin_gtk *) plugin;
-
- plugin_gtk->handle_cursor = handle_cursor;
-}
-
-static struct libdecor_frame *
-libdecor_plugin_gtk_frame_new(struct libdecor_plugin *plugin)
-{
- struct libdecor_plugin_gtk *plugin_gtk =
- (struct libdecor_plugin_gtk *) plugin;
- struct libdecor_frame_gtk *frame_gtk;
-
- frame_gtk = libdecor_frame_gtk_new(plugin_gtk);
-
- return &frame_gtk->frame;
-}
-
-static void
-toggle_maximized(struct libdecor_frame *const frame)
-{
- if (!resizable((struct libdecor_frame_gtk *)frame))
- return;
-
- if (!(libdecor_frame_get_window_state(frame) &
- LIBDECOR_WINDOW_STATE_MAXIMIZED))
- libdecor_frame_set_maximized(frame);
- else
- libdecor_frame_unset_maximized(frame);
-}
-
-static void
-buffer_release(void *user_data,
- struct wl_buffer *wl_buffer)
-{
- struct buffer *buffer = user_data;
-
- if (buffer->is_detached)
- buffer_free(buffer);
- else
- buffer->in_use = false;
-}
-
-static const struct wl_buffer_listener buffer_listener = {
- buffer_release
-};
-
-static struct buffer *
-create_shm_buffer(struct libdecor_plugin_gtk *plugin_gtk,
- int width,
- int height,
- bool opaque,
- int scale)
-{
- struct wl_shm_pool *pool;
- int fd, size, buffer_width, buffer_height, stride;
- void *data;
- struct buffer *buffer;
- enum wl_shm_format buf_fmt;
-
- buffer_width = width * scale;
- buffer_height = height * scale;
- stride = buffer_width * 4;
- size = stride * buffer_height;
-
- fd = libdecor_os_create_anonymous_file(size);
- if (fd < 0) {
- fprintf(stderr, "creating a buffer file for %d B failed: %s\n",
- size, strerror(errno));
- return NULL;
- }
-
- data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if (data == MAP_FAILED) {
- fprintf(stderr, "mmap failed: %s\n", strerror(errno));
- close(fd);
- return NULL;
- }
-
- buf_fmt = opaque ? WL_SHM_FORMAT_XRGB8888 : WL_SHM_FORMAT_ARGB8888;
-
- pool = wl_shm_create_pool(plugin_gtk->wl_shm, fd, size);
- buffer = zalloc(sizeof *buffer);
- buffer->wl_buffer = wl_shm_pool_create_buffer(pool, 0,
- buffer_width, buffer_height,
- stride,
- buf_fmt);
- wl_buffer_add_listener(buffer->wl_buffer, &buffer_listener, buffer);
- wl_shm_pool_destroy(pool);
- close(fd);
-
- buffer->data = data;
- buffer->data_size = size;
- buffer->width = width;
- buffer->height = height;
- buffer->scale = scale;
- buffer->buffer_width = buffer_width;
- buffer->buffer_height = buffer_height;
-
- return buffer;
-}
-
-static void
-buffer_free(struct buffer *buffer)
-{
- if (buffer->wl_buffer) {
- wl_buffer_destroy(buffer->wl_buffer);
- munmap(buffer->data, buffer->data_size);
- buffer->wl_buffer = NULL;
- buffer->in_use = false;
- }
- free(buffer);
-}
-
-static void
-free_border_component(struct border_component *border_component)
-{
- if (border_component->wl_surface) {
- wl_subsurface_destroy(border_component->wl_subsurface);
- border_component->wl_subsurface = NULL;
- wl_surface_destroy(border_component->wl_surface);
- border_component->wl_surface = NULL;
- }
- if (border_component->buffer) {
- buffer_free(border_component->buffer);
- border_component->buffer = NULL;
- }
- if (border_component->output_list.next != NULL) {
- struct surface_output *surface_output, *surface_output_tmp;
- wl_list_for_each_safe(surface_output, surface_output_tmp,
- &border_component->output_list, link) {
- wl_list_remove(&surface_output->link);
- free(surface_output);
- }
- }
-}
-
-static void
-libdecor_plugin_gtk_frame_free(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame)
-{
- struct libdecor_frame_gtk *frame_gtk =
- (struct libdecor_frame_gtk *) frame;
-
- g_clear_pointer (&frame_gtk->header, gtk_widget_destroy);
- g_clear_pointer (&frame_gtk->window, gtk_widget_destroy);
-
- free_border_component(&frame_gtk->headerbar);
- free_border_component(&frame_gtk->shadow);
- frame_gtk->shadow_showing = false;
-
- g_clear_pointer (&frame_gtk->shadow_blur, cairo_surface_destroy);
-
- g_clear_pointer (&frame_gtk->title, free);
-
- frame_gtk->decoration_type = DECORATION_TYPE_NONE;
-
- if (frame_gtk->link.next != NULL)
- wl_list_remove(&frame_gtk->link);
-}
-
-static bool
-is_border_surfaces_showing(struct libdecor_frame_gtk *frame_gtk)
-{
- return frame_gtk->shadow_showing;
-}
-
-static void
-hide_border_component(struct border_component *border_component)
-{
- if (!border_component->wl_surface)
- return;
-
- wl_surface_attach(border_component->wl_surface, NULL, 0, 0);
- wl_surface_commit(border_component->wl_surface);
-}
-
-static void
-hide_border_surfaces(struct libdecor_frame_gtk *frame_gtk)
-{
- hide_border_component(&frame_gtk->shadow);
- frame_gtk->shadow_showing = false;
-}
-
-static struct border_component *
-get_component_for_surface(struct libdecor_frame_gtk *frame_gtk,
- const struct wl_surface *surface)
-{
- if (frame_gtk->shadow.wl_surface == surface)
- return &frame_gtk->shadow;
- if (frame_gtk->headerbar.wl_surface == surface)
- return &frame_gtk->headerbar;
- return NULL;
-}
-
-static bool
-redraw_scale(struct libdecor_frame_gtk *frame_gtk,
- struct border_component *cmpnt)
-{
- struct surface_output *surface_output;
- int scale = 1;
-
- if (cmpnt->wl_surface == NULL)
- return false;
-
- wl_list_for_each(surface_output, &cmpnt->output_list, link) {
- scale = MAX(scale, surface_output->output->scale);
- }
- if (scale != cmpnt->scale) {
- cmpnt->scale = scale;
- if ((frame_gtk->decoration_type != DECORATION_TYPE_NONE) &&
- ((cmpnt->type != SHADOW) || is_border_surfaces_showing(frame_gtk))) {
- draw_border_component(frame_gtk, cmpnt, cmpnt->type);
- return true;
- }
- }
- return false;
-}
-
-static bool
-add_surface_output(struct libdecor_plugin_gtk *plugin_gtk,
- struct wl_output *wl_output,
- struct wl_list *list)
-{
- struct output *output;
- struct surface_output *surface_output;
-
- if (!own_output(wl_output))
- return false;
-
- output = wl_output_get_user_data(wl_output);
-
- if (output == NULL)
- return false;
-
- surface_output = zalloc(sizeof *surface_output);
- surface_output->output = output;
- wl_list_insert(list, &surface_output->link);
- return true;
-}
-
-static void
-surface_enter(void *data,
- struct wl_surface *wl_surface,
- struct wl_output *wl_output)
-{
- struct libdecor_frame_gtk *frame_gtk = data;
- struct border_component *cmpnt;
-
- if (!(own_surface(wl_surface) && own_output(wl_output)))
- return;
-
- cmpnt = get_component_for_surface(frame_gtk, wl_surface);
- if (cmpnt == NULL)
- return;
-
- if (!add_surface_output(frame_gtk->plugin_gtk, wl_output,
- &cmpnt->output_list))
- return;
-
- if (redraw_scale(frame_gtk, cmpnt))
- libdecor_frame_toplevel_commit(&frame_gtk->frame);
-}
-
-static bool
-remove_surface_output(struct wl_list *list, const struct wl_output *wl_output)
-{
- struct surface_output *surface_output;
- wl_list_for_each(surface_output, list, link) {
- if (surface_output->output->wl_output == wl_output) {
- wl_list_remove(&surface_output->link);
- free(surface_output);
- return true;
- }
- }
- return false;
-}
-
-static void
-surface_leave(void *data,
- struct wl_surface *wl_surface,
- struct wl_output *wl_output)
-{
- struct libdecor_frame_gtk *frame_gtk = data;
- struct border_component *cmpnt;
-
- if (!(own_surface(wl_surface) && own_output(wl_output)))
- return;
-
- cmpnt = get_component_for_surface(frame_gtk, wl_surface);
- if (cmpnt == NULL)
- return;
-
- if (!remove_surface_output(&cmpnt->output_list, wl_output))
- return;
-
- if (redraw_scale(frame_gtk, cmpnt))
- libdecor_frame_toplevel_commit(&frame_gtk->frame);
-}
-
-static struct wl_surface_listener surface_listener = {
- surface_enter,
- surface_leave,
-};
-
-static void
-create_surface_subsurface_pair(struct libdecor_frame_gtk *frame_gtk,
- struct wl_surface **out_wl_surface,
- struct wl_subsurface **out_wl_subsurface)
-{
- struct libdecor_plugin_gtk *plugin_gtk = frame_gtk->plugin_gtk;
- struct libdecor_frame *frame = &frame_gtk->frame;
- struct wl_compositor *wl_compositor = plugin_gtk->wl_compositor;
- struct wl_subcompositor *wl_subcompositor = plugin_gtk->wl_subcompositor;
- struct wl_surface *wl_surface;
- struct wl_surface *parent;
- struct wl_subsurface *wl_subsurface;
-
- wl_surface = wl_compositor_create_surface(wl_compositor);
- wl_proxy_set_tag((struct wl_proxy *) wl_surface,
- &libdecor_gtk_proxy_tag);
-
- parent = libdecor_frame_get_wl_surface(frame);
- wl_subsurface = wl_subcompositor_get_subsurface(wl_subcompositor,
- wl_surface,
- parent);
-
- *out_wl_surface = wl_surface;
- *out_wl_subsurface = wl_subsurface;
-}
-
-static void
-ensure_component(struct libdecor_frame_gtk *frame_gtk,
- struct border_component *cmpnt)
-{
- if (!cmpnt->wl_surface) {
- wl_list_init(&cmpnt->output_list);
- cmpnt->scale = 1;
- create_surface_subsurface_pair(frame_gtk,
- &cmpnt->wl_surface,
- &cmpnt->wl_subsurface);
- wl_surface_add_listener(cmpnt->wl_surface, &surface_listener,
- frame_gtk);
- }
-}
-
-static void
-ensure_border_surfaces(struct libdecor_frame_gtk *frame_gtk)
-{
- frame_gtk->shadow.type = SHADOW;
- frame_gtk->shadow.opaque = false;
- ensure_component(frame_gtk, &frame_gtk->shadow);
-}
-
-static void
-ensure_title_bar_surfaces(struct libdecor_frame_gtk *frame_gtk)
-{
- GtkStyleContext *context_hdr;
-
- frame_gtk->headerbar.type = HEADER;
- frame_gtk->headerbar.opaque = false;
- ensure_component(frame_gtk, &frame_gtk->headerbar);
-
- if (frame_gtk->shadow.wl_surface) {
- wl_subsurface_place_above(frame_gtk->headerbar.wl_subsurface,
- frame_gtk->shadow.wl_surface);
- }
-
- /* create an offscreen window with a header bar */
- /* TODO: This should only be done once at frame consutrction, but then
- * the window and headerbar would not change style (e.g. backdrop)
- * after construction. So we just destroy and re-create them.
- */
- /* avoid warning when restoring previously turned off decoration */
- if (GTK_IS_WIDGET(frame_gtk->header)) {
- gtk_widget_destroy(frame_gtk->header);
- frame_gtk->header = NULL;
- }
- /* avoid warning when restoring previously turned off decoration */
- if (GTK_IS_WIDGET(frame_gtk->window)) {
- gtk_widget_destroy(frame_gtk->window);
- frame_gtk->window = NULL;
- }
- frame_gtk->window = gtk_offscreen_window_new();
- frame_gtk->header = gtk_header_bar_new();
-
- g_object_get(gtk_widget_get_settings(frame_gtk->window),
- "gtk-double-click-time",
- &frame_gtk->plugin_gtk->double_click_time_ms,
- "gtk-dnd-drag-threshold",
- &frame_gtk->plugin_gtk->drag_threshold,
- NULL);
- /* set as "default" decoration */
- g_object_set(frame_gtk->header,
- "title", libdecor_frame_get_title(&frame_gtk->frame),
- "has-subtitle", FALSE,
- "show-close-button", TRUE,
- NULL);
-
- context_hdr = gtk_widget_get_style_context(frame_gtk->header);
- gtk_style_context_add_class(context_hdr, GTK_STYLE_CLASS_TITLEBAR);
- gtk_style_context_add_class(context_hdr, "default-decoration");
-
- gtk_window_set_titlebar(GTK_WINDOW(frame_gtk->window), frame_gtk->header);
- gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(frame_gtk->header), TRUE);
-
- gtk_window_set_resizable(GTK_WINDOW(frame_gtk->window), resizable(frame_gtk));
-}
-
-static void
-calculate_component_size(struct libdecor_frame_gtk *frame_gtk,
- enum component component,
- int *component_x,
- int *component_y,
- int *component_width,
- int *component_height)
-{
- struct libdecor_frame *frame = &frame_gtk->frame;
- int content_width, content_height;
-
- content_width = libdecor_frame_get_content_width(frame);
- content_height = libdecor_frame_get_content_height(frame);
-
- /* avoid warning when restoring previously turned off decoration */
- const int title_height =
- GTK_IS_WIDGET(frame_gtk->header)
- ? gtk_widget_get_allocated_height(frame_gtk->header) : 0;
-
- switch (component) {
- case NONE:
- *component_width = 0;
- *component_height = 0;
- return;
- case SHADOW:
- *component_x = -(int)SHADOW_MARGIN;
- *component_y = -(int)(SHADOW_MARGIN+title_height);
- *component_width = content_width + 2 * SHADOW_MARGIN;
- *component_height = content_height
- + 2 * SHADOW_MARGIN
- + title_height;
- return;
- case HEADER:
- *component_x = 0;
- /* reuse product of function call above */
- *component_y = - title_height;
- *component_width = gtk_widget_get_allocated_width(frame_gtk->header);
- /* reuse product of function call above */
- *component_height = title_height;
- return;
- }
-
- abort();
-}
-
-static void
-array_append(enum header_element **array, size_t *n, enum header_element item)
-{
- (*n)++;
- *array = realloc(*array, (*n) * sizeof (enum header_element));
- (*array)[(*n)-1] = item;
-}
-
-static void
-draw_header_background(struct libdecor_frame_gtk *frame_gtk,
- cairo_t *cr)
-{
- /* background */
- GtkAllocation allocation;
- GtkStyleContext* style;
-
- gtk_widget_get_allocation(GTK_WIDGET(frame_gtk->header), &allocation);
- style = gtk_widget_get_style_context(frame_gtk->header);
- gtk_render_background(style, cr, allocation.x, allocation.y, allocation.width, allocation.height);
-}
-
-static void
-draw_header_title(struct libdecor_frame_gtk *frame_gtk,
- cairo_surface_t *surface)
-{
- /* title */
- GtkWidget *label;
- GtkAllocation allocation;
- cairo_surface_t *label_surface = NULL;
- cairo_t *cr;
-
- label = find_widget_by_type(frame_gtk->header, HEADER_TITLE).widget;
- gtk_widget_get_allocation(label, &allocation);
-
- /* create subsection in which to draw label */
- label_surface = cairo_surface_create_for_rectangle(
- surface,
- allocation.x, allocation.y,
- allocation.width, allocation.height);
- cr = cairo_create(label_surface);
- gtk_widget_size_allocate(label, &allocation);
- gtk_widget_draw(label, cr);
- cairo_destroy(cr);
- cairo_surface_destroy(label_surface);
-}
-
-static void
-draw_header_button(struct libdecor_frame_gtk *frame_gtk,
- cairo_t *cr,
- cairo_surface_t *surface,
- enum header_element button_type,
- enum libdecor_window_state window_state)
-{
- struct header_element_data elem;
- GtkWidget *button;
- GtkStyleContext* button_style;
- GtkStateFlags style_state;
-
- GtkAllocation allocation;
-
- gchar *icon_name;
- int scale;
- GtkWidget *icon_widget;
- GtkAllocation allocation_icon;
- GtkIconInfo* icon_info;
-
- double sx, sy;
-
- gint icon_width, icon_height;
-
- GdkPixbuf* icon_pixbuf;
- cairo_surface_t* icon_surface;
-
- gint width = 0, height = 0;
-
- gint left = 0, top = 0, right = 0, bottom = 0;
- GtkBorder border;
-
- GtkBorder padding;
-
- elem = find_widget_by_type(frame_gtk->header, button_type);
- button = elem.widget;
- if (!button)
- return;
- button_style = gtk_widget_get_style_context(button);
- style_state = elem.state;
-
- /* change style based on window state and focus */
- if (!(window_state & LIBDECOR_WINDOW_STATE_ACTIVE)) {
- style_state |= GTK_STATE_FLAG_BACKDROP;
- }
- if (frame_gtk->hdr_focus.widget == button) {
- style_state |= GTK_STATE_FLAG_PRELIGHT;
- if (frame_gtk->hdr_focus.state & GTK_STATE_FLAG_ACTIVE) {
- style_state |= GTK_STATE_FLAG_ACTIVE;
- }
- }
-
- /* background */
- gtk_widget_get_clip(button, &allocation);
-
- gtk_style_context_save(button_style);
- gtk_style_context_set_state(button_style, style_state);
- gtk_render_background(button_style, cr,
- allocation.x, allocation.y,
- allocation.width, allocation.height);
- gtk_render_frame(button_style, cr,
- allocation.x, allocation.y,
- allocation.width, allocation.height);
- gtk_style_context_restore(button_style);
-
- /* symbol */
- switch (button_type) {
- case HEADER_MIN:
- icon_name = "window-minimize-symbolic";
- break;
- case HEADER_MAX:
- icon_name = (window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED) ?
- "window-restore-symbolic" :
- "window-maximize-symbolic";
- break;
- case HEADER_CLOSE:
- icon_name = "window-close-symbolic";
- break;
- default:
- icon_name = NULL;
- break;
- }
-
- /* get scale */
- cairo_surface_get_device_scale(surface, &sx, &sy);
- scale = (sx+sy) / 2.0;
-
- /* get original icon dimensions */
- icon_widget = gtk_bin_get_child(GTK_BIN(button));
- gtk_widget_get_allocation(icon_widget, &allocation_icon);
-
- /* icon info */
- if (!gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &icon_width, &icon_height)) {
- icon_width = 16;
- icon_height = 16;
- }
- icon_info = gtk_icon_theme_lookup_icon_for_scale(
- gtk_icon_theme_get_default(), icon_name,
- icon_width, scale, (GtkIconLookupFlags)0);
-
- /* icon pixel buffer*/
- gtk_style_context_save(button_style);
- gtk_style_context_set_state(button_style, style_state);
- icon_pixbuf = gtk_icon_info_load_symbolic_for_context(
- icon_info, button_style, NULL, NULL);
- icon_surface = gdk_cairo_surface_create_from_pixbuf(icon_pixbuf, scale, NULL);
- gtk_style_context_restore(button_style);
-
- /* dimensions and position */
- gtk_style_context_get(button_style, gtk_style_context_get_state(button_style),
- "min-width", &width, "min-height", &height, NULL);
-
- if (width < icon_width)
- width = icon_width;
- if (height < icon_height)
- height = icon_height;
-
- gtk_style_context_get_border(button_style, gtk_style_context_get_state(button_style), &border);
- left += border.left;
- right += border.right;
- top += border.top;
- bottom += border.bottom;
-
- gtk_style_context_get_padding(button_style, gtk_style_context_get_state(button_style), &padding);
- left += padding.left;
- right += padding.right;
- top += padding.top;
- bottom += padding.bottom;
-
- width += left + right;
- height += top + bottom;
-
- gtk_render_icon_surface(gtk_widget_get_style_context(icon_widget),
- cr, icon_surface,
- allocation.x + ((width - icon_width) / 2),
- allocation.y + ((height - icon_height) / 2));
- cairo_paint(cr);
- cairo_surface_destroy(icon_surface);
- g_object_unref(icon_pixbuf);
-}
-
-static void
-draw_header_buttons(struct libdecor_frame_gtk *frame_gtk,
- cairo_t *cr,
- cairo_surface_t *surface)
-{
- /* buttons */
- enum libdecor_window_state window_state;
- enum header_element *buttons = NULL;
- size_t nbuttons = 0;
-
- window_state = libdecor_frame_get_window_state(
- (struct libdecor_frame*)frame_gtk);
-
- /* set buttons by capability */
- if (minimizable(frame_gtk))
- array_append(&buttons, &nbuttons, HEADER_MIN);
- if (resizable(frame_gtk))
- array_append(&buttons, &nbuttons, HEADER_MAX);
- if (closeable(frame_gtk))
- array_append(&buttons, &nbuttons, HEADER_CLOSE);
-
- for (size_t i = 0; i < nbuttons; i++) {
- draw_header_button(frame_gtk, cr, surface, buttons[i], window_state);
- } /* loop buttons */
- free(buttons);
-}
-
-static void
-draw_header(struct libdecor_frame_gtk *frame_gtk,
- cairo_t *cr,
- cairo_surface_t *surface)
-{
- draw_header_background(frame_gtk, cr);
- draw_header_title(frame_gtk, surface);
- draw_header_buttons(frame_gtk, cr, surface);
-}
-
-static void
-draw_component_content(struct libdecor_frame_gtk *frame_gtk,
- struct buffer *buffer,
- int component_width,
- int component_height,
- enum component component)
-{
- cairo_surface_t *surface;
- cairo_t *cr;
-
- /* clear buffer */
- memset(buffer->data, 0, buffer->data_size);
-
- surface = cairo_image_surface_create_for_data(
- buffer->data, CAIRO_FORMAT_ARGB32,
- buffer->buffer_width, buffer->buffer_height,
- cairo_format_stride_for_width(
- CAIRO_FORMAT_ARGB32,
- buffer->buffer_width)
- );
-
- cr = cairo_create(surface);
-
- cairo_surface_set_device_scale(surface, buffer->scale, buffer->scale);
-
- /* background */
- switch (component) {
- case NONE:
- break;
- case SHADOW:
- render_shadow(cr,
- frame_gtk->shadow_blur,
- -(int)SHADOW_MARGIN/2,
- -(int)SHADOW_MARGIN/2,
- buffer->width + SHADOW_MARGIN,
- buffer->height + SHADOW_MARGIN,
- 64,
- 64);
- break;
- case HEADER:
- draw_header(frame_gtk, cr, surface);
- break;
- }
-
- /* mask the toplevel surface */
- if (component == SHADOW) {
- int component_x, component_y, component_width, component_height;
- calculate_component_size(frame_gtk, component,
- &component_x, &component_y,
- &component_width, &component_height);
- cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
- cairo_rectangle(cr, -component_x, -component_y,
- libdecor_frame_get_content_width(
- &frame_gtk->frame),
- libdecor_frame_get_content_height(
- &frame_gtk->frame));
- cairo_fill(cr);
- }
-
- cairo_destroy(cr);
- cairo_surface_destroy(surface);
-}
-
-static void
-set_component_input_region(struct libdecor_frame_gtk *frame_gtk,
- struct border_component *border_component)
-{
- if (border_component->type == SHADOW && frame_gtk->shadow_showing) {
- struct wl_region *input_region;
- int component_x;
- int component_y;
- int component_width;
- int component_height;
-
- calculate_component_size(frame_gtk, border_component->type,
- &component_x, &component_y,
- &component_width, &component_height);
-
- /*
- * the input region is the outer surface size minus the inner
- * content size
- */
- input_region = wl_compositor_create_region(
- frame_gtk->plugin_gtk->wl_compositor);
- wl_region_add(input_region, 0, 0,
- component_width, component_height);
- wl_region_subtract(input_region, -component_x, -component_y,
- libdecor_frame_get_content_width(&frame_gtk->frame),
- libdecor_frame_get_content_height(&frame_gtk->frame));
- wl_surface_set_input_region(border_component->wl_surface,
- input_region);
- wl_region_destroy(input_region);
- }
-}
-
-static void
-draw_border_component(struct libdecor_frame_gtk *frame_gtk,
- struct border_component *border_component,
- enum component component)
-{
- struct libdecor_plugin_gtk *plugin_gtk = frame_gtk->plugin_gtk;
- struct buffer *old_buffer;
- struct buffer *buffer = NULL;
- int component_x;
- int component_y;
- int component_width;
- int component_height;
- int scale = border_component->scale;
-
- if (border_component->wl_surface == NULL)
- return;
-
- calculate_component_size(frame_gtk, component,
- &component_x, &component_y,
- &component_width, &component_height);
-
- set_component_input_region(frame_gtk, border_component);
-
- old_buffer = border_component->buffer;
- if (old_buffer) {
- if (!old_buffer->in_use &&
- old_buffer->buffer_width == component_width * scale &&
- old_buffer->buffer_height == component_height * scale) {
- buffer = old_buffer;
- } else {
- buffer_free(old_buffer);
- border_component->buffer = NULL;
- }
- }
-
- if (!buffer)
- buffer = create_shm_buffer(plugin_gtk,
- component_width,
- component_height,
- border_component->opaque,
- border_component->scale);
-
- draw_component_content(frame_gtk, buffer,
- component_width, component_height,
- component);
-
- wl_surface_attach(border_component->wl_surface, buffer->wl_buffer, 0, 0);
- wl_surface_set_buffer_scale(border_component->wl_surface, buffer->scale);
- buffer->in_use = true;
- wl_surface_commit(border_component->wl_surface);
- wl_surface_damage_buffer(border_component->wl_surface, 0, 0,
- component_width * scale,
- component_height * scale);
- wl_subsurface_set_position(border_component->wl_subsurface,
- component_x, component_y);
-
- border_component->buffer = buffer;
-}
-
-static void
-draw_border(struct libdecor_frame_gtk *frame_gtk)
-{
- draw_border_component(frame_gtk, &frame_gtk->shadow, SHADOW);
- frame_gtk->shadow_showing = true;
-}
-
-static void
-draw_title_bar(struct libdecor_frame_gtk *frame_gtk)
-{
- GtkAllocation allocation = {0, 0, frame_gtk->content_width, 0};
- enum libdecor_window_state state;
- GtkStyleContext *style;
- int pref_width;
- int current_min_w, current_min_h, current_max_w, current_max_h, W, H;
-
- state = libdecor_frame_get_window_state((struct libdecor_frame*)frame_gtk);
- style = gtk_widget_get_style_context(frame_gtk->window);
-
- if (!(state & LIBDECOR_WINDOW_STATE_ACTIVE)) {
- gtk_widget_set_state_flags(frame_gtk->window, GTK_STATE_FLAG_BACKDROP, true);
- } else {
- gtk_widget_unset_state_flags(frame_gtk->window, GTK_STATE_FLAG_BACKDROP);
- }
-
- if (libdecor_frame_is_floating(&frame_gtk->frame)) {
- gtk_style_context_remove_class(style, "maximized");
- } else {
- gtk_style_context_add_class(style, "maximized");
- }
-
- gtk_widget_show_all(frame_gtk->window);
-
- /* set default width, using an empty title to estimate its smallest admissible value */
- gtk_header_bar_set_title(GTK_HEADER_BAR(frame_gtk->header), "");
- gtk_widget_get_preferred_width(frame_gtk->header, NULL, &pref_width);
- gtk_header_bar_set_title(GTK_HEADER_BAR(frame_gtk->header),
- libdecor_frame_get_title(&frame_gtk->frame));
- libdecor_frame_get_min_content_size(&frame_gtk->frame, &current_min_w, &current_min_h);
- if (current_min_w < pref_width) {
- current_min_w = pref_width;
- libdecor_frame_set_min_content_size(&frame_gtk->frame, current_min_w, current_min_h);
- }
- libdecor_frame_get_max_content_size(&frame_gtk->frame, &current_max_w, &current_max_h);
- if (current_max_w && current_max_w < current_min_w) {
- libdecor_frame_set_max_content_size(&frame_gtk->frame, current_min_w, current_max_h);
- }
- W = libdecor_frame_get_content_width(&frame_gtk->frame);
- H = libdecor_frame_get_content_height(&frame_gtk->frame);
- if (W < current_min_w) {
- W = current_min_w;
- struct libdecor_state *libdecor_state = libdecor_state_new(W, H);
- libdecor_frame_commit(&frame_gtk->frame, libdecor_state, NULL);
- libdecor_state_free(libdecor_state);
- return;
- }
- /* set default height */
- gtk_widget_get_preferred_height(frame_gtk->header, NULL, &allocation.height);
-
- gtk_widget_size_allocate(frame_gtk->header, &allocation);
-
- draw_border_component(frame_gtk, &frame_gtk->headerbar, HEADER);
-}
-
-static void
-draw_decoration(struct libdecor_frame_gtk *frame_gtk)
-{
- switch (frame_gtk->decoration_type) {
- case DECORATION_TYPE_NONE:
- if (frame_gtk->link.next != NULL)
- wl_list_remove(&frame_gtk->link);
- if (is_border_surfaces_showing(frame_gtk))
- hide_border_surfaces(frame_gtk);
- hide_border_component(&frame_gtk->headerbar);
- break;
- case DECORATION_TYPE_ALL:
- /* show borders */
- ensure_border_surfaces(frame_gtk);
- draw_border(frame_gtk);
- /* show title bar */
- ensure_title_bar_surfaces(frame_gtk);
- draw_title_bar(frame_gtk);
- /* link frame */
- if (frame_gtk->link.next == NULL)
- wl_list_insert(
- &frame_gtk->plugin_gtk->visible_frame_list,
- &frame_gtk->link);
- break;
- case DECORATION_TYPE_TITLE_ONLY:
- /* hide borders */
- if (is_border_surfaces_showing(frame_gtk))
- hide_border_surfaces(frame_gtk);
- /* show title bar */
- ensure_title_bar_surfaces(frame_gtk);
- draw_title_bar(frame_gtk);
- /* link frame */
- if (frame_gtk->link.next == NULL)
- wl_list_insert(
- &frame_gtk->plugin_gtk->visible_frame_list,
- &frame_gtk->link);
- break;
- }
-}
-
-static enum decoration_type
-window_state_to_decoration_type(enum libdecor_window_state window_state)
-{
- if (window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN)
- return DECORATION_TYPE_NONE;
- else if (window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED ||
- window_state & LIBDECOR_WINDOW_STATE_TILED_LEFT ||
- window_state & LIBDECOR_WINDOW_STATE_TILED_RIGHT ||
- window_state & LIBDECOR_WINDOW_STATE_TILED_TOP ||
- window_state & LIBDECOR_WINDOW_STATE_TILED_BOTTOM)
- /* title bar, no shadows */
- return DECORATION_TYPE_TITLE_ONLY;
- else
- /* title bar, shadows */
- return DECORATION_TYPE_ALL;
-}
-
-static void
-libdecor_plugin_gtk_frame_commit(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame,
- struct libdecor_state *state,
- struct libdecor_configuration *configuration)
-{
- struct libdecor_frame_gtk *frame_gtk =
- (struct libdecor_frame_gtk *) frame;
- enum libdecor_window_state old_window_state;
- enum libdecor_window_state new_window_state;
- int old_content_width, old_content_height;
- int new_content_width, new_content_height;
- enum decoration_type old_decoration_type;
- enum decoration_type new_decoration_type;
-
- old_window_state = frame_gtk->window_state;
- new_window_state = libdecor_frame_get_window_state(frame);
-
- old_content_width = frame_gtk->content_width;
- old_content_height = frame_gtk->content_height;
- new_content_width = libdecor_frame_get_content_width(frame);
- new_content_height = libdecor_frame_get_content_height(frame);
-
- old_decoration_type = frame_gtk->decoration_type;
- new_decoration_type = window_state_to_decoration_type(new_window_state);
-
- if (old_decoration_type == new_decoration_type &&
- old_content_width == new_content_width &&
- old_content_height == new_content_height &&
- old_window_state == new_window_state)
- return;
-
- frame_gtk->content_width = new_content_width;
- frame_gtk->content_height = new_content_height;
- frame_gtk->window_state = new_window_state;
- frame_gtk->decoration_type = new_decoration_type;
-
- draw_decoration(frame_gtk);
-
- /* set fixed window size */
- if (!resizable(frame_gtk)) {
- libdecor_frame_set_min_content_size(frame,
- frame_gtk->content_width,
- frame_gtk->content_height);
- libdecor_frame_set_max_content_size(frame,
- frame_gtk->content_width,
- frame_gtk->content_height);
- }
-}
-
-static void
-libdecor_plugin_gtk_frame_property_changed(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame)
-{
- struct libdecor_frame_gtk *frame_gtk =
- (struct libdecor_frame_gtk *) frame;
- bool redraw_needed = false;
- const char *new_title;
-
- /*
- * when in SSD mode, the window title is not to be managed by GTK;
- * this is detected by frame_gtk->header not being a proper GTK widget
- */
- if (!GTK_IS_WIDGET(frame_gtk->header)) return;
-
- new_title = libdecor_frame_get_title(frame);
- if (!streq(frame_gtk->title, new_title))
- redraw_needed = true;
- free(frame_gtk->title);
- frame_gtk->title = NULL;
- if (new_title)
- frame_gtk->title = strdup(new_title);
-
- if (frame_gtk->capabilities != libdecor_frame_get_capabilities(frame)) {
- frame_gtk->capabilities = libdecor_frame_get_capabilities(frame);
- redraw_needed = true;
- }
-
- if (redraw_needed) {
- draw_decoration(frame_gtk);
- libdecor_frame_toplevel_commit(frame);
- }
-}
-
-static void
-update_component_focus(struct libdecor_frame_gtk *frame_gtk,
- struct wl_surface *surface,
- struct seat *seat)
-{
- static struct border_component *border_component;
- static struct border_component *child_component;
- static struct border_component *focus_component;
-
- border_component = get_component_for_surface(frame_gtk, surface);
-
- focus_component = border_component;
- wl_list_for_each(child_component, &border_component->child_components, link) {
- int component_x = 0, component_y = 0;
- int component_width = 0, component_height = 0;
-
- calculate_component_size(frame_gtk, child_component->type,
- &component_x, &component_y,
- &component_width, &component_height);
- if (seat->pointer_x >= component_x &&
- seat->pointer_x < component_x + component_width &&
- seat->pointer_y >= component_y &&
- seat->pointer_y < component_y + component_height) {
- focus_component = child_component;
- break;
- }
- }
-
- if (frame_gtk->grab)
- frame_gtk->active = frame_gtk->grab;
- else
- frame_gtk->active = focus_component;
- frame_gtk->focus = focus_component;
-
-}
-
-static void
-sync_active_component(struct libdecor_frame_gtk *frame_gtk,
- struct seat *seat)
-{
- struct border_component *old_active;
-
- if (!seat->pointer_focus)
- return;
-
- old_active = frame_gtk->active;
- update_component_focus(frame_gtk, seat->pointer_focus, seat);
- if (old_active != frame_gtk->active) {
- draw_decoration(frame_gtk);
- libdecor_frame_toplevel_commit(&frame_gtk->frame);
- }
-
- if (update_local_cursor(seat))
- send_cursor(seat);
-}
-
-static void
-synthesize_pointer_enter(struct seat *seat)
-{
- struct wl_surface *surface;
- struct libdecor_frame_gtk *frame_gtk;
-
- surface = seat->pointer_focus;
- if (!surface || !own_surface(surface))
- return;
-
- frame_gtk = wl_surface_get_user_data(surface);
- if (!frame_gtk)
- return;
-
- update_component_focus(frame_gtk, seat->pointer_focus, seat);
- frame_gtk->grab = NULL;
-
- /* update decorations */
- if (frame_gtk->active) {
- draw_decoration(frame_gtk);
- libdecor_frame_toplevel_commit(&frame_gtk->frame);
- }
-
- update_local_cursor(seat);
- send_cursor(seat);
-}
-
-static void
-synthesize_pointer_leave(struct seat *seat)
-{
- struct wl_surface *surface;
- struct libdecor_frame_gtk *frame_gtk;
-
- surface = seat->pointer_focus;
- if (!surface || !own_surface(surface))
- return;
-
- frame_gtk = wl_surface_get_user_data(surface);
- if (!frame_gtk)
- return;
-
- if (!frame_gtk->active)
- return;
-
- frame_gtk->active = NULL;
- draw_decoration(frame_gtk);
- libdecor_frame_toplevel_commit(&frame_gtk->frame);
- update_local_cursor(seat);
-}
-
-static void
-libdecor_plugin_gtk_frame_popup_grab(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame,
- const char *seat_name)
-{
- struct libdecor_frame_gtk *frame_gtk =
- (struct libdecor_frame_gtk *) frame;
- struct libdecor_plugin_gtk *plugin_gtk = frame_gtk->plugin_gtk;
- struct seat *seat;
-
- wl_list_for_each(seat, &plugin_gtk->seat_list, link) {
- if (streq(seat->name, seat_name)) {
- if (seat->grabbed) {
- fprintf(stderr, "libdecor-WARNING: Application "
- "tried to grab seat twice\n");
- }
- synthesize_pointer_leave(seat);
- seat->grabbed = true;
- return;
- }
- }
-
- fprintf(stderr,
- "libdecor-WARNING: Application tried to grab unknown seat\n");
-}
-
-static void
-libdecor_plugin_gtk_frame_popup_ungrab(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame,
- const char *seat_name)
-{
- struct libdecor_frame_gtk *frame_gtk =
- (struct libdecor_frame_gtk *) frame;
- struct libdecor_plugin_gtk *plugin_gtk = frame_gtk->plugin_gtk;
- struct seat *seat;
-
- wl_list_for_each(seat, &plugin_gtk->seat_list, link) {
- if (streq(seat->name, seat_name)) {
- if (!seat->grabbed) {
- fprintf(stderr, "libdecor-WARNING: Application "
- "tried to ungrab seat twice\n");
- }
- seat->grabbed = false;
- synthesize_pointer_enter(seat);
- sync_active_component(frame_gtk, seat);
- return;
- }
- }
-
- fprintf(stderr,
- "libdecor-WARNING: Application tried to ungrab unknown seat\n");
-}
-
-static bool
-libdecor_plugin_gtk_frame_get_border_size(struct libdecor_plugin *plugin,
- struct libdecor_frame *frame,
- struct libdecor_configuration *configuration,
- int *left,
- int *right,
- int *top,
- int *bottom)
-{
- struct libdecor_frame_gtk *frame_gtk =
- (struct libdecor_frame_gtk *) frame;
- enum libdecor_window_state window_state;
-
- if (configuration) {
- if (!libdecor_configuration_get_window_state(
- configuration, &window_state))
- return false;
- } else {
- window_state = libdecor_frame_get_window_state(frame);
- }
-
- if (left)
- *left = 0;
- if (right)
- *right = 0;
- if (bottom)
- *bottom = 0;
- if (top) {
- enum decoration_type type = window_state_to_decoration_type(window_state);
-
- switch (type) {
- case DECORATION_TYPE_NONE:
- *top = 0;
- break;
- case DECORATION_TYPE_ALL:
- ensure_border_surfaces(frame_gtk);
- //draw_border(frame_gtk);
- G_GNUC_FALLTHROUGH;
- case DECORATION_TYPE_TITLE_ONLY:
- if (!frame_gtk->header)
- ensure_title_bar_surfaces(frame_gtk);
- gtk_widget_show_all(frame_gtk->window);
- gtk_widget_get_preferred_height(frame_gtk->header, NULL, top);
- break;
- }
- }
-
- return true;
-}
-
-static struct libdecor_plugin_interface gtk_plugin_iface = {
- .destroy = libdecor_plugin_gtk_destroy,
- .get_fd = libdecor_plugin_gtk_get_fd,
- .dispatch = libdecor_plugin_gtk_dispatch,
-
- .set_handle_application_cursor = libdecor_plugin_gtk_set_handle_application_cursor,
-
- .frame_new = libdecor_plugin_gtk_frame_new,
- .frame_free = libdecor_plugin_gtk_frame_free,
- .frame_commit = libdecor_plugin_gtk_frame_commit,
- .frame_property_changed = libdecor_plugin_gtk_frame_property_changed,
-
- .frame_popup_grab = libdecor_plugin_gtk_frame_popup_grab,
- .frame_popup_ungrab = libdecor_plugin_gtk_frame_popup_ungrab,
-
- .frame_get_border_size = libdecor_plugin_gtk_frame_get_border_size,
-};
-
-static void
-init_wl_compositor(struct libdecor_plugin_gtk *plugin_gtk,
- uint32_t id,
- uint32_t version)
-{
- plugin_gtk->wl_compositor =
- wl_registry_bind(plugin_gtk->wl_registry,
- id, &wl_compositor_interface,
- MIN(version, 4));
-}
-
-static void
-init_wl_subcompositor(struct libdecor_plugin_gtk *plugin_gtk,
- uint32_t id,
- uint32_t version)
-{
- plugin_gtk->wl_subcompositor =
- wl_registry_bind(plugin_gtk->wl_registry,
- id, &wl_subcompositor_interface, 1);
-}
-
-static void
-shm_format(void *user_data,
- struct wl_shm *wl_shm,
- uint32_t format)
-{
- struct libdecor_plugin_gtk *plugin_gtk = user_data;
-
- if (format == WL_SHM_FORMAT_ARGB8888)
- plugin_gtk->has_argb = true;
-}
-
-struct wl_shm_listener shm_listener = {
- shm_format
-};
-
-static void
-shm_callback(void *user_data,
- struct wl_callback *callback,
- uint32_t time)
-{
- struct libdecor_plugin_gtk *plugin_gtk = user_data;
- struct libdecor *context = plugin_gtk->context;
-
- wl_callback_destroy(callback);
- plugin_gtk->globals_callback_shm = NULL;
-
- if (!plugin_gtk->has_argb) {
- libdecor_notify_plugin_error(
- context,
- LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE,
- "Compositor is missing required shm format");
- return;
- }
-
- libdecor_notify_plugin_ready(context);
-}
-
-static const struct wl_callback_listener shm_callback_listener = {
- shm_callback
-};
-
-static void
-init_wl_shm(struct libdecor_plugin_gtk *plugin_gtk,
- uint32_t id,
- uint32_t version)
-{
- struct libdecor *context = plugin_gtk->context;
- struct wl_display *wl_display = libdecor_get_wl_display(context);
-
- plugin_gtk->wl_shm =
- wl_registry_bind(plugin_gtk->wl_registry,
- id, &wl_shm_interface, 1);
- wl_shm_add_listener(plugin_gtk->wl_shm, &shm_listener, plugin_gtk);
-
- plugin_gtk->globals_callback_shm = wl_display_sync(wl_display);
- wl_callback_add_listener(plugin_gtk->globals_callback_shm,
- &shm_callback_listener,
- plugin_gtk);
-}
-
-static void
-cursor_surface_enter(void *data,
- struct wl_surface *wl_surface,
- struct wl_output *wl_output)
-{
- struct seat *seat = data;
-
- if (own_output(wl_output)) {
- struct cursor_output *cursor_output;
- cursor_output = zalloc(sizeof *cursor_output);
- cursor_output->output = wl_output_get_user_data(wl_output);
- wl_list_insert(&seat->cursor_outputs, &cursor_output->link);
- if (update_local_cursor(seat))
- send_cursor(seat);
- }
-}
-
-static void
-cursor_surface_leave(void *data,
- struct wl_surface *wl_surface,
- struct wl_output *wl_output)
-{
- struct seat *seat = data;
-
- if (own_output(wl_output)) {
- struct cursor_output *cursor_output, *tmp;
- wl_list_for_each_safe(cursor_output, tmp, &seat->cursor_outputs, link) {
- if (cursor_output->output->wl_output == wl_output) {
- wl_list_remove(&cursor_output->link);
- free(cursor_output);
- }
- }
-
- if (update_local_cursor(seat))
- send_cursor(seat);
- }
-}
-
-static struct wl_surface_listener cursor_surface_listener = {
- cursor_surface_enter,
- cursor_surface_leave,
-};
-
-static void
-ensure_cursor_surface(struct seat *seat)
-{
- struct wl_compositor *wl_compositor = seat->plugin_gtk->wl_compositor;
-
- if (seat->cursor_surface)
- return;
-
- seat->cursor_surface = wl_compositor_create_surface(wl_compositor);
- wl_surface_add_listener(seat->cursor_surface,
- &cursor_surface_listener, seat);
-}
-
-static bool
-ensure_cursor_theme(struct seat *seat)
-{
- struct libdecor_plugin_gtk *plugin_gtk = seat->plugin_gtk;
- int scale = 1;
- struct wl_cursor_theme *theme;
- struct cursor_output *cursor_output;
-
- wl_list_for_each(cursor_output, &seat->cursor_outputs, link) {
- scale = MAX(scale, cursor_output->output->scale);
- }
-
- if (seat->cursor_theme && seat->cursor_scale == scale)
- return false;
-
- seat->cursor_scale = scale;
- theme = wl_cursor_theme_load(plugin_gtk->cursor_theme_name,
- plugin_gtk->cursor_size * scale,
- plugin_gtk->wl_shm);
- if (theme == NULL)
- return false;
-
- if (seat->cursor_theme)
- wl_cursor_theme_destroy(seat->cursor_theme);
-
- seat->cursor_theme = theme;
-
- for (unsigned int i = 0; i < ARRAY_LENGTH(cursor_names); i++) {
- seat->cursors[i] = wl_cursor_theme_get_cursor(
- seat->cursor_theme,
- cursor_names[i]);
- }
-
- seat->cursor_left_ptr = wl_cursor_theme_get_cursor(seat->cursor_theme,
- "left_ptr");
- seat->current_cursor = seat->cursor_left_ptr;
-
- return true;
-}
-
-enum libdecor_resize_edge
-component_edge(const struct border_component *cmpnt,
- const int pointer_x,
- const int pointer_y,
- const int margin)
-{
- const bool top = pointer_y < margin * 2;
- const bool bottom = pointer_y > (cmpnt->buffer->height - margin * 2);
- const bool left = pointer_x < margin * 2;
- const bool right = pointer_x > (cmpnt->buffer->width - margin * 2);
-
- if (top) {
- if (left)
- return LIBDECOR_RESIZE_EDGE_TOP_LEFT;
- else if (right)
- return LIBDECOR_RESIZE_EDGE_TOP_RIGHT;
- else
- return LIBDECOR_RESIZE_EDGE_TOP;
- } else if (bottom) {
- if (left)
- return LIBDECOR_RESIZE_EDGE_BOTTOM_LEFT;
- else if (right)
- return LIBDECOR_RESIZE_EDGE_BOTTOM_RIGHT;
- else
- return LIBDECOR_RESIZE_EDGE_BOTTOM;
- } else if (left) {
- return LIBDECOR_RESIZE_EDGE_LEFT;
- } else if (right) {
- return LIBDECOR_RESIZE_EDGE_RIGHT;
- } else {
- return LIBDECOR_RESIZE_EDGE_NONE;
- }
-}
-
-static bool
-update_local_cursor(struct seat *seat)
-{
- if (!seat->pointer_focus) {
- seat->current_cursor = seat->cursor_left_ptr;
- return false;
- }
-
- if (!own_surface(seat->pointer_focus))
- return false;
-
- struct libdecor_frame_gtk *frame_gtk =
- wl_surface_get_user_data(seat->pointer_focus);
- struct wl_cursor *wl_cursor = NULL;
-
- if (!frame_gtk || !frame_gtk->active) {
- seat->current_cursor = seat->cursor_left_ptr;
- return false;
- }
-
- bool theme_updated = ensure_cursor_theme(seat);
-
- if (frame_gtk->active->type == SHADOW &&
- is_border_surfaces_showing(frame_gtk) &&
- resizable(frame_gtk)) {
- enum libdecor_resize_edge edge;
- edge = component_edge(frame_gtk->active,
- seat->pointer_x,
- seat->pointer_y, SHADOW_MARGIN);
-
- if (edge != LIBDECOR_RESIZE_EDGE_NONE)
- wl_cursor = seat->cursors[edge - 1];
- } else {
- wl_cursor = seat->cursor_left_ptr;
- }
-
- if (seat->current_cursor != wl_cursor) {
- seat->current_cursor = wl_cursor;
- return true;
- }
-
- return theme_updated;
-}
-
-static void
-send_cursor(struct seat *seat)
-{
- struct wl_cursor_image *image;
- struct wl_buffer *buffer;
-
- if (seat->pointer_focus == NULL || seat->current_cursor == NULL)
- return;
-
- image = seat->current_cursor->images[0];
- buffer = wl_cursor_image_get_buffer(image);
- wl_surface_attach(seat->cursor_surface, buffer, 0, 0);
- wl_surface_set_buffer_scale(seat->cursor_surface, seat->cursor_scale);
- wl_surface_damage_buffer(seat->cursor_surface, 0, 0,
- image->width * seat->cursor_scale,
- image->height * seat->cursor_scale);
- wl_surface_commit(seat->cursor_surface);
- wl_pointer_set_cursor(seat->wl_pointer, seat->serial,
- seat->cursor_surface,
- image->hotspot_x / seat->cursor_scale,
- image->hotspot_y / seat->cursor_scale);
-}
-
-static void
-pointer_enter(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t serial,
- struct wl_surface *surface,
- wl_fixed_t surface_x,
- wl_fixed_t surface_y)
-{
- if (!surface)
- return;
-
- struct seat *seat = data;
- struct libdecor_frame_gtk *frame_gtk = NULL;
-
- if (!own_surface(surface)) {
- struct seat *seat = wl_pointer_get_user_data(wl_pointer);
- struct libdecor_plugin_gtk *plugin_gtk = seat->plugin_gtk;
-
- if (!plugin_gtk->handle_cursor)
- return;
- } else {
- frame_gtk = wl_surface_get_user_data(surface);
- }
-
- ensure_cursor_surface(seat);
-
- seat->pointer_x = wl_fixed_to_int(surface_x);
- seat->pointer_y = wl_fixed_to_int(surface_y);
- seat->serial = serial;
- seat->pointer_focus = surface;
-
- if (!frame_gtk)
- return;
-
- frame_gtk->active = get_component_for_surface(frame_gtk, surface);
-
- /* update decorations */
- if (frame_gtk->active) {
- draw_decoration(frame_gtk);
- libdecor_frame_toplevel_commit(&frame_gtk->frame);
- }
-
- update_local_cursor(seat);
- send_cursor(seat);
-}
-
-static void
-pointer_leave(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t serial,
- struct wl_surface *surface)
-{
- struct seat *seat = data;
- struct libdecor_frame_gtk *frame_gtk;
-
- seat->pointer_focus = NULL;
-
- if (!surface)
- return;
-
- if (!own_surface(surface))
- return;
-
- frame_gtk = wl_surface_get_user_data(surface);
-
- if (frame_gtk) {
- frame_gtk->titlebar_gesture.state =
- TITLEBAR_GESTURE_STATE_INIT;
- frame_gtk->titlebar_gesture.first_pressed_button = 0;
-
- frame_gtk->active = NULL;
- frame_gtk->hdr_focus.widget = NULL;
- frame_gtk->hdr_focus.type = HEADER_NONE;
- draw_decoration(frame_gtk);
- libdecor_frame_toplevel_commit(&frame_gtk->frame);
- update_local_cursor(seat);
- }
-}
-
-static void
-pointer_motion(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t time,
- wl_fixed_t surface_x,
- wl_fixed_t surface_y)
-{
- struct seat *seat = data;
- struct libdecor_frame_gtk *frame_gtk;
- struct header_element_data new_focus;
-
- if (!seat->pointer_focus || !own_surface(seat->pointer_focus))
- return;
-
- seat->pointer_x = wl_fixed_to_int(surface_x);
- seat->pointer_y = wl_fixed_to_int(surface_y);
- if (update_local_cursor(seat))
- send_cursor(seat);
-
- frame_gtk = wl_surface_get_user_data(seat->pointer_focus);
- /* avoid warnings after decoration has been turned off */
- if (!GTK_IS_WIDGET(frame_gtk->header) || frame_gtk->active->type != HEADER) {
- frame_gtk->hdr_focus.type = HEADER_NONE;
- }
-
- new_focus = get_header_focus(GTK_HEADER_BAR(frame_gtk->header),
- seat->pointer_x, seat->pointer_y);
-
- /* only update if widget change so that we keep the state */
- if (frame_gtk->hdr_focus.widget != new_focus.widget) {
- frame_gtk->hdr_focus = new_focus;
- }
- frame_gtk->hdr_focus.state |= GTK_STATE_FLAG_PRELIGHT;
- /* redraw with updated button visuals */
- draw_title_bar(frame_gtk);
- libdecor_frame_toplevel_commit(&frame_gtk->frame);
-
- switch (frame_gtk->titlebar_gesture.state) {
- case TITLEBAR_GESTURE_STATE_BUTTON_PRESSED:
- if (frame_gtk->titlebar_gesture.first_pressed_button == BTN_LEFT) {
- if (ABS ((double) seat->pointer_x -
- (double) frame_gtk->titlebar_gesture.pressed_x) >
- frame_gtk->plugin_gtk->drag_threshold ||
- ABS ((double) seat->pointer_y -
- (double) frame_gtk->titlebar_gesture.pressed_y) >
- frame_gtk->plugin_gtk->drag_threshold) {
- libdecor_frame_move(&frame_gtk->frame,
- seat->wl_seat,
- frame_gtk->titlebar_gesture.pressed_serial);
- }
- }
- case TITLEBAR_GESTURE_STATE_INIT:
- case TITLEBAR_GESTURE_STATE_CONSUMED:
- case TITLEBAR_GESTURE_STATE_DISCARDED:
- break;
- }
-}
-
-static void
-handle_button_on_shadow(struct libdecor_frame_gtk *frame_gtk,
- struct seat *seat,
- uint32_t serial,
- uint32_t time,
- uint32_t button,
- uint32_t state)
-{
- enum libdecor_resize_edge edge = LIBDECOR_RESIZE_EDGE_NONE;
-
- edge = component_edge(frame_gtk->active,
- seat->pointer_x,
- seat->pointer_y,
- SHADOW_MARGIN);
-
- if (edge != LIBDECOR_RESIZE_EDGE_NONE && resizable(frame_gtk)) {
- libdecor_frame_resize(&frame_gtk->frame,
- seat->wl_seat,
- serial,
- edge);
- }
-}
-
-enum titlebar_gesture {
- TITLEBAR_GESTURE_DOUBLE_CLICK,
- TITLEBAR_GESTURE_MIDDLE_CLICK,
- TITLEBAR_GESTURE_RIGHT_CLICK,
-};
-
-static void
-handle_titlebar_gesture(struct libdecor_frame_gtk *frame_gtk,
- struct seat *seat,
- uint32_t serial,
- enum titlebar_gesture gesture)
-{
- switch (gesture) {
- case TITLEBAR_GESTURE_DOUBLE_CLICK:
- toggle_maximized(&frame_gtk->frame);
- break;
- case TITLEBAR_GESTURE_MIDDLE_CLICK:
- break;
- case TITLEBAR_GESTURE_RIGHT_CLICK:
- {
- const int title_height = gtk_widget_get_allocated_height(frame_gtk->header);
- libdecor_frame_show_window_menu(&frame_gtk->frame,
- seat->wl_seat,
- serial,
- seat->pointer_x,
- seat->pointer_y
- -title_height);
- }
- break;
- }
-}
-
-static void
-handle_button_on_header(struct libdecor_frame_gtk *frame_gtk,
- struct seat *seat,
- uint32_t serial,
- uint32_t time,
- uint32_t button,
- uint32_t state)
-{
- switch (frame_gtk->titlebar_gesture.state) {
- case TITLEBAR_GESTURE_STATE_INIT:
- if (state != WL_POINTER_BUTTON_STATE_PRESSED)
- return;
-
- if (button == BTN_RIGHT) {
- handle_titlebar_gesture(frame_gtk,
- seat,
- serial,
- TITLEBAR_GESTURE_RIGHT_CLICK);
- frame_gtk->titlebar_gesture.state =
- TITLEBAR_GESTURE_STATE_CONSUMED;
- } else {
- if (button == BTN_LEFT &&
- frame_gtk->titlebar_gesture.first_pressed_button == BTN_LEFT &&
- time - frame_gtk->titlebar_gesture.first_pressed_time <
- (uint32_t) frame_gtk->plugin_gtk->double_click_time_ms) {
- handle_titlebar_gesture(frame_gtk,
- seat,
- serial,
- TITLEBAR_GESTURE_DOUBLE_CLICK);
- frame_gtk->titlebar_gesture.state =
- TITLEBAR_GESTURE_STATE_CONSUMED;
- } else {
- frame_gtk->titlebar_gesture.first_pressed_button = button;
- frame_gtk->titlebar_gesture.first_pressed_time = time;
- frame_gtk->titlebar_gesture.pressed_x = seat->pointer_x;
- frame_gtk->titlebar_gesture.pressed_y = seat->pointer_y;
- frame_gtk->titlebar_gesture.pressed_serial = serial;
- frame_gtk->titlebar_gesture.state =
- TITLEBAR_GESTURE_STATE_BUTTON_PRESSED;
- }
- }
-
- frame_gtk->titlebar_gesture.button_pressed_count = 1;
-
- switch (frame_gtk->hdr_focus.type) {
- case HEADER_MIN:
- case HEADER_MAX:
- case HEADER_CLOSE:
- frame_gtk->hdr_focus.state |= GTK_STATE_FLAG_ACTIVE;
- draw_title_bar(frame_gtk);
- libdecor_frame_toplevel_commit(&frame_gtk->frame);
- break;
- default:
- break;
- }
-
- break;
- case TITLEBAR_GESTURE_STATE_BUTTON_PRESSED:
- if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
- frame_gtk->titlebar_gesture.state =
- TITLEBAR_GESTURE_STATE_DISCARDED;
- frame_gtk->titlebar_gesture.button_pressed_count++;
- } else {
- frame_gtk->titlebar_gesture.button_pressed_count--;
-
- if (frame_gtk->titlebar_gesture.button_pressed_count == 0) {
- frame_gtk->titlebar_gesture.state =
- TITLEBAR_GESTURE_STATE_INIT;
- if (frame_gtk->titlebar_gesture.first_pressed_button == button &&
- button == BTN_LEFT) {
- libdecor_frame_ref(&frame_gtk->frame);
- switch (frame_gtk->hdr_focus.type) {
- case HEADER_MIN:
- if (minimizable(frame_gtk))
- libdecor_frame_set_minimized(
- &frame_gtk->frame);
- break;
- case HEADER_MAX:
- toggle_maximized(&frame_gtk->frame);
- break;
- case HEADER_CLOSE:
- if (closeable(frame_gtk)) {
- libdecor_frame_close(
- &frame_gtk->frame);
- seat->pointer_focus = NULL;
- }
- break;
- default:
- break;
- }
-
- frame_gtk->hdr_focus.state &= ~GTK_STATE_FLAG_ACTIVE;
- if (GTK_IS_WIDGET(frame_gtk->header)) {
- draw_title_bar(frame_gtk);
- libdecor_frame_toplevel_commit(&frame_gtk->frame);
- }
- libdecor_frame_unref(&frame_gtk->frame);
- }
- } else {
- frame_gtk->hdr_focus.state &= ~GTK_STATE_FLAG_ACTIVE;
- if (GTK_IS_WIDGET(frame_gtk->header)) {
- draw_title_bar(frame_gtk);
- libdecor_frame_toplevel_commit(&frame_gtk->frame);
- }
- }
-
- }
- break;
- case TITLEBAR_GESTURE_STATE_CONSUMED:
- case TITLEBAR_GESTURE_STATE_DISCARDED:
- if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
- frame_gtk->titlebar_gesture.button_pressed_count++;
- } else {
- frame_gtk->titlebar_gesture.button_pressed_count--;
- if (frame_gtk->titlebar_gesture.button_pressed_count == 0) {
- frame_gtk->titlebar_gesture.state =
- TITLEBAR_GESTURE_STATE_INIT;
- frame_gtk->titlebar_gesture.first_pressed_button = 0;
- }
- }
- break;
- }
-}
-
-static void
-pointer_button(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t serial,
- uint32_t time,
- uint32_t button,
- uint32_t state)
-{
- struct seat *seat = data;
- struct libdecor_frame_gtk *frame_gtk;
-
- if (!seat->pointer_focus || !own_surface(seat->pointer_focus))
- return;
-
- frame_gtk = wl_surface_get_user_data(seat->pointer_focus);
- if (!frame_gtk)
- return;
-
- switch (frame_gtk->active->type) {
- case SHADOW:
- handle_button_on_shadow (frame_gtk, seat, serial, time, button, state);
- break;
- case HEADER:
- handle_button_on_header (frame_gtk, seat, serial, time, button, state);
- break;
- default:
- break;
- }
-}
-
-static void
-pointer_axis(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t time,
- uint32_t axis,
- wl_fixed_t value)
-{
-}
-
-static struct wl_pointer_listener pointer_listener = {
- pointer_enter,
- pointer_leave,
- pointer_motion,
- pointer_button,
- pointer_axis
-};
-
-static void
-update_touch_focus(struct seat *seat,
- struct libdecor_frame_gtk *frame_gtk,
- wl_fixed_t x,
- wl_fixed_t y)
-{
- /* avoid warnings after decoration has been turned off */
- if (GTK_IS_WIDGET(frame_gtk->header) && frame_gtk->touch_active->type == HEADER) {
- struct header_element_data new_focus = get_header_focus(
- GTK_HEADER_BAR(frame_gtk->header),
- wl_fixed_to_int(x), wl_fixed_to_int(y));
- /* only update if widget change so that we keep the state */
- if (frame_gtk->hdr_focus.widget != new_focus.widget) {
- frame_gtk->hdr_focus = new_focus;
- }
- frame_gtk->hdr_focus.state |= GTK_STATE_FLAG_PRELIGHT;
- /* redraw with updated button visuals */
- draw_title_bar(frame_gtk);
- libdecor_frame_toplevel_commit(&frame_gtk->frame);
- } else {
- frame_gtk->hdr_focus.type = HEADER_NONE;
- }
-}
-
-static void
-touch_down(void *data,
- struct wl_touch *wl_touch,
- uint32_t serial,
- uint32_t time,
- struct wl_surface *surface,
- int32_t id,
- wl_fixed_t x,
- wl_fixed_t y)
-{
- struct seat *seat = data;
- struct libdecor_frame_gtk *frame_gtk;
-
- if (!surface || !own_surface(surface))
- return;
-
- frame_gtk = wl_surface_get_user_data(surface);
- if (!frame_gtk)
- return;
-
- seat->touch_focus = surface;
- frame_gtk->touch_active = get_component_for_surface(frame_gtk, surface);
-
- if (!frame_gtk->touch_active)
- return;
-
- update_touch_focus(seat, frame_gtk, x, y);
-
- /* update decorations */
- draw_decoration(frame_gtk);
- libdecor_frame_toplevel_commit(&frame_gtk->frame);
-
- enum libdecor_resize_edge edge =
- LIBDECOR_RESIZE_EDGE_NONE;
- switch (frame_gtk->touch_active->type) {
- case SHADOW:
- edge = component_edge(frame_gtk->touch_active,
- wl_fixed_to_int(x),
- wl_fixed_to_int(y),
- SHADOW_MARGIN);
- break;
- case HEADER:
- switch (frame_gtk->hdr_focus.type) {
- case HEADER_MIN:
- case HEADER_MAX:
- case HEADER_CLOSE:
- frame_gtk->hdr_focus.state |= GTK_STATE_FLAG_ACTIVE;
- draw_title_bar(frame_gtk);
- libdecor_frame_toplevel_commit(&frame_gtk->frame);
- break;
- default:
- if (time - seat->touch_down_time_stamp <
- (uint32_t)frame_gtk->plugin_gtk->double_click_time_ms) {
- toggle_maximized(&frame_gtk->frame);
- }
- else if (moveable(frame_gtk)) {
- seat->touch_down_time_stamp = time;
- libdecor_frame_move(&frame_gtk->frame,
- seat->wl_seat,
- serial);
- }
- break;
- }
- break;
- default:
- break;
- }
- if (edge != LIBDECOR_RESIZE_EDGE_NONE &&
- resizable(frame_gtk)) {
- libdecor_frame_resize(
- &frame_gtk->frame,
- seat->wl_seat,
- serial,
- edge);
- }
-}
-
-static void
-touch_up(void *data,
- struct wl_touch *wl_touch,
- uint32_t serial,
- uint32_t time,
- int32_t id)
-{
- struct seat *seat = data;
- struct libdecor_frame_gtk *frame_gtk;
-
- if (!seat->touch_focus || !own_surface(seat->touch_focus))
- return;
-
- frame_gtk = wl_surface_get_user_data(seat->touch_focus);
- if (!frame_gtk)
- return;
-
- if (!frame_gtk->touch_active)
- return;
-
- switch (frame_gtk->touch_active->type) {
- case HEADER:
- libdecor_frame_ref(&frame_gtk->frame);
- switch (frame_gtk->hdr_focus.type) {
- case HEADER_MIN:
- if (minimizable(frame_gtk)) {
- libdecor_frame_set_minimized(
- &frame_gtk->frame);
- }
- break;
- case HEADER_MAX:
- toggle_maximized(&frame_gtk->frame);
- break;
- case HEADER_CLOSE:
- if (closeable(frame_gtk)) {
- libdecor_frame_close(
- &frame_gtk->frame);
- seat->touch_focus = NULL;
- }
- break;
- default:
- break;
- }
- /* unset active/clicked state once released */
- frame_gtk->hdr_focus.state &= ~GTK_STATE_FLAG_ACTIVE;
- if (GTK_IS_WIDGET(frame_gtk->header)) {
- draw_title_bar(frame_gtk);
- libdecor_frame_toplevel_commit(&frame_gtk->frame);
- }
- libdecor_frame_unref(&frame_gtk->frame);
- break;
- default:
- break;
- }
-
- seat->touch_focus = NULL;
- frame_gtk->touch_active = NULL;
- frame_gtk->hdr_focus.widget = NULL;
- frame_gtk->hdr_focus.type = HEADER_NONE;
- draw_decoration(frame_gtk);
- libdecor_frame_toplevel_commit(&frame_gtk->frame);
-}
-
-static void
-touch_motion(void *data,
- struct wl_touch *wl_touch,
- uint32_t time,
- int32_t id,
- wl_fixed_t x,
- wl_fixed_t y)
-{
- struct seat *seat = data;
- struct libdecor_frame_gtk *frame_gtk;
-
- if (!seat->touch_focus || !own_surface(seat->touch_focus))
- return;
-
- frame_gtk = wl_surface_get_user_data(seat->touch_focus);
- if (!frame_gtk)
- return;
-
- update_touch_focus(seat, frame_gtk, x, y);
-}
-
-static void
-touch_frame(void *data,
- struct wl_touch *wl_touch)
-{
-}
-
-static void
-touch_cancel(void *data,
- struct wl_touch *wl_touch)
-{
-}
-
-static struct wl_touch_listener touch_listener = {
- touch_down,
- touch_up,
- touch_motion,
- touch_frame,
- touch_cancel
-};
-
-static void
-seat_capabilities(void *data,
- struct wl_seat *wl_seat,
- uint32_t capabilities)
-{
- struct seat *seat = data;
-
- if ((capabilities & WL_SEAT_CAPABILITY_POINTER) &&
- !seat->wl_pointer) {
- seat->wl_pointer = wl_seat_get_pointer(wl_seat);
- wl_pointer_add_listener(seat->wl_pointer,
- &pointer_listener, seat);
- } else if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) &&
- seat->wl_pointer) {
- wl_pointer_release(seat->wl_pointer);
- seat->wl_pointer = NULL;
- }
-
- if ((capabilities & WL_SEAT_CAPABILITY_TOUCH) &&
- !seat->wl_touch) {
- seat->wl_touch = wl_seat_get_touch(wl_seat);
- wl_touch_add_listener(seat->wl_touch,
- &touch_listener, seat);
- } else if (!(capabilities & WL_SEAT_CAPABILITY_TOUCH) &&
- seat->wl_touch) {
- wl_touch_release(seat->wl_touch);
- seat->wl_touch = NULL;
- }
-}
-
-static void
-seat_name(void *data,
- struct wl_seat *wl_seat,
- const char *name)
-{
- /* avoid warning messages when opening/closing popup window */
- struct seat *seat = (struct seat*)data;
- seat->name = strdup(name);
-}
-
-static struct wl_seat_listener seat_listener = {
- seat_capabilities,
- seat_name
-};
-
-static void
-init_wl_seat(struct libdecor_plugin_gtk *plugin_gtk,
- uint32_t id,
- uint32_t version)
-{
- struct seat *seat;
-
- if (version < 3) {
- libdecor_notify_plugin_error(
- plugin_gtk->context,
- LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE,
- "%s version 3 required but only version %i is available\n",
- wl_seat_interface.name,
- version);
- }
-
- seat = zalloc(sizeof *seat);
- seat->cursor_scale = 1;
- seat->plugin_gtk = plugin_gtk;
- wl_list_init(&seat->cursor_outputs);
- wl_list_insert(&plugin_gtk->seat_list, &seat->link);
- seat->wl_seat =
- wl_registry_bind(plugin_gtk->wl_registry,
- id, &wl_seat_interface, 3);
- wl_seat_add_listener(seat->wl_seat, &seat_listener, seat);
-}
-
-static void
-output_geometry(void *data,
- struct wl_output *wl_output,
- int32_t x,
- int32_t y,
- int32_t physical_width,
- int32_t physical_height,
- int32_t subpixel,
- const char *make,
- const char *model,
- int32_t transform)
-{
-}
-
-static void
-output_mode(void *data,
- struct wl_output *wl_output,
- uint32_t flags,
- int32_t width,
- int32_t height,
- int32_t refresh)
-{
-}
-
-static void
-output_done(void *data,
- struct wl_output *wl_output)
-{
- struct output *output = data;
- struct libdecor_frame_gtk *frame_gtk;
- struct seat *seat;
-
- wl_list_for_each(frame_gtk,
- &output->plugin_gtk->visible_frame_list, link) {
- bool updated = false;
- updated |= redraw_scale(frame_gtk, &frame_gtk->shadow);
- if (updated)
- libdecor_frame_toplevel_commit(&frame_gtk->frame);
- }
- wl_list_for_each(seat, &output->plugin_gtk->seat_list, link) {
- if (update_local_cursor(seat))
- send_cursor(seat);
- }
-}
-
-static void
-output_scale(void *data,
- struct wl_output *wl_output,
- int32_t factor)
-{
- struct output *output = data;
-
- output->scale = factor;
-}
-
-static struct wl_output_listener output_listener = {
- output_geometry,
- output_mode,
- output_done,
- output_scale
-};
-
-static void
-init_wl_output(struct libdecor_plugin_gtk *plugin_gtk,
- uint32_t id,
- uint32_t version)
-{
- struct output *output;
-
- if (version < 2) {
- libdecor_notify_plugin_error(
- plugin_gtk->context,
- LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE,
- "%s version 2 required but only version %i is available\n",
- wl_output_interface.name,
- version);
- }
-
- output = zalloc(sizeof *output);
- output->plugin_gtk = plugin_gtk;
- wl_list_insert(&plugin_gtk->output_list, &output->link);
- output->id = id;
- output->wl_output =
- wl_registry_bind(plugin_gtk->wl_registry,
- id, &wl_output_interface,
- MIN (version, 3));
- wl_proxy_set_tag((struct wl_proxy *) output->wl_output,
- &libdecor_gtk_proxy_tag);
- wl_output_add_listener(output->wl_output, &output_listener, output);
-}
-
-static void
-registry_handle_global(void *user_data,
- struct wl_registry *wl_registry,
- uint32_t id,
- const char *interface,
- uint32_t version)
-{
- struct libdecor_plugin_gtk *plugin_gtk = user_data;
-
- if (strcmp(interface, "wl_compositor") == 0)
- init_wl_compositor(plugin_gtk, id, version);
- else if (strcmp(interface, "wl_subcompositor") == 0)
- init_wl_subcompositor(plugin_gtk, id, version);
- else if (strcmp(interface, "wl_shm") == 0)
- init_wl_shm(plugin_gtk, id, version);
- else if (strcmp(interface, "wl_seat") == 0)
- init_wl_seat(plugin_gtk, id, version);
- else if (strcmp(interface, "wl_output") == 0)
- init_wl_output(plugin_gtk, id, version);
-}
-
-static void
-remove_surface_outputs(struct border_component *cmpnt, const struct output *output)
-{
- struct surface_output *surface_output;
- wl_list_for_each(surface_output, &cmpnt->output_list, link) {
- if (surface_output->output == output) {
- wl_list_remove(&surface_output->link);
- free(surface_output);
- break;
- }
- }
-}
-
-static void
-output_removed(struct libdecor_plugin_gtk *plugin_gtk,
- struct output *output)
-{
- struct libdecor_frame_gtk *frame_gtk;
- struct seat *seat;
-
- wl_list_for_each(frame_gtk, &plugin_gtk->visible_frame_list, link) {
- remove_surface_outputs(&frame_gtk->shadow, output);
- }
- wl_list_for_each(seat, &plugin_gtk->seat_list, link) {
- struct cursor_output *cursor_output;
- wl_list_for_each(cursor_output, &seat->cursor_outputs, link) {
- if (cursor_output->output == output) {
- wl_list_remove(&cursor_output->link);
- free(cursor_output);
- }
- }
- }
-
- wl_list_remove(&output->link);
- wl_output_destroy(output->wl_output);
- free(output);
-}
-
-static void
-registry_handle_global_remove(void *user_data,
- struct wl_registry *wl_registry,
- uint32_t name)
-{
- struct libdecor_plugin_gtk *plugin_gtk = user_data;
- struct output *output;
-
- wl_list_for_each(output, &plugin_gtk->output_list, link) {
- if (output->id == name) {
- output_removed(plugin_gtk, output);
- break;
- }
- }
-}
-
-static const struct wl_registry_listener registry_listener = {
- registry_handle_global,
- registry_handle_global_remove
-};
-
-static bool
-has_required_globals(struct libdecor_plugin_gtk *plugin_gtk)
-{
- if (!plugin_gtk->wl_compositor)
- return false;
- if (!plugin_gtk->wl_subcompositor)
- return false;
- if (!plugin_gtk->wl_shm)
- return false;
-
- return true;
-}
-
-static void
-globals_callback(void *user_data,
- struct wl_callback *callback,
- uint32_t time)
-{
- struct libdecor_plugin_gtk *plugin_gtk = user_data;
-
- wl_callback_destroy(callback);
- plugin_gtk->globals_callback = NULL;
-}
-
-static const struct wl_callback_listener globals_callback_listener = {
- globals_callback
-};
-
-static struct libdecor_plugin *
-libdecor_plugin_new(struct libdecor *context)
-{
- struct libdecor_plugin_gtk *plugin_gtk;
- struct wl_display *wl_display;
-
-#ifdef HAVE_GETTID
- /* Only support running on the main thread. */
- if (getpid () != gettid ())
- return NULL;
-#endif
-
- plugin_gtk = zalloc(sizeof *plugin_gtk);
- libdecor_plugin_init(&plugin_gtk->plugin,
- context,
- &gtk_plugin_iface);
- plugin_gtk->context = context;
-
- wl_list_init(&plugin_gtk->visible_frame_list);
- wl_list_init(&plugin_gtk->seat_list);
- wl_list_init(&plugin_gtk->output_list);
-
- /* fetch cursor theme and size*/
- if (!libdecor_get_cursor_settings(&plugin_gtk->cursor_theme_name,
- &plugin_gtk->cursor_size)) {
- plugin_gtk->cursor_theme_name = NULL;
- plugin_gtk->cursor_size = 24;
- }
-
- plugin_gtk->color_scheme_setting = libdecor_get_color_scheme();
-
- wl_display = libdecor_get_wl_display(context);
- plugin_gtk->wl_registry = wl_display_get_registry(wl_display);
- wl_registry_add_listener(plugin_gtk->wl_registry,
- &registry_listener,
- plugin_gtk);
-
- plugin_gtk->globals_callback = wl_display_sync(wl_display);
- wl_callback_add_listener(plugin_gtk->globals_callback,
- &globals_callback_listener,
- plugin_gtk);
- wl_display_roundtrip(wl_display);
-
- if (!has_required_globals(plugin_gtk)) {
- fprintf(stderr, "libdecor-gtk-WARNING: Could not get required globals\n");
- libdecor_plugin_gtk_destroy(&plugin_gtk->plugin);
- return NULL;
- }
-
- /* setup GTK context */
- gdk_set_allowed_backends("wayland");
- gtk_disable_setlocale();
-
- if (!gtk_init_check(NULL, NULL)) {
- fprintf(stderr, "libdecor-gtk-WARNING: Failed to initialize GTK\n");
- libdecor_plugin_gtk_destroy(&plugin_gtk->plugin);
- return NULL;
- }
-
- g_object_set(gtk_settings_get_default(),
- "gtk-application-prefer-dark-theme",
- plugin_gtk->color_scheme_setting == LIBDECOR_COLOR_SCHEME_PREFER_DARK,
- NULL);
-
- return &plugin_gtk->plugin;
-}
-
-static struct libdecor_plugin_priority priorities[] = {
- { NULL, LIBDECOR_PLUGIN_PRIORITY_HIGH }
-};
-
-LIBDECOR_EXPORT const struct libdecor_plugin_description
-libdecor_plugin_description = {
- .api_version = LIBDECOR_PLUGIN_API_VERSION,
- .capabilities = LIBDECOR_PLUGIN_CAPABILITY_BASE,
- .description = "GTK3 plugin",
- .priorities = priorities,
- .constructor = libdecor_plugin_new,
- .conflicting_symbols = {
- "png_free",
- "gdk_get_use_xshm",
- NULL,
- },
-};
diff --git a/libdecor/src/utils.h b/libdecor/src/utils.h
deleted file mode 100644
index 7892793b6..000000000
--- a/libdecor/src/utils.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright © 2017 Red Hat Inc.
- *
- * 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.
- */
-
-#ifndef UTILS_H
-#define UTILS_H
-
-#include <stdlib.h>
-
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#define MAX(a, b) (((a) > (b)) ? (a) : (b))
-
-#ifndef ARRAY_LENGTH
-#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
-#endif
-
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-#endif
-
-static inline void *
-zalloc(size_t size)
-{
- return calloc(1, size);
-}
-
-#endif /* UTILS_H */