gtk: add read-only indicator for surfaces

Fixes: #9889
This commit is contained in:
Jeffrey C. Ollie
2026-01-23 12:09:18 -06:00
parent 5de4ff3b98
commit f0b4e86ab5
4 changed files with 87 additions and 1 deletions

View File

@@ -733,6 +733,7 @@ pub const Application = extern struct {
.toggle_split_zoom => return Action.toggleSplitZoom(target),
.show_on_screen_keyboard => return Action.showOnScreenKeyboard(target),
.command_finished => return Action.commandFinished(target, value),
.readonly => return Action.setReadonly(target, value),
.start_search => Action.startSearch(target, value),
.end_search => Action.endSearch(target),
@@ -753,7 +754,6 @@ pub const Application = extern struct {
.check_for_updates,
.undo,
.redo,
.readonly,
=> {
log.warn("unimplemented action={}", .{action});
return false;
@@ -2678,6 +2678,15 @@ const Action = struct {
}
}
pub fn setReadonly(target: apprt.Target, value: apprt.Action.Value(.readonly)) bool {
switch (target) {
.app => return false,
.surface => |surface| {
return surface.rt_surface.gobj().setReadonly(value);
},
}
}
pub fn keySequence(target: apprt.Target, value: apprt.Action.Value(.key_sequence)) bool {
switch (target) {
.app => {

View File

@@ -400,6 +400,25 @@ pub const Surface = extern struct {
},
);
};
pub const readonly = struct {
pub const name = "readonly";
const impl = gobject.ext.defineProperty(
name,
Self,
bool,
.{
.default = false,
.accessor = gobject.ext.typedAccessor(
Self,
bool,
.{
.getter = getReadonly,
},
),
},
);
};
};
pub const signals = struct {
@@ -1106,6 +1125,20 @@ pub const Surface = extern struct {
return true;
}
/// Get the readonly state from the core surface.
pub fn getReadonly(self: *Self) bool {
const priv: *Private = self.private();
const surface = priv.core_surface orelse return false;
return surface.readonly;
}
/// Notify anyone interested that the readonly status has changed.
pub fn setReadonly(self: *Self, _: apprt.Action.Value(.readonly)) bool {
self.as(gobject.Object).notifyByPspec(properties.readonly.impl.param_spec);
return true;
}
/// Key press event (press or release).
///
/// At a high level, we want to construct an `input.KeyEvent` and
@@ -3480,6 +3513,7 @@ pub const Surface = extern struct {
properties.@"title-override".impl,
properties.zoom.impl,
properties.@"is-split".impl,
properties.readonly.impl,
// For Gtk.Scrollable
properties.hadjustment.impl,

View File

@@ -134,6 +134,16 @@ label.resize-overlay {
border-style: solid;
}
.surface .readonly_overlay {
/* Should be the equivalent of the following SwiftUI color: */
/* Color(hue: 0.08, saturation: 0.5, brightness: 0.8) */
color: hsl(25 50 75);
padding: 8px 8px 8px 8px;
margin: 8px 8px 8px 8px;
border-radius: 6px 6px 6px 6px;
outline-style: solid;
outline-width: 1px;
}
/*
* Command Palette
*/

View File

@@ -71,6 +71,39 @@ Overlay terminal_page {
}
};
[overlay]
Revealer {
reveal-child: bind template.readonly;
transition-type: crossfade;
transition-duration: 500;
// Revealers take up the full size, we need this to not capture events.
can-focus: false;
can-target: false;
focusable: false;
Box readonly_overlay {
styles [
"readonly_overlay",
]
// TODO: the tooltip doesn't actually work, but keep it here for now so
// that we can get the tooltip text translated.
has-tooltip: true;
tooltip-text: _("This terminal is in read-only mode. You can still view, select, and scroll through the content, but no input events will be sent to the running application.");
halign: end;
valign: start;
spacing: 6;
Image {
icon-name: "changes-prevent-symbolic";
}
Label {
label: _("Read-only");
}
}
}
[overlay]
ProgressBar progress_bar_overlay {
styles [