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>
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
;
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
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
];
112 ewmh_set_supported_hints(int phys_screen
)
114 Atom atom
[ATOM_NUMBER
];
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
);
145 ewmh_update_net_client_list(int phys_screen
)
151 for(c
= globalconf
.clients
; c
; c
= c
->next
)
152 if(get_phys_screen(c
->screen
) == phys_screen
)
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
)
161 XChangeProperty(globalconf
.display
, RootWindow(globalconf
.display
, phys_screen
),
162 net_client_list
, XA_WINDOW
, 32, PropModeReplace
, (unsigned char *) wins
, n
);
165 XFlush(globalconf
.display
);
169 ewmh_update_net_numbers_of_desktop(int phys_screen
)
174 for(tag
= globalconf
.screens
[phys_screen
].tags
; tag
; tag
= tag
->next
)
177 XChangeProperty(globalconf
.display
, RootWindow(globalconf
.display
, phys_screen
),
178 net_number_of_desktops
, XA_CARDINAL
, 32, PropModeReplace
, (unsigned char *) &count
, 1);
182 ewmh_update_net_current_desktop(int phys_screen
)
185 Tag
*tag
, **curtags
= tags_get_current(phys_screen
);
187 for(tag
= globalconf
.screens
[phys_screen
].tags
; tag
!= curtags
[0]; tag
= tag
->next
)
190 XChangeProperty(globalconf
.display
, RootWindow(globalconf
.display
, phys_screen
),
191 net_current_desktop
, XA_CARDINAL
, 32, PropModeReplace
, (unsigned char *) &count
, 1);
197 ewmh_update_net_desktop_names(int phys_screen
)
199 char buf
[1024], *pos
;
200 ssize_t len
, curr_size
;
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
);
218 ewmh_update_net_active_window(int phys_screen
)
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);
230 ewmh_process_state_atom(Client
*c
, Atom state
, int set
)
232 if(state
== net_wm_state_sticky
)
235 for(tag
= globalconf
.screens
[c
->screen
].tags
; tag
; tag
= tag
->next
)
238 else if(state
== net_wm_state_skip_taskbar
)
240 if(set
== _NET_WM_STATE_REMOVE
)
244 c
->border
= c
->oldborder
;
246 else if(set
== _NET_WM_STATE_ADD
)
250 c
->oldborder
= c
->border
;
254 else if(state
== net_wm_state_fullscreen
)
256 Area geometry
= c
->geometry
;
257 if(set
== _NET_WM_STATE_REMOVE
)
259 /* restore geometry */
260 geometry
= c
->m_geometry
;
261 c
->border
= c
->oldborder
;
263 client_setfloating(c
, c
->wasfloating
);
265 else if(set
== _NET_WM_STATE_ADD
)
267 geometry
= screen_get_area(c
->screen
, NULL
, &globalconf
.screens
[c
->screen
].padding
);
269 c
->m_geometry
= c
->geometry
;
270 c
->wasfloating
= c
->isfloating
;
271 c
->oldborder
= c
->border
;
274 client_setfloating(c
, True
);
276 widget_invalidate_cache(c
->screen
, WIDGET_CACHE_CLIENTS
);
277 client_resize(c
, geometry
, False
);
278 XRaiseWindow(globalconf
.display
, c
->win
);
283 ewmh_process_window_type_atom(Client
*c
, Atom state
)
285 if(state
== net_wm_window_type_normal
)
287 /* do nothing. this is REALLY IMPORTANT */
289 else if(state
== net_wm_window_type_dock
290 || state
== net_wm_window_type_splash
)
295 client_setfloating(c
, True
);
297 else if (state
== net_wm_window_type_dialog
)
298 client_setfloating(c
, True
);
301 ewmh_process_client_message(XClientMessageEvent
*ev
)
306 if(ev
->message_type
== net_current_desktop
)
307 for(screen
= 0; screen
< ScreenCount(globalconf
.display
); screen
++)
308 if(ev
->window
== RootWindow(globalconf
.display
, screen
))
309 tag_view_only_byindex(screen
, ev
->data
.l
[0]);
311 if(ev
->message_type
== net_close_window
)
313 if((c
= client_get_bywin(globalconf
.clients
, ev
->window
)))
316 else if(ev
->message_type
== net_wm_state
)
318 if((c
= client_get_bywin(globalconf
.clients
, ev
->window
)))
320 ewmh_process_state_atom(c
, (Atom
) ev
->data
.l
[1], ev
->data
.l
[0]);
322 ewmh_process_state_atom(c
, (Atom
) ev
->data
.l
[2], ev
->data
.l
[0]);
328 ewmh_check_client_hints(Client
*c
)
332 unsigned char *data
= NULL
;
333 unsigned long i
, n
, extra
;
335 if(XGetWindowProperty(globalconf
.display
, c
->win
, net_wm_state
, 0L, LONG_MAX
, False
,
336 XA_ATOM
, &real
, &format
, &n
, &extra
,
337 (unsigned char **) &data
) == Success
&& data
)
339 state
= (Atom
*) data
;
340 for(i
= 0; i
< n
; i
++)
341 ewmh_process_state_atom(c
, state
[i
], _NET_WM_STATE_ADD
);
346 if(XGetWindowProperty(globalconf
.display
, c
->win
, net_wm_window_type
, 0L, LONG_MAX
, False
,
347 XA_ATOM
, &real
, &format
, &n
, &extra
,
348 (unsigned char **) &data
) == Success
&& data
)
350 state
= (Atom
*) data
;
351 for(i
= 0; i
< n
; i
++)
352 ewmh_process_window_type_atom(c
, state
[i
]);
359 ewmh_get_window_icon(Window w
)
364 unsigned long items
, rest
, *data
, pixel
;
365 unsigned char *imgdata
, *wdata
;
367 if(XGetWindowProperty(globalconf
.display
, w
,
368 net_wm_icon
, 0L, LONG_MAX
, False
, XA_CARDINAL
, &type
, &format
,
369 &items
, &rest
, &wdata
) != Success
373 if(type
!= XA_CARDINAL
|| format
!= 32 || items
< 2)
379 icon
= p_new(NetWMIcon
, 1);
381 data
= (unsigned long *) wdata
;
383 icon
->width
= data
[0];
384 icon
->height
= data
[1];
385 size
= icon
->width
* icon
->height
;
394 icon
->image
= p_new(unsigned char, size
* 4);
395 for(imgdata
= icon
->image
, i
= 2; i
< size
+ 2; i
++, imgdata
+= 4)
398 imgdata
[3] = (pixel
>> 24) & 0xff; /* A */
399 imgdata
[0] = (pixel
>> 16) & 0xff; /* R */
400 imgdata
[1] = (pixel
>> 8) & 0xff; /* G */
401 imgdata
[2] = pixel
& 0xff; /* B */
409 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80