awesome-client send now everything in one message
[awesome.git] / ewmh.c
blob532f6e6ff28969c7b503f12fdcdb86a1ab30d70f
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 "widget.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 widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
269 client_resize(c, geometry, False);
270 XRaiseWindow(globalconf.display, c->win);
271 arrange(c->screen);
275 static void
276 ewmh_process_window_type_atom(Client *c, Atom state)
278 if(state == net_wm_window_type_normal)
280 /* do nothing. this is REALLY IMPORTANT */
282 else if(state == net_wm_window_type_dock
283 || state == net_wm_window_type_splash)
285 c->border = 0;
286 c->skip = True;
287 c->isfixed = True;
288 c->isfloating = True;
290 else if (state == net_wm_window_type_dialog)
291 c->isfloating = True;
293 void
294 ewmh_process_client_message(XClientMessageEvent *ev)
296 Client *c;
297 int screen;
299 if(ev->message_type == net_current_desktop)
300 for(screen = 0; screen < ScreenCount(globalconf.display); screen++)
301 if(ev->window == RootWindow(globalconf.display, screen))
302 tag_view(screen, ev->data.l[0]);
304 if(ev->message_type == net_close_window)
306 if((c = get_client_bywin(globalconf.clients, ev->window)))
307 client_kill(c);
309 else if(ev->message_type == net_wm_state)
311 if((c = get_client_bywin(globalconf.clients, ev->window)))
313 ewmh_process_state_atom(c, (Atom) ev->data.l[1], ev->data.l[0]);
314 if(ev->data.l[2])
315 ewmh_process_state_atom(c, (Atom) ev->data.l[2], ev->data.l[0]);
320 void
321 ewmh_check_client_hints(Client *c)
323 int format;
324 Atom real, *state;
325 unsigned char *data = NULL;
326 unsigned long i, n, extra;
328 if(XGetWindowProperty(globalconf.display, c->win, net_wm_state, 0L, LONG_MAX, False,
329 XA_ATOM, &real, &format, &n, &extra,
330 (unsigned char **) &data) == Success && data)
332 state = (Atom *) data;
333 for(i = 0; i < n; i++)
334 ewmh_process_state_atom(c, state[i], _NET_WM_STATE_ADD);
336 XFree(data);
339 if(XGetWindowProperty(globalconf.display, c->win, net_wm_window_type, 0L, LONG_MAX, False,
340 XA_ATOM, &real, &format, &n, &extra,
341 (unsigned char **) &data) == Success && data)
343 state = (Atom *) data;
344 for(i = 0; i < n; i++)
345 ewmh_process_window_type_atom(c, state[i]);
347 XFree(data);
351 NetWMIcon *
352 ewmh_get_window_icon(Window w)
354 NetWMIcon *icon;
355 Atom type;
356 int format, size, i;
357 unsigned long items, rest, *data, pixel;
358 unsigned char *imgdata, *wdata;
360 if(XGetWindowProperty(globalconf.display, w,
361 net_wm_icon, 0L, LONG_MAX, False, XA_CARDINAL, &type, &format,
362 &items, &rest, &wdata) != Success
363 || !wdata)
364 return NULL;
366 if(type != XA_CARDINAL || format != 32 || items < 2)
368 XFree(wdata);
369 return NULL;
372 icon = p_new(NetWMIcon, 1);
374 data = (unsigned long *) wdata;
376 icon->width = data[0];
377 icon->height = data[1];
378 size = icon->width * icon->height;
380 if(!size)
382 p_delete(&icon);
383 XFree(wdata);
384 return NULL;
387 icon->image = p_new(unsigned char, size * 4);
388 for(imgdata = icon->image, i = 2; i < size + 2; i++, imgdata += 4)
390 pixel = data[i];
391 imgdata[3] = (pixel >> 24) & 0xff; /* A */
392 imgdata[0] = (pixel >> 16) & 0xff; /* R */
393 imgdata[1] = (pixel >> 8) & 0xff; /* G */
394 imgdata[2] = pixel & 0xff; /* B */
397 XFree(wdata);
399 return icon;
402 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80