mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-25 13:16:11 +03:00
apprt/gtk-ng: resize overlay (#8012)
This implements the resize overlay. This is implemented using a new mostly generic `ResizeOverlay` class that can probably be renamed one day to something like `TemporaryOverlay` since it is generic to show a label with a duration. The only user-facing change here is `after-first` behavior has been changed in the config to actually mean "after a delay." The `after-first` behavior has been problematic since we introduced it on both macOS and Linux because a lot of windowing systems may perform multiple resizes very quickly at startup (especially tiling ones) so its less about being "first" and more about semantically only showing the overlay for user-driven resizes. We should rename this, eventually. The valgrind suppression file change is mostly to handle an alternate machine, but its all the same stuff (GTK renderers, GPU drivers, etc.), nothing new in our app code.
This commit is contained in:
@ -35,6 +35,7 @@ pub const icon_sizes: []const comptime_int = &.{ 16, 32, 128, 256, 512, 1024 };
|
|||||||
pub const blueprints: []const Blueprint = &.{
|
pub const blueprints: []const Blueprint = &.{
|
||||||
.{ .major = 1, .minor = 2, .name = "close-confirmation-dialog" },
|
.{ .major = 1, .minor = 2, .name = "close-confirmation-dialog" },
|
||||||
.{ .major = 1, .minor = 2, .name = "config-errors-dialog" },
|
.{ .major = 1, .minor = 2, .name = "config-errors-dialog" },
|
||||||
|
.{ .major = 1, .minor = 2, .name = "resize-overlay" },
|
||||||
.{ .major = 1, .minor = 2, .name = "surface" },
|
.{ .major = 1, .minor = 2, .name = "surface" },
|
||||||
.{ .major = 1, .minor = 5, .name = "window" },
|
.{ .major = 1, .minor = 5, .name = "window" },
|
||||||
};
|
};
|
||||||
|
302
src/apprt/gtk-ng/class/resize_overlay.zig
Normal file
302
src/apprt/gtk-ng/class/resize_overlay.zig
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const adw = @import("adw");
|
||||||
|
const glib = @import("glib");
|
||||||
|
const gobject = @import("gobject");
|
||||||
|
const gtk = @import("gtk");
|
||||||
|
|
||||||
|
const gresource = @import("../build/gresource.zig");
|
||||||
|
const Common = @import("../class.zig").Common;
|
||||||
|
|
||||||
|
const log = std.log.scoped(.gtk_ghostty_resize_overlay);
|
||||||
|
|
||||||
|
/// The overlay that shows the current size while a surface is resizing.
|
||||||
|
/// This can be used generically to show pretty much anything with a
|
||||||
|
/// disappearing overlay, but we have no other use at this point so it
|
||||||
|
/// is named specifically for what it does.
|
||||||
|
///
|
||||||
|
/// General usage:
|
||||||
|
///
|
||||||
|
/// 1. Add it to an overlay
|
||||||
|
/// 2. Set the label with `setLabel`
|
||||||
|
/// 3. Schedule to show it with `schedule`
|
||||||
|
///
|
||||||
|
/// Set any properties to change the behavior.
|
||||||
|
pub const ResizeOverlay = extern struct {
|
||||||
|
const Self = @This();
|
||||||
|
parent_instance: Parent,
|
||||||
|
pub const Parent = adw.Bin;
|
||||||
|
pub const getGObjectType = gobject.ext.defineClass(Self, .{
|
||||||
|
.name = "GhosttyResizeOverlay",
|
||||||
|
.instanceInit = &init,
|
||||||
|
.classInit = &Class.init,
|
||||||
|
.parent_class = &Class.parent,
|
||||||
|
.private = .{ .Type = Private, .offset = &Private.offset },
|
||||||
|
});
|
||||||
|
|
||||||
|
pub const properties = struct {
|
||||||
|
pub const duration = struct {
|
||||||
|
pub const name = "duration";
|
||||||
|
const impl = gobject.ext.defineProperty(
|
||||||
|
name,
|
||||||
|
Self,
|
||||||
|
c_uint,
|
||||||
|
.{
|
||||||
|
.nick = "Duration",
|
||||||
|
.blurb = "The duration this overlay appears in milliseconds.",
|
||||||
|
.default = 750,
|
||||||
|
.minimum = 250,
|
||||||
|
.maximum = std.math.maxInt(c_uint),
|
||||||
|
.accessor = gobject.ext.privateFieldAccessor(
|
||||||
|
Self,
|
||||||
|
Private,
|
||||||
|
&Private.offset,
|
||||||
|
"duration",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const @"first-delay" = struct {
|
||||||
|
pub const name = "first-delay";
|
||||||
|
const impl = gobject.ext.defineProperty(
|
||||||
|
name,
|
||||||
|
Self,
|
||||||
|
c_uint,
|
||||||
|
.{
|
||||||
|
.nick = "First Delay",
|
||||||
|
.blurb = "The delay in milliseconds before any overlay is shown for the first time.",
|
||||||
|
.default = 250,
|
||||||
|
.minimum = 250,
|
||||||
|
.maximum = std.math.maxInt(c_uint),
|
||||||
|
.accessor = gobject.ext.privateFieldAccessor(
|
||||||
|
Self,
|
||||||
|
Private,
|
||||||
|
&Private.offset,
|
||||||
|
"first_delay",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const @"overlay-halign" = struct {
|
||||||
|
pub const name = "overlay-halign";
|
||||||
|
const impl = gobject.ext.defineProperty(
|
||||||
|
name,
|
||||||
|
Self,
|
||||||
|
gtk.Align,
|
||||||
|
.{
|
||||||
|
.nick = "halign",
|
||||||
|
.blurb = "The alignment of the label.",
|
||||||
|
.default = .center,
|
||||||
|
.accessor = gobject.ext.privateFieldAccessor(
|
||||||
|
Self,
|
||||||
|
Private,
|
||||||
|
&Private.offset,
|
||||||
|
"halign",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const @"overlay-valign" = struct {
|
||||||
|
pub const name = "overlay-valign";
|
||||||
|
const impl = gobject.ext.defineProperty(
|
||||||
|
name,
|
||||||
|
Self,
|
||||||
|
gtk.Align,
|
||||||
|
.{
|
||||||
|
.nick = "valign",
|
||||||
|
.blurb = "The alignment of the label.",
|
||||||
|
.default = .center,
|
||||||
|
.accessor = gobject.ext.privateFieldAccessor(
|
||||||
|
Self,
|
||||||
|
Private,
|
||||||
|
&Private.offset,
|
||||||
|
"valign",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const Private = struct {
|
||||||
|
/// The label with the text
|
||||||
|
label: *gtk.Label,
|
||||||
|
|
||||||
|
/// The time that the overlay appears.
|
||||||
|
duration: c_uint,
|
||||||
|
|
||||||
|
/// The first delay before any overlay is shown. Must be specified
|
||||||
|
/// during construction otherwise it has no effect.
|
||||||
|
first_delay: c_uint,
|
||||||
|
|
||||||
|
/// The idle source that we use to update the label.
|
||||||
|
idler: ?c_uint = null,
|
||||||
|
|
||||||
|
/// The timer for dismissing the overlay.
|
||||||
|
timer: ?c_uint = null,
|
||||||
|
|
||||||
|
/// The first delay timer.
|
||||||
|
delay_timer: ?c_uint = null,
|
||||||
|
|
||||||
|
/// The alignment of the label
|
||||||
|
halign: gtk.Align,
|
||||||
|
valign: gtk.Align,
|
||||||
|
|
||||||
|
pub var offset: c_int = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn init(self: *Self, _: *Class) callconv(.C) void {
|
||||||
|
gtk.Widget.initTemplate(self.as(gtk.Widget));
|
||||||
|
|
||||||
|
const priv = self.private();
|
||||||
|
if (priv.first_delay > 0) {
|
||||||
|
priv.delay_timer = glib.timeoutAdd(
|
||||||
|
priv.first_delay,
|
||||||
|
onDelayTimer,
|
||||||
|
self,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the label for the overlay. This will not show the
|
||||||
|
/// overlay if it is currently hidden; you must call schedule.
|
||||||
|
pub fn setLabel(self: *Self, label: [:0]const u8) void {
|
||||||
|
const priv = self.private();
|
||||||
|
priv.label.setText(label.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Schedule the overlay to be shown. To avoid flickering during
|
||||||
|
/// resizes we schedule the overlay to be shown on the next idle tick.
|
||||||
|
pub fn schedule(self: *Self) void {
|
||||||
|
const priv = self.private();
|
||||||
|
|
||||||
|
// If we have a delay timer then we're not showing anything
|
||||||
|
// yet so do nothing.
|
||||||
|
if (priv.delay_timer != null) return;
|
||||||
|
|
||||||
|
// When updating a widget, wait until GTK is "idle", i.e. not in the middle
|
||||||
|
// of doing any other updates. Since we are called in the middle of resizing
|
||||||
|
// GTK is doing a lot of work rearranging all of the widgets. Not doing this
|
||||||
|
// results in a lot of warnings from GTK and _horrible_ flickering of the
|
||||||
|
// resize overlay.
|
||||||
|
if (priv.idler != null) return;
|
||||||
|
priv.idler = glib.idleAdd(onIdle, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn onIdle(ud: ?*anyopaque) callconv(.c) c_int {
|
||||||
|
const self: *Self = @ptrCast(@alignCast(ud orelse return 0));
|
||||||
|
const priv = self.private();
|
||||||
|
|
||||||
|
// No matter what our idler is complete with this callback
|
||||||
|
priv.idler = null;
|
||||||
|
|
||||||
|
// Show ourselves
|
||||||
|
self.as(gtk.Widget).setVisible(1);
|
||||||
|
|
||||||
|
if (priv.timer) |timer| {
|
||||||
|
if (glib.Source.remove(timer) == 0) {
|
||||||
|
log.warn("unable to remove size overlay timer", .{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
priv.timer = glib.timeoutAdd(
|
||||||
|
priv.duration,
|
||||||
|
onTimer,
|
||||||
|
self,
|
||||||
|
);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn onTimer(ud: ?*anyopaque) callconv(.c) c_int {
|
||||||
|
const self: *Self = @ptrCast(@alignCast(ud orelse return 0));
|
||||||
|
const priv = self.private();
|
||||||
|
priv.timer = null;
|
||||||
|
self.as(gtk.Widget).setVisible(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn onDelayTimer(ud: ?*anyopaque) callconv(.c) c_int {
|
||||||
|
const self: *Self = @ptrCast(@alignCast(ud orelse return 0));
|
||||||
|
const priv = self.private();
|
||||||
|
priv.delay_timer = null;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
// Virtual methods
|
||||||
|
|
||||||
|
fn dispose(self: *Self) callconv(.C) void {
|
||||||
|
const priv = self.private();
|
||||||
|
if (priv.idler) |v| {
|
||||||
|
if (glib.Source.remove(v) == 0) {
|
||||||
|
log.warn("unable to remove resize overlay idler", .{});
|
||||||
|
}
|
||||||
|
priv.idler = null;
|
||||||
|
}
|
||||||
|
if (priv.timer) |v| {
|
||||||
|
if (glib.Source.remove(v) == 0) {
|
||||||
|
log.warn("unable to remove resize overlay timer", .{});
|
||||||
|
}
|
||||||
|
priv.timer = null;
|
||||||
|
}
|
||||||
|
if (priv.delay_timer) |v| {
|
||||||
|
if (glib.Source.remove(v) == 0) {
|
||||||
|
log.warn("unable to remove resize overlay delay timer", .{});
|
||||||
|
}
|
||||||
|
priv.delay_timer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk.Widget.disposeTemplate(
|
||||||
|
self.as(gtk.Widget),
|
||||||
|
getGObjectType(),
|
||||||
|
);
|
||||||
|
|
||||||
|
gobject.Object.virtual_methods.dispose.call(
|
||||||
|
Class.parent,
|
||||||
|
self.as(Parent),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const C = Common(Self, Private);
|
||||||
|
pub const as = C.as;
|
||||||
|
pub const ref = C.ref;
|
||||||
|
pub const unref = C.unref;
|
||||||
|
const private = C.private;
|
||||||
|
|
||||||
|
pub const Class = extern struct {
|
||||||
|
parent_class: Parent.Class,
|
||||||
|
var parent: *Parent.Class = undefined;
|
||||||
|
pub const Instance = Self;
|
||||||
|
|
||||||
|
fn init(class: *Class) callconv(.C) void {
|
||||||
|
gtk.Widget.Class.setTemplateFromResource(
|
||||||
|
class.as(gtk.Widget.Class),
|
||||||
|
comptime gresource.blueprint(.{
|
||||||
|
.major = 1,
|
||||||
|
.minor = 2,
|
||||||
|
.name = "resize-overlay",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Bindings
|
||||||
|
class.bindTemplateChildPrivate("label", .{});
|
||||||
|
|
||||||
|
// Properties
|
||||||
|
gobject.ext.registerProperties(class, &.{
|
||||||
|
properties.duration.impl,
|
||||||
|
properties.@"first-delay".impl,
|
||||||
|
properties.@"overlay-halign".impl,
|
||||||
|
properties.@"overlay-valign".impl,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Virtual methods
|
||||||
|
gobject.Object.virtual_methods.dispose.implement(class, &dispose);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const as = C.Class.as;
|
||||||
|
pub const bindTemplateChildPrivate = C.Class.bindTemplateChildPrivate;
|
||||||
|
};
|
||||||
|
};
|
@ -19,6 +19,7 @@ const ApprtSurface = @import("../Surface.zig");
|
|||||||
const Common = @import("../class.zig").Common;
|
const Common = @import("../class.zig").Common;
|
||||||
const Application = @import("application.zig").Application;
|
const Application = @import("application.zig").Application;
|
||||||
const Config = @import("config.zig").Config;
|
const Config = @import("config.zig").Config;
|
||||||
|
const ResizeOverlay = @import("resize_overlay.zig").ResizeOverlay;
|
||||||
|
|
||||||
const log = std.log.scoped(.gtk_ghostty_surface);
|
const log = std.log.scoped(.gtk_ghostty_surface);
|
||||||
|
|
||||||
@ -202,6 +203,9 @@ pub const Surface = extern struct {
|
|||||||
url_left: *gtk.Label = undefined,
|
url_left: *gtk.Label = undefined,
|
||||||
url_right: *gtk.Label = undefined,
|
url_right: *gtk.Label = undefined,
|
||||||
|
|
||||||
|
/// The resize overlay
|
||||||
|
resize_overlay: *ResizeOverlay = undefined,
|
||||||
|
|
||||||
/// The apprt Surface.
|
/// The apprt Surface.
|
||||||
rt_surface: ApprtSurface = undefined,
|
rt_surface: ApprtSurface = undefined,
|
||||||
|
|
||||||
@ -837,6 +841,13 @@ pub const Surface = extern struct {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Some property signals
|
// Some property signals
|
||||||
|
_ = gobject.Object.signals.notify.connect(
|
||||||
|
self,
|
||||||
|
?*anyopaque,
|
||||||
|
&propConfig,
|
||||||
|
null,
|
||||||
|
.{ .detail = "config" },
|
||||||
|
);
|
||||||
_ = gobject.Object.signals.notify.connect(
|
_ = gobject.Object.signals.notify.connect(
|
||||||
self,
|
self,
|
||||||
?*anyopaque,
|
?*anyopaque,
|
||||||
@ -861,6 +872,16 @@ pub const Surface = extern struct {
|
|||||||
|
|
||||||
// Some other initialization steps
|
// Some other initialization steps
|
||||||
self.initUrlOverlay();
|
self.initUrlOverlay();
|
||||||
|
self.initResizeOverlay();
|
||||||
|
|
||||||
|
// Initialize our config
|
||||||
|
self.propConfig(undefined, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initResizeOverlay(self: *Self) void {
|
||||||
|
const priv = self.private();
|
||||||
|
const overlay = priv.overlay;
|
||||||
|
overlay.addOverlay(priv.resize_overlay.as(gtk.Widget));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initUrlOverlay(self: *Self) void {
|
fn initUrlOverlay(self: *Self) void {
|
||||||
@ -960,6 +981,58 @@ pub const Surface = extern struct {
|
|||||||
return self.private().title;
|
return self.private().title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn propConfig(
|
||||||
|
self: *Self,
|
||||||
|
_: *gobject.ParamSpec,
|
||||||
|
_: ?*anyopaque,
|
||||||
|
) callconv(.c) void {
|
||||||
|
const priv = self.private();
|
||||||
|
const config = if (priv.config) |c| c.get() else return;
|
||||||
|
|
||||||
|
// resize-overlay-duration
|
||||||
|
{
|
||||||
|
const ms = config.@"resize-overlay-duration".asMilliseconds();
|
||||||
|
var value = gobject.ext.Value.newFrom(ms);
|
||||||
|
defer value.unset();
|
||||||
|
gobject.Object.setProperty(
|
||||||
|
priv.resize_overlay.as(gobject.Object),
|
||||||
|
"duration",
|
||||||
|
&value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// resize-overlay-position
|
||||||
|
{
|
||||||
|
const hv: struct {
|
||||||
|
gtk.Align, // halign
|
||||||
|
gtk.Align, // valign
|
||||||
|
} = switch (config.@"resize-overlay-position") {
|
||||||
|
.center => .{ .center, .center },
|
||||||
|
.@"top-left" => .{ .start, .start },
|
||||||
|
.@"top-right" => .{ .end, .start },
|
||||||
|
.@"top-center" => .{ .center, .start },
|
||||||
|
.@"bottom-left" => .{ .start, .end },
|
||||||
|
.@"bottom-right" => .{ .end, .end },
|
||||||
|
.@"bottom-center" => .{ .center, .end },
|
||||||
|
};
|
||||||
|
|
||||||
|
var halign = gobject.ext.Value.newFrom(hv[0]);
|
||||||
|
defer halign.unset();
|
||||||
|
var valign = gobject.ext.Value.newFrom(hv[1]);
|
||||||
|
defer valign.unset();
|
||||||
|
gobject.Object.setProperty(
|
||||||
|
priv.resize_overlay.as(gobject.Object),
|
||||||
|
"overlay-halign",
|
||||||
|
&halign,
|
||||||
|
);
|
||||||
|
gobject.Object.setProperty(
|
||||||
|
priv.resize_overlay.as(gobject.Object),
|
||||||
|
"overlay-valign",
|
||||||
|
&valign,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn propMouseHoverUrl(
|
fn propMouseHoverUrl(
|
||||||
self: *Self,
|
self: *Self,
|
||||||
_: *gobject.ParamSpec,
|
_: *gobject.ParamSpec,
|
||||||
@ -1556,9 +1629,44 @@ pub const Surface = extern struct {
|
|||||||
surface.sizeCallback(priv.size) catch |err| {
|
surface.sizeCallback(priv.size) catch |err| {
|
||||||
log.warn("error in size callback err={}", .{err});
|
log.warn("error in size callback err={}", .{err});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Setup our resize overlay if configured
|
||||||
|
self.resizeOverlaySchedule();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resizeOverlaySchedule(self: *Self) void {
|
||||||
|
const priv = self.private();
|
||||||
|
const surface = priv.core_surface orelse return;
|
||||||
|
|
||||||
|
// Only show the resize overlay if its enabled
|
||||||
|
const config = if (priv.config) |c| c.get() else return;
|
||||||
|
switch (config.@"resize-overlay") {
|
||||||
|
.always, .@"after-first" => {},
|
||||||
|
.never => return,
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have resize overlays enabled, setup an idler
|
||||||
|
// to show that. We do this in an idle tick because doing it
|
||||||
|
// during the resize results in flickering.
|
||||||
|
var buf: [32]u8 = undefined;
|
||||||
|
priv.resize_overlay.setLabel(text: {
|
||||||
|
const grid_size = surface.size.grid();
|
||||||
|
break :text std.fmt.bufPrintZ(
|
||||||
|
&buf,
|
||||||
|
"{d} x {d}",
|
||||||
|
.{
|
||||||
|
grid_size.columns,
|
||||||
|
grid_size.rows,
|
||||||
|
},
|
||||||
|
) catch |err| err: {
|
||||||
|
log.warn("unable to format text: {}", .{err});
|
||||||
|
break :err "";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
priv.resize_overlay.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
const RealizeError = Allocator.Error || error{
|
const RealizeError = Allocator.Error || error{
|
||||||
GLAreaError,
|
GLAreaError,
|
||||||
RendererError,
|
RendererError,
|
||||||
@ -1655,6 +1763,7 @@ pub const Surface = extern struct {
|
|||||||
pub const Instance = Self;
|
pub const Instance = Self;
|
||||||
|
|
||||||
fn init(class: *Class) callconv(.C) void {
|
fn init(class: *Class) callconv(.C) void {
|
||||||
|
gobject.ext.ensureType(ResizeOverlay);
|
||||||
gtk.Widget.Class.setTemplateFromResource(
|
gtk.Widget.Class.setTemplateFromResource(
|
||||||
class.as(gtk.Widget.Class),
|
class.as(gtk.Widget.Class),
|
||||||
comptime gresource.blueprint(.{
|
comptime gresource.blueprint(.{
|
||||||
@ -1669,6 +1778,7 @@ pub const Surface = extern struct {
|
|||||||
class.bindTemplateChildPrivate("gl_area", .{});
|
class.bindTemplateChildPrivate("gl_area", .{});
|
||||||
class.bindTemplateChildPrivate("url_left", .{});
|
class.bindTemplateChildPrivate("url_left", .{});
|
||||||
class.bindTemplateChildPrivate("url_right", .{});
|
class.bindTemplateChildPrivate("url_right", .{});
|
||||||
|
class.bindTemplateChildPrivate("resize_overlay", .{});
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
gobject.ext.registerProperties(class, &.{
|
gobject.ext.registerProperties(class, &.{
|
||||||
|
@ -22,3 +22,11 @@ label.url-overlay.left {
|
|||||||
label.url-overlay.right {
|
label.url-overlay.right {
|
||||||
border-radius: 6px 0px 0px 0px;
|
border-radius: 6px 0px 0px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.size-overlay label {
|
||||||
|
padding: 4px 8px 4px 8px;
|
||||||
|
border-radius: 6px 6px 6px 6px;
|
||||||
|
outline-style: solid;
|
||||||
|
outline-width: 1px;
|
||||||
|
outline-color: #555555;
|
||||||
|
}
|
||||||
|
22
src/apprt/gtk-ng/ui/1.2/resize-overlay.blp
Normal file
22
src/apprt/gtk-ng/ui/1.2/resize-overlay.blp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using Gtk 4.0;
|
||||||
|
using Adw 1;
|
||||||
|
// We can't inherit directly from Label because its an opaque
|
||||||
|
// type in zig-gobject.
|
||||||
|
template $GhosttyResizeOverlay: Adw.Bin {
|
||||||
|
visible: false;
|
||||||
|
duration: 750;
|
||||||
|
first-delay: 250;
|
||||||
|
overlay-halign: center;
|
||||||
|
overlay-valign: center;
|
||||||
|
// See surface.blp for why we need to wrap this.
|
||||||
|
Adw.Bin {
|
||||||
|
Label label {
|
||||||
|
focusable: false;
|
||||||
|
focus-on-click: false;
|
||||||
|
justify: center;
|
||||||
|
selectable: false;
|
||||||
|
halign: bind template.overlay-halign;
|
||||||
|
valign: bind template.overlay-valign;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -42,3 +42,9 @@ Label url_right {
|
|||||||
valign: end;
|
valign: end;
|
||||||
label: bind template.mouse-hover-url;
|
label: bind template.mouse-hover-url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$GhosttyResizeOverlay resize_overlay {
|
||||||
|
styles [
|
||||||
|
"size-overlay",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
@ -20,6 +20,8 @@ extend-exclude = [
|
|||||||
"*.png",
|
"*.png",
|
||||||
"*.ico",
|
"*.ico",
|
||||||
"*.icns",
|
"*.icns",
|
||||||
|
# Valgrind nonsense
|
||||||
|
"valgrind.supp",
|
||||||
# Other
|
# Other
|
||||||
"*.pdf",
|
"*.pdf",
|
||||||
"*.data",
|
"*.data",
|
||||||
|
@ -34,6 +34,35 @@
|
|||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
GSK GPU Rendering
|
||||||
|
Memcheck:Leak
|
||||||
|
match-leak-kinds: possible
|
||||||
|
...
|
||||||
|
fun:gsk_gpu_render_pass_op_gl_command
|
||||||
|
fun:gsk_gl_frame_submit
|
||||||
|
fun:gsk_gpu_renderer_render
|
||||||
|
fun:gsk_renderer_render
|
||||||
|
fun:gtk_widget_render
|
||||||
|
fun:surface_render
|
||||||
|
fun:_gdk_marshal_BOOLEAN__BOXEDv
|
||||||
|
fun:_g_closure_invoke_va
|
||||||
|
fun:signal_emit_valist_unlocked
|
||||||
|
fun:g_signal_emit_valist
|
||||||
|
fun:g_signal_emit
|
||||||
|
fun:gdk_surface_paint_on_clock
|
||||||
|
fun:_g_closure_invoke_va
|
||||||
|
fun:signal_emit_valist_unlocked
|
||||||
|
fun:g_signal_emit_valist
|
||||||
|
fun:g_signal_emit
|
||||||
|
fun:gdk_frame_clock_paint_idle
|
||||||
|
...
|
||||||
|
fun:g_timeout_dispatch
|
||||||
|
fun:g_main_context_dispatch_unlocked
|
||||||
|
fun:g_main_context_iterate_unlocked.isra.0
|
||||||
|
fun:g_main_context_iteration
|
||||||
|
...
|
||||||
|
}
|
||||||
{
|
{
|
||||||
GTK Shader Selector
|
GTK Shader Selector
|
||||||
Memcheck:Leak
|
Memcheck:Leak
|
||||||
@ -57,7 +86,7 @@
|
|||||||
fun:g_object_new_internal.part.0
|
fun:g_object_new_internal.part.0
|
||||||
fun:g_object_new_valist
|
fun:g_object_new_valist
|
||||||
fun:g_object_new
|
fun:g_object_new
|
||||||
fun:gtk_at_spi_create_context
|
...
|
||||||
fun:gtk_at_context_create
|
fun:gtk_at_context_create
|
||||||
fun:gtk_widget_init
|
fun:gtk_widget_init
|
||||||
fun:g_type_create_instance
|
fun:g_type_create_instance
|
||||||
@ -79,7 +108,7 @@
|
|||||||
fun:g_object_new_internal.part.0
|
fun:g_object_new_internal.part.0
|
||||||
fun:g_object_new_valist
|
fun:g_object_new_valist
|
||||||
fun:g_object_new
|
fun:g_object_new
|
||||||
fun:gtk_at_spi_create_context
|
...
|
||||||
fun:gtk_at_context_create
|
fun:gtk_at_context_create
|
||||||
fun:gtk_widget_init
|
fun:gtk_widget_init
|
||||||
fun:g_type_create_instance
|
fun:g_type_create_instance
|
||||||
@ -101,6 +130,34 @@
|
|||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Fcitx
|
||||||
|
Memcheck:Leak
|
||||||
|
match-leak-kinds: definite
|
||||||
|
...
|
||||||
|
fun:g_malloc0
|
||||||
|
fun:parser_start_element
|
||||||
|
fun:emit_start_element
|
||||||
|
fun:g_markup_parse_context_parse
|
||||||
|
fun:g_dbus_node_info_new_for_xml
|
||||||
|
fun:_fcitx_g_client_*
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Fcitx
|
||||||
|
Memcheck:Leak
|
||||||
|
match-leak-kinds: possible
|
||||||
|
...
|
||||||
|
fun:g_closure_invoke
|
||||||
|
fun:signal_emit_unlocked_R.isra.0
|
||||||
|
fun:signal_emit_valist_unlocked
|
||||||
|
fun:g_signal_emit_valist
|
||||||
|
fun:g_signal_emit
|
||||||
|
fun:_fcitx_g_client_g_signal
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
GTK init
|
GTK init
|
||||||
Memcheck:Leak
|
Memcheck:Leak
|
||||||
@ -126,7 +183,7 @@
|
|||||||
fun:fc_thread_func
|
fun:fc_thread_func
|
||||||
fun:g_thread_proxy
|
fun:g_thread_proxy
|
||||||
fun:start_thread
|
fun:start_thread
|
||||||
fun:clone
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -211,17 +268,17 @@
|
|||||||
{
|
{
|
||||||
Mesa
|
Mesa
|
||||||
Memcheck:Leak
|
Memcheck:Leak
|
||||||
match-leak-kinds: possible
|
|
||||||
...
|
...
|
||||||
fun:_mesa_*
|
fun:_mesa_*
|
||||||
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Mesa
|
Mesa
|
||||||
Memcheck:Leak
|
Memcheck:Leak
|
||||||
match-leak-kinds: possible
|
|
||||||
...
|
...
|
||||||
fun:mesa_*
|
fun:mesa_*
|
||||||
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user