mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
gtk: implement sensitive content reveal on paste confirmation (#6054)
Fixes https://github.com/ghostty-org/ghostty/issues/4947 for gtk This PR implements the senstive content hiding when displaying the paste confirmation dialog in secure input mode. Following changes are implemented: - in the blueprint for each dialog add a show/hide button that is not visible by default, and a Revealer that is revealed by default - save the `secure_input` action value for each surface in the GTK apprt - pass the value when initializing the paste confirmation dialog - in the dialog code, alter the visibility of the content and reveal/hide buttons based on secure input flag value Demo: https://github.com/user-attachments/assets/c91cbd3d-ed3b-464d-b4cf-e51fe7aa23b7 I feel like this is already a nearly full implementation, but I'm leaving this as a draft for now, since i need to look into blueprints for Adwaita 1.2, and verify if it behaves properly when the dialog is in not-sensitive input mode and in OSC52 mode.
This commit is contained in:
@ -508,12 +508,12 @@ pub fn performAction(
|
|||||||
.quit_timer => self.quitTimer(value),
|
.quit_timer => self.quitTimer(value),
|
||||||
.prompt_title => try self.promptTitle(target),
|
.prompt_title => try self.promptTitle(target),
|
||||||
.toggle_quick_terminal => return try self.toggleQuickTerminal(),
|
.toggle_quick_terminal => return try self.toggleQuickTerminal(),
|
||||||
|
.secure_input => self.setSecureInput(target, value),
|
||||||
|
|
||||||
// Unimplemented
|
// Unimplemented
|
||||||
.close_all_windows,
|
.close_all_windows,
|
||||||
.toggle_visibility,
|
.toggle_visibility,
|
||||||
.cell_size,
|
.cell_size,
|
||||||
.secure_input,
|
|
||||||
.key_sequence,
|
.key_sequence,
|
||||||
.render_inspector,
|
.render_inspector,
|
||||||
.renderer_health,
|
.renderer_health,
|
||||||
@ -1415,6 +1415,15 @@ fn newWindow(self: *App, parent_: ?*CoreSurface) !void {
|
|||||||
window.present();
|
window.present();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn setSecureInput(_: *App, target: apprt.Target, value: apprt.action.SecureInput) void {
|
||||||
|
switch (target) {
|
||||||
|
.app => {},
|
||||||
|
.surface => |surface| {
|
||||||
|
surface.rt_surface.setSecureInput(value);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn quit(self: *App) void {
|
fn quit(self: *App) void {
|
||||||
// If we're already not running, do nothing.
|
// If we're already not running, do nothing.
|
||||||
if (!self.running) return;
|
if (!self.running) return;
|
||||||
|
@ -25,12 +25,17 @@ dialog: *DialogType,
|
|||||||
data: [:0]u8,
|
data: [:0]u8,
|
||||||
core_surface: *CoreSurface,
|
core_surface: *CoreSurface,
|
||||||
pending_req: apprt.ClipboardRequest,
|
pending_req: apprt.ClipboardRequest,
|
||||||
|
text_view: *gtk.TextView,
|
||||||
|
text_view_scroll: *gtk.ScrolledWindow,
|
||||||
|
reveal_button: *gtk.Button,
|
||||||
|
hide_button: *gtk.Button,
|
||||||
|
|
||||||
pub fn create(
|
pub fn create(
|
||||||
app: *App,
|
app: *App,
|
||||||
data: []const u8,
|
data: []const u8,
|
||||||
core_surface: *CoreSurface,
|
core_surface: *CoreSurface,
|
||||||
request: apprt.ClipboardRequest,
|
request: apprt.ClipboardRequest,
|
||||||
|
is_secure_input: bool,
|
||||||
) !void {
|
) !void {
|
||||||
if (app.clipboard_confirmation_window != null) return error.WindowAlreadyExists;
|
if (app.clipboard_confirmation_window != null) return error.WindowAlreadyExists;
|
||||||
|
|
||||||
@ -43,6 +48,7 @@ pub fn create(
|
|||||||
data,
|
data,
|
||||||
core_surface,
|
core_surface,
|
||||||
request,
|
request,
|
||||||
|
is_secure_input,
|
||||||
);
|
);
|
||||||
|
|
||||||
app.clipboard_confirmation_window = self;
|
app.clipboard_confirmation_window = self;
|
||||||
@ -62,6 +68,7 @@ fn init(
|
|||||||
data: []const u8,
|
data: []const u8,
|
||||||
core_surface: *CoreSurface,
|
core_surface: *CoreSurface,
|
||||||
request: apprt.ClipboardRequest,
|
request: apprt.ClipboardRequest,
|
||||||
|
is_secure_input: bool,
|
||||||
) !void {
|
) !void {
|
||||||
var builder = switch (DialogType) {
|
var builder = switch (DialogType) {
|
||||||
adw.AlertDialog => switch (request) {
|
adw.AlertDialog => switch (request) {
|
||||||
@ -79,6 +86,10 @@ fn init(
|
|||||||
defer builder.deinit();
|
defer builder.deinit();
|
||||||
|
|
||||||
const dialog = builder.getObject(DialogType, "clipboard_confirmation_window").?;
|
const dialog = builder.getObject(DialogType, "clipboard_confirmation_window").?;
|
||||||
|
const text_view = builder.getObject(gtk.TextView, "text_view").?;
|
||||||
|
const reveal_button = builder.getObject(gtk.Button, "reveal_button").?;
|
||||||
|
const hide_button = builder.getObject(gtk.Button, "hide_button").?;
|
||||||
|
const text_view_scroll = builder.getObject(gtk.ScrolledWindow, "text_view_scroll").?;
|
||||||
|
|
||||||
const copy = try app.core_app.alloc.dupeZ(u8, data);
|
const copy = try app.core_app.alloc.dupeZ(u8, data);
|
||||||
errdefer app.core_app.alloc.free(copy);
|
errdefer app.core_app.alloc.free(copy);
|
||||||
@ -88,15 +99,39 @@ fn init(
|
|||||||
.data = copy,
|
.data = copy,
|
||||||
.core_surface = core_surface,
|
.core_surface = core_surface,
|
||||||
.pending_req = request,
|
.pending_req = request,
|
||||||
|
.text_view = text_view,
|
||||||
|
.text_view_scroll = text_view_scroll,
|
||||||
|
.reveal_button = reveal_button,
|
||||||
|
.hide_button = hide_button,
|
||||||
};
|
};
|
||||||
|
|
||||||
const text_view = builder.getObject(gtk.TextView, "text_view").?;
|
|
||||||
|
|
||||||
const buffer = gtk.TextBuffer.new(null);
|
const buffer = gtk.TextBuffer.new(null);
|
||||||
errdefer buffer.unref();
|
errdefer buffer.unref();
|
||||||
buffer.insertAtCursor(copy.ptr, @intCast(copy.len));
|
buffer.insertAtCursor(copy.ptr, @intCast(copy.len));
|
||||||
text_view.setBuffer(buffer);
|
text_view.setBuffer(buffer);
|
||||||
|
|
||||||
|
if (is_secure_input) {
|
||||||
|
text_view_scroll.as(gtk.Widget).setSensitive(@intFromBool(false));
|
||||||
|
self.text_view.as(gtk.Widget).addCssClass("blurred");
|
||||||
|
|
||||||
|
self.reveal_button.as(gtk.Widget).setVisible(@intFromBool(true));
|
||||||
|
|
||||||
|
_ = gtk.Button.signals.clicked.connect(
|
||||||
|
reveal_button,
|
||||||
|
*ClipboardConfirmation,
|
||||||
|
gtkRevealButtonClicked,
|
||||||
|
self,
|
||||||
|
.{},
|
||||||
|
);
|
||||||
|
_ = gtk.Button.signals.clicked.connect(
|
||||||
|
hide_button,
|
||||||
|
*ClipboardConfirmation,
|
||||||
|
gtkHideButtonClicked,
|
||||||
|
self,
|
||||||
|
.{},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
switch (DialogType) {
|
switch (DialogType) {
|
||||||
adw.AlertDialog => {
|
adw.AlertDialog => {
|
||||||
const parent: ?*gtk.Widget = widget: {
|
const parent: ?*gtk.Widget = widget: {
|
||||||
@ -152,3 +187,19 @@ fn gtkResponse(_: *DialogType, response: [*:0]u8, self: *ClipboardConfirmation)
|
|||||||
}
|
}
|
||||||
self.destroy();
|
self.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn gtkRevealButtonClicked(_: *gtk.Button, self: *ClipboardConfirmation) callconv(.C) void {
|
||||||
|
self.text_view_scroll.as(gtk.Widget).setSensitive(@intFromBool(true));
|
||||||
|
self.text_view.as(gtk.Widget).removeCssClass("blurred");
|
||||||
|
|
||||||
|
self.hide_button.as(gtk.Widget).setVisible(@intFromBool(true));
|
||||||
|
self.reveal_button.as(gtk.Widget).setVisible(@intFromBool(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gtkHideButtonClicked(_: *gtk.Button, self: *ClipboardConfirmation) callconv(.C) void {
|
||||||
|
self.text_view_scroll.as(gtk.Widget).setSensitive(@intFromBool(false));
|
||||||
|
self.text_view.as(gtk.Widget).addCssClass("blurred");
|
||||||
|
|
||||||
|
self.hide_button.as(gtk.Widget).setVisible(@intFromBool(false));
|
||||||
|
self.reveal_button.as(gtk.Widget).setVisible(@intFromBool(true));
|
||||||
|
}
|
||||||
|
@ -308,6 +308,9 @@ context_menu: Menu(Surface, "context_menu", false),
|
|||||||
/// True when we have a precision scroll in progress
|
/// True when we have a precision scroll in progress
|
||||||
precision_scroll: bool = false,
|
precision_scroll: bool = false,
|
||||||
|
|
||||||
|
/// Flag indicating whether the surface is in secure input mode.
|
||||||
|
is_secure_input: bool = false,
|
||||||
|
|
||||||
/// The state of the key event while we're doing IM composition.
|
/// The state of the key event while we're doing IM composition.
|
||||||
/// See gtkKeyPressed for detailed descriptions.
|
/// See gtkKeyPressed for detailed descriptions.
|
||||||
pub const IMKeyEvent = enum {
|
pub const IMKeyEvent = enum {
|
||||||
@ -1163,6 +1166,7 @@ pub fn setClipboardString(
|
|||||||
val,
|
val,
|
||||||
&self.core_surface,
|
&self.core_surface,
|
||||||
.{ .osc_52_write = clipboard_type },
|
.{ .osc_52_write = clipboard_type },
|
||||||
|
self.is_secure_input,
|
||||||
) catch |window_err| {
|
) catch |window_err| {
|
||||||
log.err("failed to create clipboard confirmation window err={}", .{window_err});
|
log.err("failed to create clipboard confirmation window err={}", .{window_err});
|
||||||
};
|
};
|
||||||
@ -1211,6 +1215,7 @@ fn gtkClipboardRead(
|
|||||||
str,
|
str,
|
||||||
&self.core_surface,
|
&self.core_surface,
|
||||||
req.state,
|
req.state,
|
||||||
|
self.is_secure_input,
|
||||||
) catch |window_err| {
|
) catch |window_err| {
|
||||||
log.err("failed to create clipboard confirmation window err={}", .{window_err});
|
log.err("failed to create clipboard confirmation window err={}", .{window_err});
|
||||||
};
|
};
|
||||||
@ -2231,6 +2236,7 @@ fn doPaste(self: *Surface, data: [:0]const u8) void {
|
|||||||
data,
|
data,
|
||||||
&self.core_surface,
|
&self.core_surface,
|
||||||
.paste,
|
.paste,
|
||||||
|
self.is_secure_input,
|
||||||
) catch |window_err| {
|
) catch |window_err| {
|
||||||
log.err("failed to create clipboard confirmation window err={}", .{window_err});
|
log.err("failed to create clipboard confirmation window err={}", .{window_err});
|
||||||
};
|
};
|
||||||
@ -2323,3 +2329,11 @@ fn gtkPromptTitleResponse(source_object: ?*gobject.Object, result: *gio.AsyncRes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn setSecureInput(self: *Surface, value: apprt.action.SecureInput) void {
|
||||||
|
switch (value) {
|
||||||
|
.on => self.is_secure_input = true,
|
||||||
|
.off => self.is_secure_input = false,
|
||||||
|
.toggle => self.is_secure_input = !self.is_secure_input,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -63,3 +63,13 @@ window.ssd.no-border-radius {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.clipboard-content-view {
|
||||||
|
filter: blur(0px);
|
||||||
|
transition: filter 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clipboard-content-view.blurred {
|
||||||
|
filter: blur(5px);
|
||||||
|
transition: filter 0.3s ease;
|
||||||
|
}
|
||||||
|
@ -14,18 +14,58 @@ Adw.MessageDialog clipboard_confirmation_window {
|
|||||||
default-response: "cancel";
|
default-response: "cancel";
|
||||||
close-response: "cancel";
|
close-response: "cancel";
|
||||||
|
|
||||||
extra-child: ScrolledWindow {
|
extra-child: Overlay {
|
||||||
width-request: 500;
|
styles [
|
||||||
height-request: 250;
|
"osd"
|
||||||
|
]
|
||||||
|
|
||||||
TextView text_view {
|
ScrolledWindow text_view_scroll {
|
||||||
cursor-visible: false;
|
width-request: 500;
|
||||||
editable: false;
|
height-request: 250;
|
||||||
monospace: true;
|
|
||||||
top-margin: 8;
|
TextView text_view {
|
||||||
left-margin: 8;
|
cursor-visible: false;
|
||||||
bottom-margin: 8;
|
editable: false;
|
||||||
right-margin: 8;
|
monospace: true;
|
||||||
|
top-margin: 8;
|
||||||
|
left-margin: 8;
|
||||||
|
bottom-margin: 8;
|
||||||
|
right-margin: 8;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"clipboard-content-view"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[overlay]
|
||||||
|
Button reveal_button {
|
||||||
|
visible: false;
|
||||||
|
halign: end;
|
||||||
|
valign: start;
|
||||||
|
margin-end: 12;
|
||||||
|
margin-top: 12;
|
||||||
|
|
||||||
|
Image {
|
||||||
|
icon-name: "view-reveal-symbolic";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[overlay]
|
||||||
|
Button hide_button {
|
||||||
|
visible: false;
|
||||||
|
halign: end;
|
||||||
|
valign: start;
|
||||||
|
margin-end: 12;
|
||||||
|
margin-top: 12;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"opaque"
|
||||||
|
]
|
||||||
|
|
||||||
|
Image {
|
||||||
|
icon-name: "view-conceal-symbolic";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -7,27 +7,68 @@ corresponding .blp file and regenerate this file with blueprint-compiler.
|
|||||||
<interface domain="com.mitchellh.ghostty">
|
<interface domain="com.mitchellh.ghostty">
|
||||||
<requires lib="gtk" version="4.0"/>
|
<requires lib="gtk" version="4.0"/>
|
||||||
<object class="AdwMessageDialog" id="clipboard_confirmation_window">
|
<object class="AdwMessageDialog" id="clipboard_confirmation_window">
|
||||||
<property name="heading" translatable="yes">Authorize Clipboard Access</property>
|
<property name="heading" translatable="true">Authorize Clipboard Access</property>
|
||||||
<property name="body" translatable="yes">An application is attempting to read from the clipboard. The current clipboard contents are shown below.</property>
|
<property name="body" translatable="true">An application is attempting to read from the clipboard. The current clipboard contents are shown below.</property>
|
||||||
<responses>
|
<responses>
|
||||||
<response id="cancel" translatable="yes" appearance="suggested">Deny</response>
|
<response id="cancel" translatable="true" appearance="suggested">Deny</response>
|
||||||
<response id="ok" translatable="yes" appearance="destructive">Allow</response>
|
<response id="ok" translatable="true" appearance="destructive">Allow</response>
|
||||||
</responses>
|
</responses>
|
||||||
<property name="default-response">cancel</property>
|
<property name="default-response">cancel</property>
|
||||||
<property name="close-response">cancel</property>
|
<property name="close-response">cancel</property>
|
||||||
<property name="extra-child">
|
<property name="extra-child">
|
||||||
<object class="GtkScrolledWindow">
|
<object class="GtkOverlay">
|
||||||
<property name="width-request">500</property>
|
<style>
|
||||||
<property name="height-request">250</property>
|
<class name="osd"/>
|
||||||
|
</style>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkTextView" id="text_view">
|
<object class="GtkScrolledWindow" id="text_view_scroll">
|
||||||
<property name="cursor-visible">false</property>
|
<property name="width-request">500</property>
|
||||||
<property name="editable">false</property>
|
<property name="height-request">250</property>
|
||||||
<property name="monospace">true</property>
|
<child>
|
||||||
<property name="top-margin">8</property>
|
<object class="GtkTextView" id="text_view">
|
||||||
<property name="left-margin">8</property>
|
<property name="cursor-visible">false</property>
|
||||||
<property name="bottom-margin">8</property>
|
<property name="editable">false</property>
|
||||||
<property name="right-margin">8</property>
|
<property name="monospace">true</property>
|
||||||
|
<property name="top-margin">8</property>
|
||||||
|
<property name="left-margin">8</property>
|
||||||
|
<property name="bottom-margin">8</property>
|
||||||
|
<property name="right-margin">8</property>
|
||||||
|
<style>
|
||||||
|
<class name="clipboard-content-view"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="overlay">
|
||||||
|
<object class="GtkButton" id="reveal_button">
|
||||||
|
<property name="visible">false</property>
|
||||||
|
<property name="halign">2</property>
|
||||||
|
<property name="valign">1</property>
|
||||||
|
<property name="margin-end">12</property>
|
||||||
|
<property name="margin-top">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="icon-name">view-reveal-symbolic</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="overlay">
|
||||||
|
<object class="GtkButton" id="hide_button">
|
||||||
|
<property name="visible">false</property>
|
||||||
|
<property name="halign">2</property>
|
||||||
|
<property name="valign">1</property>
|
||||||
|
<property name="margin-end">12</property>
|
||||||
|
<property name="margin-top">12</property>
|
||||||
|
<style>
|
||||||
|
<class name="opaque"/>
|
||||||
|
</style>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="icon-name">view-conceal-symbolic</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
@ -14,18 +14,58 @@ Adw.MessageDialog clipboard_confirmation_window {
|
|||||||
default-response: "cancel";
|
default-response: "cancel";
|
||||||
close-response: "cancel";
|
close-response: "cancel";
|
||||||
|
|
||||||
extra-child: ScrolledWindow {
|
extra-child: Overlay {
|
||||||
width-request: 500;
|
styles [
|
||||||
height-request: 250;
|
"osd"
|
||||||
|
]
|
||||||
|
|
||||||
TextView text_view {
|
ScrolledWindow text_view_scroll {
|
||||||
cursor-visible: false;
|
width-request: 500;
|
||||||
editable: false;
|
height-request: 250;
|
||||||
monospace: true;
|
|
||||||
top-margin: 8;
|
TextView text_view {
|
||||||
left-margin: 8;
|
cursor-visible: false;
|
||||||
bottom-margin: 8;
|
editable: false;
|
||||||
right-margin: 8;
|
monospace: true;
|
||||||
|
top-margin: 8;
|
||||||
|
left-margin: 8;
|
||||||
|
bottom-margin: 8;
|
||||||
|
right-margin: 8;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"clipboard-content-view"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[overlay]
|
||||||
|
Button reveal_button {
|
||||||
|
visible: false;
|
||||||
|
halign: end;
|
||||||
|
valign: start;
|
||||||
|
margin-end: 12;
|
||||||
|
margin-top: 12;
|
||||||
|
|
||||||
|
Image {
|
||||||
|
icon-name: "view-reveal-symbolic";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[overlay]
|
||||||
|
Button hide_button {
|
||||||
|
visible: false;
|
||||||
|
halign: end;
|
||||||
|
valign: start;
|
||||||
|
margin-end: 12;
|
||||||
|
margin-top: 12;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"opaque"
|
||||||
|
]
|
||||||
|
|
||||||
|
Image {
|
||||||
|
icon-name: "view-conceal-symbolic";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -7,27 +7,68 @@ corresponding .blp file and regenerate this file with blueprint-compiler.
|
|||||||
<interface domain="com.mitchellh.ghostty">
|
<interface domain="com.mitchellh.ghostty">
|
||||||
<requires lib="gtk" version="4.0"/>
|
<requires lib="gtk" version="4.0"/>
|
||||||
<object class="AdwMessageDialog" id="clipboard_confirmation_window">
|
<object class="AdwMessageDialog" id="clipboard_confirmation_window">
|
||||||
<property name="heading" translatable="yes">Authorize Clipboard Access</property>
|
<property name="heading" translatable="true">Authorize Clipboard Access</property>
|
||||||
<property name="body" translatable="yes">An application is attempting to write to the clipboard. The current clipboard contents are shown below.</property>
|
<property name="body" translatable="true">An application is attempting to write to the clipboard. The current clipboard contents are shown below.</property>
|
||||||
<responses>
|
<responses>
|
||||||
<response id="cancel" translatable="yes" appearance="suggested">Deny</response>
|
<response id="cancel" translatable="true" appearance="suggested">Deny</response>
|
||||||
<response id="ok" translatable="yes" appearance="destructive">Allow</response>
|
<response id="ok" translatable="true" appearance="destructive">Allow</response>
|
||||||
</responses>
|
</responses>
|
||||||
<property name="default-response">cancel</property>
|
<property name="default-response">cancel</property>
|
||||||
<property name="close-response">cancel</property>
|
<property name="close-response">cancel</property>
|
||||||
<property name="extra-child">
|
<property name="extra-child">
|
||||||
<object class="GtkScrolledWindow">
|
<object class="GtkOverlay">
|
||||||
<property name="width-request">500</property>
|
<style>
|
||||||
<property name="height-request">250</property>
|
<class name="osd"/>
|
||||||
|
</style>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkTextView" id="text_view">
|
<object class="GtkScrolledWindow" id="text_view_scroll">
|
||||||
<property name="cursor-visible">false</property>
|
<property name="width-request">500</property>
|
||||||
<property name="editable">false</property>
|
<property name="height-request">250</property>
|
||||||
<property name="monospace">true</property>
|
<child>
|
||||||
<property name="top-margin">8</property>
|
<object class="GtkTextView" id="text_view">
|
||||||
<property name="left-margin">8</property>
|
<property name="cursor-visible">false</property>
|
||||||
<property name="bottom-margin">8</property>
|
<property name="editable">false</property>
|
||||||
<property name="right-margin">8</property>
|
<property name="monospace">true</property>
|
||||||
|
<property name="top-margin">8</property>
|
||||||
|
<property name="left-margin">8</property>
|
||||||
|
<property name="bottom-margin">8</property>
|
||||||
|
<property name="right-margin">8</property>
|
||||||
|
<style>
|
||||||
|
<class name="clipboard-content-view"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="overlay">
|
||||||
|
<object class="GtkButton" id="reveal_button">
|
||||||
|
<property name="visible">false</property>
|
||||||
|
<property name="halign">2</property>
|
||||||
|
<property name="valign">1</property>
|
||||||
|
<property name="margin-end">12</property>
|
||||||
|
<property name="margin-top">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="icon-name">view-reveal-symbolic</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="overlay">
|
||||||
|
<object class="GtkButton" id="hide_button">
|
||||||
|
<property name="visible">false</property>
|
||||||
|
<property name="halign">2</property>
|
||||||
|
<property name="valign">1</property>
|
||||||
|
<property name="margin-end">12</property>
|
||||||
|
<property name="margin-top">12</property>
|
||||||
|
<style>
|
||||||
|
<class name="opaque"/>
|
||||||
|
</style>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="icon-name">view-conceal-symbolic</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
@ -14,18 +14,58 @@ Adw.MessageDialog clipboard_confirmation_window {
|
|||||||
default-response: "cancel";
|
default-response: "cancel";
|
||||||
close-response: "cancel";
|
close-response: "cancel";
|
||||||
|
|
||||||
extra-child: ScrolledWindow {
|
extra-child: Overlay {
|
||||||
width-request: 500;
|
styles [
|
||||||
height-request: 250;
|
"osd"
|
||||||
|
]
|
||||||
|
|
||||||
TextView text_view {
|
ScrolledWindow text_view_scroll {
|
||||||
cursor-visible: false;
|
width-request: 500;
|
||||||
editable: false;
|
height-request: 250;
|
||||||
monospace: true;
|
|
||||||
top-margin: 8;
|
TextView text_view {
|
||||||
left-margin: 8;
|
cursor-visible: false;
|
||||||
bottom-margin: 8;
|
editable: false;
|
||||||
right-margin: 8;
|
monospace: true;
|
||||||
|
top-margin: 8;
|
||||||
|
left-margin: 8;
|
||||||
|
bottom-margin: 8;
|
||||||
|
right-margin: 8;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"clipboard-content-view"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[overlay]
|
||||||
|
Button reveal_button {
|
||||||
|
visible: false;
|
||||||
|
halign: end;
|
||||||
|
valign: start;
|
||||||
|
margin-end: 12;
|
||||||
|
margin-top: 12;
|
||||||
|
|
||||||
|
Image {
|
||||||
|
icon-name: "view-reveal-symbolic";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[overlay]
|
||||||
|
Button hide_button {
|
||||||
|
visible: false;
|
||||||
|
halign: end;
|
||||||
|
valign: start;
|
||||||
|
margin-end: 12;
|
||||||
|
margin-top: 12;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"opaque"
|
||||||
|
]
|
||||||
|
|
||||||
|
Image {
|
||||||
|
icon-name: "view-conceal-symbolic";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -7,27 +7,68 @@ corresponding .blp file and regenerate this file with blueprint-compiler.
|
|||||||
<interface domain="com.mitchellh.ghostty">
|
<interface domain="com.mitchellh.ghostty">
|
||||||
<requires lib="gtk" version="4.0"/>
|
<requires lib="gtk" version="4.0"/>
|
||||||
<object class="AdwMessageDialog" id="clipboard_confirmation_window">
|
<object class="AdwMessageDialog" id="clipboard_confirmation_window">
|
||||||
<property name="heading" translatable="yes">Warning: Potentially Unsafe Paste</property>
|
<property name="heading" translatable="true">Warning: Potentially Unsafe Paste</property>
|
||||||
<property name="body" translatable="yes">Pasting this text into the terminal may be dangerous as it looks like some commands may be executed.</property>
|
<property name="body" translatable="true">Pasting this text into the terminal may be dangerous as it looks like some commands may be executed.</property>
|
||||||
<responses>
|
<responses>
|
||||||
<response id="cancel" translatable="yes" appearance="suggested">Cancel</response>
|
<response id="cancel" translatable="true" appearance="suggested">Cancel</response>
|
||||||
<response id="ok" translatable="yes" appearance="destructive">Paste</response>
|
<response id="ok" translatable="true" appearance="destructive">Paste</response>
|
||||||
</responses>
|
</responses>
|
||||||
<property name="default-response">cancel</property>
|
<property name="default-response">cancel</property>
|
||||||
<property name="close-response">cancel</property>
|
<property name="close-response">cancel</property>
|
||||||
<property name="extra-child">
|
<property name="extra-child">
|
||||||
<object class="GtkScrolledWindow">
|
<object class="GtkOverlay">
|
||||||
<property name="width-request">500</property>
|
<style>
|
||||||
<property name="height-request">250</property>
|
<class name="osd"/>
|
||||||
|
</style>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkTextView" id="text_view">
|
<object class="GtkScrolledWindow" id="text_view_scroll">
|
||||||
<property name="cursor-visible">false</property>
|
<property name="width-request">500</property>
|
||||||
<property name="editable">false</property>
|
<property name="height-request">250</property>
|
||||||
<property name="monospace">true</property>
|
<child>
|
||||||
<property name="top-margin">8</property>
|
<object class="GtkTextView" id="text_view">
|
||||||
<property name="left-margin">8</property>
|
<property name="cursor-visible">false</property>
|
||||||
<property name="bottom-margin">8</property>
|
<property name="editable">false</property>
|
||||||
<property name="right-margin">8</property>
|
<property name="monospace">true</property>
|
||||||
|
<property name="top-margin">8</property>
|
||||||
|
<property name="left-margin">8</property>
|
||||||
|
<property name="bottom-margin">8</property>
|
||||||
|
<property name="right-margin">8</property>
|
||||||
|
<style>
|
||||||
|
<class name="clipboard-content-view"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="overlay">
|
||||||
|
<object class="GtkButton" id="reveal_button">
|
||||||
|
<property name="visible">false</property>
|
||||||
|
<property name="halign">2</property>
|
||||||
|
<property name="valign">1</property>
|
||||||
|
<property name="margin-end">12</property>
|
||||||
|
<property name="margin-top">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="icon-name">view-reveal-symbolic</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="overlay">
|
||||||
|
<object class="GtkButton" id="hide_button">
|
||||||
|
<property name="visible">false</property>
|
||||||
|
<property name="halign">2</property>
|
||||||
|
<property name="valign">1</property>
|
||||||
|
<property name="margin-end">12</property>
|
||||||
|
<property name="margin-top">12</property>
|
||||||
|
<style>
|
||||||
|
<class name="opaque"/>
|
||||||
|
</style>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="icon-name">view-conceal-symbolic</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
@ -14,18 +14,58 @@ Adw.AlertDialog clipboard_confirmation_window {
|
|||||||
default-response: "cancel";
|
default-response: "cancel";
|
||||||
close-response: "cancel";
|
close-response: "cancel";
|
||||||
|
|
||||||
extra-child: ScrolledWindow {
|
extra-child: Overlay {
|
||||||
width-request: 500;
|
styles [
|
||||||
height-request: 250;
|
"osd"
|
||||||
|
]
|
||||||
|
|
||||||
TextView text_view {
|
ScrolledWindow text_view_scroll {
|
||||||
cursor-visible: false;
|
width-request: 500;
|
||||||
editable: false;
|
height-request: 250;
|
||||||
monospace: true;
|
|
||||||
top-margin: 8;
|
TextView text_view {
|
||||||
left-margin: 8;
|
cursor-visible: false;
|
||||||
bottom-margin: 8;
|
editable: false;
|
||||||
right-margin: 8;
|
monospace: true;
|
||||||
|
top-margin: 8;
|
||||||
|
left-margin: 8;
|
||||||
|
bottom-margin: 8;
|
||||||
|
right-margin: 8;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"clipboard-content-view"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[overlay]
|
||||||
|
Button reveal_button {
|
||||||
|
visible: false;
|
||||||
|
halign: end;
|
||||||
|
valign: start;
|
||||||
|
margin-end: 12;
|
||||||
|
margin-top: 12;
|
||||||
|
|
||||||
|
Image {
|
||||||
|
icon-name: "view-reveal-symbolic";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[overlay]
|
||||||
|
Button hide_button {
|
||||||
|
visible: false;
|
||||||
|
halign: end;
|
||||||
|
valign: start;
|
||||||
|
margin-end: 12;
|
||||||
|
margin-top: 12;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"opaque"
|
||||||
|
]
|
||||||
|
|
||||||
|
Image {
|
||||||
|
icon-name: "view-conceal-symbolic";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -14,18 +14,58 @@ Adw.AlertDialog clipboard_confirmation_window {
|
|||||||
default-response: "cancel";
|
default-response: "cancel";
|
||||||
close-response: "cancel";
|
close-response: "cancel";
|
||||||
|
|
||||||
extra-child: ScrolledWindow {
|
extra-child: Overlay {
|
||||||
width-request: 500;
|
styles [
|
||||||
height-request: 250;
|
"osd"
|
||||||
|
]
|
||||||
|
|
||||||
TextView text_view {
|
ScrolledWindow text_view_scroll {
|
||||||
cursor-visible: false;
|
width-request: 500;
|
||||||
editable: false;
|
height-request: 250;
|
||||||
monospace: true;
|
|
||||||
top-margin: 8;
|
TextView text_view {
|
||||||
left-margin: 8;
|
cursor-visible: false;
|
||||||
bottom-margin: 8;
|
editable: false;
|
||||||
right-margin: 8;
|
monospace: true;
|
||||||
|
top-margin: 8;
|
||||||
|
left-margin: 8;
|
||||||
|
bottom-margin: 8;
|
||||||
|
right-margin: 8;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"clipboard-content-view"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[overlay]
|
||||||
|
Button reveal_button {
|
||||||
|
visible: false;
|
||||||
|
halign: end;
|
||||||
|
valign: start;
|
||||||
|
margin-end: 12;
|
||||||
|
margin-top: 12;
|
||||||
|
|
||||||
|
Image {
|
||||||
|
icon-name: "view-reveal-symbolic";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[overlay]
|
||||||
|
Button hide_button {
|
||||||
|
visible: false;
|
||||||
|
halign: end;
|
||||||
|
valign: start;
|
||||||
|
margin-end: 12;
|
||||||
|
margin-top: 12;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"opaque"
|
||||||
|
]
|
||||||
|
|
||||||
|
Image {
|
||||||
|
icon-name: "view-conceal-symbolic";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -14,18 +14,58 @@ Adw.AlertDialog clipboard_confirmation_window {
|
|||||||
default-response: "cancel";
|
default-response: "cancel";
|
||||||
close-response: "cancel";
|
close-response: "cancel";
|
||||||
|
|
||||||
extra-child: ScrolledWindow {
|
extra-child: Overlay {
|
||||||
width-request: 500;
|
styles [
|
||||||
height-request: 250;
|
"osd"
|
||||||
|
]
|
||||||
|
|
||||||
TextView text_view {
|
ScrolledWindow text_view_scroll {
|
||||||
cursor-visible: false;
|
width-request: 500;
|
||||||
editable: false;
|
height-request: 250;
|
||||||
monospace: true;
|
|
||||||
top-margin: 8;
|
TextView text_view {
|
||||||
left-margin: 8;
|
cursor-visible: false;
|
||||||
bottom-margin: 8;
|
editable: false;
|
||||||
right-margin: 8;
|
monospace: true;
|
||||||
|
top-margin: 8;
|
||||||
|
left-margin: 8;
|
||||||
|
bottom-margin: 8;
|
||||||
|
right-margin: 8;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"clipboard-content-view"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[overlay]
|
||||||
|
Button reveal_button {
|
||||||
|
visible: false;
|
||||||
|
halign: end;
|
||||||
|
valign: start;
|
||||||
|
margin-end: 12;
|
||||||
|
margin-top: 12;
|
||||||
|
|
||||||
|
Image {
|
||||||
|
icon-name: "view-reveal-symbolic";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[overlay]
|
||||||
|
Button hide_button {
|
||||||
|
visible: false;
|
||||||
|
halign: end;
|
||||||
|
valign: start;
|
||||||
|
margin-end: 12;
|
||||||
|
margin-top: 12;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"opaque"
|
||||||
|
]
|
||||||
|
|
||||||
|
Image {
|
||||||
|
icon-name: "view-conceal-symbolic";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user