adding option 'x' and 'y' and general cleanup
[awesome.git] / ewmh.c
blob767a57405c79de52ce05907a6cd07077af7041b5
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"
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_icon;
50 static Atom net_wm_state;
51 static Atom net_wm_state_sticky;
52 static Atom net_wm_state_skip_taskbar;
53 static Atom net_wm_state_fullscreen;
55 static Atom utf8_string;
57 typedef struct
59 const char *name;
60 Atom *atom;
61 } AtomItem;
63 static AtomItem AtomNames[] =
65 { "_NET_SUPPORTED", &net_supported },
66 { "_NET_CLIENT_LIST", &net_client_list },
67 { "_NET_NUMBER_OF_DESKTOPS", &net_number_of_desktops },
68 { "_NET_CURRENT_DESKTOP", &net_current_desktop },
69 { "_NET_DESKTOP_NAMES", &net_desktop_names },
70 { "_NET_ACTIVE_WINDOW", &net_active_window },
72 { "_NET_CLOSE_WINDOW", &net_close_window },
74 { "_NET_WM_NAME", &net_wm_name },
75 { "_NET_WM_ICON_NAME", &net_wm_icon_name },
76 { "_NET_WM_WINDOW_TYPE", &net_wm_window_type },
77 { "_NET_WM_WINDOW_TYPE_NORMAL", &net_wm_window_type_normal },
78 { "_NET_WM_WINDOW_TYPE_DOCK", &net_wm_window_type_dock },
79 { "_NET_WM_WINDOW_TYPE_SPLASH", &net_wm_window_type_splash },
80 { "_NET_WM_ICON", &net_wm_icon },
81 { "_NET_WM_STATE", &net_wm_state },
82 { "_NET_WM_STATE_STICKY", &net_wm_state_sticky },
83 { "_NET_WM_STATE_SKIP_TASKBAR", &net_wm_state_skip_taskbar },
84 { "_NET_WM_STATE_FULLSCREEN", &net_wm_state_fullscreen },
86 { "UTF8_STRING", &utf8_string },
89 #define ATOM_NUMBER (sizeof(AtomNames)/sizeof(AtomItem))
91 #define _NET_WM_STATE_REMOVE 0
92 #define _NET_WM_STATE_ADD 1
93 #define _NET_WM_STATE_TOGGLE 2
95 void
96 ewmh_init_atoms(void)
98 unsigned int i;
99 char *names[ATOM_NUMBER];
100 Atom atoms[ATOM_NUMBER];
102 for(i = 0; i < ATOM_NUMBER; i++)
103 names[i] = (char *) AtomNames[i].name;
104 XInternAtoms(globalconf.display, names, ATOM_NUMBER, False, atoms);
105 for(i = 0; i < ATOM_NUMBER; i++)
106 *AtomNames[i].atom = atoms[i];
109 void
110 ewmh_set_supported_hints(int phys_screen)
112 Atom atom[ATOM_NUMBER];
113 int i = 0;
115 atom[i++] = net_supported;
116 atom[i++] = net_client_list;
117 atom[i++] = net_number_of_desktops;
118 atom[i++] = net_current_desktop;
119 atom[i++] = net_desktop_names;
120 atom[i++] = net_active_window;
122 atom[i++] = net_close_window;
124 atom[i++] = net_wm_name;
125 atom[i++] = net_wm_icon_name;
126 atom[i++] = net_wm_window_type;
127 atom[i++] = net_wm_window_type_normal;
128 atom[i++] = net_wm_window_type_dock;
129 atom[i++] = net_wm_window_type_splash;
130 atom[i++] = net_wm_icon;
131 atom[i++] = net_wm_state;
132 atom[i++] = net_wm_state_sticky;
133 atom[i++] = net_wm_state_skip_taskbar;
134 atom[i++] = net_wm_state_fullscreen;
136 XChangeProperty(globalconf.display, RootWindow(globalconf.display, phys_screen),
137 net_supported, XA_ATOM, 32,
138 PropModeReplace, (unsigned char *) atom, i);
141 void
142 ewmh_update_net_client_list(int phys_screen)
144 Window *wins;
145 Client *c;
146 int n = 0;
148 for(c = globalconf.clients; c; c = c->next)
149 if(get_phys_screen(c->screen) == phys_screen)
150 n++;
152 wins = p_new(Window, n + 1);
154 for(n = 0, c = globalconf.clients; c; c = c->next, n++)
155 if(get_phys_screen(c->screen) == phys_screen)
156 wins[n] = c->win;
158 XChangeProperty(globalconf.display, RootWindow(globalconf.display, phys_screen),
159 net_client_list, XA_WINDOW, 32, PropModeReplace, (unsigned char *) wins, n);
161 p_delete(&wins);
162 XFlush(globalconf.display);
165 void
166 ewmh_update_net_numbers_of_desktop(int phys_screen)
168 CARD32 count = 0;
169 Tag *tag;
171 for(tag = globalconf.screens[phys_screen].tags; tag; tag = tag->next)
172 count++;
174 XChangeProperty(globalconf.display, RootWindow(globalconf.display, phys_screen),
175 net_number_of_desktops, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &count, 1);
178 void
179 ewmh_update_net_current_desktop(int phys_screen)
181 CARD32 count = 0;
182 Tag *tag, **curtags = get_current_tags(phys_screen);
184 for(tag = globalconf.screens[phys_screen].tags; tag != curtags[0]; tag = tag->next)
185 count++;
187 XChangeProperty(globalconf.display, RootWindow(globalconf.display, phys_screen),
188 net_current_desktop, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &count, 1);
190 p_delete(&curtags);
193 void
194 ewmh_update_net_desktop_names(int phys_screen)
196 char buf[1024], *pos;
197 ssize_t len, curr_size;
198 Tag *tag;
200 pos = buf;
201 len = 0;
202 for(tag = globalconf.screens[phys_screen].tags; tag; tag = tag->next)
204 curr_size = a_strlen(tag->name);
205 a_strcpy(pos, sizeof(buf), tag->name);
206 pos += curr_size + 1;
207 len += curr_size + 1;
210 XChangeProperty(globalconf.display, RootWindow(globalconf.display, phys_screen),
211 net_desktop_names, utf8_string, 8, PropModeReplace, (unsigned char *) buf, len);
214 void
215 ewmh_update_net_active_window(int phys_screen)
217 Window win;
218 Client *sel = focus_get_current_client(phys_screen);
220 win = sel ? sel->win : None;
222 XChangeProperty(globalconf.display, RootWindow(globalconf.display, phys_screen),
223 net_active_window, XA_WINDOW, 32, PropModeReplace, (unsigned char *) &win, 1);
226 static void
227 ewmh_process_state_atom(Client *c, Atom state, int set)
229 if(state == net_wm_state_sticky)
231 Tag *tag;
232 for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next)
233 tag_client(c, tag);
235 else if(state == net_wm_state_skip_taskbar)
237 if(set == _NET_WM_STATE_REMOVE)
238 c->skiptb = False;
239 else if(set == _NET_WM_STATE_ADD)
240 c->skiptb = True;
242 else if(state == net_wm_state_fullscreen)
244 Area area = get_screen_area(c->screen, NULL, NULL);
245 /* reset max attribute */
246 if(set == _NET_WM_STATE_REMOVE)
247 c->ismax = True;
248 else if(set == _NET_WM_STATE_ADD)
249 c->ismax = False;
250 client_maximize(c, area.x, area.y, area.width, area.height, True);
254 static void
255 ewmh_process_window_type_atom(Client *c, Atom state)
257 if(state == net_wm_window_type_normal)
259 /* do nothing */
261 else if(state == net_wm_window_type_dock
262 || state == net_wm_window_type_splash)
264 c->border = 0;
265 c->skip = True;
266 c->isfixed = True;
267 c->isfloating = True;
270 void
271 ewmh_process_client_message(XClientMessageEvent *ev)
273 Client *c;
274 int screen;
276 if(ev->message_type == net_current_desktop)
277 for(screen = 0; screen < ScreenCount(globalconf.display); screen++)
278 if(ev->window == RootWindow(globalconf.display, screen))
279 tag_view(screen, ev->data.l[0]);
281 if(ev->message_type == net_close_window)
283 if((c = get_client_bywin(globalconf.clients, ev->window)))
284 client_kill(c);
286 else if(ev->message_type == net_wm_state)
288 if((c = get_client_bywin(globalconf.clients, ev->window)))
290 ewmh_process_state_atom(c, (Atom) ev->data.l[1], ev->data.l[0]);
291 if(ev->data.l[2])
292 ewmh_process_state_atom(c, (Atom) ev->data.l[2], ev->data.l[0]);
297 void
298 ewmh_check_client_hints(Client *c)
300 int format;
301 Atom real, *state;
302 unsigned char *data = NULL;
303 unsigned long i, n, extra;
305 if(XGetWindowProperty(globalconf.display, c->win, net_wm_state, 0L, LONG_MAX, False,
306 XA_ATOM, &real, &format, &n, &extra,
307 (unsigned char **) &data) == Success && data)
309 state = (Atom *) data;
310 for(i = 0; i < n; i++)
311 ewmh_process_state_atom(c, state[i], _NET_WM_STATE_ADD);
313 XFree(data);
316 if(XGetWindowProperty(globalconf.display, c->win, net_wm_window_type, 0L, LONG_MAX, False,
317 XA_ATOM, &real, &format, &n, &extra,
318 (unsigned char **) &data) == Success && data)
320 state = (Atom *) data;
321 for(i = 0; i < n; i++)
322 ewmh_process_window_type_atom(c, state[i]);
324 XFree(data);
328 NetWMIcon *
329 ewmh_get_window_icon(Window w)
331 NetWMIcon *icon;
332 Atom type;
333 int format, size, i;
334 unsigned long items, rest, *data, pixel;
335 unsigned char *imgdata, *wdata;
337 if(XGetWindowProperty(globalconf.display, w,
338 net_wm_icon, 0L, LONG_MAX, False, XA_CARDINAL, &type, &format,
339 &items, &rest, &wdata) != Success
340 || !wdata)
341 return NULL;
343 if(type != XA_CARDINAL || format != 32 || items < 2)
345 XFree(wdata);
346 return NULL;
349 icon = p_new(NetWMIcon, 1);
351 data = (unsigned long *) wdata;
353 icon->width = data[0];
354 icon->height = data[1];
355 size = icon->width * icon->height;
357 if(!size)
359 p_delete(&icon);
360 XFree(wdata);
361 return NULL;
364 icon->image = p_new(unsigned char, size * 4);
365 for(imgdata = icon->image, i = 2; i < size + 2; i++, imgdata += 4)
367 pixel = data[i];
368 imgdata[3] = (pixel >> 24) & 0xff; /* A */
369 imgdata[0] = (pixel >> 16) & 0xff; /* R */
370 imgdata[1] = (pixel >> 8) & 0xff; /* G */
371 imgdata[2] = pixel & 0xff; /* B */
374 XFree(wdata);
376 return icon;
379 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80