Compare commits

...

15 Commits

Author SHA1 Message Date
Kovid Goyal
139f56b2eb Port the code to set window size limits to wl_decor 2024-04-03 18:55:27 +05:30
Kovid Goyal
84ef1dce92 Migrate setting of title and app id to wl_decor 2024-04-03 18:55:27 +05:30
Kovid Goyal
14c0d76f86 Port set minimized to wl_decor 2024-04-03 18:55:27 +05:30
Kovid Goyal
fbc2b4fc1c Migrate maximized state management to wl_decor 2024-04-03 18:55:27 +05:30
Kovid Goyal
d557d4cbec Migrate setting of fullscreen to wl_decor 2024-04-03 18:55:27 +05:30
Kovid Goyal
16b5948c95 ... 2024-04-03 18:55:26 +05:30
Kovid Goyal
4e9e833397 Only initialize edge_spacing_func if glfw init succeeds 2024-04-03 18:55:26 +05:30
Kovid Goyal
1f15002ace Set GDK_BACKEND if needed before loading libdecor 2024-04-03 18:55:26 +05:30
Kovid Goyal
886ca2d0e6 Store library handle in funcs struct 2024-04-03 18:55:26 +05:30
Kovid Goyal
45f3577f35 O_CLOEXEC for linux joystick open 2024-04-03 18:55:26 +05:30
Kovid Goyal
8b66c3faa4 Propagate failures to get video mode 2024-04-03 18:55:26 +05:30
Kovid Goyal
5346c95ff4 Integrate libdecor into event loop 2024-04-03 18:55:26 +05:30
Kovid Goyal
aecacb0295 Note that file transfer wont work through tmux in the FAQ 2024-04-03 18:55:26 +05:30
Kovid Goyal
34ddcaaa57 Create decoration context 2024-04-03 18:55:26 +05:30
Kovid Goyal
92253521b1 dlopen libdecor 2024-04-03 18:55:26 +05:30
15 changed files with 346 additions and 89 deletions

View File

