Repository navigation
GTK: --gtk-single-instance launch sometimes opens no window; the remote instance exits before its Activate call is sent
#14822
Issue DescriptionWith A The cause: on a remote instance, This looks different from #13554, where the request reaches a long-running instance that then makes no surface. Proposed FixFlush the session bus before the remote path returns. With this, the reproduction below loses no activations. Commit: AlJohri@6be6267 --- a/src/apprt/gtk/class/application.zig
+++ b/src/apprt/gtk/class/application.zig
@@ -556,6 +556,23 @@ pub const Application = extern struct {
"application is remote, exiting run loop after activation",
.{},
);
+
+ // On a remote instance, activate() only queues an asynchronous
+ // D-Bus call. Flush the connection so that the call is sent
+ // before the process exits.
+ if (self.as(gio.Application).getDbusConnection()) |dbus| {
+ var flush_err: ?*glib.Error = null;
+ if (dbus.flushSync(null, &flush_err) == 0) {
+ if (flush_err) |err| {
+ defer err.free();
+ log.warn(
+ "error flushing D-Bus connection: {s}",
+ .{err.f_message orelse "(unknown)"},
+ );
+ }
+ }
+ }
+
return;
}
Expected BehaviorEach launch of a remote instance opens a window in the primary instance. Actual BehaviorSome launches send no Reproduction StepsThe race depends on thread timing, so the reproduction makes the client compete for one CPU core. It does not need a running Ghostty, and it opens no windows: a stand-in primary on a private session bus counts the activations.
import signal
from gi.repository import Gio, GLib
count = 0
app = Gio.Application(application_id="com.mitchellh.ghostty")
def on_activate(_app):
global count
count += 1
def on_term():
print(count, flush=True)
loop.quit()
app.connect("activate", on_activate)
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGTERM, on_term)
loop = GLib.MainLoop()
app.register(None)
loop.run()Run from a Wayland session: taskset -c 0 sh -c 'while :; do :; done' & # keep core 0 busy
dbus-run-session -- sh -c '
python3 fake-primary.py > count.txt & sleep 1
for i in $(seq 200); do taskset -c 0 ghostty --gtk-single-instance=true >/dev/null 2>&1; done
sleep 1; kill -TERM $!; wait'
kill %1
cat count.txt # expect 200Results, 2 runs of 200 launches each, every launch exited 0:
Without the busy loop, Arch's 1.3.1 build still lost 19 of 200 when pinned to one core. Ghostty LogsNothing from Ghostty points at the failure. The client's output is the same for a launch that works and a launch that fails, and it exits 0. Ghostty VersionOS Version InformationArch Linux, kernel 7.2.8; glib2 2.90.1, gtk4 4.24.1, libadwaita 1.10.0. Also on NixOS (glib 2.88.3). (Linux only) Display ServerWayland (Linux only) Desktop Environment/Window ManagerHyprland 0.56.2 Minimal Ghostty ConfigurationI used Claude Code to trace the D-Bus traffic, write the reproduction, and draft the patch. I reviewed and edited this text and the patch myself. |
Replies: 2 comments
|
!vouch @AlJohri I've vouched you if you want to submit your patch as a PR. The only suggestion I have would be to put the flush in the cleanup ghostty/src/apprt/gtk/class/application.zig Lines 505 to 518 in 22f100c |
|
!vouch |
#14823
!vouch
@AlJohri I've vouched you if you want to submit your patch as a PR. The only suggestion I have would be to put the flush in the cleanup
deferso that it's always run, not just on the remote case.ghostty/src/apprt/gtk/class/application.zig
Lines 505 to 518 in 22f100c