diff --git a/glfw/source-info.json b/glfw/source-info.json index cef1ba66f..e45950196 100644 --- a/glfw/source-info.json +++ b/glfw/source-info.json @@ -56,6 +56,7 @@ "posix_thread.h", "wl_cursors.h", "wl_text_input.h", + "wl_decor.h", "xkb_glfw.h", "dbus_glfw.h", "ibus_glfw.h", @@ -90,6 +91,7 @@ "wl_monitor.c", "wl_window.c", "wl_cursors.c", + "wl_decor.c", "wl_text_input.c", "wl_client_side_decorations.c", "posix_thread.c", diff --git a/glfw/wl_decor.c b/glfw/wl_decor.c new file mode 100644 index 000000000..6dbe7a7e3 --- /dev/null +++ b/glfw/wl_decor.c @@ -0,0 +1,106 @@ +/* + * wl_decor.c + * Copyright (C) 2024 Kovid Goyal + * + * Distributed under terms of the GPL3 license. + */ + +#include "wl_decor.h" +#include "internal.h" +#include "libdecor-0/libdecor.h" +#include +#include + +// Boilerplate to dynload libdecor {{{ +#define funcs F(libdecor_new); F(libdecor_unref); F(libdecor_get_fd); F(libdecor_dispatch); F(libdecor_decorate); F(libdecor_frame_unref); \ + F(libdecor_frame_set_app_id); F(libdecor_frame_set_title); F(libdecor_frame_set_minimized); F(libdecor_frame_set_fullscreen); \ + F(libdecor_frame_unset_fullscreen); F(libdecor_frame_map); F(libdecor_frame_commit); F(libdecor_frame_set_min_content_size); \ + F(libdecor_frame_set_max_content_size); F(libdecor_frame_set_maximized); F(libdecor_frame_unset_maximized); \ + F(libdecor_frame_set_capabilities); F(libdecor_frame_unset_capabilities); F(libdecor_frame_set_visibility); \ + F(libdecor_frame_get_xdg_toplevel); F(libdecor_configuration_get_content_size); F(libdecor_configuration_get_window_state); \ + F(libdecor_state_new); F(libdecor_state_free); + +#define F(name) __typeof__(name) (*name) +static void* libdecor_handle = NULL; +static struct { + funcs +} libdecor_funcs = {0}; +#undef F + +#define LOAD_FUNC(handle, name) { \ + glfw_dlsym(libdecor_funcs.name, handle, #name); \ + if (!libdecor_funcs.name) { \ + const char* error = dlerror(); \ + _glfwInputError(GLFW_PLATFORM_ERROR, "failed to load libdecor function %s with error: %s", #name, error ? error : "(null)"); \ + memset(&libdecor_funcs, 0, sizeof(libdecor_funcs)); \ + dlclose(handle); handle = NULL; return false; \ + } \ +} + +static bool +glfw_wl_load_libdecor(void) { + if (libdecor_handle != NULL) return true; + const char* libnames[] = { +#ifdef _GLFW_DECOR_LIBRARY + _GLFW_DECOR_LIBRARY, +#else + "libdecor-0.so", + // some installs are missing the .so symlink, so try the full name + "libdecor-0.so.0", +#endif + NULL + }; + for (int i = 0; libnames[i]; i++) { + libdecor_handle = _glfw_dlopen(libnames[i]); + if (libdecor_handle) break; + } + if (!libdecor_handle) { + libdecor_handle = _glfw_dlopen(libnames[0]); + if (!libdecor_handle) { + _glfwInputError(GLFW_PLATFORM_ERROR, "failed to dlopen %s with error: %s", libnames[0], dlerror()); + return false; + } + } + dlerror(); /* Clear any existing error */ + +#define F(name) LOAD_FUNC(libdecor_handle, name) + funcs +#undef F + return true; +} + +void glfw_wl_load_decorations_library(void) { glfw_wl_load_libdecor(); } +void glfw_wl_unload_decorations_library(void) { + if (libdecor_handle) { + dlclose(libdecor_handle); libdecor_handle = NULL; + memset(&libdecor_funcs, 0, sizeof(libdecor_funcs)); \ + } +} +#define libdecor_new libdecor_funcs.libdecor_new +#define libdecor_unref libdecor_funcs.libdecor_unref +#define libdecor_get_fd libdecor_funcs.libdecor_get_fd +#define libdecor_dispatch libdecor_funcs.libdecor_dispatch +#define libdecor_decorate libdecor_funcs.libdecor_decorate +#define libdecor_frame_unref libdecor_funcs.libdecor_frame_unref +#define libdecor_frame_set_app_id libdecor_funcs.libdecor_frame_set_app_id +#define libdecor_frame_set_title libdecor_funcs.libdecor_frame_set_title +#define libdecor_frame_set_minimized libdecor_funcs.libdecor_frame_set_minimized +#define libdecor_frame_set_fullscreen libdecor_funcs.libdecor_frame_set_fullscreen +#define libdecor_frame_unset_fullscreen libdecor_funcs.libdecor_frame_unset_fullscreen +#define libdecor_frame_map libdecor_funcs.libdecor_frame_map +#define libdecor_frame_commit libdecor_funcs.libdecor_frame_commit +#define libdecor_frame_set_min_content_size libdecor_funcs.libdecor_frame_set_min_content_size +#define libdecor_frame_set_max_content_size libdecor_funcs.libdecor_frame_set_max_content_size +#define libdecor_frame_set_maximized libdecor_funcs.libdecor_frame_set_maximized +#define libdecor_frame_unset_maximized libdecor_funcs.libdecor_frame_unset_maximized +#define libdecor_frame_set_capabilities libdecor_funcs.libdecor_frame_set_capabilities +#define lilibdecor_frame_set_capabilities libdecor_funcs.lilibdecor_frame_set_capabilities +#define libdecor_frame_set_visibility libdecor_funcs.libdecor_frame_set_visibility +#define libdecor_frame_get_xdg_toplevel libdecor_funcs.libdecor_frame_get_xdg_toplevel +#define libdecor_configuration_get_content_size libdecor_funcs.libdecor_configuration_get_content_size +#define libdecor_configuration_get_window_state libdecor_funcs.libdecor_configuration_get_window_state +#define libdecor_state_new libdecor_funcs.libdecor_state_new +#define libdecor_state_free libdecor_funcs.libdecor_state_free +// }}} + + diff --git a/glfw/wl_decor.h b/glfw/wl_decor.h new file mode 100644 index 000000000..d00857d5d --- /dev/null +++ b/glfw/wl_decor.h @@ -0,0 +1,11 @@ +/* + * wl_decor.h + * Copyright (C) 2024 Kovid Goyal + * + * Distributed under terms of the GPL3 license. + */ + +#pragma once + +void glfw_wl_load_decorations_library(void); +void glfw_wl_unload_decorations_library(void); diff --git a/glfw/wl_init.c b/glfw/wl_init.c index ade814823..1edc49d63 100644 --- a/glfw/wl_init.c +++ b/glfw/wl_init.c @@ -28,6 +28,7 @@ #define _GNU_SOURCE #include "internal.h" +#include "wl_decor.h" #include "backend_utils.h" #include "linux_desktop_settings.h" #include "../kitty/monotonic.h" @@ -862,6 +863,7 @@ int _glfwPlatformInit(void) glfw_dlsym(_glfw.wl.egl.window_create, _glfw.wl.egl.handle, "wl_egl_window_create"); glfw_dlsym(_glfw.wl.egl.window_destroy, _glfw.wl.egl.handle, "wl_egl_window_destroy"); glfw_dlsym(_glfw.wl.egl.window_resize, _glfw.wl.egl.handle, "wl_egl_window_resize"); + glfw_wl_load_decorations_library(); _glfw.wl.display = wl_display_connect(NULL); if (!_glfw.wl.display) @@ -925,6 +927,7 @@ int _glfwPlatformInit(void) void _glfwPlatformTerminate(void) { + glfw_wl_unload_decorations_library(); if (_glfw.wl.activation_requests.array) { for (size_t i=0; i < _glfw.wl.activation_requests.sz; i++) { glfw_wl_xdg_activation_request *r = _glfw.wl.activation_requests.array + i; diff --git a/setup.py b/setup.py index 2de5b98bb..571e6cc66 100755 --- a/setup.py +++ b/setup.py @@ -198,6 +198,7 @@ class Options: startup_notification_library: Optional[str] = os.getenv('KITTY_STARTUP_NOTIFICATION_LIBRARY') canberra_library: Optional[str] = os.getenv('KITTY_CANBERRA_LIBRARY') fontconfig_library: Optional[str] = os.getenv('KITTY_FONTCONFIG_LIBRARY') + decor_library: Optional[str] = os.getenv('KITTY_DECOR_LIBRARY') building_arch: str = '' # Extras @@ -451,6 +452,7 @@ def init_env( startup_notification_library: Optional[str] = None, canberra_library: Optional[str] = None, fontconfig_library: Optional[str] = None, + decor_library: Optional[str] = None, extra_logging: Iterable[str] = (), extra_include_dirs: Iterable[str] = (), ignore_compiler_warnings: bool = False, @@ -535,6 +537,7 @@ def init_env( library_paths.setdefault(which, []).append(f'{name}="{val}"') add_lpath('glfw/egl_context.c', '_GLFW_EGL_LIBRARY', egl_library) + add_lpath('glfw/wl_decor.c', '_GLFW_DECOR_LIBRARY', decor_library) add_lpath('kitty/desktop.c', '_KITTY_STARTUP_NOTIFICATION_LIBRARY', startup_notification_library) add_lpath('kitty/desktop.c', '_KITTY_CANBERRA_LIBRARY', canberra_library) add_lpath('kitty/fontconfig.c', '_KITTY_FONTCONFIG_LIBRARY', fontconfig_library) @@ -973,7 +976,7 @@ def init_env_from_args(args: Options, native_optimizations: bool = False) -> Non global env env = init_env( args.debug, args.sanitize, native_optimizations, args.link_time_optimization, args.profile, - args.egl_library, args.startup_notification_library, args.canberra_library, args.fontconfig_library, + args.egl_library, args.startup_notification_library, args.canberra_library, args.fontconfig_library, args.decor_library, args.extra_logging, args.extra_include_dirs, args.ignore_compiler_warnings, args.building_arch, args.extra_library_dirs, verbose=args.verbose > 0, vcs_rev=args.vcs_rev, ) @@ -1936,6 +1939,13 @@ def option_parser() -> argparse.ArgumentParser: # {{{ help='The filename argument passed to dlopen for libfontconfig.' ' This can be used to change the name of the loaded library or specify an absolute path.' ) + p.add_argument( + '--decor-library', + type=str, + default=Options.decor_library, + help='The filename argument passed to dlopen for libdecor.' + ' This can be used to change the name of the loaded library or specify an absolute path.' + ) p.add_argument( '--disable-link-time-optimization', dest='link_time_optimization',