2 #-# Copyright © 2021 Eric Bina, Dave Black, TJ Phan,
3 #-# Vincent Renardias, Willem Vermin
5 #-# Permission is hereby granted, free of charge, to any person
6 #-# obtaining a copy of this software and associated documentation
7 #-# files (the “Software”), to deal in the Software without
8 #-# restriction, including without limitation the rights to use,
9 #-# copy, modify, merge, publish, distribute, sublicense, and/or
10 #-# sell copies of the Software, and to permit persons to whom
11 #-# the Software is furnished to do so, subject to the following
14 #-# The above copyright notice and this permission notice shall
15 #-# be included in all copies or substantial portions of the Software.
17 #-# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
18 #-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 #-# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 #-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 #-# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 #-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 #-# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 #-# OTHER DEALINGS IN THE SOFTWARE.
29 #include <X11/Intrinsic.h>
30 #include "transwindow.h"
34 static int setvaria(GtkWidget
*widget
);
37 * creates transparent window using gtk3/cairo.
38 * transwindow: (input) GtkWidget to create transparent window in
39 * fullscreen: (input) full-screen or not full screen
40 * sticky: (input) visible on all workspaces or not
41 * below: (input) 1: below all other windows 2: above all other windows 0: no action
42 * dock: (input) make it a 'dock' window: no decoration and not interfering with xsnow, xpenguins
43 * NOTE: with dock=1, gtk ignores the value of below: window is above all other windows
44 * NOTE: with decorations set to TRUE (see gtk_window_set_decorated()),
45 * the window is not click-through in Gnome
46 * So: dock = 1 is good for Gnome, or call gtk_window_set_decorated(w,FALSE)
47 * before this function
48 * gdk_window: (output) GdkWindow created
49 * x11_window: (output) Window X11 window created
51 int make_trans_window(GtkWidget
*transwindow
, int fullscreen
, int sticky
, int below
, int dock
,
52 GdkWindow
**gdk_window
, Window
*x11_window
)
59 // We take full responsibility for drawing background etc.
60 // Also, this is essential to obtain the desired effect.
61 gtk_widget_set_app_paintable(transwindow
, TRUE
);
63 // essential in Gnome:
64 gtk_window_set_decorated(GTK_WINDOW(transwindow
),FALSE
);
65 // essential everywhere:
66 gtk_window_set_accept_focus(GTK_WINDOW(transwindow
), FALSE
);
68 // take care that 'below' and 'sticky' are taken care of in gtk_main loop:
69 g_signal_connect(transwindow
, "draw", G_CALLBACK(setvaria
), NULL
);
71 // remove our things from transwindow:
72 g_object_steal_data(G_OBJECT(transwindow
),"trans_sticky");
73 g_object_steal_data(G_OBJECT(transwindow
),"trans_below");
74 g_object_steal_data(G_OBJECT(transwindow
),"trans_nobelow");
75 g_object_steal_data(G_OBJECT(transwindow
),"trans_done");
80 g_object_set_data(G_OBJECT(transwindow
),"trans_sticky",&somechar
);
85 g_object_set_data(G_OBJECT(transwindow
),"trans_nobelow",&somechar
);
88 g_object_set_data(G_OBJECT(transwindow
),"trans_below",&somechar
);
92 /* To check if the display supports alpha channels, get the visual */
93 GdkScreen
*screen
= gtk_widget_get_screen(transwindow
);
95 if (!gdk_screen_is_composited(screen
))
98 gtk_window_close(GTK_WINDOW(transwindow
));
102 // Ensure the widget (the window, actually) can take RGBA
103 gtk_widget_set_visual(transwindow
, gdk_screen_get_rgba_visual(screen
));
105 // set full screen if so desired:
109 XWindowAttributes attr
;
110 Display
*display
= XOpenDisplay(NULL
);
111 XGetWindowAttributes(display
,DefaultRootWindow(display
),&attr
);
112 gtk_widget_set_size_request(GTK_WIDGET(transwindow
),attr
.width
,attr
.height
);
113 XCloseDisplay(display
);
117 P("NOT fullsscreen\n");
120 gtk_widget_show_all(transwindow
);
121 GdkWindow
*gdkwin
= gtk_widget_get_window(GTK_WIDGET(transwindow
));
123 // so that apps like xsnow will ignore this window:
125 gdk_window_set_type_hint(gdkwin
,GDK_WINDOW_TYPE_HINT_DOCK
);
127 gdk_window_hide(gdkwin
);
129 gdk_window_move(gdkwin
,0,0);
130 gdk_window_show(gdkwin
);
133 *x11_window
= gdk_x11_window_get_xid(gdkwin
);
135 *gdk_window
= gdkwin
;
137 usleep(200000); // seems sometimes to be necessary with nvidia
139 // just to be sure all settings are communicated with the server
140 gtk_widget_hide(transwindow
);
141 gtk_widget_show_all(transwindow
);
143 // set some things, but note that this has to be repeated in the gkt_main loop.
145 P("explicitly call setvaria\n");
146 setvaria(transwindow
);
147 P("end explicit call\n");
148 g_object_steal_data(G_OBJECT(transwindow
),"trans_done");
153 // for some reason, in some environments the 'below' and 'stick' properties
154 // disappear. It works again, if we express our wishes after starting gtk_main
155 // and the best place is in the draw event.
157 int setvaria(GtkWidget
*widget
)
159 // We want to reset the settings at least once to be sure.
160 // Things like sticky and below should be stored in the widget beforehand.
161 // Use the value of p itself, not what it points to.
162 // Following the C standard, we have to use an array to subtract pointers.
163 enum {rep
= 1,nrep
}; // must be >= 0, and is equal to the number of times the settings
164 // will be done when called more than once
165 static char something
[nrep
];
166 char *p
= (char *)g_object_get_data(G_OBJECT(widget
),"trans_done");
169 P("setvaria %p %p %d\n",p
,&something
,(int)(p
-&something
[0]));
170 if (p
- &something
[0] >= rep
)
173 g_object_set_data(G_OBJECT(widget
),"trans_done",p
);
175 P("setvaria %p %p %d\n",p
, (void *)widget
,(int)(p
- &something
[0]));
178 GdkWindow
*gdk_window1
= gtk_widget_get_window(widget
);
179 const int Usepassthru
= 0;
181 gdk_window_set_pass_through(gdk_window1
,TRUE
); // does not work as expected
184 cairo_region_t
*cairo_region1
= cairo_region_create();
185 gdk_window_input_shape_combine_region(gdk_window1
, cairo_region1
, 0,0);
186 cairo_region_destroy(cairo_region1
);
188 P("setvaria %d widget: %p gdkwin: %p passthru: %d\n",counter
++,(void *)widget
,(void *)gdk_window1
,gdk_window_get_pass_through(gdk_window1
));
191 if(!g_object_get_data(G_OBJECT(widget
),"trans_nobelow"))
193 if(g_object_get_data(G_OBJECT(widget
),"trans_below"))
194 setbelow(GTK_WINDOW(widget
));
196 setabove(GTK_WINDOW(widget
));
201 if(g_object_get_data(G_OBJECT(widget
),"trans_sticky"))
202 gtk_window_stick(GTK_WINDOW(widget
));
204 gtk_window_unstick(GTK_WINDOW(widget
));
211 // Force window below or above other windows.
212 // It appears that, to get a window below other windows, it can be necessary
213 // to do first the opposite, and then vice-versa.
214 // These codes are probably somewhat too exuberant ....
215 void setbelow(GtkWindow
*w
)
217 gtk_window_set_keep_above(GTK_WINDOW(w
), TRUE
);
218 gtk_window_set_keep_below(GTK_WINDOW(w
), TRUE
);
219 GdkWindow
*gdkw
= gtk_widget_get_window(GTK_WIDGET(w
));
220 Window xwin
= gdk_x11_window_get_xid(gdkw
);
221 XWindowChanges changes
;
222 changes
.stack_mode
= Below
;
223 Display
*display
= XOpenDisplay(NULL
);
224 XConfigureWindow(display
,xwin
,CWStackMode
,&changes
);
225 P("setbelow %#lx\n",xwin
);
226 XCloseDisplay(display
);
229 void setabove(GtkWindow
*w
)
231 gtk_window_set_keep_below(GTK_WINDOW(w
), TRUE
);
232 gtk_window_set_keep_above(GTK_WINDOW(w
), TRUE
);
233 GdkWindow
*gdkw
= gtk_widget_get_window(GTK_WIDGET(w
));
234 Window xwin
= gdk_x11_window_get_xid(gdkw
);
235 XWindowChanges changes
;
236 changes
.stack_mode
= Above
;
237 Display
*display
= XOpenDisplay(NULL
);
238 XConfigureWindow(display
,xwin
,CWStackMode
,&changes
);
239 P("setabove %#lx\n",xwin
);
240 XCloseDisplay(display
);