mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
apprt/gtk: add support for _NET_WM_STATE
This commit is contained in:
@ -856,6 +856,37 @@ pub fn setInitialWindowSize(self: *const Surface, width: u32, height: u32) !void
|
|||||||
@intCast(width),
|
@intCast(width),
|
||||||
@intCast(height),
|
@intCast(height),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// TODO: move this check somewhere else so we can reuse it
|
||||||
|
// If the current WM doesn't support _NET_WM_STATE, we shouldn't try to set it.
|
||||||
|
const gdk_surface = c.gtk_native_get_surface(@ptrCast(window.window));
|
||||||
|
if (c.g_type_check_instance_is_a(@ptrCast(@alignCast(gdk_surface)), c.gdk_x11_surface_get_type()) == 0) return; // X11 only, sorry Wayland
|
||||||
|
|
||||||
|
if (c.XInternAtom(c.gdk_x11_display_get_xdisplay(c.gdk_surface_get_display(gdk_surface)), "_NET_WM_STATE", 1) == 0) {
|
||||||
|
log.warn("current WM does not support _NET_WM_STATE", .{});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const workarea = self.getWorkarea(gdk_surface) orelse return;
|
||||||
|
if (height >= workarea.height and width >= workarea.width) {
|
||||||
|
c.gtk_window_maximize(@ptrCast(window.window));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getWorkarea(self: *const Surface, gdk_surface: ?*c.GdkSurface) ?c.GdkRectangle {
|
||||||
|
const monitor = c.gdk_display_get_monitor_at_surface(
|
||||||
|
c.gdk_display_get_default(),
|
||||||
|
gdk_surface,
|
||||||
|
);
|
||||||
|
|
||||||
|
var workarea: c.GdkRectangle = std.mem.zeroes(c.GdkRectangle);
|
||||||
|
if (self.app.wayland != null) {
|
||||||
|
c.gdk_monitor_get_geometry(monitor, &workarea);
|
||||||
|
} else {
|
||||||
|
c.gdk_x11_monitor_get_workarea(monitor, &workarea);
|
||||||
|
}
|
||||||
|
|
||||||
|
return workarea;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setSizeLimits(self: *const Surface, min: apprt.SurfaceSize, max_: ?apprt.SurfaceSize) !void {
|
pub fn setSizeLimits(self: *const Surface, min: apprt.SurfaceSize, max_: ?apprt.SurfaceSize) !void {
|
||||||
|
@ -211,6 +211,7 @@ pub fn init(self: *Window, app: *App) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_ = c.g_signal_connect_data(gtk_window, "notify::decorated", c.G_CALLBACK(>kWindowNotifyDecorated), self, null, c.G_CONNECT_DEFAULT);
|
_ = c.g_signal_connect_data(gtk_window, "notify::decorated", c.G_CALLBACK(>kWindowNotifyDecorated), self, null, c.G_CONNECT_DEFAULT);
|
||||||
|
_ = c.g_signal_connect_data(gtk_window, "notify::maximized", c.G_CALLBACK(>kWindowNotifyMaximized), self, null, c.G_CONNECT_DEFAULT);
|
||||||
|
|
||||||
// If we are disabling decorations then disable them right away.
|
// If we are disabling decorations then disable them right away.
|
||||||
if (!app.config.@"window-decoration") {
|
if (!app.config.@"window-decoration") {
|
||||||
@ -613,6 +614,46 @@ fn gtkWindowNotifyDecorated(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handle setting or removing the _NET_WM_STATE property on the window.
|
||||||
|
/// This is used to notify the window manager if the window is maximized.
|
||||||
|
/// Though, this depends on the window manager supporting _NET_WM_STATE.
|
||||||
|
fn gtkWindowNotifyMaximized(
|
||||||
|
window: *c.GtkWindow,
|
||||||
|
_: *c.GParamSpec,
|
||||||
|
_: ?*anyopaque,
|
||||||
|
) callconv(.C) void {
|
||||||
|
const gdk_surface = c.gtk_native_get_surface(@ptrCast(window));
|
||||||
|
if (c.g_type_check_instance_is_a(@ptrCast(@alignCast(gdk_surface)), c.gdk_x11_surface_get_type()) == 0) return; // X11 only, sorry Wayland
|
||||||
|
|
||||||
|
const xdisplay = c.gdk_x11_display_get_xdisplay(c.gdk_surface_get_display(gdk_surface)) orelse return;
|
||||||
|
|
||||||
|
// If the WM doesn't support _NET_WM_STATE, no need to continue.
|
||||||
|
if (c.XInternAtom(xdisplay, "_NET_WM_STATE", 1) == 0) {
|
||||||
|
log.warn("current WM does not support _NET_WM_STATE", .{});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://tronche.com/gui/x/xlib/events/client-communication/client-message.html#XClientMessageEvent
|
||||||
|
var client_message_event: c.XClientMessageEvent = std.mem.zeroes(c.XClientMessageEvent);
|
||||||
|
client_message_event.type = c.ClientMessage;
|
||||||
|
client_message_event.window = c.gdk_x11_surface_get_xid(gdk_surface);
|
||||||
|
client_message_event.message_type = c.XInternAtom(xdisplay, "_NET_WM_STATE", 0);
|
||||||
|
client_message_event.format = 32;
|
||||||
|
client_message_event.data.l[0] = c.gtk_window_is_maximized(window);
|
||||||
|
client_message_event.data.l[1] = @intCast(c.XInternAtom(xdisplay, "_NET_WM_STATE_MAXIMIZED_VERT", 0));
|
||||||
|
|
||||||
|
// https://tronche.com/gui/x/xlib/event-handling/XSendEvent.html
|
||||||
|
_ = c.XSendEvent(
|
||||||
|
xdisplay,
|
||||||
|
c.DefaultRootWindow(xdisplay),
|
||||||
|
0,
|
||||||
|
c.SubstructureRedirectMask | c.SubstructureNotifyMask,
|
||||||
|
@ptrCast(&client_message_event),
|
||||||
|
);
|
||||||
|
|
||||||
|
_ = c.XFlush(xdisplay);
|
||||||
|
}
|
||||||
|
|
||||||
// Note: we MUST NOT use the GtkButton parameter because gtkActionNewTab
|
// Note: we MUST NOT use the GtkButton parameter because gtkActionNewTab
|
||||||
// sends an undefined value.
|
// sends an undefined value.
|
||||||
fn gtkTabNewClick(_: *c.GtkButton, ud: ?*anyopaque) callconv(.C) void {
|
fn gtkTabNewClick(_: *c.GtkButton, ud: ?*anyopaque) callconv(.C) void {
|
||||||
|
Reference in New Issue
Block a user