mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-25 13:16:11 +03:00
apprt/gtk-ng: clipboard confirmation dialog
This commit is contained in:
@ -7,6 +7,7 @@ const gtk = @import("gtk");
|
||||
|
||||
const apprt = @import("../../../apprt.zig");
|
||||
const gresource = @import("../build/gresource.zig");
|
||||
const i18n = @import("../../../os/main.zig").i18n;
|
||||
const Common = @import("../class.zig").Common;
|
||||
const Dialog = @import("dialog.zig").Dialog;
|
||||
|
||||
@ -25,6 +26,26 @@ pub const ClipboardConfirmationDialog = extern struct {
|
||||
});
|
||||
|
||||
pub const properties = struct {
|
||||
pub const @"can-remember" = struct {
|
||||
pub const name = "can-remember";
|
||||
const impl = gobject.ext.defineProperty(
|
||||
name,
|
||||
Self,
|
||||
bool,
|
||||
.{
|
||||
.nick = "Can Remember",
|
||||
.blurb = "Allow remembering the choice.",
|
||||
.default = false,
|
||||
.accessor = gobject.ext.privateFieldAccessor(
|
||||
Self,
|
||||
Private,
|
||||
&Private.offset,
|
||||
"can_remember",
|
||||
),
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
pub const request = struct {
|
||||
pub const name = "request";
|
||||
const impl = gobject.ext.defineProperty(
|
||||
@ -43,12 +64,37 @@ pub const ClipboardConfirmationDialog = extern struct {
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
pub const @"clipboard-contents" = struct {
|
||||
pub const name = "clipboard-contents";
|
||||
const impl = gobject.ext.defineProperty(
|
||||
name,
|
||||
Self,
|
||||
?*gtk.TextBuffer,
|
||||
.{
|
||||
.nick = "Clipboard Contents",
|
||||
.blurb = "The clipboard contents being read/written.",
|
||||
.accessor = gobject.ext.privateFieldAccessor(
|
||||
Self,
|
||||
Private,
|
||||
&Private.offset,
|
||||
"clipboard_contents",
|
||||
),
|
||||
},
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
const Private = struct {
|
||||
/// The request that this dialog is for.
|
||||
request: ?*apprt.ClipboardRequest = null,
|
||||
|
||||
/// The clipboard contents being read/written.
|
||||
clipboard_contents: ?*gtk.TextBuffer = null,
|
||||
|
||||
/// Whether the user can remember the choice.
|
||||
can_remember: bool = false,
|
||||
|
||||
pub var offset: c_int = 0;
|
||||
};
|
||||
|
||||
@ -58,16 +104,60 @@ pub const ClipboardConfirmationDialog = extern struct {
|
||||
|
||||
fn init(self: *Self, _: *Class) callconv(.C) void {
|
||||
gtk.Widget.initTemplate(self.as(gtk.Widget));
|
||||
|
||||
// Some property signals
|
||||
_ = gobject.Object.signals.notify.connect(
|
||||
self,
|
||||
?*anyopaque,
|
||||
&propRequest,
|
||||
null,
|
||||
.{ .detail = "request" },
|
||||
);
|
||||
|
||||
// Trigger initial values
|
||||
self.propRequest(undefined, null);
|
||||
}
|
||||
|
||||
pub fn present(self: *Self, parent: ?*gtk.Widget) void {
|
||||
self.as(Dialog).present(parent);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Signal Handlers
|
||||
|
||||
fn propRequest(
|
||||
self: *Self,
|
||||
_: *gobject.ParamSpec,
|
||||
_: ?*anyopaque,
|
||||
) callconv(.c) void {
|
||||
const priv = self.private();
|
||||
const req = priv.request orelse return;
|
||||
switch (req.*) {
|
||||
.osc_52_write => {
|
||||
self.as(Dialog.Parent).setHeading(i18n._("Authorize Clipboard Access"));
|
||||
self.as(Dialog.Parent).setBody(i18n._("An application is attempting to write to the clipboard. The current clipboard contents are shown below."));
|
||||
},
|
||||
.osc_52_read => {
|
||||
self.as(Dialog.Parent).setHeading(i18n._("Authorize Clipboard Access"));
|
||||
self.as(Dialog.Parent).setBody(i18n._("An application is attempting to read from the clipboard. The current clipboard contents are shown below."));
|
||||
},
|
||||
.paste => {
|
||||
self.as(Dialog.Parent).setHeading(i18n._("Warning: Potentially Unsafe Paste"));
|
||||
self.as(Dialog.Parent).setBody(i18n._("Pasting this text into the terminal may be dangerous as it looks like some commands may be executed."));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Virtual methods
|
||||
|
||||
fn dispose(self: *Self) callconv(.C) void {
|
||||
const priv = self.private();
|
||||
if (priv.clipboard_contents) |v| {
|
||||
v.unref();
|
||||
priv.clipboard_contents = null;
|
||||
}
|
||||
|
||||
gtk.Widget.disposeTemplate(
|
||||
self.as(gtk.Widget),
|
||||
getGObjectType(),
|
||||
@ -79,6 +169,19 @@ pub const ClipboardConfirmationDialog = extern struct {
|
||||
);
|
||||
}
|
||||
|
||||
fn finalize(self: *Self) callconv(.C) void {
|
||||
const priv = self.private();
|
||||
if (priv.request) |v| {
|
||||
glib.ext.destroy(v);
|
||||
priv.request = null;
|
||||
}
|
||||
|
||||
gobject.Object.virtual_methods.finalize.call(
|
||||
Class.parent,
|
||||
self.as(Parent),
|
||||
);
|
||||
}
|
||||
|
||||
const C = Common(Self, Private);
|
||||
pub const as = C.as;
|
||||
pub const ref = C.ref;
|
||||
@ -101,15 +204,18 @@ pub const ClipboardConfirmationDialog = extern struct {
|
||||
);
|
||||
|
||||
// Bindings
|
||||
//class.bindTemplateChildPrivate("label", .{});
|
||||
//class.bindTemplateChildPrivate("remember_bin", .{});
|
||||
|
||||
// Properties
|
||||
gobject.ext.registerProperties(class, &.{
|
||||
properties.@"can-remember".impl,
|
||||
properties.@"clipboard-contents".impl,
|
||||
properties.request.impl,
|
||||
});
|
||||
|
||||
// Virtual methods
|
||||
gobject.Object.virtual_methods.dispose.implement(class, &dispose);
|
||||
gobject.Object.virtual_methods.finalize.implement(class, &finalize);
|
||||
}
|
||||
|
||||
pub const as = C.Class.as;
|
||||
|
@ -2001,19 +2001,21 @@ const Clipboard = struct {
|
||||
return;
|
||||
}
|
||||
|
||||
// Build a text buffer for our contents
|
||||
const contents_buf: *gtk.TextBuffer = .new(null);
|
||||
defer contents_buf.unref();
|
||||
contents_buf.insertAtCursor(val, @intCast(val.len));
|
||||
|
||||
// Confirm
|
||||
const diag = gobject.ext.newInstance(
|
||||
ClipboardConfirmationDialog,
|
||||
.{ .request = &apprt.ClipboardRequest{
|
||||
.osc_52_write = clipboard_type,
|
||||
} },
|
||||
.{
|
||||
.request = &apprt.ClipboardRequest{ .osc_52_write = clipboard_type },
|
||||
.@"can-remember" = true,
|
||||
.@"clipboard-contents" = contents_buf,
|
||||
},
|
||||
);
|
||||
|
||||
// We need to trigger the dialog
|
||||
|
||||
diag.present(self.as(gtk.Widget));
|
||||
|
||||
log.warn("TODO: confirmation window", .{});
|
||||
}
|
||||
|
||||
/// Request data from the clipboard (read the clipboard). This
|
||||
|
@ -4,6 +4,9 @@
|
||||
* https://gnome.pages.gitlab.gnome.org/libadwaita/doc/1.3/styles-and-appearance.html#custom-styles
|
||||
*/
|
||||
|
||||
/*
|
||||
* GhosttySurface URL overlay
|
||||
*/
|
||||
label.url-overlay {
|
||||
padding: 4px 8px 4px 8px;
|
||||
outline-style: solid;
|
||||
@ -23,6 +26,9 @@ label.url-overlay.right {
|
||||
border-radius: 6px 0px 0px 0px;
|
||||
}
|
||||
|
||||
/*
|
||||
* GhosttySurface resize overlay
|
||||
*/
|
||||
.size-overlay label {
|
||||
padding: 4px 8px 4px 8px;
|
||||
border-radius: 6px 6px 6px 6px;
|
||||
@ -30,3 +36,22 @@ label.url-overlay.right {
|
||||
outline-width: 1px;
|
||||
outline-color: #555555;
|
||||
}
|
||||
|
||||
/*
|
||||
* GhosttyClipboardConfirmationDialog
|
||||
*
|
||||
* Based on boxed-list-separate:
|
||||
* https://gitlab.gnome.org/GNOME/libadwaita/-/blob/ad446167acf3e6d1ee693f98ca636268be8592a1/src/stylesheet/widgets/_lists.scss#L548
|
||||
*/
|
||||
.clipboard-confirmation-dialog list {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.clipboard-confirmation-dialog list > row {
|
||||
border: none;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.clipboard-confirmation-dialog list > row:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
@ -3,8 +3,13 @@ using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
template $GhosttyClipboardConfirmationDialog: $GhosttyDialog {
|
||||
styles [
|
||||
"clipboard-confirmation-dialog",
|
||||
]
|
||||
|
||||
heading: _("Authorize Clipboard Access");
|
||||
body: _("An application is attempting to write to the clipboard. The current clipboard contents are shown below.");
|
||||
// Not localized because this is a placeholder users never see.
|
||||
body: "If you see this text, there is a bug in Ghostty. Please report it.";
|
||||
|
||||
responses [
|
||||
cancel: _("Deny") suggested,
|
||||
@ -17,10 +22,6 @@ template $GhosttyClipboardConfirmationDialog: $GhosttyDialog {
|
||||
extra-child: ListBox {
|
||||
selection-mode: none;
|
||||
|
||||
styles [
|
||||
"boxed-list-separate",
|
||||
]
|
||||
|
||||
Overlay {
|
||||
styles [
|
||||
"osd",
|
||||
@ -32,6 +33,10 @@ template $GhosttyClipboardConfirmationDialog: $GhosttyDialog {
|
||||
height-request: 200;
|
||||
|
||||
TextView text_view {
|
||||
styles [
|
||||
"clipboard-content-view",
|
||||
]
|
||||
|
||||
cursor-visible: false;
|
||||
editable: false;
|
||||
monospace: true;
|
||||
@ -39,10 +44,7 @@ template $GhosttyClipboardConfirmationDialog: $GhosttyDialog {
|
||||
left-margin: 8;
|
||||
bottom-margin: 8;
|
||||
right-margin: 8;
|
||||
|
||||
styles [
|
||||
"clipboard-content-view",
|
||||
]
|
||||
buffer: bind template.clipboard-contents;
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,6 +76,11 @@ template $GhosttyClipboardConfirmationDialog: $GhosttyDialog {
|
||||
}
|
||||
|
||||
Adw.SwitchRow remember_choice {
|
||||
styles [
|
||||
"card",
|
||||
]
|
||||
|
||||
visible: bind template.can-remember;
|
||||
title: _("Remember choice for this split");
|
||||
subtitle: _("Reload configuration to show this prompt again");
|
||||
}
|
||||
|
Reference in New Issue
Block a user