apprt/gtk-ng: toasts

This commit is contained in:
Mitchell Hashimoto
2025-07-26 12:29:07 -07:00
parent 18831374ca
commit ccde429bde
4 changed files with 71 additions and 8 deletions

View File

@ -275,7 +275,10 @@ pub const Surface = extern struct {
const impl = gobject.ext.defineSignal(
name,
Self,
&.{},
&.{
apprt.Clipboard,
[*:0]const u8,
},
void,
);
};
@ -2236,7 +2239,7 @@ const Clipboard = struct {
Surface.signals.@"clipboard-write".impl.emit(
self,
null,
.{},
.{ clipboard_type, val.ptr },
null,
);

View File

@ -8,6 +8,7 @@ const gobject = @import("gobject");
const gtk = @import("gtk");
const i18n = @import("../../../os/main.zig").i18n;
const apprt = @import("../../../apprt.zig");
const input = @import("../../../input.zig");
const CoreSurface = @import("../../../Surface.zig");
const gtk_version = @import("../gtk_version.zig");
@ -122,7 +123,8 @@ pub const Window = extern struct {
config: ?*Config = null,
// Template bindings
surface: *Surface = undefined,
surface: *Surface,
toast_overlay: *adw.ToastOverlay,
pub var offset: c_int = 0;
};
@ -227,6 +229,18 @@ pub const Window = extern struct {
};
}
/// Queue a simple text-based toast. All text-based toasts share the
/// same timeout for consistency.
///
// This is not `pub` because we should be using signals emitted by
// other widgets to trigger our toasts. Other objects should not
// trigger toasts directly.
fn addToast(self: *Window, title: [*:0]const u8) void {
const toast = adw.Toast.new(title);
toast.setTimeout(3);
self.private().toast_overlay.addToast(toast);
}
//---------------------------------------------------------------
// Properties
@ -264,6 +278,7 @@ pub const Window = extern struct {
_: *gobject.ParamSpec,
self: *Self,
) callconv(.c) void {
self.addToast(i18n._("Reloaded the configuration"));
self.syncAppearance();
}
@ -377,6 +392,29 @@ pub const Window = extern struct {
self.as(gtk.Window).destroy();
}
fn surfaceClipboardWrite(
_: *Surface,
clipboard_type: apprt.Clipboard,
text: [*:0]const u8,
self: *Self,
) callconv(.c) void {
// We only toast for the standard clipboard.
if (clipboard_type != .standard) return;
// We only toast if configured to
const priv = self.private();
const config_obj = priv.config orelse return;
const config = config_obj.get();
if (!config.@"app-notifications".@"clipboard-copy") {
return;
}
if (text[0] != 0)
self.addToast(i18n._("Copied to clipboard"))
else
self.addToast(i18n._("Cleared clipboard"));
}
fn surfaceCloseRequest(
surface: *Surface,
scope: *const Surface.CloseScope,
@ -542,9 +580,11 @@ pub const Window = extern struct {
// Bindings
class.bindTemplateChildPrivate("surface", .{});
class.bindTemplateChildPrivate("toast_overlay", .{});
// Template Callbacks
class.bindTemplateCallback("close_request", &windowCloseRequest);
class.bindTemplateCallback("surface_clipboard_write", &surfaceClipboardWrite);
class.bindTemplateCallback("surface_close_request", &surfaceCloseRequest);
class.bindTemplateCallback("surface_toggle_fullscreen", &surfaceToggleFullscreen);
class.bindTemplateCallback("surface_toggle_maximize", &surfaceToggleMaximize);

View File

@ -43,10 +43,13 @@ template $GhosttyWindow: Adw.ApplicationWindow {
visible: bind template.debug;
}
$GhosttySurface surface {
close-request => $surface_close_request();
toggle-fullscreen => $surface_toggle_fullscreen();
toggle-maximize => $surface_toggle_maximize();
Adw.ToastOverlay toast_overlay {
$GhosttySurface surface {
close-request => $surface_close_request();
clipboard-write => $surface_clipboard_write();
toggle-fullscreen => $surface_toggle_fullscreen();
toggle-maximize => $surface_toggle_maximize();
}
}
};
}

View File

@ -29,10 +29,27 @@ pub const IMEPos = struct {
/// The clipboard type.
///
/// If this is changed, you must also update ghostty.h
pub const Clipboard = enum(u2) {
pub const Clipboard = enum(Backing) {
standard = 0, // ctrl+c/v
selection = 1,
primary = 2,
// Our backing isn't is as small as we can in Zig, but a full
// C int if we're binding to C APIs.
const Backing = switch (build_config.app_runtime) {
.gtk, .@"gtk-ng" => c_int,
else => u2,
};
/// Make this a valid gobject if we're in a GTK environment.
pub const getGObjectType = switch (build_config.app_runtime) {
.gtk, .@"gtk-ng" => @import("gobject").ext.defineEnum(
Clipboard,
.{ .name = "GhosttyApprtClipboard" },
),
.none => void,
};
};
pub const ClipboardRequestType = enum(u8) {