mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
core/gtk: add apprt action to show native GUI warning when child exits
Addresses #7649 for the core and GTK. macOS support will need to be added later. This adds an apprt action to show a native GUI warning of some kind when the child process of a terminal exits. Also adds a basic GTK implementation of this. In GTK it overlays an Adwaita banner at the bottom of the window (similar to the banner that shows up in at the top of windows in debug builds).
This commit is contained in:
@ -680,6 +680,12 @@ typedef struct {
|
||||
uintptr_t len;
|
||||
} ghostty_action_open_url_s;
|
||||
|
||||
// apprt.surface.Message.ChildExited
|
||||
typedef struct {
|
||||
uint32_t exit_code;
|
||||
uint64_t timetime_ms;
|
||||
} ghostty_surface_message_childexited_s;
|
||||
|
||||
// apprt.Action.Key
|
||||
typedef enum {
|
||||
GHOSTTY_ACTION_QUIT,
|
||||
@ -731,6 +737,7 @@ typedef enum {
|
||||
GHOSTTY_ACTION_REDO,
|
||||
GHOSTTY_ACTION_CHECK_FOR_UPDATES,
|
||||
GHOSTTY_ACTION_OPEN_URL,
|
||||
GHOSTTY_ACTION_SHOW_CHILD_EXITED
|
||||
} ghostty_action_tag_e;
|
||||
|
||||
typedef union {
|
||||
@ -759,6 +766,7 @@ typedef union {
|
||||
ghostty_action_reload_config_s reload_config;
|
||||
ghostty_action_config_change_s config_change;
|
||||
ghostty_action_open_url_s open_url;
|
||||
ghostty_surface_message_childexited_s child_exited;
|
||||
} ghostty_action_u;
|
||||
|
||||
typedef struct {
|
||||
|
@ -579,6 +579,8 @@ extension Ghostty {
|
||||
case GHOSTTY_ACTION_SIZE_LIMIT:
|
||||
fallthrough
|
||||
case GHOSTTY_ACTION_QUIT_TIMER:
|
||||
fallthrough
|
||||
case GHOSTTY_SHOW_CHILD_EXITED:
|
||||
Ghostty.logger.info("known but unimplemented action action=\(action.tag.rawValue)")
|
||||
return false
|
||||
default:
|
||||
|
@ -1018,6 +1018,14 @@ fn childExited(self: *Surface, info: apprt.surface.Message.ChildExited) void {
|
||||
return;
|
||||
};
|
||||
|
||||
_ = self.rt_app.performAction(
|
||||
.{ .surface = self },
|
||||
.show_child_exited,
|
||||
info,
|
||||
) catch |err| {
|
||||
log.err("error trying to show native child exited GUI err={}", .{err});
|
||||
};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1044,6 +1052,14 @@ fn childExited(self: *Surface, info: apprt.surface.Message.ChildExited) void {
|
||||
t.screen.kitty_keyboard.set(.set, .{});
|
||||
}
|
||||
|
||||
_ = self.rt_app.performAction(
|
||||
.{ .surface = self },
|
||||
.show_child_exited,
|
||||
info,
|
||||
) catch |err| {
|
||||
log.err("error trying to show native child exited GUI err={}", .{err});
|
||||
};
|
||||
|
||||
// Waiting after command we stop here. The terminal is updated, our
|
||||
// state is updated, and now its up to the user to decide what to do.
|
||||
if (self.config.wait_after_command) return;
|
||||
|
@ -272,6 +272,9 @@ pub const Action = union(Key) {
|
||||
/// apprt.
|
||||
open_url: OpenUrl,
|
||||
|
||||
/// Show a native GUI notification that the child process has exited.
|
||||
show_child_exited: apprt.surface.Message.ChildExited,
|
||||
|
||||
/// Sync with: ghostty_action_tag_e
|
||||
pub const Key = enum(c_int) {
|
||||
quit,
|
||||
@ -323,6 +326,7 @@ pub const Action = union(Key) {
|
||||
redo,
|
||||
check_for_updates,
|
||||
open_url,
|
||||
show_child_exited,
|
||||
};
|
||||
|
||||
/// Sync with: ghostty_action_u
|
||||
|
@ -521,6 +521,7 @@ pub fn performAction(
|
||||
.ring_bell => try self.ringBell(target),
|
||||
.toggle_command_palette => try self.toggleCommandPalette(target),
|
||||
.open_url => self.openUrl(value),
|
||||
.show_child_exited => try self.showChildExited(target, value),
|
||||
|
||||
// Unimplemented
|
||||
.close_all_windows,
|
||||
@ -846,6 +847,13 @@ fn toggleCommandPalette(_: *App, target: apprt.Target) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn showChildExited(_: *App, target: apprt.Target, value: apprt.surface.Message.ChildExited) !void {
|
||||
switch (target) {
|
||||
.app => {},
|
||||
.surface => |surface| try surface.rt_surface.showChildExited(value),
|
||||
}
|
||||
}
|
||||
|
||||
fn quitTimer(self: *App, mode: apprt.action.QuitTimer) void {
|
||||
switch (mode) {
|
||||
.start => self.startQuitTimer(),
|
||||
|
@ -2503,3 +2503,20 @@ fn gtkStreamError(media_file: *gtk.MediaFile, _: *gobject.ParamSpec, _: ?*anyopa
|
||||
fn gtkStreamEnded(media_file: *gtk.MediaFile, _: *gobject.ParamSpec, _: ?*anyopaque) callconv(.c) void {
|
||||
media_file.unref();
|
||||
}
|
||||
|
||||
pub fn showChildExited(self: *Surface, _: apprt.surface.Message.ChildExited) (error{})!void {
|
||||
if (!adw_version.supportsBanner()) return;
|
||||
|
||||
const warning_box = gtk.Box.new(.vertical, 0);
|
||||
|
||||
warning_box.as(gtk.Widget).setHalign(.fill);
|
||||
warning_box.as(gtk.Widget).setValign(.end);
|
||||
|
||||
const warning_text = i18n._("⚠️ Process exited. Press any key to close the terminal.");
|
||||
const banner = adw.Banner.new(warning_text);
|
||||
banner.setRevealed(1);
|
||||
|
||||
warning_box.append(banner.as(gtk.Widget));
|
||||
|
||||
self.overlay.addOverlay(warning_box.as(gtk.Widget));
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ pub const Message = union(enum) {
|
||||
// This enum is a placeholder for future title styles.
|
||||
};
|
||||
|
||||
pub const ChildExited = struct {
|
||||
pub const ChildExited = extern struct {
|
||||
exit_code: u32,
|
||||
runtime_ms: u64,
|
||||
};
|
||||
|
Reference in New Issue
Block a user