New upstream version 3.1.1
[xfishtank.git] / src / transwindow.c
1 /* -copyright-
2 #-# Copyright © 2021 Eric Bina, Dave Black, TJ Phan,
3 #-# Vincent Renardias, Willem Vermin
4 #-#
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
12 #-# conditions:
13 #-#
14 #-# The above copyright notice and this permission notice shall
15 #-# be included in all copies or substantial portions of the Software.
16 #-#
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.
25 #-#
26 */
27 #include <gtk/gtk.h>
28 #include <gdk/gdkx.h>
29 #include <X11/Intrinsic.h>
30 #include "transwindow.h"
31 #include "debug.h"
32
33
34 static int setvaria(GtkWidget *widget);
35
36 /*
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
50 */
51 int make_trans_window(GtkWidget *transwindow, int fullscreen, int sticky, int below, int dock,
52 GdkWindow **gdk_window, Window *x11_window)
53 {
54 if(gdk_window)
55 *gdk_window = NULL;
56 if(x11_window)
57 *x11_window = 0;
58
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);
62
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);
67
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);
70
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");
76
77
78 static char somechar;
79 if (sticky)
80 g_object_set_data(G_OBJECT(transwindow),"trans_sticky",&somechar);
81
82 switch(below)
83 {
84 case 0:
85 g_object_set_data(G_OBJECT(transwindow),"trans_nobelow",&somechar);
86 break;
87 case 1:
88 g_object_set_data(G_OBJECT(transwindow),"trans_below",&somechar);
89 break;
90 }
91
92 /* To check if the display supports alpha channels, get the visual */
93 GdkScreen *screen = gtk_widget_get_screen(transwindow);
94
95 if (!gdk_screen_is_composited(screen))
96 {
97 P("No alpha\n");
98 gtk_window_close(GTK_WINDOW(transwindow));
99 return FALSE;
100 }
101
102 // Ensure the widget (the window, actually) can take RGBA
103 gtk_widget_set_visual(transwindow, gdk_screen_get_rgba_visual(screen));
104
105 // set full screen if so desired:
106 if(fullscreen)
107 {
108 P("fullscreen\n");
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);
114 }
115 else
116 {
117 P("NOT fullsscreen\n");
118 }
119
120 gtk_widget_show_all(transwindow);
121 GdkWindow *gdkwin = gtk_widget_get_window(GTK_WIDGET(transwindow));
122
123 // so that apps like xsnow will ignore this window:
124 if(dock)
125 gdk_window_set_type_hint(gdkwin,GDK_WINDOW_TYPE_HINT_DOCK);
126
127 gdk_window_hide(gdkwin);
128 if(fullscreen)
129 gdk_window_move(gdkwin,0,0);
130 gdk_window_show(gdkwin);
131
132 if (x11_window)
133 *x11_window = gdk_x11_window_get_xid(gdkwin);
134 if (gdk_window)
135 *gdk_window = gdkwin;
136
137 usleep(200000); // seems sometimes to be necessary with nvidia
138
139 // just to be sure all settings are communicated with the server
140 gtk_widget_hide(transwindow);
141 gtk_widget_show_all(transwindow);
142
143 // set some things, but note that this has to be repeated in the gkt_main loop.
144
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");
149
150 return TRUE;
151 }
152
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.
156 //
157 int setvaria(GtkWidget *widget)
158 {
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");
167 if (!p)
168 p = &something[0];
169 P("setvaria %p %p %d\n",p,&something,(int)(p-&something[0]));
170 if (p - &something[0] >= rep)
171 return FALSE;
172 p++;
173 g_object_set_data(G_OBJECT(widget),"trans_done",p);
174
175 P("setvaria %p %p %d\n",p, (void *)widget,(int)(p - &something[0]));
176
177
178 GdkWindow *gdk_window1 = gtk_widget_get_window(widget);
179 const int Usepassthru = 0;
180 if(Usepassthru)
181 gdk_window_set_pass_through(gdk_window1,TRUE); // does not work as expected
182 else
183 {
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);
187 }
188 P("setvaria %d widget: %p gdkwin: %p passthru: %d\n",counter++,(void *)widget,(void *)gdk_window1,gdk_window_get_pass_through(gdk_window1));
189
190
191 if(!g_object_get_data(G_OBJECT(widget),"trans_nobelow"))
192 {
193 if(g_object_get_data(G_OBJECT(widget),"trans_below"))
194 setbelow(GTK_WINDOW(widget));
195 else
196 setabove(GTK_WINDOW(widget));
197 }
198
199 if(1)
200 {
201 if(g_object_get_data(G_OBJECT(widget),"trans_sticky"))
202 gtk_window_stick(GTK_WINDOW(widget));
203 else
204 gtk_window_unstick(GTK_WINDOW(widget));
205 }
206
207 return FALSE;
208 }
209
210
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)
216 {
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);
227 }
228
229 void setabove(GtkWindow *w)
230 {
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);
241 }
This page took 0.029012 seconds and 4 git commands to generate.