1package launcher
2
3import (
4 "context"
5 "net"
6 "os/exec"
7 "time"
8
9 "github.com/bnema/zerowrap"
10)
11
12// sessionVars are the displays D-Bus and systemd user services (portals,
13// notification daemons) need to reach the session.
14var sessionVars = []string{"WAYLAND_DISPLAY", "DISPLAY", "XDG_CURRENT_DESKTOP", "XDG_SESSION_TYPE"}
15
16// ExportSession shares the session's displays with D-Bus and systemd user
17// services, and waits for it: clients started next may activate them.
18func ExportSession(ctx context.Context, env []string, log zerowrap.Logger) {
19 ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
20 defer cancel()
21 runSessionCommand(ctx, env, log, append([]string{"--systemd"}, sessionVars...), "session exported")
22}
23
24// UnexportSession withdraws the displays from the systemd user manager on
25// exit, so services started after logout do not reach a dead display.
26func UnexportSession(env []string, log zerowrap.Logger) {
27 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
28 defer cancel()
29 path, err := childLookPath("systemctl", env)
30 if err != nil {
31 return
32 }
33 cmd := exec.CommandContext(ctx, path, append([]string{"--user", "unset-environment"}, sessionVars...)...)
34 cmd.Env = env
35 if err := cmd.Run(); err != nil {
36 log.Warn().Err(err).Msg("session unexport failed")
37 }
38}
39
40func runSessionCommand(ctx context.Context, env []string, log zerowrap.Logger, args []string, done string) {
41 path, err := childLookPath("dbus-update-activation-environment", env)
42 if err != nil {
43 log.Warn().Err(err).Msg("session export skipped: dbus-update-activation-environment not found")
44 return
45 }
46 cmd := exec.CommandContext(ctx, path, args...)
47 cmd.Env = env
48 if err := cmd.Run(); err != nil {
49 log.Warn().Err(err).Msg("session export failed")
50 return
51 }
52 log.Info().Strs("vars", sessionVars).Msg(done)
53}
54
55// NotifyReady tells the systemd user manager that the compositor is ready.
56func NotifyReady(socket string, log zerowrap.Logger) {
57 if socket == "" {
58 return
59 }
60 conn, err := net.DialUnix("unixgram", nil, &net.UnixAddr{Name: socket, Net: "unixgram"})
61 if err != nil {
62 log.Warn().Err(err).Msg("session readiness notification failed")
63 return
64 }
65 defer conn.Close()
66 if _, err := conn.Write([]byte("READY=1")); err != nil {
67 log.Warn().Err(err).Msg("session readiness notification failed")
68 return
69 }
70 log.Info().Msg("session ready")
71}