@@ -108,6 +108,60 @@ func getWindowPosition() (int, int) {
108108 return x , y
109109}
110110
111- // setWindowOpacity is a no-op on Linux (xprop/_NET_WM_WINDOW_OPACITY requires
112- // a compositing manager; omitted for simplicity).
113- func setWindowOpacity (_ int ) {}
111+ // setWindowOpacity applies whole-window transparency on Linux/X11 by setting
112+ // the _NET_WM_WINDOW_OPACITY property via xprop. This requires a compositing
113+ // manager (Picom, Mutter, KWin, etc.) to take effect.
114+ //
115+ // Unlike Windows (which supports background-only color-key transparency),
116+ // X11 _NET_WM_WINDOW_OPACITY affects the entire window including content.
117+ // To keep text and icons readable, the user-facing opacity values are mapped
118+ // to less aggressive X11 values:
119+ //
120+ // User 100% → X11 100% (fully opaque)
121+ // User 75% → X11 85%
122+ // User 50% → X11 70%
123+ // User 25% → X11 55%
124+ func setWindowOpacity (opacityPercent int ) {
125+ // Map user-facing opacity to X11 whole-window opacity so content stays
126+ // readable. The window background dims while text/icons remain legible.
127+ x11Percent := opacityPercent
128+ switch {
129+ case opacityPercent >= 100 :
130+ x11Percent = 100
131+ case opacityPercent >= 75 :
132+ x11Percent = 85
133+ case opacityPercent >= 50 :
134+ x11Percent = 70
135+ case opacityPercent >= 25 :
136+ x11Percent = 55
137+ default :
138+ x11Percent = 55
139+ }
140+
141+ go func () {
142+ // Give the window a moment to be mapped if called at startup.
143+ time .Sleep (600 * time .Millisecond )
144+
145+ if x11Percent >= 100 {
146+ // Remove the property entirely — fully opaque.
147+ cmd := exec .Command ("xprop" , "-name" , widgetTitle , "-remove" , "_NET_WM_WINDOW_OPACITY" )
148+ if err := cmd .Run (); err != nil {
149+ log .Printf ("Linux: setWindowOpacity: failed to remove _NET_WM_WINDOW_OPACITY: %v" , err )
150+ }
151+ return
152+ }
153+
154+ // _NET_WM_WINDOW_OPACITY is a 32-bit cardinal where 0xFFFFFFFF = fully opaque.
155+ opacity := uint64 (x11Percent ) * 0xFFFFFFFF / 100
156+ val := strconv .FormatUint (opacity , 10 )
157+
158+ cmd := exec .Command ("xprop" , "-name" , widgetTitle ,
159+ "-f" , "_NET_WM_WINDOW_OPACITY" , "32c" ,
160+ "-set" , "_NET_WM_WINDOW_OPACITY" , val )
161+ if err := cmd .Run (); err != nil {
162+ log .Printf ("Linux: setWindowOpacity: xprop failed (is x11-utils installed? is a compositor running?): %v" , err )
163+ return
164+ }
165+ log .Printf ("Linux: set window opacity to %d%% (user: %d%%, _NET_WM_WINDOW_OPACITY=%s)" , x11Percent , opacityPercent , val )
166+ }()
167+ }
0 commit comments