mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-22 03:36:14 +03:00
apprt/gtk
This commit is contained in:
@ -2,6 +2,14 @@ const std = @import("std");
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const CoreSurface = @import("../Surface.zig");
|
const CoreSurface = @import("../Surface.zig");
|
||||||
|
|
||||||
|
/// The target for an action. This is generally the thing that had focus
|
||||||
|
/// while the action was made but the concept of "focus" is not guaranteed
|
||||||
|
/// since actions can also be triggered by timers, scripts, etc.
|
||||||
|
pub const Target = union(enum) {
|
||||||
|
app,
|
||||||
|
surface: *CoreSurface,
|
||||||
|
};
|
||||||
|
|
||||||
/// The possible actions an apprt has to react to. Actions are one-way
|
/// The possible actions an apprt has to react to. Actions are one-way
|
||||||
/// messages that are sent to the app runtime to trigger some behavior.
|
/// messages that are sent to the app runtime to trigger some behavior.
|
||||||
///
|
///
|
||||||
@ -69,7 +77,7 @@ pub const Action = union(enum) {
|
|||||||
/// after the configured delay. This can be cancelled by sending
|
/// after the configured delay. This can be cancelled by sending
|
||||||
/// another quit_timer action with "stop". Multiple "starts" shouldn't
|
/// another quit_timer action with "stop". Multiple "starts" shouldn't
|
||||||
/// happen and can be ignored or cause a restart it isn't that important.
|
/// happen and can be ignored or cause a restart it isn't that important.
|
||||||
quit_timer: enum { start, stop },
|
quit_timer: QuitTimer,
|
||||||
|
|
||||||
/// Set the secure input functionality on or off. "Secure input" means
|
/// Set the secure input functionality on or off. "Secure input" means
|
||||||
/// that the user is currently at some sort of prompt where they may be
|
/// that the user is currently at some sort of prompt where they may be
|
||||||
@ -92,14 +100,6 @@ pub const Action = union(enum) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The target for an action. This is generally the thing that had focus
|
|
||||||
/// while the action was made but the concept of "focus" is not guaranteed
|
|
||||||
/// since actions can also be triggered by timers, scripts, etc.
|
|
||||||
pub const Target = union(enum) {
|
|
||||||
app,
|
|
||||||
surface: *CoreSurface,
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is made extern (c_int) to make interop easier with our embedded
|
// This is made extern (c_int) to make interop easier with our embedded
|
||||||
// runtime. The small size cost doesn't make a difference in our union.
|
// runtime. The small size cost doesn't make a difference in our union.
|
||||||
pub const SplitDirection = enum(c_int) {
|
pub const SplitDirection = enum(c_int) {
|
||||||
@ -165,6 +165,11 @@ pub const Inspector = enum(c_int) {
|
|||||||
hide,
|
hide,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const QuitTimer = enum(c_int) {
|
||||||
|
start,
|
||||||
|
stop,
|
||||||
|
};
|
||||||
|
|
||||||
/// The desktop notification to show.
|
/// The desktop notification to show.
|
||||||
pub const DesktopNotification = struct {
|
pub const DesktopNotification = struct {
|
||||||
title: [:0]const u8,
|
title: [:0]const u8,
|
||||||
|
@ -27,6 +27,7 @@ const Surface = @import("Surface.zig");
|
|||||||
const Window = @import("Window.zig");
|
const Window = @import("Window.zig");
|
||||||
const ConfigErrorsWindow = @import("ConfigErrorsWindow.zig");
|
const ConfigErrorsWindow = @import("ConfigErrorsWindow.zig");
|
||||||
const ClipboardConfirmationWindow = @import("ClipboardConfirmationWindow.zig");
|
const ClipboardConfirmationWindow = @import("ClipboardConfirmationWindow.zig");
|
||||||
|
const Split = @import("Split.zig");
|
||||||
const c = @import("c.zig").c;
|
const c = @import("c.zig").c;
|
||||||
const inspector = @import("inspector.zig");
|
const inspector = @import("inspector.zig");
|
||||||
const key = @import("key.zig");
|
const key = @import("key.zig");
|
||||||
@ -341,9 +342,249 @@ pub fn terminate(self: *App) void {
|
|||||||
self.config.deinit();
|
self.config.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Open the configuration in the system editor.
|
/// Perform a given action.
|
||||||
pub fn openConfig(self: *App) !void {
|
pub fn performAction(
|
||||||
try configpkg.edit.open(self.core_app.alloc);
|
self: *App,
|
||||||
|
target: apprt.Target,
|
||||||
|
comptime action: apprt.Action.Key,
|
||||||
|
value: apprt.Action.Value(action),
|
||||||
|
) !void {
|
||||||
|
switch (action) {
|
||||||
|
.new_window => _ = try self.newWindow(switch (target) {
|
||||||
|
.app => null,
|
||||||
|
.surface => |v| v,
|
||||||
|
}),
|
||||||
|
.toggle_fullscreen => self.toggleFullscreen(target, value),
|
||||||
|
|
||||||
|
.new_tab => try self.newTab(target),
|
||||||
|
.goto_tab => self.gotoTab(target, value),
|
||||||
|
.new_split => try self.newSplit(target, value),
|
||||||
|
.resize_split => self.resizeSplit(target, value),
|
||||||
|
.equalize_splits => self.equalizeSplits(target),
|
||||||
|
.goto_split => self.gotoSplit(target, value),
|
||||||
|
.open_config => try configpkg.edit.open(self.core_app.alloc),
|
||||||
|
.inspector => self.controlInspector(target, value),
|
||||||
|
.desktop_notification => self.showDesktopNotification(target, value),
|
||||||
|
.present_terminal => self.presentTerminal(target),
|
||||||
|
.toggle_window_decorations => self.toggleWindowDecorations(target),
|
||||||
|
.quit_timer => self.quitTimer(value),
|
||||||
|
|
||||||
|
// Unimplemented
|
||||||
|
.close_all_windows,
|
||||||
|
.toggle_split_zoom,
|
||||||
|
.secure_input,
|
||||||
|
=> log.warn("unimplemented action={}", .{action}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn newTab(_: *App, target: apprt.Target) !void {
|
||||||
|
switch (target) {
|
||||||
|
.app => {},
|
||||||
|
.surface => |v| {
|
||||||
|
const window = v.rt_surface.container.window() orelse {
|
||||||
|
log.info(
|
||||||
|
"new_tab invalid for container={s}",
|
||||||
|
.{@tagName(v.rt_surface.container)},
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
try window.newTab(v);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gotoTab(_: *App, target: apprt.Target, tab: apprt.action.GotoTab) void {
|
||||||
|
switch (target) {
|
||||||
|
.app => {},
|
||||||
|
.surface => |v| {
|
||||||
|
const window = v.rt_surface.container.window() orelse {
|
||||||
|
log.info(
|
||||||
|
"gotoTab invalid for container={s}",
|
||||||
|
.{@tagName(v.rt_surface.container)},
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (tab) {
|
||||||
|
.previous => window.gotoPreviousTab(v.rt_surface),
|
||||||
|
.next => window.gotoNextTab(v.rt_surface),
|
||||||
|
.last => window.gotoLastTab(),
|
||||||
|
else => window.gotoTab(@intCast(@intFromEnum(tab))),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn newSplit(
|
||||||
|
self: *App,
|
||||||
|
target: apprt.Target,
|
||||||
|
direction: apprt.action.SplitDirection,
|
||||||
|
) !void {
|
||||||
|
switch (target) {
|
||||||
|
.app => {},
|
||||||
|
.surface => |v| {
|
||||||
|
const alloc = self.core_app.alloc;
|
||||||
|
_ = try Split.create(alloc, v.rt_surface, direction);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn equalizeSplits(_: *App, target: apprt.Target) void {
|
||||||
|
switch (target) {
|
||||||
|
.app => {},
|
||||||
|
.surface => |v| {
|
||||||
|
const tab = v.rt_surface.container.tab() orelse return;
|
||||||
|
const top_split = switch (tab.elem) {
|
||||||
|
.split => |s| s,
|
||||||
|
else => return,
|
||||||
|
};
|
||||||
|
_ = top_split.equalize();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gotoSplit(
|
||||||
|
_: *const App,
|
||||||
|
target: apprt.Target,
|
||||||
|
direction: apprt.action.GotoSplit,
|
||||||
|
) void {
|
||||||
|
switch (target) {
|
||||||
|
.app => {},
|
||||||
|
.surface => |v| {
|
||||||
|
const s = v.rt_surface.container.split() orelse return;
|
||||||
|
const map = s.directionMap(switch (v.rt_surface.container) {
|
||||||
|
.split_tl => .top_left,
|
||||||
|
.split_br => .bottom_right,
|
||||||
|
.none, .tab_ => unreachable,
|
||||||
|
});
|
||||||
|
const surface_ = map.get(direction) orelse return;
|
||||||
|
if (surface_) |surface| surface.grabFocus();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resizeSplit(
|
||||||
|
_: *const App,
|
||||||
|
target: apprt.Target,
|
||||||
|
resize: apprt.action.ResizeSplit,
|
||||||
|
) void {
|
||||||
|
switch (target) {
|
||||||
|
.app => {},
|
||||||
|
.surface => |v| {
|
||||||
|
const s = v.rt_surface.container.firstSplitWithOrientation(
|
||||||
|
Split.Orientation.fromResizeDirection(resize.direction),
|
||||||
|
) orelse return;
|
||||||
|
s.moveDivider(resize.direction, resize.amount);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn presentTerminal(
|
||||||
|
_: *const App,
|
||||||
|
target: apprt.Target,
|
||||||
|
) void {
|
||||||
|
switch (target) {
|
||||||
|
.app => {},
|
||||||
|
.surface => |v| v.rt_surface.present(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn controlInspector(
|
||||||
|
_: *const App,
|
||||||
|
target: apprt.Target,
|
||||||
|
mode: apprt.action.Inspector,
|
||||||
|
) void {
|
||||||
|
const surface: *Surface = switch (target) {
|
||||||
|
.app => return,
|
||||||
|
.surface => |v| v.rt_surface,
|
||||||
|
};
|
||||||
|
|
||||||
|
surface.controlInspector(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toggleFullscreen(
|
||||||
|
_: *App,
|
||||||
|
target: apprt.Target,
|
||||||
|
_: apprt.action.Fullscreen,
|
||||||
|
) void {
|
||||||
|
switch (target) {
|
||||||
|
.app => {},
|
||||||
|
.surface => |v| {
|
||||||
|
const window = v.rt_surface.container.window() orelse {
|
||||||
|
log.info(
|
||||||
|
"toggleFullscreen invalid for container={s}",
|
||||||
|
.{@tagName(v.rt_surface.container)},
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
window.toggleFullscreen();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toggleWindowDecorations(
|
||||||
|
_: *App,
|
||||||
|
target: apprt.Target,
|
||||||
|
) void {
|
||||||
|
switch (target) {
|
||||||
|
.app => {},
|
||||||
|
.surface => |v| {
|
||||||
|
const window = v.rt_surface.container.window() orelse {
|
||||||
|
log.info(
|
||||||
|
"toggleFullscreen invalid for container={s}",
|
||||||
|
.{@tagName(v.rt_surface.container)},
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
window.toggleWindowDecorations();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn quitTimer(self: *App, mode: apprt.action.QuitTimer) void {
|
||||||
|
switch (mode) {
|
||||||
|
.start => self.startQuitTimer(),
|
||||||
|
.stop => self.stopQuitTimer(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn showDesktopNotification(
|
||||||
|
self: *App,
|
||||||
|
target: apprt.Target,
|
||||||
|
n: apprt.action.DesktopNotification,
|
||||||
|
) void {
|
||||||
|
// Set a default title if we don't already have one
|
||||||
|
const t = switch (n.title.len) {
|
||||||
|
0 => "Ghostty",
|
||||||
|
else => n.title,
|
||||||
|
};
|
||||||
|
|
||||||
|
const notification = c.g_notification_new(t.ptr);
|
||||||
|
defer c.g_object_unref(notification);
|
||||||
|
c.g_notification_set_body(notification, n.body.ptr);
|
||||||
|
|
||||||
|
const icon = c.g_themed_icon_new("com.mitchellh.ghostty");
|
||||||
|
defer c.g_object_unref(icon);
|
||||||
|
c.g_notification_set_icon(notification, icon);
|
||||||
|
|
||||||
|
const pointer = c.g_variant_new_uint64(switch (target) {
|
||||||
|
.app => 0,
|
||||||
|
.surface => |v| @intFromPtr(v),
|
||||||
|
});
|
||||||
|
c.g_notification_set_default_action_and_target_value(
|
||||||
|
notification,
|
||||||
|
"app.present-surface",
|
||||||
|
pointer,
|
||||||
|
);
|
||||||
|
|
||||||
|
const g_app: *c.GApplication = @ptrCast(self.app);
|
||||||
|
|
||||||
|
// We set the notification ID to the body content. If the content is the
|
||||||
|
// same, this notification may replace a previous notification
|
||||||
|
c.g_application_send_notification(g_app, n.body.ptr, notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reload the configuration. This should return the new configuration.
|
/// Reload the configuration. This should return the new configuration.
|
||||||
@ -565,9 +806,9 @@ pub fn gtkQuitTimerExpired(ud: ?*anyopaque) callconv(.C) c.gboolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This will get called when there are no more open surfaces.
|
/// This will get called when there are no more open surfaces.
|
||||||
pub fn startQuitTimer(self: *App) void {
|
fn startQuitTimer(self: *App) void {
|
||||||
// Cancel any previous timer.
|
// Cancel any previous timer.
|
||||||
self.cancelQuitTimer();
|
self.stopQuitTimer();
|
||||||
|
|
||||||
// This is a no-op unless we are configured to quit after last window is closed.
|
// This is a no-op unless we are configured to quit after last window is closed.
|
||||||
if (!self.config.@"quit-after-last-window-closed") return;
|
if (!self.config.@"quit-after-last-window-closed") return;
|
||||||
@ -582,7 +823,7 @@ pub fn startQuitTimer(self: *App) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This will get called when a new surface gets opened.
|
/// This will get called when a new surface gets opened.
|
||||||
pub fn cancelQuitTimer(self: *App) void {
|
fn stopQuitTimer(self: *App) void {
|
||||||
switch (self.quit_timer) {
|
switch (self.quit_timer) {
|
||||||
.off => {},
|
.off => {},
|
||||||
.expired => self.quit_timer = .{ .off = {} },
|
.expired => self.quit_timer = .{ .off = {} },
|
||||||
@ -608,7 +849,7 @@ pub fn redrawInspector(self: *App, surface: *Surface) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Called by CoreApp to create a new window with a new surface.
|
/// Called by CoreApp to create a new window with a new surface.
|
||||||
pub fn newWindow(self: *App, parent_: ?*CoreSurface) !void {
|
fn newWindow(self: *App, parent_: ?*CoreSurface) !void {
|
||||||
const alloc = self.core_app.alloc;
|
const alloc = self.core_app.alloc;
|
||||||
|
|
||||||
// Allocate a fixed pointer for our window. We try to minimize
|
// Allocate a fixed pointer for our window. We try to minimize
|
||||||
|
@ -7,7 +7,6 @@ const Allocator = std.mem.Allocator;
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const apprt = @import("../../apprt.zig");
|
const apprt = @import("../../apprt.zig");
|
||||||
const font = @import("../../font/main.zig");
|
const font = @import("../../font/main.zig");
|
||||||
const input = @import("../../input.zig");
|
|
||||||
const CoreSurface = @import("../../Surface.zig");
|
const CoreSurface = @import("../../Surface.zig");
|
||||||
|
|
||||||
const Surface = @import("Surface.zig");
|
const Surface = @import("Surface.zig");
|
||||||
@ -21,14 +20,14 @@ pub const Orientation = enum {
|
|||||||
horizontal,
|
horizontal,
|
||||||
vertical,
|
vertical,
|
||||||
|
|
||||||
pub fn fromDirection(direction: apprt.SplitDirection) Orientation {
|
pub fn fromDirection(direction: apprt.action.SplitDirection) Orientation {
|
||||||
return switch (direction) {
|
return switch (direction) {
|
||||||
.right => .horizontal,
|
.right => .horizontal,
|
||||||
.down => .vertical,
|
.down => .vertical,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fromResizeDirection(direction: input.SplitResizeDirection) Orientation {
|
pub fn fromResizeDirection(direction: apprt.action.ResizeSplit.Direction) Orientation {
|
||||||
return switch (direction) {
|
return switch (direction) {
|
||||||
.up, .down => .vertical,
|
.up, .down => .vertical,
|
||||||
.left, .right => .horizontal,
|
.left, .right => .horizontal,
|
||||||
@ -58,7 +57,7 @@ bottom_right: Surface.Container.Elem,
|
|||||||
pub fn create(
|
pub fn create(
|
||||||
alloc: Allocator,
|
alloc: Allocator,
|
||||||
sibling: *Surface,
|
sibling: *Surface,
|
||||||
direction: apprt.SplitDirection,
|
direction: apprt.action.SplitDirection,
|
||||||
) !*Split {
|
) !*Split {
|
||||||
var split = try alloc.create(Split);
|
var split = try alloc.create(Split);
|
||||||
errdefer alloc.destroy(split);
|
errdefer alloc.destroy(split);
|
||||||
@ -69,7 +68,7 @@ pub fn create(
|
|||||||
pub fn init(
|
pub fn init(
|
||||||
self: *Split,
|
self: *Split,
|
||||||
sibling: *Surface,
|
sibling: *Surface,
|
||||||
direction: apprt.SplitDirection,
|
direction: apprt.action.SplitDirection,
|
||||||
) !void {
|
) !void {
|
||||||
// Create the new child surface for the other direction.
|
// Create the new child surface for the other direction.
|
||||||
const alloc = sibling.app.core_app.alloc;
|
const alloc = sibling.app.core_app.alloc;
|
||||||
@ -164,7 +163,11 @@ fn removeChild(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Move the divider in the given direction by the given amount.
|
/// Move the divider in the given direction by the given amount.
|
||||||
pub fn moveDivider(self: *Split, direction: input.SplitResizeDirection, amount: u16) void {
|
pub fn moveDivider(
|
||||||
|
self: *Split,
|
||||||
|
direction: apprt.action.ResizeSplit.Direction,
|
||||||
|
amount: u16,
|
||||||
|
) void {
|
||||||
const min_pos = 10;
|
const min_pos = 10;
|
||||||
|
|
||||||
const pos = c.gtk_paned_get_position(self.paned);
|
const pos = c.gtk_paned_get_position(self.paned);
|
||||||
@ -263,7 +266,7 @@ fn updateChildren(self: *const Split) void {
|
|||||||
|
|
||||||
/// A mapping of direction to the element (if any) in that direction.
|
/// A mapping of direction to the element (if any) in that direction.
|
||||||
pub const DirectionMap = std.EnumMap(
|
pub const DirectionMap = std.EnumMap(
|
||||||
input.SplitFocusDirection,
|
apprt.action.GotoSplit,
|
||||||
?*Surface,
|
?*Surface,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -688,7 +688,10 @@ pub fn close(self: *Surface, processActive: bool) void {
|
|||||||
c.gtk_widget_show(alert);
|
c.gtk_widget_show(alert);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn controlInspector(self: *Surface, mode: input.InspectorMode) void {
|
pub fn controlInspector(
|
||||||
|
self: *Surface,
|
||||||
|
mode: apprt.action.Inspector,
|
||||||
|
) void {
|
||||||
const show = switch (mode) {
|
const show = switch (mode) {
|
||||||
.toggle => self.inspector == null,
|
.toggle => self.inspector == null,
|
||||||
.show => true,
|
.show => true,
|
||||||
@ -715,30 +718,6 @@ pub fn controlInspector(self: *Surface, mode: input.InspectorMode) void {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toggleFullscreen(self: *Surface, mac_non_native: configpkg.NonNativeFullscreen) void {
|
|
||||||
const window = self.container.window() orelse {
|
|
||||||
log.info(
|
|
||||||
"toggleFullscreen invalid for container={s}",
|
|
||||||
.{@tagName(self.container)},
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
window.toggleFullscreen(mac_non_native);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn toggleWindowDecorations(self: *Surface) void {
|
|
||||||
const window = self.container.window() orelse {
|
|
||||||
log.info(
|
|
||||||
"toggleWindowDecorations invalid for container={s}",
|
|
||||||
.{@tagName(self.container)},
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
window.toggleWindowDecorations();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getTitleLabel(self: *Surface) ?*c.GtkWidget {
|
pub fn getTitleLabel(self: *Surface) ?*c.GtkWidget {
|
||||||
switch (self.title) {
|
switch (self.title) {
|
||||||
.none => return null,
|
.none => return null,
|
||||||
@ -749,64 +728,6 @@ pub fn getTitleLabel(self: *Surface) ?*c.GtkWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn newSplit(self: *Surface, direction: apprt.SplitDirection) !void {
|
|
||||||
const alloc = self.app.core_app.alloc;
|
|
||||||
_ = try Split.create(alloc, self, direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn gotoSplit(self: *const Surface, direction: input.SplitFocusDirection) void {
|
|
||||||
const s = self.container.split() orelse return;
|
|
||||||
const map = s.directionMap(switch (self.container) {
|
|
||||||
.split_tl => .top_left,
|
|
||||||
.split_br => .bottom_right,
|
|
||||||
.none, .tab_ => unreachable,
|
|
||||||
});
|
|
||||||
const surface_ = map.get(direction) orelse return;
|
|
||||||
if (surface_) |surface| surface.grabFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resizeSplit(self: *const Surface, direction: input.SplitResizeDirection, amount: u16) void {
|
|
||||||
const s = self.container.firstSplitWithOrientation(
|
|
||||||
Split.Orientation.fromResizeDirection(direction),
|
|
||||||
) orelse return;
|
|
||||||
s.moveDivider(direction, amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn equalizeSplits(self: *const Surface) void {
|
|
||||||
const tab = self.container.tab() orelse return;
|
|
||||||
const top_split = switch (tab.elem) {
|
|
||||||
.split => |s| s,
|
|
||||||
else => return,
|
|
||||||
};
|
|
||||||
_ = top_split.equalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn newTab(self: *Surface) !void {
|
|
||||||
const window = self.container.window() orelse {
|
|
||||||
log.info("surface cannot create new tab when not attached to a window", .{});
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
try window.newTab(&self.core_surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn gotoTab(self: *Surface, tab: apprt.GotoTab) void {
|
|
||||||
const window = self.container.window() orelse {
|
|
||||||
log.info(
|
|
||||||
"gotoTab invalid for container={s}",
|
|
||||||
.{@tagName(self.container)},
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (tab) {
|
|
||||||
.previous => window.gotoPreviousTab(self),
|
|
||||||
.next => window.gotoNextTab(self),
|
|
||||||
.last => window.gotoLastTab(),
|
|
||||||
else => window.gotoTab(@intCast(@intFromEnum(tab))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setShouldClose(self: *Surface) void {
|
pub fn setShouldClose(self: *Surface) void {
|
||||||
_ = self;
|
_ = self;
|
||||||
}
|
}
|
||||||
@ -1975,7 +1896,7 @@ fn translateMods(state: c.GdkModifierType) input.Mods {
|
|||||||
return mods;
|
return mods;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn presentSurface(self: *Surface) void {
|
pub fn present(self: *Surface) void {
|
||||||
if (self.container.window()) |window| {
|
if (self.container.window()) |window| {
|
||||||
if (self.container.tab()) |tab| {
|
if (self.container.tab()) |tab| {
|
||||||
if (window.notebook.getTabPosition(tab)) |position|
|
if (window.notebook.getTabPosition(tab)) |position|
|
||||||
@ -1983,5 +1904,6 @@ pub fn presentSurface(self: *Surface) void {
|
|||||||
}
|
}
|
||||||
c.gtk_window_present(window.window);
|
c.gtk_window_present(window.window);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.grabFocus();
|
self.grabFocus();
|
||||||
}
|
}
|
||||||
|
@ -459,7 +459,7 @@ pub fn gotoTab(self: *Window, n: usize) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Toggle fullscreen for this window.
|
/// Toggle fullscreen for this window.
|
||||||
pub fn toggleFullscreen(self: *Window, _: configpkg.NonNativeFullscreen) void {
|
pub fn toggleFullscreen(self: *Window) void {
|
||||||
const is_fullscreen = c.gtk_window_is_fullscreen(self.window);
|
const is_fullscreen = c.gtk_window_is_fullscreen(self.window);
|
||||||
if (is_fullscreen == 0) {
|
if (is_fullscreen == 0) {
|
||||||
c.gtk_window_fullscreen(self.window);
|
c.gtk_window_fullscreen(self.window);
|
||||||
|
Reference in New Issue
Block a user