layershell_preload.go RawHistoryFolder
1package bootstrap
2
3import (
4 "maps"
5 "os"
6 "path/filepath"
7 "strings"
8)
9
10const layerShellLibrarySubstring = "libgtk4-layer-shell"
11
12var layerShellLibraryCandidates = []string{
13 "/usr/lib/libgtk4-layer-shell.so.0",
14 "/usr/lib64/libgtk4-layer-shell.so.0",
15 "/usr/lib/aarch64-linux-gnu/libgtk4-layer-shell.so.0",
16 "/usr/lib/x86_64-linux-gnu/libgtk4-layer-shell.so.0",
17 "/lib/x86_64-linux-gnu/libgtk4-layer-shell.so.0",
18}
19
20func ShouldPreloadLayerShell(env map[string]string) bool {
21 if env["WAYLAND_DISPLAY"] == "" {
22 return false
23 }
24
25 return !LayerShellPreloadPresent(env)
26}
27
28func LayerShellPreloadPresent(env map[string]string) bool {
29 return strings.Contains(env["LD_PRELOAD"], layerShellLibrarySubstring)
30}
31
32func CurrentEnvMap() map[string]string {
33 env := make(map[string]string)
34 for _, entry := range os.Environ() {
35 key, value, ok := strings.Cut(entry, "=")
36 if !ok {
37 continue
38 }
39 env[key] = value
40 }
41 return env
42}
43
44func FindLayerShellLibrary(env map[string]string, exists func(path string) bool) string {
45 for _, path := range layerShellLibrarySearchPaths(env) {
46 if exists(path) {
47 return path
48 }
49 }
50
51 return ""
52}
53
54func LayerShellLibraryPath() string {
55 return FindLayerShellLibrary(CurrentEnvMap(), func(path string) bool {
56 info, err := os.Stat(filepath.Clean(path))
57 return err == nil && !info.IsDir()
58 })
59}
60
61func layerShellLibrarySearchPaths(env map[string]string) []string {
62 paths := make([]string, 0, len(layerShellLibraryCandidates)+4)
63 paths = append(paths, layerShellLibraryCandidates...)
64
65 seen := make(map[string]struct{}, len(paths))
66 for _, path := range paths {
67 seen[path] = struct{}{}
68 }
69
70 for _, dir := range strings.FieldsFunc(env["LD_LIBRARY_PATH"], func(r rune) bool { return r == ':' }) {
71 if dir == "" {
72 continue
73 }
74 candidate := filepath.Join(dir, "libgtk4-layer-shell.so.0")
75 if _, ok := seen[candidate]; ok {
76 continue
77 }
78 seen[candidate] = struct{}{}
79 paths = append(paths, candidate)
80 }
81
82 return paths
83}
84
85func LayerShellPreloadEnv(env map[string]string, libraryPath string) map[string]string {
86 cloned := make(map[string]string, len(env)+1)
87 maps.Copy(cloned, env)
88
89 if libraryPath == "" {
90 return cloned
91 }
92
93 if current := cloned["LD_PRELOAD"]; current != "" {
94 cloned["LD_PRELOAD"] = libraryPath + " " + current
95 return cloned
96 }
97
98 cloned["LD_PRELOAD"] = libraryPath
99 return cloned
100}