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),
|
||||
.prompt_title => try self.promptTitle(target),
|
||||
.toggle_quick_terminal => return try self.toggleQuickTerminal(),
|
||||
.secure_input => self.setSecureInput(target, value),
|
||||
|
||||
// Unimplemented
|
||||
.close_all_windows,
|
||||
.toggle_visibility,
|
||||
.cell_size,
|
||||
.secure_input,
|
||||
.key_sequence,
|
||||
.render_inspector,
|
||||
.renderer_health,
|
||||
@ -1415,6 +1415,15 @@ fn newWindow(self: *App, parent_: ?*CoreSurface) !void {
|
||||
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 {
|
||||
// If we're already not running, do nothing.
|
||||
if (!self.running) return;
|
||||
|
@ -25,12 +25,17 @@ dialog: *DialogType,
|
||||
data: [:0]u8,
|
||||
core_surface: *CoreSurface,
|
||||
pending_req: apprt.ClipboardRequest,
|
||||
text_view: *gtk.TextView,
|
||||
text_view_scroll: *gtk.ScrolledWindow,
|
||||
reveal_button: *gtk.Button,
|
||||
hide_button: *gtk.Button,
|
||||
|
||||
pub fn create(
|
||||
app: *App,
|
||||
data: []const u8,
|
||||
core_surface: *CoreSurface,
|
||||
request: apprt.ClipboardRequest,
|
||||
is_secure_input: bool,
|
||||
) !void {
|
||||
if (app.clipboard_confirmation_window != null) return error.WindowAlreadyExists;
|
||||
|
||||
@ -43,6 +48,7 @@ pub fn create(
|
||||
data,
|
||||
core_surface,
|
||||
request,
|
||||
is_secure_input,
|
||||
);
|
||||
|
||||
app.clipboard_confirmation_window = self;
|
||||
@ -62,6 +68,7 @@ fn init(
|
||||
data: []const u8,
|
||||
core_surface: *CoreSurface,
|
||||
request: apprt.ClipboardRequest,
|
||||
is_secure_input: bool,
|
||||
) !void {
|
||||
var builder = switch (DialogType) {
|
||||
adw.AlertDialog => switch (request) {
|
||||
@ -79,6 +86,10 @@ fn init(
|
||||
defer builder.deinit();
|
||||
|
||||
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);
|
||||
errdefer app.core_app.alloc.free(copy);
|
||||
@ -88,15 +99,39 @@ fn init(
|
||||
.data = copy,
|
||||
.core_surface = core_surface,
|
||||
.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);
|
||||
errdefer buffer.unref();
|
||||
buffer.insertAtCursor(copy.ptr, @intCast(copy.len));
|
||||
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) {
|
||||
adw.AlertDialog => {
|
||||
const parent: ?*gtk.Widget = widget: {
|
||||
@ -152,3 +187,19 @@ fn gtkResponse(_: *DialogType, response: [*:0]u8, self: *ClipboardConfirmation)
|
||||
}
|
||||
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
|
||||
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.
|
||||
/// See gtkKeyPressed for detailed descriptions.
|
||||
pub const IMKeyEvent = enum {
|
||||
@ -1163,6 +1166,7 @@ pub fn setClipboardString(
|
||||
val,
|
||||
&self.core_surface,
|
||||
.{ .osc_52_write = clipboard_type },
|
||||
self.is_secure_input,
|
||||
) catch |window_err| {
|
||||
log.err("failed to create clipboard confirmation window err={}", .{window_err});
|
||||
};
|
||||
@ -1211,6 +1215,7 @@ fn gtkClipboardRead(
|
||||
str,
|
||||
&self.core_surface,
|
||||
req.state,
|
||||
self.is_secure_input,
|
||||
) catch |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,
|
||||
&self.core_surface,
|
||||
.paste,
|
||||
self.is_secure_input,
|
||||
) catch |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;
|
||||
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";
|
||||
close-response: "cancel";
|
||||
|
||||
extra-child: ScrolledWindow {
|
||||
width-request: 500;
|
||||
height-request: 250;
|
||||
extra-child: Overlay {
|
||||
styles [
|
||||
"osd"
|
||||
]
|
||||
|
||||
TextView text_view {
|
||||
cursor-visible: false;
|
||||
editable: false;
|
||||
monospace: true;
|
||||
top-margin: 8;
|
||||
left-margin: 8;
|
||||
bottom-margin: 8;
|
||||
right-margin: 8;
|
||||
ScrolledWindow text_view_scroll {
|
||||
width-request: 500;
|
||||
height-request: 250;
|
||||
|
||||
TextView text_view {
|
||||
cursor-visible: false;
|
||||
editable: false;
|
||||
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">
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<object class="AdwMessageDialog" id="clipboard_confirmation_window">
|
||||
<property name="heading" translatable="yes">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="heading" translatable="true">Authorize Clipboard Access</property>
|
||||
<property name="body" translatable="true">An application is attempting to read from the clipboard. The current clipboard contents are shown below.</property>
|
||||
<responses>
|
||||
<response id="cancel" translatable="yes" appearance="suggested">Deny</response>
|
||||
<response id="ok" translatable="yes" appearance="destructive">Allow</response>
|
||||
<response id="cancel" translatable="true" appearance="suggested">Deny</response>
|
||||
<response id="ok" translatable="true" appearance="destructive">Allow</response>
|
||||
</responses>
|
||||
<property name="default-response">cancel</property>
|
||||
<property name="close-response">cancel</property>
|
||||
<property name="extra-child">
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="width-request">500</property>
|
||||
<property name="height-request">250</property>
|
||||
<object class="GtkOverlay">
|
||||
<style>
|
||||
<class name="osd"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkTextView" id="text_view">
|
||||
<property name="cursor-visible">false</property>
|
||||
<property name="editable">false</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>
|
||||
<object class="GtkScrolledWindow" id="text_view_scroll">
|
||||
<property name="width-request">500</property>
|
||||
<property name="height-request">250</property>
|
||||
<child>
|
||||
<object class="GtkTextView" id="text_view">
|
||||
<property name="cursor-visible">false</property>
|
||||
<property name="editable">false</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>
|
||||
</child>
|
||||
</object>
|
||||
|
@ -14,18 +14,58 @@ Adw.MessageDialog clipboard_confirmation_window {
|
||||
default-response: "cancel";
|
||||
close-response: "cancel";
|
||||
|
||||
extra-child: ScrolledWindow {
|
||||
width-request: 500;
|
||||
height-request: 250;
|
||||
extra-child: Overlay {
|
||||
styles [
|
||||
"osd"
|
||||
]
|
||||
|
||||
TextView text_view {
|
||||
cursor-visible: false;
|
||||
editable: false;
|
||||
monospace: true;
|
||||
top-margin: 8;
|
||||
left-margin: 8;
|
||||
bottom-margin: 8;
|
||||
right-margin: 8;
|
||||
ScrolledWindow text_view_scroll {
|
||||
width-request: 500;
|
||||
height-request: 250;
|
||||
|
||||
TextView text_view {
|
||||
cursor-visible: false;
|
||||
editable: false;
|
||||
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">
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<object class="AdwMessageDialog" id="clipboard_confirmation_window">
|
||||
<property name="heading" translatable="yes">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="heading" translatable="true">Authorize Clipboard Access</property>
|
||||
<property name="body" translatable="true">An application is attempting to write to the clipboard. The current clipboard contents are shown below.</property>
|
||||
<responses>
|
||||
<response id="cancel" translatable="yes" appearance="suggested">Deny</response>
|
||||
<response id="ok" translatable="yes" appearance="destructive">Allow</response>
|
||||
<response id="cancel" translatable="true" appearance="suggested">Deny</response>
|
||||
<response id="ok" translatable="true" appearance="destructive">Allow</response>
|
||||
</responses>
|
||||
<property name="default-response">cancel</property>
|
||||
<property name="close-response">cancel</property>
|
||||
<property name="extra-child">
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="width-request">500</property>
|
||||
<property name="height-request">250</property>
|
||||
<object class="GtkOverlay">
|
||||
<style>
|
||||
<class name="osd"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkTextView" id="text_view">
|
||||
<property name="cursor-visible">false</property>
|
||||
<property name="editable">false</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>
|
||||
<object class="GtkScrolledWindow" id="text_view_scroll">
|
||||
<property name="width-request">500</property>
|
||||
<property name="height-request">250</property>
|
||||
<child>
|
||||
<object class="GtkTextView" id="text_view">
|
||||
<property name="cursor-visible">false</property>
|
||||
<property name="editable">false</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>
|
||||
</child>
|
||||
</object>
|
||||
|
@ -14,18 +14,58 @@ Adw.MessageDialog clipboard_confirmation_window {
|
||||
default-response: "cancel";
|
||||
close-response: "cancel";
|
||||
|
||||
extra-child: ScrolledWindow {
|
||||
width-request: 500;
|
||||
height-request: 250;
|
||||
extra-child: Overlay {
|
||||
styles [
|
||||
"osd"
|
||||
]
|
||||
|
||||
TextView text_view {
|
||||
cursor-visible: false;
|
||||
editable: false;
|
||||
monospace: true;
|
||||
top-margin: 8;
|
||||
left-margin: 8;
|
||||
bottom-margin: 8;
|
||||
right-margin: 8;
|
||||
ScrolledWindow text_view_scroll {
|
||||
width-request: 500;
|
||||
height-request: 250;
|
||||
|
||||
TextView text_view {
|
||||
cursor-visible: false;
|
||||
editable: false;
|
||||
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">
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<object class="AdwMessageDialog" id="clipboard_confirmation_window">
|
||||
<property name="heading" translatable="yes">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="heading" translatable="true">Warning: Potentially Unsafe Paste</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>
|
||||
<response id="cancel" translatable="yes" appearance="suggested">Cancel</response>
|
||||
<response id="ok" translatable="yes" appearance="destructive">Paste</response>
|
||||
<response id="cancel" translatable="true" appearance="suggested">Cancel</response>
|
||||
<response id="ok" translatable="true" appearance="destructive">Paste</response>
|
||||
</responses>
|
||||
<property name="default-response">cancel</property>
|
||||
<property name="close-response">cancel</property>
|
||||
<property name="extra-child">
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="width-request">500</property>
|
||||
<property name="height-request">250</property>
|
||||
<object class="GtkOverlay">
|
||||
<style>
|
||||
<class name="osd"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkTextView" id="text_view">
|
||||
<property name="cursor-visible">false</property>
|
||||
<property name="editable">false</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>
|
||||
<object class="GtkScrolledWindow" id="text_view_scroll">
|
||||
<property name="width-request">500</property>
|
||||
<property name="height-request">250</property>
|
||||
<child>
|
||||
<object class="GtkTextView" id="text_view">
|
||||
<property name="cursor-visible">false</property>
|
||||
<property name="editable">false</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>
|
||||
</child>
|
||||
</object>
|
||||
|
@ -14,18 +14,58 @@ Adw.AlertDialog clipboard_confirmation_window {
|
||||
default-response: "cancel";
|
||||
close-response: "cancel";
|
||||
|
||||
extra-child: ScrolledWindow {
|
||||
width-request: 500;
|
||||
height-request: 250;
|
||||
extra-child: Overlay {
|
||||
styles [
|
||||
"osd"
|
||||
]
|
||||
|
||||
TextView text_view {
|
||||
cursor-visible: false;
|
||||
editable: false;
|
||||
monospace: true;
|
||||
top-margin: 8;
|
||||
left-margin: 8;
|
||||
bottom-margin: 8;
|
||||
right-margin: 8;
|
||||
ScrolledWindow text_view_scroll {
|
||||
width-request: 500;
|
||||
height-request: 250;
|
||||
|
||||
TextView text_view {
|
||||
cursor-visible: false;
|
||||
editable: false;
|
||||
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";
|
||||
close-response: "cancel";
|
||||
|
||||
extra-child: ScrolledWindow {
|
||||
width-request: 500;
|
||||
height-request: 250;
|
||||
extra-child: Overlay {
|
||||
styles [
|
||||
"osd"
|
||||
]
|
||||
|
||||
TextView text_view {
|
||||
cursor-visible: false;
|
||||
editable: false;
|
||||
monospace: true;
|
||||
top-margin: 8;
|
||||
left-margin: 8;
|
||||
bottom-margin: 8;
|
||||
right-margin: 8;
|
||||
ScrolledWindow text_view_scroll {
|
||||
width-request: 500;
|
||||
height-request: 250;
|
||||
|
||||
TextView text_view {
|
||||
cursor-visible: false;
|
||||
editable: false;
|
||||
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";
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -10,22 +10,62 @@ Adw.AlertDialog clipboard_confirmation_window {
|
||||
cancel: _("Cancel") suggested,
|
||||
ok: _("Paste") destructive
|
||||
]
|
||||
|
||||
|
||||
default-response: "cancel";
|
||||
close-response: "cancel";
|
||||
|
||||
extra-child: ScrolledWindow {
|
||||
width-request: 500;
|
||||
height-request: 250;
|
||||
|
||||
TextView text_view {
|
||||
cursor-visible: false;
|
||||
editable: false;
|
||||
monospace: true;
|
||||
top-margin: 8;
|
||||
left-margin: 8;
|
||||
bottom-margin: 8;
|
||||
right-margin: 8;
|
||||
extra-child: Overlay {
|
||||
styles [
|
||||
"osd"
|
||||
]
|
||||
|
||||
ScrolledWindow text_view_scroll {
|
||||
width-request: 500;
|
||||
height-request: 250;
|
||||
|
||||
TextView text_view {
|
||||
cursor-visible: false;
|
||||
editable: false;
|
||||
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