Merge pull request #2608 from Pangoraw/toggle_split_zoom

gtk: implement toggle_split_zoom
This commit is contained in:
Mitchell Hashimoto
2024-11-09 09:59:29 -08:00
committed by GitHub
4 changed files with 95 additions and 11 deletions

View File

@ -471,12 +471,12 @@ pub fn performAction(
.mouse_shape => try self.setMouseShape(target, value),
.mouse_over_link => self.setMouseOverLink(target, value),
.toggle_tab_overview => self.toggleTabOverview(target),
.toggle_split_zoom => self.toggleSplitZoom(target),
.toggle_window_decorations => self.toggleWindowDecorations(target),
.quit_timer => self.quitTimer(value),
// Unimplemented
.close_all_windows,
.toggle_split_zoom,
.toggle_quick_terminal,
.toggle_visibility,
.size_limit,
@ -671,6 +671,13 @@ fn toggleTabOverview(_: *App, target: apprt.Target) void {
}
}
fn toggleSplitZoom(_: *App, target: apprt.Target) void {
switch (target) {
.app => {},
.surface => |surface| surface.rt_surface.toggleSplitZoom(),
}
}
fn toggleWindowDecorations(
_: *App,
target: apprt.Target,

View File

@ -77,6 +77,7 @@ pub fn init(
});
errdefer surface.destroy(alloc);
sibling.dimSurface();
sibling.setSplitZoom(false);
// Create the actual GTKPaned, attach the proper children.
const orientation: c_uint = switch (direction) {
@ -258,7 +259,7 @@ pub fn grabFocus(self: *Split) void {
/// Update the paned children to represent the current state.
/// This should be called anytime the top/left or bottom/right
/// element is changed.
fn updateChildren(self: *const Split) void {
pub fn updateChildren(self: *const Split) void {
// We have to set both to null. If we overwrite the pane with
// the same value, then GTK bugs out (the GL area unrealizes
// and never rerealizes).
@ -372,7 +373,15 @@ fn directionNext(self: *const Split, from: Side) ?struct {
}
}
fn removeChildren(self: *const Split) void {
c.gtk_paned_set_start_child(@ptrCast(self.paned), null);
c.gtk_paned_set_end_child(@ptrCast(self.paned), null);
pub fn detachTopLeft(self: *const Split) void {
c.gtk_paned_set_start_child(self.paned, null);
}
pub fn detachBottomRight(self: *const Split) void {
c.gtk_paned_set_end_child(self.paned, null);
}
fn removeChildren(self: *const Split) void {
self.detachTopLeft();
self.detachBottomRight();
}

View File

@ -330,6 +330,9 @@ url_widget: ?URLWidget = null,
/// The overlay that shows resizing information.
resize_overlay: ResizeOverlay = .{},
/// Whether or not the current surface is zoomed in (see `toggle_split_zoom`).
zoomed_in: bool = false,
/// If non-null this is the widget on the overlay which dims the surface when it is unfocused
unfocused_widget: ?*c.GtkWidget = null,
@ -643,6 +646,8 @@ pub fn redraw(self: *Surface) void {
/// Close this surface.
pub fn close(self: *Surface, processActive: bool) void {
self.setSplitZoom(false);
// If we're not part of a window hierarchy, we never confirm
// so we can just directly remove ourselves and exit.
const window = self.container.window() orelse {
@ -791,7 +796,16 @@ pub fn setInitialWindowSize(self: *const Surface, width: u32, height: u32) !void
}
pub fn grabFocus(self: *Surface) void {
if (self.container.tab()) |tab| tab.focus_child = self;
if (self.container.tab()) |tab| {
// If any other surface was focused and zoomed in, set it to non zoomed in
// so that self can grab focus.
if (tab.focus_child) |focus_child| {
if (focus_child.zoomed_in and focus_child != self) {
focus_child.setSplitZoom(false);
}
}
tab.focus_child = self;
}
const widget = @as(*c.GtkWidget, @ptrCast(self.gl_area));
_ = c.gtk_widget_grab_focus(widget);
@ -801,7 +815,7 @@ pub fn grabFocus(self: *Surface) void {
fn updateTitleLabels(self: *Surface) void {
// If we have no title, then we have nothing to update.
const title = self.title_text orelse return;
const title = self.getTitle() orelse return;
// If we have a tab and are the focused child, then we have to update the tab
if (self.container.tab()) |tab| {
@ -822,9 +836,19 @@ fn updateTitleLabels(self: *Surface) void {
}
}
const zoom_title_prefix = "🔍 ";
pub fn setTitle(self: *Surface, slice: [:0]const u8) !void {
const alloc = self.app.core_app.alloc;
const copy = try alloc.dupeZ(u8, slice);
// Always allocate with the "🔍 " at the beginning and slice accordingly
// is the surface is zoomed in or not.
const copy: [:0]const u8 = copy: {
const new_title = try alloc.allocSentinel(u8, zoom_title_prefix.len + slice.len, 0);
@memcpy(new_title[0..zoom_title_prefix.len], zoom_title_prefix);
@memcpy(new_title[zoom_title_prefix.len..], slice);
break :copy new_title;
};
errdefer alloc.free(copy);
if (self.title_text) |old| alloc.free(old);
@ -834,7 +858,14 @@ pub fn setTitle(self: *Surface, slice: [:0]const u8) !void {
}
pub fn getTitle(self: *Surface) ?[:0]const u8 {
return self.title_text;
if (self.title_text) |title_text| {
return if (self.zoomed_in)
title_text
else
title_text[zoom_title_prefix.len..];
}
return null;
}
pub fn setMouseShape(
@ -1875,3 +1906,41 @@ pub fn present(self: *Surface) void {
self.grabFocus();
}
fn detachFromSplit(self: *Surface) void {
const split = self.container.split() orelse return;
switch (self.container.splitSide() orelse unreachable) {
.top_left => split.detachTopLeft(),
.bottom_right => split.detachBottomRight(),
}
}
fn attachToSplit(self: *Surface) void {
const split = self.container.split() orelse return;
split.updateChildren();
}
pub fn setSplitZoom(self: *Surface, new_split_zoom: bool) void {
if (new_split_zoom == self.zoomed_in) return;
const tab = self.container.tab() orelse return;
const tab_widget = tab.elem.widget();
const surface_widget = self.primaryWidget();
if (new_split_zoom) {
self.detachFromSplit();
c.gtk_box_remove(tab.box, tab_widget);
c.gtk_box_append(tab.box, surface_widget);
} else {
c.gtk_box_remove(tab.box, surface_widget);
self.attachToSplit();
c.gtk_box_append(tab.box, tab_widget);
}
self.zoomed_in = new_split_zoom;
self.grabFocus();
}
pub fn toggleSplitZoom(self: *Surface) void {
self.setSplitZoom(!self.zoomed_in);
}

View File

@ -317,8 +317,7 @@ pub const Action = union(enum) {
/// Focus on a split in a given direction.
goto_split: SplitFocusDirection,
/// zoom/unzoom the current split. This is currently only supported
/// on macOS. Contributions welcome for other platforms.
/// zoom/unzoom the current split.
toggle_split_zoom: void,
/// Resize the current split by moving the split divider in the given