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>
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
;
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
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
];
113 ewmh_set_supported_hints(int phys_screen
)
115 Atom atom
[ATOM_NUMBER
];
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
);
146 ewmh_update_net_client_list(int phys_screen
)
152 for(c
= globalconf
.clients
; c
; c
= c
->next
)
153 if(get_phys_screen(c
->screen
) == phys_screen
)
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
)
162 XChangeProperty(globalconf
.display
, RootWindow(globalconf
.display
, phys_screen
),
163 net_client_list
, XA_WINDOW
, 32, PropModeReplace
, (unsigned char *) wins
, n
);
166 XFlush(globalconf
.display
);
170 ewmh_update_net_numbers_of_desktop(int phys_screen
)
175 for(tag
= globalconf
.screens
[phys_screen
].tags
; tag
; tag
= tag
->next
)
178 XChangeProperty(globalconf
.display
, RootWindow(globalconf
.display
, phys_screen
),
179 net_number_of_desktops
, XA_CARDINAL
, 32, PropModeReplace
, (unsigned char *) &count
, 1);
183 ewmh_update_net_current_desktop(int phys_screen
)
186 Tag
*tag
, **curtags
= get_current_tags(phys_screen
);
188 for(tag
= globalconf
.screens
[phys_screen
].tags
; tag
!= curtags
[0]; tag
= tag
->next
)
191 XChangeProperty(globalconf
.display
, RootWindow(globalconf
.display
, phys_screen
),
192 net_current_desktop
, XA_CARDINAL
, 32, PropModeReplace
, (unsigned char *) &count
, 1);
198 ewmh_update_net_desktop_names(int phys_screen
)
200 char buf
[1024], *pos
;
201 ssize_t len
, curr_size
;
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
);
219 ewmh_update_net_active_window(int phys_screen
)
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);
231 ewmh_process_state_atom(Client
*c
, Atom state
, int set
)
233 if(state
== net_wm_state_sticky
)
236 for(tag
= globalconf
.screens
[c
->screen
].tags
; tag
; tag
= tag
->next
)
239 else if(state
== net_wm_state_skip_taskbar
)
241 if(set
== _NET_WM_STATE_REMOVE
)
243 else if(set
== _NET_WM_STATE_ADD
)
246 else if(state
== net_wm_state_fullscreen
)
249 if(set
== _NET_WM_STATE_REMOVE
)
251 /* restore geometry */
252 geometry
= c
->m_geometry
;
253 c
->border
= c
->oldborder
;
255 c
->isfloating
= c
->wasfloating
;
257 else if(set
== _NET_WM_STATE_ADD
)
259 geometry
= get_screen_area(c
->screen
, NULL
, NULL
);
261 c
->m_geometry
= c
->geometry
;
262 c
->wasfloating
= c
->isfloating
;
263 c
->oldborder
= c
->border
;
266 c
->isfloating
= True
;
268 statusbar_draw_all(c
->screen
);
269 client_resize(c
, geometry
, False
);
270 XRaiseWindow(globalconf
.display
, c
->win
);
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
)
287 c
->isfloating
= True
;
289 else if (state
== net_wm_window_type_dialog
)
290 c
->isfloating
= True
;
293 ewmh_process_client_message(XClientMessageEvent
*ev
)
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
)))
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]);
314 ewmh_process_state_atom(c
, (Atom
) ev
->data
.l
[2], ev
->data
.l
[0]);
320 ewmh_check_client_hints(Client
*c
)
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
);
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
]);
351 ewmh_get_window_icon(Window w
)
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
365 if(type
!= XA_CARDINAL
|| format
!= 32 || items
< 2)
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
;
386 icon
->image
= p_new(unsigned char, size
* 4);
387 for(imgdata
= icon
->image
, i
= 2; i
< size
+ 2; i
++, imgdata
+= 4)
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 */
401 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80