Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ singularity_core_sources = files(
'src/components/sidebar/pages/performance_page.vala',
'src/core/display_manager.vala',
'src/core/hot_corner_manager.vala',
'src/core/layer_window.vala',
'src/core/monitor_osd.vala',
'src/core/system_components.vala',
'src/core/debug_manager.vala',
Expand Down
14 changes: 7 additions & 7 deletions src/components/dock/dock.vala
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ namespace Singularity {
}
if (key == "panel-fusion") {
update_fusion();
((Gtk.Widget) this).hide();
close_layer_window (this);
update_visibility_mode();
pulse_frame_clock();
}
Expand All @@ -257,7 +257,7 @@ namespace Singularity {
if (key == "dock-enabled") {
_enabled = _settings.get_boolean("dock-enabled");
if (!_enabled) {
((Gtk.Widget) this).hide();
close_layer_window (this);
set_exclusive_zone(this, 0);
app_system.shell_dock_height = 0;
_set_reveal_barrier_active(false);
Expand Down Expand Up @@ -927,7 +927,7 @@ namespace Singularity {
queue_draw();
break;
case "remap":
hide();
close_layer_window (this);
present();
queue_draw();
break;
Expand Down Expand Up @@ -1036,7 +1036,7 @@ namespace Singularity {
// is live right after the remap (and we pulse it), so the content
// transform is presented reliably without moving the surface.
set_body_class("dock-reveal-offset", true);
((Gtk.Widget) this).hide();
close_layer_window (this);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep frame-clock pulses paired across dock remaps

When an autohiding dock starts hiding and is revealed again within the 350 ms pulse window, this newly added unrealize creates a different surface/frame clock. pulse_frame_clock() begins updating the old clock at line 977, but its timeout fetches the current clock at lines 979-980; after this remap, the old timeout therefore ends the new clock early, and the new timeout later calls end_updating() on it again. This can truncate the reveal transition or trigger an unmatched frame-clock update warning during ordinary rapid pointer leave/re-enter, so the timeout should retain and end the same fc instance it began rather than looking it up again.

Useful? React with 👍 / 👎.

present();
start_content_slide();
}
Expand Down Expand Up @@ -1140,7 +1140,7 @@ namespace Singularity {
return;
}
if (!_enabled) {
((Gtk.Widget) this).hide();
close_layer_window (this);
set_exclusive_zone(this, 0);
app_system.shell_dock_height = 0;
_set_reveal_barrier_active(false);
Expand All @@ -1157,7 +1157,7 @@ namespace Singularity {
// Re-trigger size_allocate to restore the correct exclusive zone
queue_resize();
} else if (visibility_mode == "overview-only") {
hide();
close_layer_window (this);
set_exclusive_zone(this, 0);
}
update_autohide_state();
Expand Down Expand Up @@ -1207,7 +1207,7 @@ namespace Singularity {
// window covering it) is not composited until a frame is
// committed, so closing a focused fullscreen window left the
// dock buried. Remap to force a fresh buffer and present.
((Gtk.Widget) this).hide();
close_layer_window (this);
present();
update_visibility_mode();
pulse_frame_clock();
Expand Down
15 changes: 14 additions & 1 deletion src/components/overview/app_launcher_grid.vala
Original file line number Diff line number Diff line change
Expand Up @@ -377,9 +377,22 @@ namespace Singularity {
return GLib.Source.CONTINUE;
}

public void depopulate() {
/**
* Dismiss any open folder overlay without tearing down the grid.
*
* A folder overlay is its own toplevel layer-shell window, so hiding
* the launcher that spawned it leaves it on screen. Closing the
* overlays is cheap; dropping the grid contents is not, which is why
* depopulate() stays on its idle timer and this can be called
* immediately on close.
*/
public void close_folder_overlays() {
_folder_overlays.foreach((id, ov) => ov.close_overlay());
_folder_overlays.remove_all();
}

public void depopulate() {
close_folder_overlays();
Widget? c = grid.get_first_child();
while (c != null) { Widget nc = c.get_next_sibling(); grid.remove(c); c = nc; }
}
Expand Down
8 changes: 4 additions & 4 deletions src/components/overview/app_menu.vala
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ namespace Singularity {
});
((Gtk.Widget)this).add_controller(key_controller);

hide();
close_layer_window (this);
}

private void apply_monitor_sizing() {
Expand Down Expand Up @@ -269,7 +269,7 @@ namespace Singularity {
menu_animation.tick.connect(() => { opacity = menu_animation.value; });
menu_animation.done.connect(() => {
if (_is_open) return;
hide();
close_layer_window (this);
if (widgets_grid != null) widgets_grid.depopulate();
hidden();
});
Expand Down Expand Up @@ -333,7 +333,7 @@ namespace Singularity {
opacity = target;
if (stay_open) search_entry.grab_focus();
else {
hide();
close_layer_window (this);
if (widgets_grid != null) widgets_grid.depopulate();
hidden();
}
Expand All @@ -353,7 +353,7 @@ namespace Singularity {
if (menu_animation == animation) menu_animation = null;
if (stay_open) search_entry.grab_focus();
else {
hide();
close_layer_window (this);
if (widgets_grid != null) widgets_grid.depopulate();
hidden();
}
Expand Down
13 changes: 11 additions & 2 deletions src/components/overview/overview.vala
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,13 @@ namespace Singularity {
_anim_out_timer = GLib.Timeout.add(180, () => {
_anim_out_timer = 0;
main_box.remove_css_class("animating-out");
hide();
close_layer_window (this);
// A folder overlay is a separate toplevel layer window, so
// it does not go away with the launcher. Dismiss it now --
// waiting for the idle depopulate below left it on screen
// for IDLE_DEPOPULATE_MS, or indefinitely if the overview
// was reopened before that timer fired and cancelled it.
launcher_grid.close_folder_overlays();
PreviewCache.get_default().clear();
hidden();
// The overview just freed its grid widgets, icon textures
Expand Down Expand Up @@ -433,7 +439,10 @@ namespace Singularity {
}

private void finish_gesture_hide() {
hide();
close_layer_window (this);
// Same reason as the animated close path: the folder overlay is its
// own toplevel and does not go away with the launcher.
launcher_grid.close_folder_overlays();
PreviewCache.get_default().clear();
hidden();
Singularity.trim_heap();
Expand Down
8 changes: 4 additions & 4 deletions src/components/overview/workspace_overview.vala
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ namespace Singularity {
wp_manager.wallpaper_changed.connect(update_wallpaper);
update_wallpaper();

hide();
close_layer_window (this);
}

private void update_wallpaper() {
Expand Down Expand Up @@ -420,7 +420,7 @@ namespace Singularity {
_anim_out_timer = 0;
opacity = 0;
anim_box.remove_css_class("animating-out");
hide();
close_layer_window (this);
// Free all window preview textures - they'll be re-captured on next open
clear_overview_content();
hidden();
Expand Down Expand Up @@ -498,7 +498,7 @@ namespace Singularity {
|| Math.fabs(opacity - target) < 0.001) {
opacity = target;
if (!stay_open) {
hide();
close_layer_window (this);
clear_overview_content();
hidden();
}
Expand All @@ -517,7 +517,7 @@ namespace Singularity {
opacity = target;
if (_gesture_animation == animation) _gesture_animation = null;
if (!stay_open) {
hide();
close_layer_window (this);
clear_overview_content();
hidden();
}
Expand Down
10 changes: 5 additions & 5 deletions src/components/sidebar/sidebar.vala
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ namespace Singularity {
toggle_settings();
});
system_view.hide_sidebar.connect(() => {
hide();
close_layer_window (this);
});
system_view.open_settings_page.connect((page) => {
open_page(page);
Expand All @@ -90,15 +90,15 @@ namespace Singularity {
main_stack.notify["visible-child-name"].connect(() => update_vertical_anchor());
update_vertical_anchor();

hide();
close_layer_window (this);

// Close on Escape key
var key_controller = new Gtk.EventControllerKey();
key_controller.key_pressed.connect((keyval, keycode, state) => {
if (keyval == Gdk.Key.Escape) {
if (!Singularity.DebugManager.get_default().sidebar_pinned) {
desktop_settings.set_boolean("bar-layout-edit-mode", false);
hide();
close_layer_window (this);
}
return true;
}
Expand Down Expand Up @@ -133,7 +133,7 @@ namespace Singularity {
_can_close_on_focus_loss = false;
opacity = 1;
GtkLayerShell.set_margin(this, GtkLayerShell.Edge.RIGHT, 40);
hide();
close_layer_window (this);
return;
}
// Null before skip so old done handler sees slide_animation != old_anim
Expand All @@ -155,7 +155,7 @@ namespace Singularity {
slide_animation = null;
_is_closing = false;
_can_close_on_focus_loss = false;
hide();
close_layer_window (this);
}
});
anim.play();
Expand Down
4 changes: 2 additions & 2 deletions src/core/hot_corner_manager.vala
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ namespace Singularity {
hint.add_overlay(badge);

set_child(hint);
hide();
close_layer_window (this);
}

public void show_hint(string action) {
Expand All @@ -235,7 +235,7 @@ namespace Singularity {

public void hide_hint() {
hint.remove_css_class("visible");
hide();
close_layer_window (this);
}

private static string icon_for_action(string? action) {
Expand Down
37 changes: 37 additions & 0 deletions src/core/layer_window.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Gtk;

namespace Singularity {

/**
* Hide a layer-shell window and drop its GdkSurface.
*
* GTK keeps one wl_surface alive across hide/show, while gtk4-layer-shell
* destroys the zwlr_layer_surface_v1 at unmap and creates a NEW one over
* that same wl_surface on the next open. wl_surface state is persistent, so
* a frame that lands after the unmap leaves a buffer attached, and creating
* a layer surface over a surface that still holds a buffer is a client
* error the compositor answers by killing the connection:
*
* Gdk-Message: Error 71 (Protocol error) dispatching to Wayland display
* zwlr_layer_surface_v1 has never been configured
*
* Whether the stray frame lands is a race on wl_buffer.release, which is
* why a window would survive a variable number of open/close cycles before
* dying. Dropping the GdkSurface means the next open allocates a fresh
* wl_surface that cannot carry a stale buffer.
*
* This is the same sequence gtk4-layer-shell performs internally in
* gtk_layer_surface_remap(), so it is a supported, exercised path.
* unrealize() on a never-realized widget is a documented no-op, which makes
* this safe to call from a constructor-time hide.
*
* The cast matters: GtkWindow implements GtkNative, so a bare unrealize()
* binds to gtk_native_unrealize -- an internal vfunc -- rather than
* gtk_widget_unrealize. Verified by inspecting the C that valac emits for
* each spelling.
*/
public void close_layer_window (Gtk.Window window) {
((Gtk.Widget) window).hide ();
((Gtk.Widget) window).unrealize ();
}
}
11 changes: 10 additions & 1 deletion src/core/main.vala
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,16 @@ public class SingularityApp : Singularity.ShellApplication, Singularity.Shell.Sh

private void sync_bar_layout_edit_mode() {
if (settings.get_boolean("bar-layout-edit-mode")) {
sidebar?.hide();
if (sidebar != null) {
sidebar.hide();
// Drop the GdkSurface here too. This is the one close path that
// lives OUTSIDE Sidebar, so the in-class resets do not cover it,
// and re-opening via a panel or dock toggle calls present() on
// the old surface -- the same stale-buffer fault.
// Cast required: GtkWindow implements GtkNative, so a bare
// unrealize() binds to gtk_native_unrealize, not the widget one.
((Gtk.Widget) sidebar).unrealize();
}
settings_window?.hide();
if (bar_layout_edit_overlay == null) {
bar_layout_edit_overlay = new Singularity.BarLayoutEditOverlay(this);
Expand Down