Mercurial > audlegacy
comparison audacious/hints.c @ 0:cb178e5ad177 trunk
[svn] Import audacious source.
author | nenolod |
---|---|
date | Mon, 24 Oct 2005 03:06:47 -0700 |
parents | |
children | 5c457dac866a |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:cb178e5ad177 |
---|---|
1 /* BMP - Cross-platform multimedia player | |
2 * Copyright (C) 2003-2004 BMP development team. | |
3 * | |
4 * Based on XMMS: | |
5 * Copyright (C) 1998-2003 XMMS development team. | |
6 * | |
7 * This program is free software; you can redistribute it and/or modify | |
8 * it under the terms of the GNU General Public License as published by | |
9 * the Free Software Foundation; either version 2 of the License, or | |
10 * (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 * GNU General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU General Public License | |
18 * along with this program; if not, write to the Free Software | |
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
20 */ | |
21 | |
22 #include "hints.h" | |
23 | |
24 #include <glib.h> | |
25 #include <gtk/gtk.h> | |
26 | |
27 #include "equalizer.h" | |
28 #include "mainwin.h" | |
29 #include "playlistwin.h" | |
30 | |
31 #include <gdk/gdkx.h> | |
32 #include <gdk/gdkprivate.h> | |
33 #include <X11/Xlib.h> | |
34 #include <X11/Xmd.h> | |
35 #include <X11/Xatom.h> | |
36 | |
37 /* flags for the window layer */ | |
38 typedef enum { | |
39 WIN_LAYER_DESKTOP = 0, | |
40 WIN_LAYER_BELOW = 2, | |
41 WIN_LAYER_NORMAL = 4, | |
42 WIN_LAYER_ONTOP = 6, | |
43 WIN_LAYER_DOCK = 8, | |
44 WIN_LAYER_ABOVE_DOCK = 10 | |
45 } WinLayer; | |
46 | |
47 #define WIN_STATE_STICKY (1 << 0) | |
48 | |
49 #define WIN_HINTS_SKIP_WINLIST (1 << 1) /* not in win list */ | |
50 #define WIN_HINTS_SKIP_TASKBAR (1 << 2) /* not on taskbar */ | |
51 | |
52 #define _NET_WM_STATE_REMOVE 0 | |
53 #define _NET_WM_STATE_ADD 1 | |
54 #define _NET_WM_STATE_TOGGLE 2 | |
55 | |
56 #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 | |
57 #define _NET_WM_MOVERESIZE_SIZE_TOP 1 | |
58 #define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 | |
59 #define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 | |
60 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 | |
61 #define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 | |
62 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 | |
63 #define _NET_WM_MOVERESIZE_SIZE_LEFT 7 | |
64 #define _NET_WM_MOVERESIZE_MOVE 8 | |
65 | |
66 | |
67 static void (*set_always_func) (GtkWidget *, gboolean) = NULL; | |
68 static void (*set_sticky_func) (GtkWidget *, gboolean) = NULL; | |
69 static void (*set_skip_winlist_func) (GtkWidget *) = NULL; | |
70 static void (*move_resize_func) (GtkWidget *, gint, gint, gboolean) = NULL; | |
71 | |
72 void | |
73 hint_set_skip_winlist(GtkWidget * window) | |
74 { | |
75 if (set_skip_winlist_func) | |
76 set_skip_winlist_func(window); | |
77 } | |
78 | |
79 void | |
80 hint_set_always(gboolean always) | |
81 { | |
82 if (set_always_func) { | |
83 set_always_func(mainwin, always); | |
84 set_always_func(equalizerwin, always); | |
85 set_always_func(playlistwin, always); | |
86 } | |
87 } | |
88 | |
89 gboolean | |
90 hint_always_on_top_available(void) | |
91 { | |
92 return !!set_always_func; | |
93 } | |
94 | |
95 void | |
96 hint_set_sticky(gboolean sticky) | |
97 { | |
98 if (sticky) { | |
99 gtk_window_stick(GTK_WINDOW(mainwin)); | |
100 gtk_window_stick(GTK_WINDOW(equalizerwin)); | |
101 gtk_window_stick(GTK_WINDOW(playlistwin)); | |
102 } | |
103 else { | |
104 gtk_window_unstick(GTK_WINDOW(mainwin)); | |
105 gtk_window_unstick(GTK_WINDOW(equalizerwin)); | |
106 gtk_window_unstick(GTK_WINDOW(playlistwin)); | |
107 } | |
108 } | |
109 | |
110 gboolean | |
111 hint_move_resize_available(void) | |
112 { | |
113 return !!move_resize_func; | |
114 } | |
115 | |
116 void | |
117 hint_move_resize(GtkWidget * window, gint x, gint y, gboolean move) | |
118 { | |
119 move_resize_func(window, x, y, move); | |
120 } | |
121 | |
122 static gboolean | |
123 net_wm_found(void) | |
124 { | |
125 Atom r_type, support_check; | |
126 gint r_format, p; | |
127 gulong count, bytes_remain; | |
128 guchar *prop = NULL, *prop2 = NULL; | |
129 gboolean ret = FALSE; | |
130 | |
131 gdk_error_trap_push(); | |
132 support_check = | |
133 XInternAtom(GDK_DISPLAY(), "_NET_SUPPORTING_WM_CHECK", FALSE); | |
134 | |
135 p = XGetWindowProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), support_check, | |
136 0, 1, False, XA_WINDOW, &r_type, &r_format, | |
137 &count, &bytes_remain, &prop); | |
138 | |
139 if (p == Success && prop && r_type == XA_WINDOW && | |
140 r_format == 32 && count == 1) { | |
141 Window n = *(Window *) prop; | |
142 | |
143 p = XGetWindowProperty(GDK_DISPLAY(), n, support_check, 0, 1, | |
144 False, XA_WINDOW, &r_type, &r_format, | |
145 &count, &bytes_remain, &prop2); | |
146 | |
147 if (p == Success && prop2 && *prop2 == *prop && | |
148 r_type == XA_WINDOW && r_format == 32 && count == 1) | |
149 ret = TRUE; | |
150 } | |
151 | |
152 if (prop) | |
153 XFree(prop); | |
154 if (prop2) | |
155 XFree(prop2); | |
156 if (gdk_error_trap_pop()) | |
157 return FALSE; | |
158 return ret; | |
159 } | |
160 | |
161 static void | |
162 net_wm_set_property(GtkWidget * window, gchar * atom, gboolean state) | |
163 { | |
164 XEvent xev; | |
165 gint set = _NET_WM_STATE_ADD; | |
166 Atom type, property; | |
167 | |
168 if (state == FALSE) | |
169 set = _NET_WM_STATE_REMOVE; | |
170 | |
171 type = XInternAtom(GDK_DISPLAY(), "_NET_WM_STATE", FALSE); | |
172 property = XInternAtom(GDK_DISPLAY(), atom, FALSE); | |
173 | |
174 | |
175 xev.type = ClientMessage; | |
176 xev.xclient.type = ClientMessage; | |
177 xev.xclient.window = GDK_WINDOW_XWINDOW(window->window); | |
178 xev.xclient.message_type = type; | |
179 xev.xclient.format = 32; | |
180 xev.xclient.data.l[0] = set; | |
181 xev.xclient.data.l[1] = property; | |
182 xev.xclient.data.l[2] = 0; | |
183 | |
184 XSendEvent(GDK_DISPLAY(), GDK_ROOT_WINDOW(), False, | |
185 SubstructureNotifyMask, &xev); | |
186 } | |
187 | |
188 static void | |
189 net_wm_set_desktop(GtkWidget * window, gboolean all) | |
190 { | |
191 XEvent xev; | |
192 guint32 current_desktop = 0; | |
193 | |
194 if (!all) { | |
195 gint r_format, p; | |
196 gulong count, bytes_remain; | |
197 guchar *prop; | |
198 Atom r_type; | |
199 Atom current = | |
200 XInternAtom(GDK_DISPLAY(), "_NET_CURRENT_DESKTOP", FALSE); | |
201 | |
202 p = XGetWindowProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), current, | |
203 0, 1, False, XA_CARDINAL, &r_type, | |
204 &r_format, &count, &bytes_remain, &prop); | |
205 | |
206 if (p == Success && prop && r_type == XA_CARDINAL && | |
207 r_format == 32 && count == 1) { | |
208 current_desktop = *(long *) prop; | |
209 XFree(prop); | |
210 } | |
211 } | |
212 else | |
213 current_desktop = 0xffffffff; | |
214 | |
215 xev.type = ClientMessage; | |
216 xev.xclient.type = ClientMessage; | |
217 xev.xclient.window = GDK_WINDOW_XWINDOW(window->window); | |
218 xev.xclient.message_type = | |
219 XInternAtom(GDK_DISPLAY(), "_NET_WM_DESKTOP", FALSE); | |
220 xev.xclient.format = 32; | |
221 xev.xclient.data.l[0] = current_desktop; | |
222 | |
223 XSendEvent(GDK_DISPLAY(), GDK_ROOT_WINDOW(), False, | |
224 SubstructureNotifyMask, &xev); | |
225 } | |
226 | |
227 | |
228 | |
229 static void | |
230 net_wm_set_window_always(GtkWidget * window, gboolean always) | |
231 { | |
232 net_wm_set_property(window, "_NET_WM_STATE_STAYS_ON_TOP", always); | |
233 } | |
234 | |
235 static void | |
236 net_wm_set_window_above(GtkWidget * window, gboolean always) | |
237 { | |
238 net_wm_set_property(window, "_NET_WM_STATE_ABOVE", always); | |
239 } | |
240 | |
241 static void | |
242 net_wm_move_resize(GtkWidget * window, gint x, gint y, gboolean move) | |
243 { | |
244 XEvent xev; | |
245 gint dir; | |
246 Atom type; | |
247 | |
248 if (move) | |
249 dir = _NET_WM_MOVERESIZE_MOVE; | |
250 else | |
251 dir = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT; | |
252 | |
253 gdk_pointer_ungrab(GDK_CURRENT_TIME); | |
254 | |
255 type = XInternAtom(GDK_DISPLAY(), "_NET_WM_MOVERESIZE", FALSE); | |
256 | |
257 xev.type = ClientMessage; | |
258 xev.xclient.type = ClientMessage; | |
259 xev.xclient.window = GDK_WINDOW_XWINDOW(window->window); | |
260 xev.xclient.message_type = type; | |
261 xev.xclient.format = 32; | |
262 xev.xclient.data.l[0] = x; | |
263 xev.xclient.data.l[1] = y; | |
264 xev.xclient.data.l[2] = dir; | |
265 xev.xclient.data.l[3] = 1; /* button */ | |
266 | |
267 | |
268 XSendEvent(GDK_DISPLAY(), GDK_ROOT_WINDOW(), False, | |
269 SubstructureNotifyMask, &xev); | |
270 } | |
271 | |
272 static gboolean | |
273 find_atom(Atom * atoms, gint n, const gchar * name) | |
274 { | |
275 Atom a = XInternAtom(GDK_DISPLAY(), name, FALSE); | |
276 gint i; | |
277 | |
278 for (i = 0; i < n; i++) | |
279 if (a == atoms[i]) | |
280 return TRUE; | |
281 return FALSE; | |
282 } | |
283 | |
284 static gboolean | |
285 get_supported_atoms(Atom ** atoms, gulong * natoms, const gchar * name) | |
286 { | |
287 Atom supported = XInternAtom(GDK_DISPLAY(), name, FALSE), r_type; | |
288 gulong bremain; | |
289 gint r_format, p; | |
290 | |
291 *atoms = NULL; | |
292 gdk_error_trap_push(); | |
293 p = XGetWindowProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), supported, | |
294 0, 1000, False, XA_ATOM, &r_type, &r_format, | |
295 natoms, &bremain, (guchar **) atoms); | |
296 if (gdk_error_trap_pop() || p != Success || r_type != XA_ATOM || | |
297 *natoms == 0 || *atoms == NULL) | |
298 return FALSE; | |
299 | |
300 return TRUE; | |
301 } | |
302 | |
303 static void | |
304 net_wm_check_features(void) | |
305 { | |
306 Atom *atoms; | |
307 gulong n_atoms; | |
308 | |
309 if (!get_supported_atoms(&atoms, &n_atoms, "_NET_SUPPORTED")) | |
310 return; | |
311 | |
312 if (find_atom(atoms, n_atoms, "_NET_WM_STATE")) { | |
313 if (!set_always_func && | |
314 find_atom(atoms, n_atoms, "_NET_WM_STATE_ABOVE")) | |
315 set_always_func = net_wm_set_window_above; | |
316 if (!set_always_func && | |
317 find_atom(atoms, n_atoms, "_NET_WM_STATE_STAYS_ON_TOP")) | |
318 set_always_func = net_wm_set_window_always; | |
319 if (!set_sticky_func && find_atom(atoms, n_atoms, "_NET_WM_DESKTOP")) | |
320 set_sticky_func = net_wm_set_desktop; | |
321 } | |
322 | |
323 if (find_atom(atoms, n_atoms, "_NET_WM_MOVERESIZE")) | |
324 move_resize_func = net_wm_move_resize; | |
325 | |
326 XFree(atoms); | |
327 } | |
328 | |
329 void | |
330 check_wm_hints(void) | |
331 { | |
332 if (net_wm_found()) { | |
333 g_message("found NET_WM"); | |
334 net_wm_check_features(); | |
335 } | |
336 | |
337 } |