@@ -465,8 +465,9 @@ for tmux refusing to support images.
If you use any of the advanced features that kitty has innovated, such as
:doc:`styled underlines </underlines>`, :doc:`desktop notifications
</desktop-notifications>`, :doc:`extended keyboard support
</keyboard-protocol>`, etc. they may or may not work, depending on the whims of
tmux's maintainer, your version of tmux, etc.
</keyboard-protocol>`, :doc:`file transfer </kittens/transfer>`, etc.
they may or may not work, depending on the whims of tmux's maintainer,
your version of tmux, etc.
I opened and closed a lot of windows/tabs and top shows kitty's memory usage is very high?

View File

@@ -618,9 +618,13 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
return result;
}
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode)
bool _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode)
{
CGDisplayModeRef native = CGDisplayCopyDisplayMode(monitor->ns.displayID);
if (!native) {
_glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to query display mode");
return false;
}
*mode = vidmodeFromCGDisplayMode(native, monitor->ns.fallbackRefreshRate);
CGDisplayModeRelease(native);
}

2
glfw/internal.h vendored
View File

@@ -686,7 +686,7 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
float* xscale, float* yscale);
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height);
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count);
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode);
bool _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode);
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp);
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp);

View File

@@ -27,6 +27,8 @@
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#define _POSIX_C_SOURCE 200809L
#include "internal.h"
#include <sys/types.h>
@@ -39,6 +41,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#ifndef SYN_DROPPED // < v2.6.39 kernel headers
// Workaround for CentOS-6, which is supported till 2020-11-30, but still on v2.6.32
@@ -135,7 +138,7 @@ static bool openJoystickDevice(const char* path)
}
_GLFWjoystickLinux linjs = {0};
linjs.fd = open(path, O_RDONLY | O_NONBLOCK);
linjs.fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
if (linjs.fd == -1)
return false;

2
glfw/monitor.c vendored
View File

@@ -445,7 +445,7 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle)
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_glfwPlatformGetVideoMode(monitor, &monitor->currentMode);
if (!_glfwPlatformGetVideoMode(monitor, &monitor->currentMode)) return NULL;
return &monitor->currentMode;
}

View File

@@ -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",

246
glfw/wl_decor.c vendored Normal file
View File

@@ -0,0 +1,246 @@
/*
* wl_decor.c
* Copyright (C) 2024 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#define _POSIX_C_SOURCE 200809L
#include "wl_decor.h"
#include "wl_client_side_decorations.h"
#include "libdecor-0/libdecor.h"
#include <dlfcn.h>
#include <string.h>
#include <stdlib.h>
// 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 struct {
void* libdecor_handle;
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)"); \
dlclose(handle); handle = NULL; return false; \
memset(&libdecor_funcs, 0, sizeof(libdecor_funcs)); \
} \
}
static bool
glfw_wl_load_libdecor(void) {
if (libdecor_funcs.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_funcs.libdecor_handle = _glfw_dlopen(libnames[i]);
if (libdecor_funcs.libdecor_handle) break;
}
if (!libdecor_funcs.libdecor_handle) {
libdecor_funcs.libdecor_handle = _glfw_dlopen(libnames[0]);
if (!libdecor_funcs.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_funcs.libdecor_handle, name)
funcs
#undef F
return true;
}
#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
// }}}
typedef struct DecorLibState {
struct libdecor* libdecor;
} DecorLibState;
void handle_libdecor_error(struct libdecor* context UNUSED, enum libdecor_error error, const char* message) {
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: libdecor error %u: %s", error, message);
}
static struct libdecor_interface libdecor_interface = {
.error = handle_libdecor_error
};
static DECOR_LIB_HANDLE
glfw_wl_load_decorations_library_(struct wl_display *display) {
if (!glfw_wl_load_libdecor()) return NULL;
DecorLibState *ans = calloc(1, sizeof(DecorLibState));
if (!ans) { _glfwInputError(GLFW_PLATFORM_ERROR, "Out of memory"); return NULL; }
ans->libdecor = libdecor_new(display, &libdecor_interface);
if (!ans->libdecor) _glfwInputError(GLFW_PLATFORM_ERROR, "libdecor_new() returned NULL");
return (DECOR_LIB_HANDLE) ans;
}
DECOR_LIB_HANDLE
glfw_wl_load_decorations_library(struct wl_display *display) {
// See https://gitlab.freedesktop.org/libdecor/libdecor/-/issues/65 for why we need this nautanki with GDK_BACKEND
char *gdk_backend = getenv("GDK_BACKEND");
if (gdk_backend && strcmp(gdk_backend, "wayland") != 0) {
gdk_backend = strdup(gdk_backend);
setenv("GDK_BACKEND", "wayland", 1);
}
DECOR_LIB_HANDLE ans = glfw_wl_load_decorations_library_(display);
if (gdk_backend) {
setenv("GDK_BACKEND", gdk_backend, 1);
free(gdk_backend);
}
return ans;
}
void
glfw_wl_unload_decorations_library(DECOR_LIB_HANDLE h_) {
if (h_) {
DecorLibState *h = (DecorLibState*)h_;
if (h->libdecor) { libdecor_unref(h->libdecor); }
free(h);
}
if (libdecor_funcs.libdecor_handle) {
dlclose(libdecor_funcs.libdecor_handle); libdecor_funcs.libdecor_handle = NULL;
memset(&libdecor_funcs, 0, sizeof(libdecor_funcs));
}
}
int
glfw_wl_dispatch_decor_events(void) {
// TODO: change this to just call while (g_main_context_iteration(NULL, FALSE)); when using the gtk plugin
// will require a patch to libdecor. The libdecor API currently has no way to either tell what plugin
// is being used or to just dispatch non-Wayland events.
// https://gitlab.freedesktop.org/libdecor/libdecor/-/issues/70
return libdecor_dispatch(((DecorLibState*)_glfw.wl.decor)->libdecor, 0);
}
typedef struct Frame {
struct libdecor_frame *libdecor;
} Frame;
void
glfw_wl_set_fullscreen(_GLFWwindow *w, bool on, struct wl_output *monitor) {
Frame *d = (Frame*)w->wl.frame;
if (d && d->libdecor) {
if (on) libdecor_frame_set_fullscreen(d->libdecor, monitor);
else libdecor_frame_unset_fullscreen(d->libdecor);
} else if (w->wl.xdg.toplevel) {
if (on) {
xdg_toplevel_set_fullscreen(w->wl.xdg.toplevel, monitor);
if (!w->wl.decorations.serverSide) free_csd_surfaces(w);
} else {
xdg_toplevel_unset_fullscreen(w->wl.xdg.toplevel);
ensure_csd_resources(w);
}
}
}
void
glfw_wl_set_maximized(_GLFWwindow *w, bool on) {
Frame *d = (Frame*)w->wl.frame;
if (d && d->libdecor) {
if (on) libdecor_frame_set_maximized(d->libdecor);
else libdecor_frame_unset_maximized(d->libdecor);
} else if (w->wl.xdg.toplevel) {
if (on) xdg_toplevel_set_maximized(w->wl.xdg.toplevel);
else xdg_toplevel_unset_maximized(w->wl.xdg.toplevel);
}
}
void
glfw_wl_set_minimized(_GLFWwindow *w) {
Frame *d = (Frame*)w->wl.frame;
if (d && d->libdecor) libdecor_frame_set_minimized(d->libdecor);
else if (w->wl.xdg.toplevel) xdg_toplevel_set_minimized(w->wl.xdg.toplevel);
}
void
glfw_wl_set_title(_GLFWwindow *w, const char *title) {
// Wayland cannot handle requests larger than ~8200 bytes. Sending
// one causes an abort(). Since titles this large are meaningless anyway
// ensure they do not happen.
if (!title) title = "";
char *safe_title = utf_8_strndup(title, 2048);
if (!safe_title) return;
if (w->wl.title && strcmp(w->wl.title, safe_title) == 0) { free(safe_title); return; }
free(w->wl.title); w->wl.title = safe_title;
Frame *d = (Frame*)w->wl.frame;
if (d && d->libdecor) libdecor_frame_set_title(d->libdecor, w->wl.title);
else if (w->wl.xdg.toplevel) {
xdg_toplevel_set_title(w->wl.xdg.toplevel, w->wl.title);
change_csd_title(w);
}
}
void
glfw_wl_set_app_id(_GLFWwindow *w, const char *appid) {
if (!appid || !appid[0]) return;
Frame *d = (Frame*)w->wl.frame;
if (d && d->libdecor) libdecor_frame_set_app_id(d->libdecor, appid);
else if (w->wl.xdg.toplevel) xdg_toplevel_set_app_id(w->wl.xdg.toplevel, appid);
}
void
glfw_wl_set_size_limits(_GLFWwindow *w, int minwidth, int minheight, int maxwidth, int maxheight) {
if (w->wl.xdg.toplevel) {
minwidth = minwidth == GLFW_DONT_CARE ? 0 : minwidth;
minheight = minheight == GLFW_DONT_CARE ? 0 : minheight;
maxwidth = maxwidth == GLFW_DONT_CARE ? 0 : maxwidth;
maxheight = maxheight == GLFW_DONT_CARE ? 0 : maxheight;
Frame *d = (Frame*)w->wl.frame;
if (d && d->libdecor) {
libdecor_frame_set_min_content_size(d->libdecor, minwidth, minheight);
libdecor_frame_set_max_content_size(d->libdecor, maxwidth, maxheight);
} else {
xdg_toplevel_set_min_size(w->wl.xdg.toplevel, minwidth, minheight);
xdg_toplevel_set_max_size(w->wl.xdg.toplevel, maxwidth, maxheight);
}
}
}

22
glfw/wl_decor.h vendored Normal file
View File

@@ -0,0 +1,22 @@
/*
* wl_decor.h
* Copyright (C) 2024 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#pragma once
#include <wayland-client.h>
#include <stdbool.h>
#include "internal.h"
DECOR_LIB_HANDLE glfw_wl_load_decorations_library(struct wl_display*);
void glfw_wl_unload_decorations_library(DECOR_LIB_HANDLE);
int glfw_wl_dispatch_decor_events(void);
void glfw_wl_set_fullscreen(_GLFWwindow *w, bool on, struct wl_output *monitor);
void glfw_wl_set_maximized(_GLFWwindow *w, bool on);
void glfw_wl_set_minimized(_GLFWwindow *w);
void glfw_wl_set_title(_GLFWwindow *w, const char *title);
void glfw_wl_set_app_id(_GLFWwindow *w, const char *appid);
void glfw_wl_set_size_limits(_GLFWwindow *w, int minwidth, int minheight, int maxwidth, int maxheight);

8
glfw/wl_init.c vendored
View File

@@ -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"
@@ -254,10 +255,7 @@ static void pointerHandleButton(void* data UNUSED,
window->wl.decorations.last_click_on_top_decoration_at = monotonic();
if (window->wl.decorations.last_click_on_top_decoration_at - last_click_at <= _glfwPlatformGetDoubleClickInterval(window)) {
window->wl.decorations.last_click_on_top_decoration_at = 0;
if (window->wl.current.toplevel_states & TOPLEVEL_STATE_MAXIMIZED)
xdg_toplevel_unset_maximized(window->wl.xdg.toplevel);
else
xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
glfw_wl_set_maximized(window, !_glfwPlatformWindowMaximized(window));
return;
}
}
@@ -883,6 +881,7 @@ int _glfwPlatformInit(void)
wl_registry_add_listener(_glfw.wl.registry, &registryListener, NULL);
if (!glfw_xkb_create_context(&_glfw.wl.xkb)) return false;
if (!(_glfw.wl.decor = glfw_wl_load_decorations_library(_glfw.wl.display))) return false;
// Sync so we got all registry objects
wl_display_roundtrip(_glfw.wl.display);
@@ -925,6 +924,7 @@ int _glfwPlatformInit(void)
void _glfwPlatformTerminate(void)
{
glfw_wl_unload_decorations_library(_glfw.wl.decor);
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;

8
glfw/wl_monitor.c vendored
View File

@@ -195,9 +195,13 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
return monitor->modes;
}
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
bool _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
{
*mode = monitor->modes[monitor->wl.currentMode];
if (monitor->modeCount > monitor->wl.currentMode) {
*mode = monitor->modes[monitor->wl.currentMode];
return true;
}
return false;
}
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor UNUSED, GLFWgammaramp* ramp UNUSED)

5
glfw/wl_platform.h vendored
View File

@@ -117,6 +117,9 @@ typedef struct _GLFWWaylandCSDEdge {
int x, y;
} _GLFWWaylandCSDEdge;
typedef struct {int x;} *DECOR_LIB_HANDLE;
typedef struct {int x;} *DECOR_FRAME_HANDLE;
typedef enum WaylandWindowState {
TOPLEVEL_STATE_NONE = 0,
@@ -254,6 +257,7 @@ typedef struct _GLFWwindowWayland
uint32_t toplevel_states;
uint32_t decoration_mode;
} current, pending;
DECOR_FRAME_HANDLE frame;
} _GLFWwindowWayland;
typedef enum _GLFWWaylandOfferType
@@ -357,6 +361,7 @@ typedef struct _GLFWlibraryWayland
size_t dataOffersCounter;
_GLFWWaylandDataOffer dataOffers[8];
bool has_preferred_buffer_scale;
DECOR_LIB_HANDLE decor;
} _GLFWlibraryWayland;
// Wayland-specific per-monitor data

99
glfw/wl_window.c vendored
View File

@@ -28,7 +28,7 @@
#define _GNU_SOURCE
#include "internal.h"
#include "wl_decor.h"
#include "backend_utils.h"
#include "linux_notify.h"
#include "wl_client_side_decorations.h"
@@ -597,20 +597,8 @@ static bool createSurface(_GLFWwindow* window,
return true;
}
static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, bool on)
{
if (window->wl.xdg.toplevel)
{
if (on) {
xdg_toplevel_set_fullscreen(
window->wl.xdg.toplevel,
monitor ? monitor->wl.output : NULL);
if (!window->wl.decorations.serverSide) free_csd_surfaces(window);
} else {
xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel);
ensure_csd_resources(window);
}
}
static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, bool on) {
glfw_wl_set_fullscreen(window, on, monitor ? monitor->wl.output : NULL);
}
@@ -1022,33 +1010,20 @@ create_window_desktop_surface(_GLFWwindow* window)
&xdgToplevelListener,
window);
if (window->wl.title)
xdg_toplevel_set_title(window->wl.xdg.toplevel, window->wl.title);
if (window->minwidth != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE)
xdg_toplevel_set_min_size(window->wl.xdg.toplevel,
window->minwidth, window->minheight);
if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE)
xdg_toplevel_set_max_size(window->wl.xdg.toplevel,
window->maxwidth, window->maxheight);
glfw_wl_set_size_limits(window, window->minwidth, window->minheight, window->maxwidth, window->maxheight);
if (window->monitor)
{
xdg_toplevel_set_fullscreen(window->wl.xdg.toplevel,
window->monitor->wl.output);
glfw_wl_set_fullscreen(window, true, window->monitor->wl.output);
}
else if (window->wl.maximize_on_first_show)
{
window->wl.maximize_on_first_show = false;
xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
setXdgDecorations(window);
glfw_wl_set_maximized(window, true);
}
else
{
setXdgDecorations(window);
}
if (strlen(window->wl.appId))
xdg_toplevel_set_app_id(window->wl.xdg.toplevel, window->wl.appId);
if (!window->monitor) setXdgDecorations(window);
glfw_wl_set_app_id(window, window->wl.appId);
if (window->wl.title)
glfw_wl_set_title(window, window->wl.title);
wl_surface_commit(window->wl.surface);
wl_display_roundtrip(_glfw.wl.display);
@@ -1104,8 +1079,8 @@ wayland_read_events(int poll_result, int events, void *data UNUSED) {
else wl_display_cancel_read(_glfw.wl.display);
}
static void handleEvents(monotonic_t timeout)
{
static void
handleEvents(monotonic_t timeout) {
struct wl_display* display = _glfw.wl.display;
errno = 0;
EVDBG("starting handleEvents(%.2f)", monotonic_t_to_s_double(timeout));
@@ -1141,6 +1116,13 @@ static void handleEvents(monotonic_t timeout)
}
glfw_ibus_dispatch(&_glfw.wl.xkb.ibus);
glfw_dbus_session_bus_dispatch();
// technically we should wait on the libdecor fd but
// for both cairo and gtk plugins the fd is just the wayland display fd so
// no need to wait on it
if (_glfw.wl.decor) {
int num = glfw_wl_dispatch_decor_events(); (void)num;
EVDBG("dispatched %d Wayland events", num);
}
EVDBG("other dispatch done");
if (_glfw.wl.eventLoopData.wakeup_fd_ready) check_for_wakeup_events(&_glfw.wl.eventLoopData);
}
@@ -1333,19 +1315,7 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
wl_callback_destroy(window->wl.frameCallbackData.current_wl_callback);
}
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
{
if (window->wl.title) {
if (title && strcmp(title, window->wl.title) == 0) return;
free(window->wl.title);
} else if (!title) return;
// Wayland cannot handle requests larger than ~8200 bytes. Sending
// one causes an abort(). Since titles this large are meaningless anyway
// ensure they do not happen.
window->wl.title = utf_8_strndup(title, 2048);
if (window->wl.xdg.toplevel) xdg_toplevel_set_title(window->wl.xdg.toplevel, window->wl.title);
change_csd_title(window);
}
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) { glfw_wl_set_title(window, title); }
void _glfwPlatformSetWindowIcon(_GLFWwindow* window UNUSED,
int count UNUSED, const GLFWimage* images UNUSED)
@@ -1397,20 +1367,9 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
}
}
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
int minwidth, int minheight,
int maxwidth, int maxheight)
{
if (window->wl.xdg.toplevel)
{
if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE)
minwidth = minheight = 0;
if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)
maxwidth = maxheight = 0;
xdg_toplevel_set_min_size(window->wl.xdg.toplevel, minwidth, minheight);
xdg_toplevel_set_max_size(window->wl.xdg.toplevel, maxwidth, maxheight);
commit_window_surface_if_safe(window);
}
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight) {
glfw_wl_set_size_limits(window, minwidth, minheight, maxwidth, maxheight);
commit_window_surface_if_safe(window);
}
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window UNUSED,
@@ -1472,20 +1431,16 @@ monotonic_t _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
return ms_to_monotonic_t(500ll);
}
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
{
if (window->wl.xdg.toplevel)
xdg_toplevel_set_minimized(window->wl.xdg.toplevel);
}
void _glfwPlatformIconifyWindow(_GLFWwindow* window) { glfw_wl_set_minimized(window); }
void _glfwPlatformRestoreWindow(_GLFWwindow* window)
{
if (window->wl.xdg.toplevel)
{
if (window->monitor)
xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel);
glfw_wl_set_fullscreen(window, false, window->monitor->wl.output);
if (window->wl.current.toplevel_states & TOPLEVEL_STATE_MAXIMIZED)
xdg_toplevel_unset_maximized(window->wl.xdg.toplevel);
glfw_wl_set_maximized(window, false);
// There is no way to unset minimized, or even to know if we are
// minimized, so there is nothing to do in this case.
}
@@ -1496,7 +1451,7 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
{
if (window->wl.xdg.toplevel)
{
xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
glfw_wl_set_maximized(window, true);
}
}

10
glfw/x11_monitor.c vendored
View File

@@ -494,8 +494,8 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
return result;
}
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
{
bool _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) {
bool ok = false;
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
{
XRRScreenResources* sr =
@@ -505,8 +505,10 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
if (ci)
{
const XRRModeInfo* mi = getModeInfo(sr, ci->mode);
if (mi) // mi can be NULL if the monitor has been disconnected
if (mi) { // mi can be NULL if the monitor has been disconnected
*mode = vidmodeFromModeInfo(mi, ci);
ok = true;
}
XRRFreeCrtcInfo(ci);
}
@@ -515,6 +517,7 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
}
else
{
ok = true;
mode->width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen);
mode->height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen);
mode->refreshRate = 0;
@@ -522,6 +525,7 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
_glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen),
&mode->redBits, &mode->greenBits, &mode->blueBits);
}
return ok;
}
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)

View File

@@ -1462,8 +1462,8 @@ glfw_init(PyObject UNUSED *self, PyObject *args) {
glfwSetDrawTextFunction(draw_text_callback);
#endif
get_window_dpi(NULL, &global_state.default_dpi.x, &global_state.default_dpi.y);
edge_spacing_func = edge_sf; Py_INCREF(edge_spacing_func);
}
edge_spacing_func = edge_sf; Py_INCREF(edge_spacing_func);
Py_INCREF(ans);
return ans;
}
@@ -1823,6 +1823,7 @@ static PyObject*
primary_monitor_size(PYNOARG) {
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
if (mode == NULL) { PyErr_SetString(PyExc_ValueError, "Failed to get video mode for primary monitor"); return NULL; }
return Py_BuildValue("ii", mode->width, mode->height);
}

View File

@@ -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',