From 1f695c2646fc7ca3cbe43c77918d8b5c0cb47fa3 Mon Sep 17 00:00:00 2001 From: Maciej Bartczak <39600846+maciekbartczak@users.noreply.github.com> Date: Sun, 2 Mar 2025 17:38:47 +0100 Subject: [PATCH 1/4] gtk: implement sensitive content reveal mechanism when showing paste confirmation in secure input mode --- src/apprt/gtk/App.zig | 11 +++- src/apprt/gtk/ClipboardConfirmationWindow.zig | 32 ++++++++++- src/apprt/gtk/Surface.zig | 26 ++++----- src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp | 50 +++++++++++++---- src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp | 50 +++++++++++++---- src/apprt/gtk/ui/1.5/ccw-paste.blp | 54 ++++++++++++++----- 6 files changed, 174 insertions(+), 49 deletions(-) diff --git a/src/apprt/gtk/App.zig b/src/apprt/gtk/App.zig index 50b15f6a3..6266d4c30 100644 --- a/src/apprt/gtk/App.zig +++ b/src/apprt/gtk/App.zig @@ -502,12 +502,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, @@ -1409,6 +1409,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; diff --git a/src/apprt/gtk/ClipboardConfirmationWindow.zig b/src/apprt/gtk/ClipboardConfirmationWindow.zig index 632f64fa3..ff20342fe 100644 --- a/src/apprt/gtk/ClipboardConfirmationWindow.zig +++ b/src/apprt/gtk/ClipboardConfirmationWindow.zig @@ -25,12 +25,16 @@ dialog: *DialogType, data: [:0]u8, core_surface: *CoreSurface, pending_req: apprt.ClipboardRequest, +content_revealer: *gtk.Revealer, +reveal_button_widget: *gtk.Widget, +hide_button_widget: *gtk.Widget, 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 +47,7 @@ pub fn create( data, core_surface, request, + is_secure_input, ); app.clipboard_confirmation_window = self; @@ -62,6 +67,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 +85,9 @@ fn init( defer builder.deinit(); const dialog = builder.getObject(DialogType, "clipboard_confirmation_window").?; + const content_revealer = builder.getObject(gtk.Revealer, "content_revealer").?; + const reveal_button: *gtk.Button = builder.getObject(gtk.Button, "reveal_button").?; + const hide_button: *gtk.Button = builder.getObject(gtk.Button, "hide_button").?; const copy = try app.core_app.alloc.dupeZ(u8, data); errdefer app.core_app.alloc.free(copy); @@ -88,15 +97,24 @@ fn init( .data = copy, .core_surface = core_surface, .pending_req = request, + .content_revealer = content_revealer, + .reveal_button_widget = gobject.ext.cast(gtk.Widget, reveal_button).?, + .hide_button_widget = gobject.ext.cast(gtk.Widget, 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) { + content_revealer.setRevealChild(@intFromBool(false)); + self.reveal_button_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 +170,15 @@ fn gtkResponse(_: *DialogType, response: [*:0]u8, self: *ClipboardConfirmation) } self.destroy(); } + +fn gtkRevealButtonClicked(_: *gtk.Button, self: *ClipboardConfirmation) callconv(.C) void { + self.content_revealer.setRevealChild(@intFromBool(true)); + self.hide_button_widget.setVisible(@intFromBool(true)); + self.reveal_button_widget.setVisible(@intFromBool(false)); +} + +fn gtkHideButtonClicked(_: *gtk.Button, self: *ClipboardConfirmation) callconv(.C) void { + self.content_revealer.setRevealChild(@intFromBool(false)); + self.hide_button_widget.setVisible(@intFromBool(false)); + self.reveal_button_widget.setVisible(@intFromBool(true)); +} diff --git a/src/apprt/gtk/Surface.zig b/src/apprt/gtk/Surface.zig index ba2e4d244..47b0867ba 100644 --- a/src/apprt/gtk/Surface.zig +++ b/src/apprt/gtk/Surface.zig @@ -307,6 +307,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 { @@ -1162,6 +1165,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}); }; @@ -1205,12 +1209,7 @@ fn gtkClipboardRead( error.UnauthorizedPaste, => { // Create a dialog and ask the user if they want to paste anyway. - ClipboardConfirmationWindow.create( - self.app, - str, - &self.core_surface, - req.state, - ) catch |window_err| { + ClipboardConfirmationWindow.create(self.app, str, &self.core_surface, req.state, self.is_secure_input) catch |window_err| { log.err("failed to create clipboard confirmation window err={}", .{window_err}); }; return; @@ -2225,12 +2224,7 @@ fn doPaste(self: *Surface, data: [:0]const u8) void { error.UnsafePaste, error.UnauthorizedPaste, => { - ClipboardConfirmationWindow.create( - self.app, - data, - &self.core_surface, - .paste, - ) catch |window_err| { + ClipboardConfirmationWindow.create(self.app, data, &self.core_surface, .paste, self.is_secure_input) catch |window_err| { log.err("failed to create clipboard confirmation window err={}", .{window_err}); }; }, @@ -2321,3 +2315,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, + } +} diff --git a/src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp b/src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp index 3319bc597..d894059da 100644 --- a/src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp +++ b/src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp @@ -14,18 +14,46 @@ Adw.AlertDialog clipboard_confirmation_window { default-response: "cancel"; close-response: "cancel"; - extra-child: ScrolledWindow { - width-request: 500; - height-request: 250; + extra-child: Box { + orientation: vertical; + spacing: 12; - TextView text_view { - cursor-visible: false; - editable: false; - monospace: true; - top-margin: 8; - left-margin: 8; - bottom-margin: 8; - right-margin: 8; + Button reveal_button { + visible: false; + + styles [ + "destructive-action" + ] + + Adw.ButtonContent { + label: _("Reveal Potentially Sensitive Content"); + icon-name: "dialog-warning-symbolic"; + } + } + + Button hide_button { + visible: false; + label: _("Hide Potentially Sensitive Content"); + } + + Revealer content_revealer { + reveal-child: true; + transition-type: slide_down; + + 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; + } + } } }; } diff --git a/src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp b/src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp index 8372f0ccb..a51a9cc2c 100644 --- a/src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp +++ b/src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp @@ -14,18 +14,46 @@ Adw.AlertDialog clipboard_confirmation_window { default-response: "cancel"; close-response: "cancel"; - extra-child: ScrolledWindow { - width-request: 500; - height-request: 250; + extra-child: Box { + orientation: vertical; + spacing: 12; - TextView text_view { - cursor-visible: false; - editable: false; - monospace: true; - top-margin: 8; - left-margin: 8; - bottom-margin: 8; - right-margin: 8; + Button reveal_button { + visible: false; + + styles [ + "destructive-action" + ] + + Adw.ButtonContent { + label: _("Reveal Potentially Sensitive Content"); + icon-name: "dialog-warning-symbolic"; + } + } + + Button hide_button { + visible: false; + label: _("Hide Potentially Sensitive Content"); + } + + Revealer content_revealer { + reveal-child: true; + transition-type: slide_down; + + 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; + } + } } }; } diff --git a/src/apprt/gtk/ui/1.5/ccw-paste.blp b/src/apprt/gtk/ui/1.5/ccw-paste.blp index 57aaabfd1..771c99058 100644 --- a/src/apprt/gtk/ui/1.5/ccw-paste.blp +++ b/src/apprt/gtk/ui/1.5/ccw-paste.blp @@ -10,22 +10,50 @@ 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: Box { + orientation: vertical; + spacing: 12; + + Button reveal_button { + visible: false; + + styles [ + "destructive-action" + ] + + Adw.ButtonContent { + label: _("Reveal Potentially Sensitive Content"); + icon-name: "dialog-warning-symbolic"; + } + } + + Button hide_button { + visible: false; + label: _("Hide Potentially Sensitive Content"); + } + + Revealer content_revealer { + reveal-child: true; + transition-type: slide_down; + + 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; + } + } } }; } From 7123d4e055df6f36331cd136a48746e198e9914e Mon Sep 17 00:00:00 2001 From: Maciej Bartczak <39600846+maciekbartczak@users.noreply.github.com> Date: Sun, 2 Mar 2025 21:07:19 +0100 Subject: [PATCH 2/4] gtk: blur the content view instead of using a Revealer widget --- src/apprt/gtk/ClipboardConfirmationWindow.zig | 43 ++++++++++++++----- src/apprt/gtk/style.css | 10 +++++ src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp | 29 ++++++------- src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp | 29 ++++++------- src/apprt/gtk/ui/1.5/ccw-paste.blp | 29 ++++++------- 5 files changed, 84 insertions(+), 56 deletions(-) diff --git a/src/apprt/gtk/ClipboardConfirmationWindow.zig b/src/apprt/gtk/ClipboardConfirmationWindow.zig index ff20342fe..d967fd06f 100644 --- a/src/apprt/gtk/ClipboardConfirmationWindow.zig +++ b/src/apprt/gtk/ClipboardConfirmationWindow.zig @@ -25,7 +25,8 @@ dialog: *DialogType, data: [:0]u8, core_surface: *CoreSurface, pending_req: apprt.ClipboardRequest, -content_revealer: *gtk.Revealer, +text_view: *gtk.TextView, +text_view_scroll: *gtk.ScrolledWindow, reveal_button_widget: *gtk.Widget, hide_button_widget: *gtk.Widget, @@ -85,9 +86,10 @@ fn init( defer builder.deinit(); const dialog = builder.getObject(DialogType, "clipboard_confirmation_window").?; - const content_revealer = builder.getObject(gtk.Revealer, "content_revealer").?; - const reveal_button: *gtk.Button = builder.getObject(gtk.Button, "reveal_button").?; - const hide_button: *gtk.Button = builder.getObject(gtk.Button, "hide_button").?; + 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); @@ -97,22 +99,37 @@ fn init( .data = copy, .core_surface = core_surface, .pending_req = request, - .content_revealer = content_revealer, + .text_view = text_view, + .text_view_scroll = text_view_scroll, .reveal_button_widget = gobject.ext.cast(gtk.Widget, reveal_button).?, .hide_button_widget = gobject.ext.cast(gtk.Widget, 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) { - content_revealer.setRevealChild(@intFromBool(false)); + gobject.ext.as(gtk.Widget, text_view_scroll).setSensitive(@intFromBool(false)); + gobject.ext.as(gtk.Widget, self.text_view).addCssClass("blurred"); + self.reveal_button_widget.setVisible(@intFromBool(true)); - _ = gtk.Button.signals.clicked.connect(reveal_button, *ClipboardConfirmation, gtkRevealButtonClicked, self, .{}); - _ = gtk.Button.signals.clicked.connect(hide_button, *ClipboardConfirmation, gtkHideButtonClicked, self, .{}); + + _ = gtk.Button.signals.clicked.connect( + reveal_button, + *ClipboardConfirmation, + gtkRevealButtonClicked, + self, + .{}, + ); + _ = gtk.Button.signals.clicked.connect( + hide_button, + *ClipboardConfirmation, + gtkHideButtonClicked, + self, + .{}, + ); } switch (DialogType) { @@ -172,13 +189,17 @@ fn gtkResponse(_: *DialogType, response: [*:0]u8, self: *ClipboardConfirmation) } fn gtkRevealButtonClicked(_: *gtk.Button, self: *ClipboardConfirmation) callconv(.C) void { - self.content_revealer.setRevealChild(@intFromBool(true)); + gobject.ext.as(gtk.Widget, self.text_view_scroll).setSensitive(@intFromBool(true)); + gobject.ext.as(gtk.Widget, self.text_view).removeCssClass("blurred"); + self.hide_button_widget.setVisible(@intFromBool(true)); self.reveal_button_widget.setVisible(@intFromBool(false)); } fn gtkHideButtonClicked(_: *gtk.Button, self: *ClipboardConfirmation) callconv(.C) void { - self.content_revealer.setRevealChild(@intFromBool(false)); + gobject.ext.as(gtk.Widget, self.text_view_scroll).setSensitive(@intFromBool(false)); + gobject.ext.as(gtk.Widget, self.text_view).addCssClass("blurred"); + self.hide_button_widget.setVisible(@intFromBool(false)); self.reveal_button_widget.setVisible(@intFromBool(true)); } diff --git a/src/apprt/gtk/style.css b/src/apprt/gtk/style.css index 75d020a06..ecaef6b33 100644 --- a/src/apprt/gtk/style.css +++ b/src/apprt/gtk/style.css @@ -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; +} diff --git a/src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp b/src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp index d894059da..25353e801 100644 --- a/src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp +++ b/src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp @@ -36,23 +36,22 @@ Adw.AlertDialog clipboard_confirmation_window { label: _("Hide Potentially Sensitive Content"); } - Revealer content_revealer { - reveal-child: true; - transition-type: slide_down; + ScrolledWindow text_view_scroll { + width-request: 500; + height-request: 250; - 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; - 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" + ] } } }; diff --git a/src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp b/src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp index a51a9cc2c..1c4e740e4 100644 --- a/src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp +++ b/src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp @@ -36,23 +36,22 @@ Adw.AlertDialog clipboard_confirmation_window { label: _("Hide Potentially Sensitive Content"); } - Revealer content_revealer { - reveal-child: true; - transition-type: slide_down; + ScrolledWindow text_view_scroll { + width-request: 500; + height-request: 250; - 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; - 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" + ] } } }; diff --git a/src/apprt/gtk/ui/1.5/ccw-paste.blp b/src/apprt/gtk/ui/1.5/ccw-paste.blp index 771c99058..395556f3d 100644 --- a/src/apprt/gtk/ui/1.5/ccw-paste.blp +++ b/src/apprt/gtk/ui/1.5/ccw-paste.blp @@ -36,23 +36,22 @@ Adw.AlertDialog clipboard_confirmation_window { label: _("Hide Potentially Sensitive Content"); } - Revealer content_revealer { - reveal-child: true; - transition-type: slide_down; + ScrolledWindow text_view_scroll { + width-request: 500; + height-request: 250; - 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; - 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" + ] } } }; From f71b294697e32c304c944ea9c7818d4845de4ef1 Mon Sep 17 00:00:00 2001 From: Maciej Bartczak <39600846+maciekbartczak@users.noreply.github.com> Date: Mon, 3 Mar 2025 19:28:34 +0100 Subject: [PATCH 3/4] gtk: new approach to reveal/hide buttons --- src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp | 57 ++++++++++++++--------- src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp | 57 ++++++++++++++--------- src/apprt/gtk/ui/1.5/ccw-paste.blp | 57 ++++++++++++++--------- 3 files changed, 105 insertions(+), 66 deletions(-) diff --git a/src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp b/src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp index 25353e801..9f3b806a6 100644 --- a/src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp +++ b/src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp @@ -14,28 +14,7 @@ Adw.AlertDialog clipboard_confirmation_window { default-response: "cancel"; close-response: "cancel"; - extra-child: Box { - orientation: vertical; - spacing: 12; - - Button reveal_button { - visible: false; - - styles [ - "destructive-action" - ] - - Adw.ButtonContent { - label: _("Reveal Potentially Sensitive Content"); - icon-name: "dialog-warning-symbolic"; - } - } - - Button hide_button { - visible: false; - label: _("Hide Potentially Sensitive Content"); - } - + extra-child: Overlay { ScrolledWindow text_view_scroll { width-request: 500; height-request: 250; @@ -54,5 +33,39 @@ Adw.AlertDialog clipboard_confirmation_window { ] } } + + [overlay] + Button reveal_button { + visible: false; + halign: end; + valign: start; + margin-end: 12; + margin-top: 12; + + styles [ + "destructive-action", + ] + + Image { + icon-name: "view-reveal-symbolic"; + } + } + + [overlay] + Button hide_button { + visible: false; + halign: end; + valign: start; + margin-end: 12; + margin-top: 12; + + styles [ + "suggested-action", + ] + + Image { + icon-name: "view-conceal-symbolic"; + } + } }; } diff --git a/src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp b/src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp index 1c4e740e4..a745de597 100644 --- a/src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp +++ b/src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp @@ -14,28 +14,7 @@ Adw.AlertDialog clipboard_confirmation_window { default-response: "cancel"; close-response: "cancel"; - extra-child: Box { - orientation: vertical; - spacing: 12; - - Button reveal_button { - visible: false; - - styles [ - "destructive-action" - ] - - Adw.ButtonContent { - label: _("Reveal Potentially Sensitive Content"); - icon-name: "dialog-warning-symbolic"; - } - } - - Button hide_button { - visible: false; - label: _("Hide Potentially Sensitive Content"); - } - + extra-child: Overlay { ScrolledWindow text_view_scroll { width-request: 500; height-request: 250; @@ -54,5 +33,39 @@ Adw.AlertDialog clipboard_confirmation_window { ] } } + + [overlay] + Button reveal_button { + visible: false; + halign: end; + valign: start; + margin-end: 12; + margin-top: 12; + + styles [ + "destructive-action", + ] + + Image { + icon-name: "view-reveal-symbolic"; + } + } + + [overlay] + Button hide_button { + visible: false; + halign: end; + valign: start; + margin-end: 12; + margin-top: 12; + + styles [ + "suggested-action", + ] + + Image { + icon-name: "view-conceal-symbolic"; + } + } }; } diff --git a/src/apprt/gtk/ui/1.5/ccw-paste.blp b/src/apprt/gtk/ui/1.5/ccw-paste.blp index 395556f3d..1066ecae7 100644 --- a/src/apprt/gtk/ui/1.5/ccw-paste.blp +++ b/src/apprt/gtk/ui/1.5/ccw-paste.blp @@ -14,28 +14,7 @@ Adw.AlertDialog clipboard_confirmation_window { default-response: "cancel"; close-response: "cancel"; - extra-child: Box { - orientation: vertical; - spacing: 12; - - Button reveal_button { - visible: false; - - styles [ - "destructive-action" - ] - - Adw.ButtonContent { - label: _("Reveal Potentially Sensitive Content"); - icon-name: "dialog-warning-symbolic"; - } - } - - Button hide_button { - visible: false; - label: _("Hide Potentially Sensitive Content"); - } - + extra-child: Overlay { ScrolledWindow text_view_scroll { width-request: 500; height-request: 250; @@ -54,5 +33,39 @@ Adw.AlertDialog clipboard_confirmation_window { ] } } + + [overlay] + Button reveal_button { + visible: false; + halign: end; + valign: start; + margin-end: 12; + margin-top: 12; + + styles [ + "destructive-action", + ] + + Image { + icon-name: "view-reveal-symbolic"; + } + } + + [overlay] + Button hide_button { + visible: false; + halign: end; + valign: start; + margin-end: 12; + margin-top: 12; + + styles [ + "suggested-action", + ] + + Image { + icon-name: "view-conceal-symbolic"; + } + } }; } From bd617c52e9857e1c181baaea70265421cbb40ffc Mon Sep 17 00:00:00 2001 From: Maciej Bartczak <39600846+maciekbartczak@users.noreply.github.com> Date: Wed, 5 Mar 2025 21:01:49 +0100 Subject: [PATCH 4/4] code review: - implement blueprints for Adwaita 1.2 - use postifx notation for casting gtk widgets - fix formatting --- src/apprt/gtk/ClipboardConfirmationWindow.zig | 30 ++++---- src/apprt/gtk/Surface.zig | 16 ++++- src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp | 62 +++++++++++++--- src/apprt/gtk/ui/1.2/ccw-osc-52-read.ui | 71 +++++++++++++++---- src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp | 62 +++++++++++++--- src/apprt/gtk/ui/1.2/ccw-osc-52-write.ui | 71 +++++++++++++++---- src/apprt/gtk/ui/1.2/ccw-paste.blp | 62 +++++++++++++--- src/apprt/gtk/ui/1.2/ccw-paste.ui | 71 +++++++++++++++---- src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp | 10 +-- src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp | 10 +-- src/apprt/gtk/ui/1.5/ccw-paste.blp | 10 +-- 11 files changed, 365 insertions(+), 110 deletions(-) diff --git a/src/apprt/gtk/ClipboardConfirmationWindow.zig b/src/apprt/gtk/ClipboardConfirmationWindow.zig index d967fd06f..9260d1c7b 100644 --- a/src/apprt/gtk/ClipboardConfirmationWindow.zig +++ b/src/apprt/gtk/ClipboardConfirmationWindow.zig @@ -27,8 +27,8 @@ core_surface: *CoreSurface, pending_req: apprt.ClipboardRequest, text_view: *gtk.TextView, text_view_scroll: *gtk.ScrolledWindow, -reveal_button_widget: *gtk.Widget, -hide_button_widget: *gtk.Widget, +reveal_button: *gtk.Button, +hide_button: *gtk.Button, pub fn create( app: *App, @@ -101,8 +101,8 @@ fn init( .pending_req = request, .text_view = text_view, .text_view_scroll = text_view_scroll, - .reveal_button_widget = gobject.ext.cast(gtk.Widget, reveal_button).?, - .hide_button_widget = gobject.ext.cast(gtk.Widget, hide_button).?, + .reveal_button = reveal_button, + .hide_button = hide_button, }; const buffer = gtk.TextBuffer.new(null); @@ -111,10 +111,10 @@ fn init( text_view.setBuffer(buffer); if (is_secure_input) { - gobject.ext.as(gtk.Widget, text_view_scroll).setSensitive(@intFromBool(false)); - gobject.ext.as(gtk.Widget, self.text_view).addCssClass("blurred"); + text_view_scroll.as(gtk.Widget).setSensitive(@intFromBool(false)); + self.text_view.as(gtk.Widget).addCssClass("blurred"); - self.reveal_button_widget.setVisible(@intFromBool(true)); + self.reveal_button.as(gtk.Widget).setVisible(@intFromBool(true)); _ = gtk.Button.signals.clicked.connect( reveal_button, @@ -189,17 +189,17 @@ fn gtkResponse(_: *DialogType, response: [*:0]u8, self: *ClipboardConfirmation) } fn gtkRevealButtonClicked(_: *gtk.Button, self: *ClipboardConfirmation) callconv(.C) void { - gobject.ext.as(gtk.Widget, self.text_view_scroll).setSensitive(@intFromBool(true)); - gobject.ext.as(gtk.Widget, self.text_view).removeCssClass("blurred"); + self.text_view_scroll.as(gtk.Widget).setSensitive(@intFromBool(true)); + self.text_view.as(gtk.Widget).removeCssClass("blurred"); - self.hide_button_widget.setVisible(@intFromBool(true)); - self.reveal_button_widget.setVisible(@intFromBool(false)); + 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 { - gobject.ext.as(gtk.Widget, self.text_view_scroll).setSensitive(@intFromBool(false)); - gobject.ext.as(gtk.Widget, self.text_view).addCssClass("blurred"); + self.text_view_scroll.as(gtk.Widget).setSensitive(@intFromBool(false)); + self.text_view.as(gtk.Widget).addCssClass("blurred"); - self.hide_button_widget.setVisible(@intFromBool(false)); - self.reveal_button_widget.setVisible(@intFromBool(true)); + self.hide_button.as(gtk.Widget).setVisible(@intFromBool(false)); + self.reveal_button.as(gtk.Widget).setVisible(@intFromBool(true)); } diff --git a/src/apprt/gtk/Surface.zig b/src/apprt/gtk/Surface.zig index 47b0867ba..cba436fec 100644 --- a/src/apprt/gtk/Surface.zig +++ b/src/apprt/gtk/Surface.zig @@ -1209,7 +1209,13 @@ fn gtkClipboardRead( error.UnauthorizedPaste, => { // Create a dialog and ask the user if they want to paste anyway. - ClipboardConfirmationWindow.create(self.app, str, &self.core_surface, req.state, self.is_secure_input) catch |window_err| { + ClipboardConfirmationWindow.create( + self.app, + str, + &self.core_surface, + req.state, + self.is_secure_input, + ) catch |window_err| { log.err("failed to create clipboard confirmation window err={}", .{window_err}); }; return; @@ -2224,7 +2230,13 @@ fn doPaste(self: *Surface, data: [:0]const u8) void { error.UnsafePaste, error.UnauthorizedPaste, => { - ClipboardConfirmationWindow.create(self.app, data, &self.core_surface, .paste, self.is_secure_input) catch |window_err| { + ClipboardConfirmationWindow.create( + self.app, + data, + &self.core_surface, + .paste, + self.is_secure_input, + ) catch |window_err| { log.err("failed to create clipboard confirmation window err={}", .{window_err}); }; }, diff --git a/src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp b/src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp index eafa92e1b..c76b69884 100644 --- a/src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp +++ b/src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp @@ -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"; + } } }; } diff --git a/src/apprt/gtk/ui/1.2/ccw-osc-52-read.ui b/src/apprt/gtk/ui/1.2/ccw-osc-52-read.ui index 9c89835a0..82512e3a2 100644 --- a/src/apprt/gtk/ui/1.2/ccw-osc-52-read.ui +++ b/src/apprt/gtk/ui/1.2/ccw-osc-52-read.ui @@ -7,27 +7,68 @@ corresponding .blp file and regenerate this file with blueprint-compiler. - Authorize Clipboard Access - An application is attempting to read from the clipboard. The current clipboard contents are shown below. + Authorize Clipboard Access + An application is attempting to read from the clipboard. The current clipboard contents are shown below. - Deny - Allow + Deny + Allow cancel cancel - - 500 - 250 + + - - false - false - true - 8 - 8 - 8 - 8 + + 500 + 250 + + + false + false + true + 8 + 8 + 8 + 8 + + + + + + + + false + 2 + 1 + 12 + 12 + + + view-reveal-symbolic + + + + + + + false + 2 + 1 + 12 + 12 + + + + view-conceal-symbolic + + diff --git a/src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp b/src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp index ecd58929b..529a2fc52 100644 --- a/src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp +++ b/src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp @@ -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"; + } } }; } diff --git a/src/apprt/gtk/ui/1.2/ccw-osc-52-write.ui b/src/apprt/gtk/ui/1.2/ccw-osc-52-write.ui index a8904de0d..195fb1de1 100644 --- a/src/apprt/gtk/ui/1.2/ccw-osc-52-write.ui +++ b/src/apprt/gtk/ui/1.2/ccw-osc-52-write.ui @@ -7,27 +7,68 @@ corresponding .blp file and regenerate this file with blueprint-compiler. - Authorize Clipboard Access - An application is attempting to write to the clipboard. The current clipboard contents are shown below. + Authorize Clipboard Access + An application is attempting to write to the clipboard. The current clipboard contents are shown below. - Deny - Allow + Deny + Allow cancel cancel - - 500 - 250 + + - - false - false - true - 8 - 8 - 8 - 8 + + 500 + 250 + + + false + false + true + 8 + 8 + 8 + 8 + + + + + + + + false + 2 + 1 + 12 + 12 + + + view-reveal-symbolic + + + + + + + false + 2 + 1 + 12 + 12 + + + + view-conceal-symbolic + + diff --git a/src/apprt/gtk/ui/1.2/ccw-paste.blp b/src/apprt/gtk/ui/1.2/ccw-paste.blp index 916860368..3ca12e966 100644 --- a/src/apprt/gtk/ui/1.2/ccw-paste.blp +++ b/src/apprt/gtk/ui/1.2/ccw-paste.blp @@ -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"; + } } }; } diff --git a/src/apprt/gtk/ui/1.2/ccw-paste.ui b/src/apprt/gtk/ui/1.2/ccw-paste.ui index 33e75b3e8..342c767e6 100644 --- a/src/apprt/gtk/ui/1.2/ccw-paste.ui +++ b/src/apprt/gtk/ui/1.2/ccw-paste.ui @@ -7,27 +7,68 @@ corresponding .blp file and regenerate this file with blueprint-compiler. - Warning: Potentially Unsafe Paste - Pasting this text into the terminal may be dangerous as it looks like some commands may be executed. + Warning: Potentially Unsafe Paste + Pasting this text into the terminal may be dangerous as it looks like some commands may be executed. - Cancel - Paste + Cancel + Paste cancel cancel - - 500 - 250 + + - - false - false - true - 8 - 8 - 8 - 8 + + 500 + 250 + + + false + false + true + 8 + 8 + 8 + 8 + + + + + + + + false + 2 + 1 + 12 + 12 + + + view-reveal-symbolic + + + + + + + false + 2 + 1 + 12 + 12 + + + + view-conceal-symbolic + + diff --git a/src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp b/src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp index 9f3b806a6..60fca5b00 100644 --- a/src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp +++ b/src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp @@ -15,6 +15,10 @@ Adw.AlertDialog clipboard_confirmation_window { close-response: "cancel"; extra-child: Overlay { + styles [ + "osd" + ] + ScrolledWindow text_view_scroll { width-request: 500; height-request: 250; @@ -42,10 +46,6 @@ Adw.AlertDialog clipboard_confirmation_window { margin-end: 12; margin-top: 12; - styles [ - "destructive-action", - ] - Image { icon-name: "view-reveal-symbolic"; } @@ -60,7 +60,7 @@ Adw.AlertDialog clipboard_confirmation_window { margin-top: 12; styles [ - "suggested-action", + "opaque" ] Image { diff --git a/src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp b/src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp index a745de597..7ef17def0 100644 --- a/src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp +++ b/src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp @@ -15,6 +15,10 @@ Adw.AlertDialog clipboard_confirmation_window { close-response: "cancel"; extra-child: Overlay { + styles [ + "osd" + ] + ScrolledWindow text_view_scroll { width-request: 500; height-request: 250; @@ -42,10 +46,6 @@ Adw.AlertDialog clipboard_confirmation_window { margin-end: 12; margin-top: 12; - styles [ - "destructive-action", - ] - Image { icon-name: "view-reveal-symbolic"; } @@ -60,7 +60,7 @@ Adw.AlertDialog clipboard_confirmation_window { margin-top: 12; styles [ - "suggested-action", + "opaque" ] Image { diff --git a/src/apprt/gtk/ui/1.5/ccw-paste.blp b/src/apprt/gtk/ui/1.5/ccw-paste.blp index 1066ecae7..57539fb44 100644 --- a/src/apprt/gtk/ui/1.5/ccw-paste.blp +++ b/src/apprt/gtk/ui/1.5/ccw-paste.blp @@ -15,6 +15,10 @@ Adw.AlertDialog clipboard_confirmation_window { close-response: "cancel"; extra-child: Overlay { + styles [ + "osd" + ] + ScrolledWindow text_view_scroll { width-request: 500; height-request: 250; @@ -42,10 +46,6 @@ Adw.AlertDialog clipboard_confirmation_window { margin-end: 12; margin-top: 12; - styles [ - "destructive-action", - ] - Image { icon-name: "view-reveal-symbolic"; } @@ -60,7 +60,7 @@ Adw.AlertDialog clipboard_confirmation_window { margin-top: 12; styles [ - "suggested-action", + "opaque" ] Image {