// Copyright (c) 2026 Storm Dragon // Authors: Storm Dragon, Angus Kola // SPDX-License-Identifier: GPL-3.0-or-later // Package sessionbus selects the same desktop session bus as GLib clients, // including Python Cthulhu and I38lock, without changing the process environment. package sessionbus /* #cgo pkg-config: gio-2.0 #include */ import "C" import ( "context" "fmt" "log/slog" "time" "unsafe" "github.com/godbus/dbus/v5" ) func sessionAddress() (string, error) { var nativeError *C.GError address := C.g_dbus_address_get_for_bus_sync(C.G_BUS_TYPE_SESSION, nil, &nativeError) if nativeError != nil { defer C.g_error_free(nativeError) return "", fmt.Errorf("resolve desktop session bus: %s", C.GoString(nativeError.message)) } if address == nil { return "", fmt.Errorf("resolve desktop session bus: no address") } defer C.g_free(C.gpointer(unsafe.Pointer(address))) return C.GoString(address), nil } // Connect uses GLib's session address discovery and godbus's private connection. // Bus IDs let debug logs identify mismatched buses without exposing addresses. func Connect(logger *slog.Logger, component string) (*dbus.Conn, error) { address, err := sessionAddress() if err != nil { return nil, err } connection, err := dbus.Connect(address) if err != nil { return nil, err } if logger != nil && logger.Enabled(context.Background(), slog.LevelDebug) { ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) defer cancel() var busID string if err := connection.BusObject().CallWithContext(ctx, "org.freedesktop.DBus.GetId", 0).Store(&busID); err != nil { logger.Debug("query session bus identity", "component", component, "error", err) } else { logger.Debug("connected to session bus", "component", component, "bus_id", busID) } } return connection, nil }