add support for _NET_WM_WINDOW_TYPE_DIALOG
[awesome.git] / ewmh.c
blobfabfaf5c97957791b141b6d6091be22744e148f5
1 /*
2 * ewmh.c - EWMH support functions
4 * Copyright © 2007-2008 Julien Danjou <julien@danjou.info>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include <X11/Xatom.h>
23 #include <X11/Xmd.h>
25 #include "ewmh.h"
26 #include "util.h"
27 #include "tag.h"
28 #include "focus.h"
29 #include "screen.h"
30 #include "client.h"
31 #include "statusbar.h"
33 extern AwesomeConf globalconf;
35 static Atom net_supported;
36 static Atom net_client_list;
37 static Atom net_number_of_desktops;
38 static Atom net_current_desktop;
39 static Atom net_desktop_names;
40 static Atom net_active_window;
42 static Atom net_close_window;
44 static Atom net_wm_name;
45 static Atom net_wm_icon_name;
46 static Atom net_wm_window_type;
47 static Atom net_wm_window_type_normal;
48 static Atom net_wm_window_type_dock;
49 static Atom net_wm_window_type_splash;
50 static Atom net_wm_window_type_dialog;
51 static Atom net_wm_icon;
52 static Atom net_wm_state;
53 static Atom net_wm_state_sticky;
54 static Atom net_wm_state_skip_taskbar;
55 static Atom net_wm_state_fullscreen;
57 static Atom utf8_string;
59 typedef struct
61 const char *name;
62 Atom *atom;
63 } AtomItem;
65 static AtomItem AtomNames[] =
67 { "_NET_SUPPORTED", &net_supported },
68 { "_NET_CLIENT_LIST", &net_client_list },
69 { "_NET_NUMBER_OF_DESKTOPS", &net_number_of_desktops },
70 { "_NET_CURRENT_DESKTOP", &net_current_desktop },
71 { "_NET_DESKTOP_NAMES", &net_desktop_names },
72 { "_NET_ACTIVE_WINDOW", &net_active_window },
74 { "_NET_CLOSE_WINDOW", &net_close_window },
76 { "_NET_WM_NAME", &net_wm_name },
77 { "_NET_WM_ICON_NAME", &net_wm_icon_name },
78 { "_NET_WM_WINDOW_TYPE", &net_wm_window_type },
79 { "_NET_WM_WINDOW_TYPE_NORMAL", &net_wm_window_type_normal },
80 { "_NET_WM_WINDOW_TYPE_DOCK", &net_wm_window_type_dock },
81 { "_NET_WM_WINDOW_TYPE_SPLASH", &net_wm_window_type_splash },
82 { "_NET_WM_WINDOW_TYPE_DIALOG", &net_wm_window_type_dialog },
83 { "_NET_WM_ICON", &net_wm_icon },
84 { "_NET_WM_STATE", &net_wm_state },
85 { "_NET_WM_STATE_STICKY", &net_wm_state_sticky },
86 { "_NET_WM_STATE_SKIP_TASKBAR", &net_wm_state_skip_taskbar },
87 { "_NET_WM_STATE_FULLSCREEN", &net_wm_state_fullscreen },
89 { "UTF8_STRING", &utf8_string },
92 #define ATOM_NUMBER (sizeof(AtomNames)/sizeof(AtomItem))
94 #define _NET_WM_STATE_REMOVE 0
95 #define _NET_WM_STATE_ADD 1
96 #define _NET_WM_STATE_TOGGLE 2
98 void
99 ewmh_init_atoms(void)
101 unsigned int i;
102 char *names[ATOM_NUMBER];
103 Atom atoms[ATOM_NUMBER];
105 for(i = 0; i < ATOM_NUMBER; i++)
106 names[i] = (char *) AtomNames[i].name;
107 XInternAtoms(globalconf.display, names, ATOM_NUMBER, False, atoms);
108 for(i = 0; i < ATOM_NUMBER; i++)
109 *AtomNames[i].atom = atoms[i];
112 void
113 ewmh_set_supported_hints(int phys_screen)
115 Atom atom[ATOM_NUMBER];
116 int i = 0;
118 atom[i++] = net_supported;
119 atom[i++] = net_client_list;
120 atom[i++] = net_number_of_desktops;
121 atom[i++] = net_current_desktop;
122 atom[i++] = net_desktop_names;
123 atom[i++] = net_active_window;
125 atom[i++] = net_close_window;
127 atom[i++] = net_wm_name;
128 atom[i++] = net_wm_icon_name;
129 atom[i++] = net_wm_window_type;
130 atom[i++] = net_wm_window_type_normal;
131 atom[i++] = net_wm_window_type_dock;
132 atom[i++] = net_wm_window_type_splash;
133 atom[i++] = net_wm_window_type_dialog;
134 atom[i++] = net_wm_icon;
135 atom[i++] = net_wm_state;
136 atom[i++] = net_wm_state_sticky;
137 atom[i++] = net_wm_state_skip_taskbar;
138 atom[i++] = net_wm_state_fullscreen;
140 XChangeProperty(globalconf.display, RootWindow(globalconf.display, phys_screen),
141 net_supported, XA_ATOM, 32,
142 PropModeReplace, (unsigned char *) atom, i);
145 void
146 ewmh_update_net_client_list(int phys_screen)
148 Window *wins;
149 Client *c;
150 int n = 0;
152 for(c = globalconf.clients; c; c = c->next)
153 if(get_phys_screen(c->screen) == phys_screen)
154 n++;
156 wins = p_new(Window, n + 1);
158 for(n = 0, c = globalconf.clients; c; c = c->next, n++)
159 if(get_phys_screen(c->screen) == phys_screen)
160 wins[n] = c->win;
162 XChangeProperty(globalconf.display, RootWindow(globalconf.display, phys_screen),
163 net_client_list, XA_WINDOW, 32, PropModeReplace, (unsigned char *) wins, n);
165 p_delete(&wins);
166 XFlush(globalconf.display);
169 void
170 ewmh_update_net_numbers_of_desktop(int phys_screen)
172 CARD32 count = 0;
173 Tag *tag;
175 for(tag = globalconf.screens[phys_screen].tags; tag; tag = tag->next)
176 count++;
178 XChangeProperty(globalconf.display, RootWindow(globalconf.display, phys_screen),
179 net_number_of_desktops, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &count, 1);
182 void
183 ewmh_update_net_current_desktop(int phys_screen)
185 CARD32 count = 0;
186 Tag *tag, **curtags = get_current_tags(phys_screen);
188 for(tag = globalconf.screens[phys_screen].tags; tag != curtags[0]; tag = tag->next)
189 count++;
191 XChangeProperty(globalconf.display, RootWindow(globalconf.display, phys_screen),
192 net_current_desktop, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &count, 1);
194 p_delete(&curtags);
197 void
198 ewmh_update_net_desktop_names(int phys_screen)
200 char buf[1024], *pos;
201 ssize_t len, curr_size;
202 Tag *tag;
204 pos = buf;
205 len = 0;
206 for(tag = globalconf.screens[phys_screen].tags; tag; tag = tag->next)
208 curr_size = a_strlen(tag->name);
209 a_strcpy(pos, sizeof(buf), tag->name);
210 pos += curr_size + 1;
211 len += curr_size + 1;
214 XChangeProperty(globalconf.display, RootWindow(globalconf.display, phys_screen),
215 net_desktop_names, utf8_string, 8, PropModeReplace, (unsigned char *) buf, len);
218 void
219 ewmh_update_net_active_window(int phys_screen)
221 Window win;
222 Client *sel = focus_get_current_client(phys_screen);
224 win = sel ? sel->win : None;
226 XChangeProperty(globalconf.display, RootWindow(globalconf.display, phys_screen),
227 net_active_window, XA_WINDOW, 32, PropModeReplace, (unsigned char *) &win, 1);
230 static void
231 ewmh_process_state_atom(Client *c, Atom state, int set)
233 if(state == net_wm_state_sticky)
235 Tag *tag;
236 for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next)
237 tag_client(c, tag);
239 else if(state == net_wm_state_skip_taskbar)
241 if(set == _NET_WM_STATE_REMOVE)
242 c->skiptb = False;
243 else if(set == _NET_WM_STATE_ADD)
244 c->skiptb = True;
246 else if(state == net_wm_state_fullscreen)
248 Area geometry;
249 if(set == _NET_WM_STATE_REMOVE)
251 /* restore geometry */
252 geometry = c->m_geometry;
253 c->border = c->oldborder;
254 c->ismax = False;
255 c->isfloating = c->wasfloating;
257 else if(set == _NET_WM_STATE_ADD)
259 geometry = get_screen_area(c->screen, NULL, NULL);
260 /* save geometry */
261 c->m_geometry = c->geometry;
262 c->wasfloating = c->isfloating;
263 c->oldborder = c->border;
264 c->border = 0;
265 c->ismax = True;
266 c->isfloating = True;
268 statusbar_draw_all(c->screen);
269 client_resize(c, geometry, False);
270 XRaiseWindow(globalconf.display, c->win);
274 static void
275 ewmh_process_window_type_atom(Client *c, Atom state)
277 if(state == net_wm_window_type_normal)
279 /* do nothing. this is REALLY IMPORTANT */
281 else if(state == net_wm_window_type_dock
282 || state == net_wm_window_type_splash)
284 c->border = 0;
285 c->skip = True;
286 c->isfixed = True;
287 c->isfloating = True;
289 else if (state == net_wm_window_type_dialog)
290 c->isfloating = True;
292 void
293 ewmh_process_client_message(XClientMessageEvent *ev)
295 Client *c;
296 int screen;
298 if(ev->message_type == net_current_desktop)
299 for(screen = 0; screen < ScreenCount(globalconf.display); screen++)
300 if(ev->window == RootWindow(globalconf.display, screen))
301 tag_view(screen, ev->data.l[0]);
303 if(ev->message_type == net_close_window)
305 if((c = get_client_bywin(globalconf.clients, ev->window)))
306 client_kill(c);
308 else if(ev->message_type == net_wm_state)
310 if((c = get_client_bywin(globalconf.clients, ev->window)))
312 ewmh_process_state_atom(c, (Atom) ev->data.l[1], ev->data.l[0]);
313 if(ev->data.l[2])
314 ewmh_process_state_atom(c, (Atom) ev->data.l[2], ev->data.l[0]);
319 void
320 ewmh_check_client_hints(Client *c)
322 int format;
323 Atom real, *state;
324 unsigned char *data = NULL;
325 unsigned long i, n, extra;
327 if(XGetWindowProperty(globalconf.display, c->win, net_wm_state, 0L, LONG_MAX, False,
328 XA_ATOM, &real, &format, &n, &extra,
329 (unsigned char **) &data) == Success && data)
331 state = (Atom *) data;
332 for(i = 0; i < n; i++)
333 ewmh_process_state_atom(c, state[i], _NET_WM_STATE_ADD);
335 XFree(data);
338 if(XGetWindowProperty(globalconf.display, c->win, net_wm_window_type, 0L, LONG_MAX, False,
339 XA_ATOM, &real, &format, &n, &extra,
340 (unsigned char **) &data) == Success && data)
342 state = (Atom *) data;
343 for(i = 0; i < n; i++)
344 ewmh_process_window_type_atom(c, state[i]);
346 XFree(data);
350 NetWMIcon *
351 ewmh_get_window_icon(Window w)
353 NetWMIcon *icon;
354 Atom type;
355 int format, size, i;
356 unsigned long items, rest, *data, pixel;
357 unsigned char *imgdata, *wdata;
359 if(XGetWindowProperty(globalconf.display, w,
360 net_wm_icon, 0L, LONG_MAX, False, XA_CARDINAL, &type, &format,
361 &items, &rest, &wdata) != Success
362 || !wdata)
363 return NULL;
365 if(type != XA_CARDINAL || format != 32 || items < 2)
367 XFree(wdata);
368 return NULL;
371 icon = p_new(NetWMIcon, 1);
373 data = (unsigned long *) wdata;
375 icon->width = data[0];
376 icon->height = data[1];
377 size = icon->width * icon->height;
379 if(!size)
381 p_delete(&icon);
382 XFree(wdata);
383 return NULL;
386 icon->image = p_new(unsigned char, size * 4);
387 for(imgdata = icon->image, i = 2; i < size + 2; i++, imgdata += 4)
389 pixel = data[i];
390 imgdata[3] = (pixel >> 24) & 0xff; /* A */
391 imgdata[0] = (pixel >> 16) & 0xff; /* R */
392 imgdata[1] = (pixel >> 8) & 0xff; /* G */
393 imgdata[2] = pixel & 0xff; /* B */
396 XFree(wdata);
398 return icon;
401 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80