gtk: add "remember choice" toggle for clipboard confirmation dialog (#6783)

Implements #6763 (not backporting to the 1.2 version since I'm way too
lazy)


![image](https://github.com/user-attachments/assets/9c9aca3e-8b42-4d47-8a96-841612add812)
pull/7718/head
Mitchell Hashimoto 2025-06-28 14:55:31 -07:00 committed by GitHub
commit 2637400904
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 228 additions and 120 deletions

View File

@ -1,5 +1,5 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR Mitchell Hashimoto, Ghostty contributors
# Copyright (C) YEAR "Mitchell Hashimoto, Ghostty contributors"
# This file is distributed under the same license as the com.mitchellh.ghostty package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-04-23 16:58+0800\n"
"POT-Creation-Date: 2025-06-28 17:01+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -26,7 +26,8 @@ msgid "Leave blank to restore the default title."
msgstr ""
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/CloseDialog.zig:44
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr ""
@ -35,22 +36,26 @@ msgid "OK"
msgstr ""
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr ""
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
msgstr ""
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr ""
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr ""
@ -89,7 +94,7 @@ msgstr ""
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr ""
@ -119,7 +124,7 @@ msgstr ""
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
#: src/apprt/gtk/Window.zig:255
#: src/apprt/gtk/Window.zig:263
msgid "New Tab"
msgstr ""
@ -160,7 +165,7 @@ msgid "Terminal Inspector"
msgstr ""
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1024
#: src/apprt/gtk/Window.zig:1036
msgid "About Ghostty"
msgstr ""
@ -170,10 +175,13 @@ msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@ -181,52 +189,67 @@ msgstr ""
#: 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.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
msgstr ""
#: src/apprt/gtk/Window.zig:208
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr ""
#: src/apprt/gtk/Window.zig:229
#: src/apprt/gtk/Window.zig:238
msgid "View Open Tabs"
msgstr ""
#: src/apprt/gtk/Window.zig:256
#: src/apprt/gtk/Window.zig:264
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:319
#: src/apprt/gtk/Window.zig:327
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
#: src/apprt/gtk/Window.zig:765
#: src/apprt/gtk/Window.zig:773
msgid "Reloaded the configuration"
msgstr ""
#: src/apprt/gtk/Window.zig:1005
#: src/apprt/gtk/Window.zig:1017
msgid "Ghostty Developers"
msgstr ""
@ -270,6 +293,6 @@ msgstr ""
msgid "The currently running process in this split will be terminated."
msgstr ""
#: src/apprt/gtk/Surface.zig:1243
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr ""

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-04-23 16:58+0800\n"
"POT-Creation-Date: 2025-06-28 17:01+0200\n"
"PO-Revision-Date: 2025-02-27 09:16+0100\n"
"Last-Translator: Leah <hi@pluie.me>\n"
"Language-Team: Chinese (simplified) <i18n-zh@googlegroups.com>\n"
@ -26,7 +26,8 @@ msgid "Leave blank to restore the default title."
msgstr "留空以重置至默认标题。"
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/CloseDialog.zig:44
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "取消"
@ -35,10 +36,12 @@ msgid "OK"
msgstr "确认"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "配置错误"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
@ -46,12 +49,14 @@ msgstr ""
"加载配置时发现了以下错误。请仔细阅读错误信息,并选择忽略或重新加载配置文件。"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "忽略"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "重新加载配置"
@ -90,7 +95,7 @@ msgstr "复制"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "粘贴"
@ -120,7 +125,7 @@ msgstr "标签页"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
#: src/apprt/gtk/Window.zig:255
#: src/apprt/gtk/Window.zig:263
msgid "New Tab"
msgstr "新建标签页"
@ -161,7 +166,7 @@ msgid "Terminal Inspector"
msgstr "终端调试器"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1024
#: src/apprt/gtk/Window.zig:1036
msgid "About Ghostty"
msgstr "关于 Ghostty"
@ -171,10 +176,13 @@ msgstr "退出"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "剪贴板访问授权"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@ -182,52 +190,67 @@ msgstr "一个应用正在试图从剪贴板读取内容。剪贴板目前的内
#: 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.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "拒绝"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "允许"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr "为本分屏记住当前选择"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr "本提示将在重载配置后再次出现"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
msgstr "一个应用正在试图向剪贴板写入内容。剪贴板目前的内容如下:"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "警告:粘贴内容可能不安全"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
msgstr "将以下内容粘贴至终端内将可能执行有害命令。"
#: src/apprt/gtk/Window.zig:208
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "主菜单"
#: src/apprt/gtk/Window.zig:229
#: src/apprt/gtk/Window.zig:238
msgid "View Open Tabs"
msgstr "浏览标签页"
#: src/apprt/gtk/Window.zig:256
#: src/apprt/gtk/Window.zig:264
msgid "New Split"
msgstr "新建分屏"
#: src/apprt/gtk/Window.zig:319
#: src/apprt/gtk/Window.zig:327
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr "⚠️ Ghostty 正在以调试模式运行!性能将大打折扣。"
#: src/apprt/gtk/Window.zig:765
#: src/apprt/gtk/Window.zig:773
msgid "Reloaded the configuration"
msgstr "已重新加载配置"
#: src/apprt/gtk/Window.zig:1005
#: src/apprt/gtk/Window.zig:1017
msgid "Ghostty Developers"
msgstr "Ghostty 开发团队"
@ -271,6 +294,6 @@ msgstr "标签页内所有运行中的进程将被终止。"
msgid "The currently running process in this split will be terminated."
msgstr "分屏内正在运行中的进程将被终止。"
#: src/apprt/gtk/Surface.zig:1243
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "已复制至剪贴板"

View File

@ -17,7 +17,7 @@ const adw_version = @import("adw_version.zig");
const log = std.log.scoped(.gtk);
const DialogType = if (adw_version.atLeast(1, 5, 0)) adw.AlertDialog else adw.MessageDialog;
const DialogType = if (adw_version.supportsDialogs()) adw.AlertDialog else adw.MessageDialog;
app: *App,
dialog: *DialogType,
@ -28,6 +28,7 @@ text_view: *gtk.TextView,
text_view_scroll: *gtk.ScrolledWindow,
reveal_button: *gtk.Button,
hide_button: *gtk.Button,
remember_choice: if (adw_version.supportsSwitchRow()) ?*adw.SwitchRow else ?*anyopaque,
pub fn create(
app: *App,
@ -89,6 +90,10 @@ fn init(
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 remember_choice = if (adw_version.supportsSwitchRow())
builder.getObject(adw.SwitchRow, "remember_choice")
else
null;
const copy = try app.core_app.alloc.dupeZ(u8, data);
errdefer app.core_app.alloc.free(copy);
@ -102,6 +107,7 @@ fn init(
.text_view_scroll = text_view_scroll,
.reveal_button = reveal_button,
.hide_button = hide_button,
.remember_choice = remember_choice,
};
const buffer = gtk.TextBuffer.new(null);
@ -152,8 +158,10 @@ fn init(
}
}
fn gtkResponse(_: *DialogType, response: [*:0]u8, self: *ClipboardConfirmation) callconv(.c) void {
if (std.mem.orderZ(u8, response, "ok") == .eq) {
fn handleResponse(self: *ClipboardConfirmation, response: [*:0]const u8) void {
const is_ok = std.mem.orderZ(u8, response, "ok") == .eq;
if (is_ok) {
self.core_surface.completeClipboardRequest(
self.pending_req,
self.data,
@ -162,8 +170,30 @@ fn gtkResponse(_: *DialogType, response: [*:0]u8, self: *ClipboardConfirmation)
log.err("Failed to requeue clipboard request: {}", .{err});
};
}
if (self.remember_choice) |remember| remember: {
if (!adw_version.supportsSwitchRow()) break :remember;
if (remember.getActive() == 0) break :remember;
switch (self.pending_req) {
.osc_52_read => self.core_surface.config.clipboard_read = if (is_ok) .allow else .deny,
.osc_52_write => self.core_surface.config.clipboard_write = if (is_ok) .allow else .deny,
.paste => {},
}
}
self.destroy();
}
fn gtkChoose(dialog_: ?*gobject.Object, result: *gio.AsyncResult, ud: ?*anyopaque) callconv(.C) void {
const dialog = gobject.ext.cast(DialogType, dialog_.?).?;
const self: *ClipboardConfirmation = @ptrCast(@alignCast(ud.?));
const response = dialog.chooseFinish(result);
self.handleResponse(response);
}
fn gtkResponse(_: *DialogType, response: [*:0]u8, self: *ClipboardConfirmation) callconv(.C) void {
self.handleResponse(response);
}
fn gtkRevealButtonClicked(_: *gtk.Button, self: *ClipboardConfirmation) callconv(.c) void {
self.text_view_scroll.as(gtk.Widget).setSensitive(@intFromBool(true));

View File

@ -109,6 +109,10 @@ pub inline fn supportsTabOverview() bool {
return atLeast(1, 4, 0);
}
pub inline fn supportsSwitchRow() bool {
return atLeast(1, 4, 0);
}
pub inline fn supportsToolbarView() bool {
return atLeast(1, 4, 0);
}

View File

@ -64,14 +64,18 @@ window.ssd.no-border-radius {
padding: 0;
}
.clipboard-overlay {
border-radius: 10px;
}
.clipboard-content-view {
filter: blur(0px);
transition: filter 0.3s ease;
border-radius: 10px;
}
.clipboard-content-view.blurred {
filter: blur(5px);
transition: filter 0.3s ease;
}
.command-palette-search {

View File

@ -14,58 +14,72 @@ Adw.AlertDialog clipboard_confirmation_window {
default-response: "cancel";
close-response: "cancel";
extra-child: Overlay {
extra-child: ListBox {
selection-mode: none;
styles [
"osd",
"boxed-list-separate",
]
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;
Overlay {
styles [
"opaque",
"osd",
"clipboard-overlay",
]
Image {
icon-name: "view-conceal-symbolic";
ScrolledWindow text_view_scroll {
width-request: 500;
height-request: 200;
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";
}
}
}
Adw.SwitchRow remember_choice {
title: _("Remember choice for this split");
subtitle: _("Reload configuration to show this prompt again");
}
};
}

View File

@ -14,58 +14,68 @@ Adw.AlertDialog clipboard_confirmation_window {
default-response: "cancel";
close-response: "cancel";
extra-child: Overlay {
extra-child: ListBox {
selection-mode: none;
styles [
"osd",
"boxed-list-separate",
]
ScrolledWindow text_view_scroll {
width-request: 500;
height-request: 250;
Overlay {
styles [
"osd",
"clipboard-overlay",
]
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: 200;
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 [
"clipboard-content-view",
"opaque",
]
}
}
[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";
}
Adw.SwitchRow remember_choice {
title: _("Remember choice for this split");
subtitle: _("Reload configuration to show this prompt again");
}
};
}