mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-17 09:16:11 +03:00
apprt/gtk: subscribe to AdwStyleManager::dark for ColorScheme (#6007)
This commit is contained in:
@ -14,6 +14,7 @@ const gtk = @import("gtk");
|
|||||||
const gio = @import("gio");
|
const gio = @import("gio");
|
||||||
const glib = @import("glib");
|
const glib = @import("glib");
|
||||||
const gobject = @import("gobject");
|
const gobject = @import("gobject");
|
||||||
|
const adw = @import("adw");
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
@ -1256,9 +1257,22 @@ pub fn run(self: *App) !void {
|
|||||||
self.transient_cgroup_base = path;
|
self.transient_cgroup_base = path;
|
||||||
} else log.debug("cgroup isolation disabled config={}", .{self.config.@"linux-cgroup"});
|
} else log.debug("cgroup isolation disabled config={}", .{self.config.@"linux-cgroup"});
|
||||||
|
|
||||||
// Setup our D-Bus connection for listening to settings changes,
|
// Setup color scheme notifications
|
||||||
// and asynchronously request the initial color scheme
|
const adw_app: *adw.Application = @ptrCast(@alignCast(self.app));
|
||||||
self.initDbus();
|
const style_manager: *adw.StyleManager = adw_app.getStyleManager();
|
||||||
|
_ = gobject.Object.signals.notify.connect(
|
||||||
|
style_manager,
|
||||||
|
*App,
|
||||||
|
adwNotifyDark,
|
||||||
|
self,
|
||||||
|
.{
|
||||||
|
.detail = "dark",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Make an initial request to set up the color scheme
|
||||||
|
const light = style_manager.getDark() == 0;
|
||||||
|
self.colorSchemeEvent(if (light) .light else .dark);
|
||||||
|
|
||||||
// Setup our actions
|
// Setup our actions
|
||||||
self.initActions();
|
self.initActions();
|
||||||
@ -1292,57 +1306,6 @@ pub fn run(self: *App) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Subscribe to various DBus signals and get information from the FreeDesktop
|
|
||||||
/// portals by calling various DBus methods
|
|
||||||
fn initDbus(self: *App) void {
|
|
||||||
// FIXME: when self.app is converted to zig-gobject
|
|
||||||
const app: *gio.Application = @ptrCast(@alignCast(self.app));
|
|
||||||
const dbus = app.getDbusConnection() orelse {
|
|
||||||
log.warn("unable to get dbus connection, not setting up events", .{});
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Listen for light/dark color scheme changes.
|
|
||||||
_ = dbus.signalSubscribe(
|
|
||||||
null,
|
|
||||||
"org.freedesktop.portal.Settings",
|
|
||||||
"SettingChanged",
|
|
||||||
"/org/freedesktop/portal/desktop",
|
|
||||||
"org.freedesktop.appearance",
|
|
||||||
.{ .match_arg0_namespace = true },
|
|
||||||
gtkNotifyColorScheme,
|
|
||||||
self,
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Request the initial color scheme asynchronously.
|
|
||||||
{
|
|
||||||
const parameters = glib.Variant.new(
|
|
||||||
"(ss)",
|
|
||||||
"org.freedesktop.appearance",
|
|
||||||
"color-scheme",
|
|
||||||
);
|
|
||||||
defer glib.free(parameters);
|
|
||||||
|
|
||||||
const reply_type = glib.VariantType.new("(v)");
|
|
||||||
defer glib.free(reply_type);
|
|
||||||
|
|
||||||
dbus.call(
|
|
||||||
"org.freedesktop.portal.Desktop",
|
|
||||||
"/org/freedesktop/portal/desktop",
|
|
||||||
"org.freedesktop.portal.Settings",
|
|
||||||
"ReadOne",
|
|
||||||
parameters,
|
|
||||||
reply_type,
|
|
||||||
.{},
|
|
||||||
-1,
|
|
||||||
null,
|
|
||||||
dbusColorSchemeCallbackReadOne,
|
|
||||||
self,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This timeout function is started when no surfaces are open. It can be
|
// This timeout function is started when no surfaces are open. It can be
|
||||||
// cancelled if a new surface is opened before the timer expires.
|
// cancelled if a new surface is opened before the timer expires.
|
||||||
pub fn gtkQuitTimerExpired(ud: ?*anyopaque) callconv(.C) c.gboolean {
|
pub fn gtkQuitTimerExpired(ud: ?*anyopaque) callconv(.C) c.gboolean {
|
||||||
@ -1578,163 +1541,15 @@ fn gtkWindowIsActive(
|
|||||||
core_app.focusEvent(false);
|
core_app.focusEvent(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dbusColorSchemeCallbackReadOne(
|
fn adwNotifyDark(
|
||||||
source_object: ?*gobject.Object,
|
style_manager: *adw.StyleManager,
|
||||||
result: *gio.AsyncResult,
|
_: *gobject.ParamSpec,
|
||||||
ud: ?*anyopaque,
|
self: *App,
|
||||||
) callconv(.C) void {
|
) callconv(.C) void {
|
||||||
const self: *App = @ptrCast(@alignCast(ud.?));
|
const color_scheme: apprt.ColorScheme = if (style_manager.getDark() == 0)
|
||||||
const dbus = gobject.ext.cast(gio.DBusConnection, source_object.?).?;
|
.light
|
||||||
|
|
||||||
if (dbusColorSchemeFinish(dbus, result)) |scheme| {
|
|
||||||
self.colorSchemeEvent(scheme);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we got null, we should retry with the older `Read` method
|
|
||||||
const parameters = glib.Variant.new(
|
|
||||||
"(ss)",
|
|
||||||
"org.freedesktop.appearance",
|
|
||||||
"color-scheme",
|
|
||||||
);
|
|
||||||
defer glib.free(parameters);
|
|
||||||
|
|
||||||
const reply_type = glib.VariantType.new("(v)");
|
|
||||||
defer glib.free(reply_type);
|
|
||||||
|
|
||||||
// Request the initial color scheme asynchronously.
|
|
||||||
dbus.call(
|
|
||||||
"org.freedesktop.portal.Desktop",
|
|
||||||
"/org/freedesktop/portal/desktop",
|
|
||||||
"org.freedesktop.portal.Settings",
|
|
||||||
"Read",
|
|
||||||
parameters,
|
|
||||||
reply_type,
|
|
||||||
.{},
|
|
||||||
-1,
|
|
||||||
null,
|
|
||||||
dbusColorSchemeCallbackRead,
|
|
||||||
self,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dbusColorSchemeCallbackRead(
|
|
||||||
source_object: ?*gobject.Object,
|
|
||||||
result: *gio.AsyncResult,
|
|
||||||
ud: ?*anyopaque,
|
|
||||||
) callconv(.C) void {
|
|
||||||
const self: *App = @ptrCast(@alignCast(ud.?));
|
|
||||||
const dbus = gobject.ext.cast(gio.DBusConnection, source_object.?).?;
|
|
||||||
|
|
||||||
if (dbusColorSchemeFinish(dbus, result)) |scheme| {
|
|
||||||
self.colorSchemeEvent(scheme);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.colorSchemeEvent(.light);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dbusColorSchemeFinish(dbus: *gio.DBusConnection, result: *gio.AsyncResult) ?apprt.ColorScheme {
|
|
||||||
var err: ?*glib.Error = null;
|
|
||||||
defer if (err) |e| e.free();
|
|
||||||
|
|
||||||
const value = dbus.callFinish(result, &err) orelse {
|
|
||||||
const e = err orelse {
|
|
||||||
log.warn("dbus call failed but no error?", .{});
|
|
||||||
return .light;
|
|
||||||
};
|
|
||||||
|
|
||||||
// If `ReadOne` is not yet implemented, fall back to deprecated `Read` method
|
|
||||||
// Error code: GDBus.Error:org.freedesktop.DBus.Error.UnknownMethod: No such method “ReadOne”
|
|
||||||
if (e.f_code == 19) return null;
|
|
||||||
|
|
||||||
log.warn("unable to get current color scheme: {s}", .{
|
|
||||||
if (e.f_message) |msg|
|
|
||||||
msg
|
|
||||||
else
|
|
||||||
"(unknown error)",
|
|
||||||
});
|
|
||||||
return .light;
|
|
||||||
};
|
|
||||||
|
|
||||||
defer value.unref();
|
|
||||||
const value_type = glib.VariantType.new("(v)");
|
|
||||||
defer glib.free(value_type);
|
|
||||||
|
|
||||||
if (value.isOfType(value_type) == 0) {
|
|
||||||
return .light;
|
|
||||||
}
|
|
||||||
|
|
||||||
var tmp: ?*glib.Variant = null;
|
|
||||||
value.get("(v)", &tmp);
|
|
||||||
|
|
||||||
const inner = tmp orelse return .light;
|
|
||||||
defer inner.unref();
|
|
||||||
|
|
||||||
const inner_type = glib.VariantType.new("u");
|
|
||||||
defer glib.free(inner_type);
|
|
||||||
|
|
||||||
if (inner.isOfType(inner_type) == 0) return .light;
|
|
||||||
|
|
||||||
return switch (inner.getUint32()) {
|
|
||||||
1 => .dark,
|
|
||||||
else => .light,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This will be called by D-Bus when the style changes between light & dark.
|
|
||||||
fn gtkNotifyColorScheme(
|
|
||||||
_: *gio.DBusConnection,
|
|
||||||
_: ?[*:0]const u8,
|
|
||||||
_: [*:0]const u8,
|
|
||||||
_: [*:0]const u8,
|
|
||||||
_: [*:0]const u8,
|
|
||||||
parameters: *glib.Variant,
|
|
||||||
user_data: ?*anyopaque,
|
|
||||||
) callconv(.C) void {
|
|
||||||
const self: *App = @ptrCast(@alignCast(user_data orelse {
|
|
||||||
log.err("style change notification: userdata is null", .{});
|
|
||||||
return;
|
|
||||||
}));
|
|
||||||
|
|
||||||
{
|
|
||||||
const variant_type = glib.VariantType.new("(ssv)");
|
|
||||||
defer glib.free(variant_type);
|
|
||||||
|
|
||||||
if (parameters.isOfType(variant_type) == 0) {
|
|
||||||
log.err("unexpected parameter type: {s}", .{parameters.getTypeString()});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var namespace: [*c]u8 = undefined;
|
|
||||||
var setting: [*c]u8 = undefined;
|
|
||||||
var value: *glib.Variant = undefined;
|
|
||||||
|
|
||||||
parameters.get("(ssv)", &namespace, &setting, &value);
|
|
||||||
defer {
|
|
||||||
glib.free(namespace);
|
|
||||||
glib.free(setting);
|
|
||||||
value.unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ignore any setting changes that we aren't interested in
|
|
||||||
if (std.mem.orderZ(u8, "org.freedesktop.appearance", namespace) != .eq) return;
|
|
||||||
if (std.mem.orderZ(u8, "color-scheme", setting) != .eq) return;
|
|
||||||
|
|
||||||
{
|
|
||||||
const variant_type = glib.VariantType.new("u");
|
|
||||||
defer glib.free(variant_type);
|
|
||||||
|
|
||||||
if (value.isOfType(variant_type) == 0) {
|
|
||||||
log.err("unexpected value type: {s}", .{value.getTypeString()});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const color_scheme: apprt.ColorScheme = if (value.getUint32() == 1)
|
|
||||||
.dark
|
|
||||||
else
|
else
|
||||||
.light;
|
.dark;
|
||||||
|
|
||||||
self.colorSchemeEvent(color_scheme);
|
self.colorSchemeEvent(color_scheme);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user