diff --git a/src/apprt/gtk/ResizeOverlay.zig b/src/apprt/gtk/ResizeOverlay.zig index 9c4c7a3d5..c0db30c85 100644 --- a/src/apprt/gtk/ResizeOverlay.zig +++ b/src/apprt/gtk/ResizeOverlay.zig @@ -1,3 +1,5 @@ +const ResizeOverlay = @This(); + const std = @import("std"); const c = @import("c.zig"); const configpkg = @import("../../config.zig"); @@ -23,14 +25,18 @@ first: bool = true, /// If we're configured to do so, create a label widget for displaying the size /// of the surface during a resize event. -pub fn init(surface: *Surface, config: *configpkg.Config, overlay: *c.GtkOverlay) @This() { +pub fn init( + surface: *Surface, + config: *configpkg.Config, + overlay: *c.GtkOverlay, +) ResizeOverlay { // At this point the surface object has been _created_ but not // _initialized_ so we can't use any information from it. if (config.@"resize-overlay" == .never) return .{}; + // Create the label that will show the resize information. const widget = c.gtk_label_new(""); - c.gtk_widget_add_css_class(widget, "view"); c.gtk_widget_add_css_class(widget, "size-overlay"); c.gtk_widget_add_css_class(widget, "hidden"); @@ -39,15 +45,13 @@ pub fn init(surface: *Surface, config: *configpkg.Config, overlay: *c.GtkOverlay c.gtk_widget_set_can_target(widget, c.FALSE); c.gtk_label_set_justify(@ptrCast(widget), c.GTK_JUSTIFY_CENTER); c.gtk_label_set_selectable(@ptrCast(widget), c.FALSE); - setOverlayWidgetPosition(widget, config); - c.gtk_overlay_add_overlay(overlay, widget); return .{ .surface = surface, .widget = widget }; } -pub fn deinit(self: *@This()) void { +pub fn deinit(self: *ResizeOverlay) void { if (self.idler) |idler| { if (c.g_source_remove(idler) == c.FALSE) { log.warn("unable to remove resize overlay idler", .{}); @@ -66,21 +70,28 @@ pub fn deinit(self: *@This()) void { /// If we're configured to do so, update the text in the resize overlay widget /// and make it visible. Schedule a timer to hide the widget after the delay /// expires. -pub fn maybeShowResizeOverlay(self: *@This()) void { +/// +/// If we're not configured to show the overlay, do nothing. +pub fn maybeShowResizeOverlay(self: *ResizeOverlay) void { if (self.widget == null) return; const surface = self.surface orelse return; - if (surface.app.config.@"resize-overlay" == .never) return; - - if (surface.app.config.@"resize-overlay" == .@"after-first" and self.first) { - self.first = false; - return; + switch (surface.app.config.@"resize-overlay") { + .never => return, + .always => {}, + .@"after-first" => if (self.first) { + self.first = false; + return; + }, } self.first = false; // When updating a widget, do so from GTK's thread, but not if there's - // already an update queued up. + // already an update queued up. Even though all our function calls ARE + // from the main thread, we have to do this to avoid GTK warnings. My + // guess is updating a widget in the hierarchy while another widget is + // being resized is a bad idea. if (self.idler != null) return; self.idler = c.g_idle_add(gtkUpdateOverlayWidget, @ptrCast(self)); } @@ -88,7 +99,10 @@ pub fn maybeShowResizeOverlay(self: *@This()) void { /// Actually update the overlay widget. This should only be called as an idle /// handler. fn gtkUpdateOverlayWidget(ud: ?*anyopaque) callconv(.C) c.gboolean { - const self: *@This() = @ptrCast(@alignCast(ud)); + const self: *ResizeOverlay = @ptrCast(@alignCast(ud)); + + // No matter what our idler is complete with this callback + self.idler = null; const widget = self.widget orelse return c.FALSE; const surface = self.surface orelse return c.FALSE; @@ -123,8 +137,6 @@ fn gtkUpdateOverlayWidget(ud: ?*anyopaque) callconv(.C) c.gboolean { @ptrCast(self), ); - self.idler = null; - return c.FALSE; } @@ -152,11 +164,11 @@ fn setOverlayWidgetPosition(widget: *c.GtkWidget, config: *configpkg.Config) voi /// If this fires, it means that the delay period has expired and the resize /// overlay widget should be hidden. fn gtkResizeOverlayTimerExpired(ud: ?*anyopaque) callconv(.C) c.gboolean { - const self: *@This() = @ptrCast(@alignCast(ud)); + const self: *ResizeOverlay = @ptrCast(@alignCast(ud)); + self.timer = null; if (self.widget) |widget| { c.gtk_widget_add_css_class(@ptrCast(widget), "hidden"); c.gtk_widget_set_visible(@ptrCast(widget), c.FALSE); } - self.timer = null; return c.FALSE; } diff --git a/src/apprt/gtk/Surface.zig b/src/apprt/gtk/Surface.zig index e35717a4c..44deb4a1d 100644 --- a/src/apprt/gtk/Surface.zig +++ b/src/apprt/gtk/Surface.zig @@ -326,6 +326,7 @@ gl_area: *c.GtkGLArea, /// If non-null this is the widget on the overlay that shows the URL. url_widget: ?URLWidget = null, +/// The overlay that shows resizing information. resize_overlay: ResizeOverlay = .{}, /// If non-null this is the widget on the overlay which dims the surface when it is unfocused @@ -459,8 +460,6 @@ pub fn init(self: *Surface, app: *App, opts: Options) !void { break :font_size parent.font_size; }; - const resize_overlay = ResizeOverlay.init(self, &app.config, @ptrCast(overlay)); - // If the parent has a transient cgroup, then we're creating cgroups // for each surface if we can. We need to create a child cgroup. const cgroup_path: ?[]const u8 = cgroup: { @@ -497,6 +496,7 @@ pub fn init(self: *Surface, app: *App, opts: Options) !void { .container = .{ .none = {} }, .overlay = @ptrCast(overlay), .gl_area = @ptrCast(gl_area), + .resize_overlay = ResizeOverlay.init(self, &app.config, @ptrCast(overlay)), .title_text = null, .core_surface = undefined, .font_size = font_size, @@ -505,7 +505,6 @@ pub fn init(self: *Surface, app: *App, opts: Options) !void { .cursor_pos = .{ .x = 0, .y = 0 }, .im_context = im_context, .cgroup_path = cgroup_path, - .resize_overlay = resize_overlay, }; errdefer self.* = undefined;