mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-07-31 04:39:01 +00:00
gtk: honor suspended window state
GTK exposes the Wayland xdg_toplevel suspended state when the compositor knows a window is not visible. Ghostty previously only used widget map state, so it could continue rendering a mapped surface on an inactive workspace or behind other windows. Combine the mapped and suspended states for surface occlusion and update all displayed surfaces whenever the toplevel suspension state changes. Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-019fa965-aa5f-7099-85b4-a9679d2c8bd3
This commit is contained in:
@@ -3324,7 +3324,7 @@ pub const Surface = extern struct {
|
||||
self: *Self,
|
||||
) callconv(.c) void {
|
||||
self.updateMapped(true);
|
||||
self.updateOcclusion(true);
|
||||
self.updateOcclusion();
|
||||
}
|
||||
|
||||
fn glareaUnmap(
|
||||
@@ -3332,7 +3332,7 @@ pub const Surface = extern struct {
|
||||
self: *Self,
|
||||
) callconv(.c) void {
|
||||
self.updateMapped(false);
|
||||
self.updateOcclusion(false);
|
||||
self.updateOcclusion();
|
||||
}
|
||||
|
||||
fn updateMapped(self: *Self, mapped: bool) void {
|
||||
@@ -3341,13 +3341,23 @@ pub const Surface = extern struct {
|
||||
self.as(gobject.Object).notifyByPspec(properties.mapped.impl.param_spec);
|
||||
}
|
||||
|
||||
fn updateOcclusion(self: *Self, visible: bool) void {
|
||||
/// Update the core surface visibility based on both GTK widget and
|
||||
/// toplevel state. This is public so the window can call it when its
|
||||
/// suspended state changes.
|
||||
pub fn updateOcclusion(self: *Self) void {
|
||||
const surface = self.core() orelse return;
|
||||
const visible = self.private().mapped and !self.windowSuspended();
|
||||
surface.occlusionCallback(visible) catch |err| {
|
||||
log.warn("error in occlusion callback err={}", .{err});
|
||||
};
|
||||
}
|
||||
|
||||
fn windowSuspended(self: *Self) bool {
|
||||
const native = self.as(gtk.Widget).getNative() orelse return false;
|
||||
const window = gobject.ext.cast(gtk.Window, native) orelse return false;
|
||||
return window.isSuspended() != 0;
|
||||
}
|
||||
|
||||
fn glareaRender(
|
||||
_: *gtk.GLArea,
|
||||
_: *gdk.GLContext,
|
||||
|
||||
@@ -1374,11 +1374,33 @@ pub const Window = extern struct {
|
||||
}
|
||||
}
|
||||
|
||||
// Notify every displayed surface when the compositor changes the
|
||||
// Wayland xdg_toplevel suspended state.
|
||||
_ = gobject.Object.signals.notify.connect(
|
||||
self.as(gtk.Window),
|
||||
*Self,
|
||||
propSuspended,
|
||||
self,
|
||||
.{ .detail = "suspended" },
|
||||
);
|
||||
|
||||
// When we are realized we always setup our appearance since this
|
||||
// calls some winproto functions.
|
||||
self.syncAppearance();
|
||||
}
|
||||
|
||||
fn propSuspended(
|
||||
_: *gtk.Window,
|
||||
_: *gobject.ParamSpec,
|
||||
self: *Self,
|
||||
) callconv(.c) void {
|
||||
const tab = self.getSelectedTab() orelse return;
|
||||
const tree = tab.getSurfaceTree() orelse return;
|
||||
|
||||
var it = tree.iterator();
|
||||
while (it.next()) |entry| entry.view.updateOcclusion();
|
||||
}
|
||||
|
||||
fn btnNewTab(_: *adw.SplitButton, self: *Self) callconv(.c) void {
|
||||
self.performBindingAction(.new_tab);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user