change prev_selected
[awesome.git] / ewmh.c
blob13f142e1ff1a49e24222fff177f97c22eff4a829
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 "tag.h"
27 #include "focus.h"
28 #include "screen.h"
29 #include "client.h"
30 #include "widget.h"
32 extern AwesomeConf globalconf;
34 static Atom net_supported;
35 static Atom net_client_list;
36 static Atom net_number_of_desktops;
37 static Atom net_current_desktop;
38 static Atom net_desktop_names;
39 static Atom net_active_window;
41 static Atom net_close_window;
43 static Atom net_wm_name;
44 static Atom net_wm_icon_name;
45 static Atom net_wm_window_type;
46 static Atom net_wm_window_type_normal;
47 static Atom net_wm_window_type_dock;
48 static Atom net_wm_window_type_splash;
49 static Atom net_wm_window_type_dialog;
50 static Atom net_wm_icon;
51 static Atom net_wm_state;
52 static Atom net_wm_state_sticky;
53 static Atom net_wm_state_skip_taskbar;
54 static Atom net_wm_state_fullscreen;
56 static Atom utf8_string;
58 typedef struct
60 const char *name;
61 Atom *atom;
62 } AtomItem;
64 static AtomItem AtomNames[] =
66 { "_NET_SUPPORTED", &net_supported },
67 { "_NET_CLIENT_LIST", &net_client_list },
68 { "_NET_NUMBER_OF_DESKTOPS", &net_number_of_desktops },
69 { "_NET_CURRENT_DESKTOP", &net_current_desktop },
70 { "_NET_DESKTOP_NAMES", &net_desktop_names },
71 { "_NET_ACTIVE_WINDOW", &net_active_window },
73 { "_NET_CLOSE_WINDOW", &net_close_window },
75 { "_NET_WM_NAME", &net_wm_name },
76 { "_NET_WM_ICON_NAME", &net_wm_icon_name },
77 { "_NET_WM_WINDOW_TYPE", &net_wm_window_type },
78 { "_NET_WM_WINDOW_TYPE_NORMAL", &net_wm_window_type_normal },
79 { "_NET_WM_WINDOW_TYPE_DOCK", &net_wm_window_type_dock },
80 { "_NET_WM_WINDOW_TYPE_SPLASH", &net_wm_window_type_splash },
81 { "_NET_WM_WINDOW_TYPE_DIALOG", &net_wm_window_type_dialog },
82 { "_NET_WM_ICON", &net_wm_icon },
83 { "_NET_WM_STATE", &net_wm_state },
84 { "_NET_WM_STATE_STICKY", &net_wm_state_sticky },
85 { "_NET_WM_STATE_SKIP_TASKBAR", &net_wm_state_skip_taskbar },
86 { "_NET_WM_STATE_FULLSCREEN", &net_wm_state_fullscreen },
88 { "UTF8_STRING", &utf8_string },
91 #define ATOM_NUMBER (sizeof(AtomNames)/sizeof(AtomItem))
93 #define _NET_WM_STATE_REMOVE 0
94 #define _NET_WM_STATE_ADD 1
95 #define _NET_WM_STATE_TOGGLE 2
97 void
98 ewmh_init_atoms(void)
100 unsigned int i;
101 char *names[ATOM_NUMBER];
102 Atom atoms[ATOM_NUMBER];
104 for(i = 0; i < ATOM_NUMBER; i++)
105 names[i] = (char *) AtomNames[i].name;
106 XInternAtoms(globalconf.display, names, ATOM_NUMBER, False, atoms);
107 for(i = 0; i < ATOM_NUMBER; i++)
108 *AtomNames[i].atom = atoms[i];
111 void
112 ewmh_set_supported_hints(int phys_screen)
114 Atom atom[ATOM_NUMBER];
115 int i = 0;
117 atom[i++] = net_supported;
118 atom[i++] = net_client_list;
119 atom[i++] = net_number_of_desktops;
120 atom[i++] = net_current_desktop;
121 atom[i++] = net_desktop_names;
122 atom[i++] = net_active_window;
124 atom[i++] = net_close_window;
126 atom[i++] = net_wm_name;
127 atom[i++] = net_wm_icon_name;
128 atom[i++] = net_wm_window_type;
129 atom[i++] = net_wm_window_type_normal;
130 atom[i++] = net_wm_window_type_dock;
131 atom[i++] = net_wm_window_type_splash;
132 atom[i++] = net_wm_window_type_dialog;
133 atom[i++] = net_wm_icon;
134 atom[i++] = net_wm_state;
135 atom[i++] = net_wm_state_sticky;
136 atom[i++] = net_wm_state_skip_taskbar;
137 atom[i++] = net_wm_state_fullscreen;
139 XChangeProperty(globalconf.display, RootWindow(globalconf.display, phys_screen),
140 net_supported, XA_ATOM, 32,
141 PropModeReplace, (unsigned char *) atom, i);
144 void
145 ewmh_update_net_client_list(int phys_screen)
147 Window *wins;
148 Client *c;
149 int n = 0;
151 for(c = globalconf.clients; c; c = c->next)
152 if(get_phys_screen(c->screen) == phys_screen)
153 n++;
155 wins = p_new(Window, n + 1);
157 for(n = 0, c = globalconf.clients; c; c = c->next, n++)
158 if(get_phys_screen(c->screen) == phys_screen)
159 wins[n] = c->win;
161 XChangeProperty(globalconf.display, RootWindow(globalconf.display, phys_screen),
162 net_client_list, XA_WINDOW, 32, PropModeReplace, (unsigned char *) wins, n);
164 p_delete(&wins);
165 XFlush(globalconf.display);
168 void
169 ewmh_update_net_numbers_of_desktop(int phys_screen)
171 CARD32 count = 0;
172 Tag *tag;
174 for(tag = globalconf.screens[phys_screen].tags; tag; tag = tag->next)
175 count++;
177 XChangeProperty(globalconf.display, RootWindow(globalconf.display, phys_screen),
178 net_number_of_desktops, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &count, 1);
181 void
182 ewmh_update_net_current_desktop(int phys_screen)
184 CARD32 count = 0;
185 Tag *tag, **curtags = tags_get_current(phys_screen);
187 for(tag = globalconf.screens[phys_screen].tags; tag != curtags[0]; tag = tag->next)
188 count++;
190 XChangeProperty(globalconf.display, RootWindow(globalconf.display, phys_screen),
191 net_current_desktop, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &count, 1);
193 p_delete(&curtags);
196 void
197 ewmh_update_net_desktop_names(int phys_screen)
199 char buf[1024], *pos;
200 ssize_t len, curr_size;
201 Tag *tag;
203 pos = buf;
204 len = 0;
205 for(tag = globalconf.screens[phys_screen].tags; tag; tag = tag->next)
207 curr_size = a_strlen(tag->name);
208 a_strcpy(pos, sizeof(buf), tag->name);
209 pos += curr_size + 1;
210 len += curr_size + 1;
213 XChangeProperty(globalconf.display, RootWindow(globalconf.display, phys_screen),
214 net_desktop_names, utf8_string, 8, PropModeReplace, (unsigned char *) buf, len);
217 void
218 ewmh_update_net_active_window(int phys_screen)
220 Window win;
221 Client *sel = focus_get_current_client(phys_screen);
223 win = sel ? sel->win : None;
225 XChangeProperty(globalconf.display, RootWindow(globalconf.display, phys_screen),
226 net_active_window, XA_WINDOW, 32, PropModeReplace, (unsigned char *) &win, 1);
229 static void
230 ewmh_process_state_atom(Client *c, Atom state, int set)
232 if(state == net_wm_state_sticky)
234 Tag *tag;
235 for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next)
236 tag_client(c, tag);
238 else if(state == net_wm_state_skip_taskbar)
240 if(set == _NET_WM_STATE_REMOVE)
242 c->skiptb = False;
243 c->border = c->oldborder;
245 else if(set == _NET_WM_STATE_ADD)
247 c->skiptb = True;
248 c->oldborder = c->border;
249 c->border = 0;
252 else if(state == net_wm_state_fullscreen)
254 Area geometry = c->geometry;
255 if(set == _NET_WM_STATE_REMOVE)
257 /* restore geometry */
258 geometry = c->m_geometry;
259 c->border = c->oldborder;
260 c->ismax = False;
261 client_setfloating(c, c->wasfloating);
263 else if(set == _NET_WM_STATE_ADD)
265 geometry = screen_get_area(c->screen, NULL, &globalconf.screens[c->screen].padding);
266 /* save geometry */
267 c->m_geometry = c->geometry;
268 c->wasfloating = c->isfloating;
269 c->oldborder = c->border;
270 c->border = 0;
271 c->ismax = True;
272 client_setfloating(c, True);
274 widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
275 client_resize(c, geometry, False);
276 XRaiseWindow(globalconf.display, c->win);
280 static void
281 ewmh_process_window_type_atom(Client *c, Atom state)
283 if(state == net_wm_window_type_normal)
285 /* do nothing. this is REALLY IMPORTANT */
287 else if(state == net_wm_window_type_dock
288 || state == net_wm_window_type_splash)
290 c->border = 0;
291 c->skip = True;
292 c->isfixed = True;
293 client_setfloating(c, True);
295 else if (state == net_wm_window_type_dialog)
296 client_setfloating(c, True);
298 void
299 ewmh_process_client_message(XClientMessageEvent *ev)
301 Client *c;
302 int screen;
304 if(ev->message_type == net_current_desktop)
305 for(screen = 0; screen < ScreenCount(globalconf.display); screen++)
306 if(ev->window == RootWindow(globalconf.display, screen))
307 tag_view_only_byindex(screen, ev->data.l[0]);
309 if(ev->message_type == net_close_window)
311 if((c = client_get_bywin(globalconf.clients, ev->window)))
312 client_kill(c);
314 else if(ev->message_type == net_wm_state)
316 if((c = client_get_bywin(globalconf.clients, ev->window)))
318 ewmh_process_state_atom(c, (Atom) ev->data.l[1], ev->data.l[0]);
319 if(ev->data.l[2])
320 ewmh_process_state_atom(c, (Atom) ev->data.l[2], ev->data.l[0]);
325 void
326 ewmh_check_client_hints(Client *c)
328 int format;
329 Atom real, *state;
330 unsigned char *data = NULL;
331 unsigned long i, n, extra;
333 if(XGetWindowProperty(globalconf.display, c->win, net_wm_state, 0L, LONG_MAX, False,
334 XA_ATOM, &real, &format, &n, &extra,
335 (unsigned char **) &data) == Success && data)
337 state = (Atom *) data;
338 for(i = 0; i < n; i++)
339 ewmh_process_state_atom(c, state[i], _NET_WM_STATE_ADD);
341 XFree(data);
344 if(XGetWindowProperty(globalconf.display, c->win, net_wm_window_type, 0L, LONG_MAX, False,
345 XA_ATOM, &real, &format, &n, &extra,
346 (unsigned char **) &data) == Success && data)
348 state = (Atom *) data;
349 for(i = 0; i < n; i++)
350 ewmh_process_window_type_atom(c, state[i]);
352 XFree(data);
356 NetWMIcon *
357 ewmh_get_window_icon(Window w)
359 NetWMIcon *icon;
360 Atom type;
361 int format, size, i;
362 unsigned long items, rest, *data, pixel;
363 unsigned char *imgdata, *wdata;
365 if(XGetWindowProperty(globalconf.display, w,
366 net_wm_icon, 0L, LONG_MAX, False, XA_CARDINAL, &type, &format,
367 &items, &rest, &wdata) != Success
368 || !wdata)
369 return NULL;
371 if(type != XA_CARDINAL || format != 32 || items < 2)
373 XFree(wdata);
374 return NULL;
377 icon = p_new(NetWMIcon, 1);
379 data = (unsigned long *) wdata;
381 icon->width = data[0];
382 icon->height = data[1];
383 size = icon->width * icon->height;
385 if(!size)
387 p_delete(&icon);
388 XFree(wdata);
389 return NULL;
392 icon->image = p_new(unsigned char, size * 4);
393 for(imgdata = icon->image, i = 2; i < size + 2; i++, imgdata += 4)
395 pixel = data[i];
396 imgdata[3] = (pixel >> 24) & 0xff; /* A */
397 imgdata[0] = (pixel >> 16) & 0xff; /* R */
398 imgdata[1] = (pixel >> 8) & 0xff; /* G */
399 imgdata[2] = pixel & 0xff; /* B */
402 XFree(wdata);
404 return icon;
407 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80