apprt/gtk-ng: clean up close handling of all types
This cleans up our close handling of all types (surfaces, tabs, windows). Surfaces no longer emit their scope; their scope is always just the surface itself. For tab and window scope we use widget actions. This makes `close_tab` work properly (previously broken).pull/8233/head
parent
3eda14e2d6
commit
83d1bdcfcb
|
|
@ -32,7 +32,8 @@ pub fn rtApp(self: *Self) *ApprtApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(self: *Self, process_active: bool) void {
|
pub fn close(self: *Self, process_active: bool) void {
|
||||||
self.surface.close(.{ .surface = process_active });
|
_ = process_active;
|
||||||
|
self.surface.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cgroup(self: *Self) ?[]const u8 {
|
pub fn cgroup(self: *Self) ?[]const u8 {
|
||||||
|
|
|
||||||
|
|
@ -542,8 +542,8 @@ pub const Application = extern struct {
|
||||||
value: apprt.Action.Value(action),
|
value: apprt.Action.Value(action),
|
||||||
) !bool {
|
) !bool {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
.close_tab => Action.close(target, .tab),
|
.close_tab => return Action.closeTab(target),
|
||||||
.close_window => Action.close(target, .window),
|
.close_window => return Action.closeWindow(target),
|
||||||
|
|
||||||
.config_change => try Action.configChange(
|
.config_change => try Action.configChange(
|
||||||
self,
|
self,
|
||||||
|
|
@ -1582,13 +1582,23 @@ pub const Application = extern struct {
|
||||||
|
|
||||||
/// All apprt action handlers
|
/// All apprt action handlers
|
||||||
const Action = struct {
|
const Action = struct {
|
||||||
pub fn close(
|
pub fn closeTab(target: apprt.Target) bool {
|
||||||
target: apprt.Target,
|
|
||||||
scope: Surface.CloseScope,
|
|
||||||
) void {
|
|
||||||
switch (target) {
|
switch (target) {
|
||||||
.app => {},
|
.app => return false,
|
||||||
.surface => |v| v.rt_surface.surface.close(scope),
|
.surface => |core| {
|
||||||
|
const surface = core.rt_surface.surface;
|
||||||
|
return surface.as(gtk.Widget).activateAction("tab.close", null) != 0;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn closeWindow(target: apprt.Target) bool {
|
||||||
|
switch (target) {
|
||||||
|
.app => return false,
|
||||||
|
.surface => |core| {
|
||||||
|
const surface = core.rt_surface.surface;
|
||||||
|
return surface.as(gtk.Widget).activateAction("win.close", null) != 0;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -407,6 +407,22 @@ pub const SplitTree = extern struct {
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// Properties
|
// Properties
|
||||||
|
|
||||||
|
/// Returns true if this split tree needs confirmation before quitting based
|
||||||
|
/// on the various Ghostty configurations.
|
||||||
|
pub fn getNeedsConfirmQuit(self: *Self) bool {
|
||||||
|
const tree = self.getTree() orelse return false;
|
||||||
|
var it = tree.iterator();
|
||||||
|
while (it.next()) |entry| {
|
||||||
|
if (entry.view.core()) |core| {
|
||||||
|
if (core.needsConfirmQuit()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the currently active surface. See the "active-surface" property.
|
/// Get the currently active surface. See the "active-surface" property.
|
||||||
/// This does not ref the value.
|
/// This does not ref the value.
|
||||||
pub fn getActiveSurface(self: *Self) ?*Surface {
|
pub fn getActiveSurface(self: *Self) ?*Surface {
|
||||||
|
|
@ -636,18 +652,8 @@ pub const SplitTree = extern struct {
|
||||||
|
|
||||||
fn surfaceCloseRequest(
|
fn surfaceCloseRequest(
|
||||||
surface: *Surface,
|
surface: *Surface,
|
||||||
scope: *const Surface.CloseScope,
|
|
||||||
self: *Self,
|
self: *Self,
|
||||||
) callconv(.c) void {
|
) callconv(.c) void {
|
||||||
switch (scope.*) {
|
|
||||||
// Handled upstream... this will probably go away for widget
|
|
||||||
// actions eventually.
|
|
||||||
.window, .tab => return,
|
|
||||||
|
|
||||||
// Remove the surface from the tree.
|
|
||||||
.surface => {},
|
|
||||||
}
|
|
||||||
|
|
||||||
const core = surface.core() orelse return;
|
const core = surface.core() orelse return;
|
||||||
|
|
||||||
// Reset our pending close state
|
// Reset our pending close state
|
||||||
|
|
|
||||||
|
|
@ -275,7 +275,7 @@ pub const Surface = extern struct {
|
||||||
const impl = gobject.ext.defineSignal(
|
const impl = gobject.ext.defineSignal(
|
||||||
name,
|
name,
|
||||||
Self,
|
Self,
|
||||||
&.{*const CloseScope},
|
&.{},
|
||||||
void,
|
void,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
@ -1047,11 +1047,11 @@ pub const Surface = extern struct {
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// Libghostty Callbacks
|
// Libghostty Callbacks
|
||||||
|
|
||||||
pub fn close(self: *Self, scope: CloseScope) void {
|
pub fn close(self: *Self) void {
|
||||||
signals.@"close-request".impl.emit(
|
signals.@"close-request".impl.emit(
|
||||||
self,
|
self,
|
||||||
null,
|
null,
|
||||||
.{&scope},
|
.{},
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1749,7 +1749,7 @@ pub const Surface = extern struct {
|
||||||
self: *Self,
|
self: *Self,
|
||||||
) callconv(.c) void {
|
) callconv(.c) void {
|
||||||
// This closes the surface with no confirmation.
|
// This closes the surface with no confirmation.
|
||||||
self.close(.{ .surface = false });
|
self.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contextMenuClosed(
|
fn contextMenuClosed(
|
||||||
|
|
@ -2709,25 +2709,6 @@ pub const Surface = extern struct {
|
||||||
pub const bindTemplateCallback = C.Class.bindTemplateCallback;
|
pub const bindTemplateCallback = C.Class.bindTemplateCallback;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The scope of a close request.
|
|
||||||
pub const CloseScope = union(enum) {
|
|
||||||
/// Close the surface. The boolean determines if there is a
|
|
||||||
/// process active.
|
|
||||||
surface: bool,
|
|
||||||
|
|
||||||
/// Close the tab. We can't know if there are processes active
|
|
||||||
/// for the entire tab scope so listeners must query the app.
|
|
||||||
tab,
|
|
||||||
|
|
||||||
/// Close the window.
|
|
||||||
window,
|
|
||||||
|
|
||||||
pub const getGObjectType = gobject.ext.defineBoxed(
|
|
||||||
CloseScope,
|
|
||||||
.{ .name = "GhosttySurfaceCloseScope" },
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Simple dimensions struct for the surface used by various properties.
|
/// Simple dimensions struct for the surface used by various properties.
|
||||||
pub const Size = extern struct {
|
pub const Size = extern struct {
|
||||||
width: u32,
|
width: u32,
|
||||||
|
|
|
||||||
|
|
@ -208,6 +208,7 @@ pub const Tab = extern struct {
|
||||||
// For action names:
|
// For action names:
|
||||||
// https://docs.gtk.org/gio/type_func.Action.name_is_valid.html
|
// https://docs.gtk.org/gio/type_func.Action.name_is_valid.html
|
||||||
const actions = .{
|
const actions = .{
|
||||||
|
.{ "close", actionClose, null },
|
||||||
.{ "ring-bell", actionRingBell, null },
|
.{ "ring-bell", actionRingBell, null },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -262,9 +263,8 @@ pub const Tab = extern struct {
|
||||||
/// Returns true if this tab needs confirmation before quitting based
|
/// Returns true if this tab needs confirmation before quitting based
|
||||||
/// on the various Ghostty configurations.
|
/// on the various Ghostty configurations.
|
||||||
pub fn getNeedsConfirmQuit(self: *Self) bool {
|
pub fn getNeedsConfirmQuit(self: *Self) bool {
|
||||||
const surface = self.getActiveSurface() orelse return false;
|
const tree = self.getSplitTree();
|
||||||
const core_surface = surface.core() orelse return false;
|
return tree.getNeedsConfirmQuit();
|
||||||
return core_surface.needsConfirmQuit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the tab page holding this tab, if any.
|
/// Get the tab page holding this tab, if any.
|
||||||
|
|
@ -344,6 +344,22 @@ pub const Tab = extern struct {
|
||||||
self.as(gobject.Object).notifyByPspec(properties.@"active-surface".impl.param_spec);
|
self.as(gobject.Object).notifyByPspec(properties.@"active-surface".impl.param_spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn actionClose(
|
||||||
|
_: *gio.SimpleAction,
|
||||||
|
_: ?*glib.Variant,
|
||||||
|
self: *Self,
|
||||||
|
) callconv(.c) void {
|
||||||
|
const tab_view = ext.getAncestor(
|
||||||
|
adw.TabView,
|
||||||
|
self.as(gtk.Widget),
|
||||||
|
) orelse return;
|
||||||
|
const page = tab_view.getPage(self.as(gtk.Widget));
|
||||||
|
|
||||||
|
// Delegate to our parent to handle this, since this will emit
|
||||||
|
// a close-page signal that the parent can intercept.
|
||||||
|
tab_view.closePage(page);
|
||||||
|
}
|
||||||
|
|
||||||
fn actionRingBell(
|
fn actionRingBell(
|
||||||
_: *gio.SimpleAction,
|
_: *gio.SimpleAction,
|
||||||
_: ?*glib.Variant,
|
_: ?*glib.Variant,
|
||||||
|
|
|
||||||
|
|
@ -683,13 +683,6 @@ pub const Window = extern struct {
|
||||||
var it = tree.iterator();
|
var it = tree.iterator();
|
||||||
while (it.next()) |entry| {
|
while (it.next()) |entry| {
|
||||||
const surface = entry.view;
|
const surface = entry.view;
|
||||||
_ = Surface.signals.@"close-request".connect(
|
|
||||||
surface,
|
|
||||||
*Self,
|
|
||||||
surfaceCloseRequest,
|
|
||||||
self,
|
|
||||||
.{},
|
|
||||||
);
|
|
||||||
_ = Surface.signals.@"present-request".connect(
|
_ = Surface.signals.@"present-request".connect(
|
||||||
surface,
|
surface,
|
||||||
*Self,
|
*Self,
|
||||||
|
|
@ -1458,25 +1451,6 @@ pub const Window = extern struct {
|
||||||
self.addToast(i18n._("Cleared clipboard"));
|
self.addToast(i18n._("Cleared clipboard"));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn surfaceCloseRequest(
|
|
||||||
_: *Surface,
|
|
||||||
scope: *const Surface.CloseScope,
|
|
||||||
self: *Self,
|
|
||||||
) callconv(.c) void {
|
|
||||||
switch (scope.*) {
|
|
||||||
// Handled directly by the tab. If the surface is the last
|
|
||||||
// surface then the tab will emit its own signal to request
|
|
||||||
// closing itself.
|
|
||||||
.surface => return,
|
|
||||||
|
|
||||||
// Also handled directly by the tab.
|
|
||||||
.tab => return,
|
|
||||||
|
|
||||||
// The only one we care about!
|
|
||||||
.window => self.as(gtk.Window).close(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn surfaceMenu(
|
fn surfaceMenu(
|
||||||
_: *Surface,
|
_: *Surface,
|
||||||
self: *Self,
|
self: *Self,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue