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_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_ICON", &net_wm_icon
},
82 { "_NET_WM_STATE", &net_wm_state
},
83 { "_NET_WM_STATE_STICKY", &net_wm_state_sticky
},
84 { "_NET_WM_STATE_SKIP_TASKBAR", &net_wm_state_skip_taskbar
},
85 { "_NET_WM_STATE_FULLSCREEN", &net_wm_state_fullscreen
},
87 { "UTF8_STRING", &utf8_string
},
90 #define ATOM_NUMBER (sizeof(AtomNames)/sizeof(AtomItem))
92 #define _NET_WM_STATE_REMOVE 0
93 #define _NET_WM_STATE_ADD 1
94 #define _NET_WM_STATE_TOGGLE 2
100 char *names
[ATOM_NUMBER
];
101 Atom atoms
[ATOM_NUMBER
];
103 for(i
= 0; i
< ATOM_NUMBER
; i
++)
104 names
[i
] = (char *) AtomNames
[i
].name
;
105 XInternAtoms(globalconf
.display
, names
, ATOM_NUMBER
, False
, atoms
);
106 for(i
= 0; i
< ATOM_NUMBER
; i
++)
107 *AtomNames
[i
].atom
= atoms
[i
];
111 ewmh_set_supported_hints(int phys_screen
)
113 Atom atom
[ATOM_NUMBER
];
116 atom
[i
++] = net_supported
;
117 atom
[i
++] = net_client_list
;
118 atom
[i
++] = net_number_of_desktops
;
119 atom
[i
++] = net_current_desktop
;
120 atom
[i
++] = net_desktop_names
;
121 atom
[i
++] = net_active_window
;
123 atom
[i
++] = net_close_window
;
125 atom
[i
++] = net_wm_name
;
126 atom
[i
++] = net_wm_icon_name
;
127 atom
[i
++] = net_wm_window_type
;
128 atom
[i
++] = net_wm_window_type_normal
;
129 atom
[i
++] = net_wm_window_type_dock
;
130 atom
[i
++] = net_wm_window_type_splash
;
131 atom
[i
++] = net_wm_icon
;
132 atom
[i
++] = net_wm_state
;
133 atom
[i
++] = net_wm_state_sticky
;
134 atom
[i
++] = net_wm_state_skip_taskbar
;
135 atom
[i
++] = net_wm_state_fullscreen
;
137 XChangeProperty(globalconf
.display
, RootWindow(globalconf
.display
, phys_screen
),
138 net_supported
, XA_ATOM
, 32,
139 PropModeReplace
, (unsigned char *) atom
, i
);
143 ewmh_update_net_client_list(int phys_screen
)
149 for(c
= globalconf
.clients
; c
; c
= c
->next
)
150 if(get_phys_screen(c
->screen
) == phys_screen
)
153 wins
= p_new(Window
, n
+ 1);
155 for(n
= 0, c
= globalconf
.clients
; c
; c
= c
->next
, n
++)
156 if(get_phys_screen(c
->screen
) == phys_screen
)
159 XChangeProperty(globalconf
.display
, RootWindow(globalconf
.display
, phys_screen
),
160 net_client_list
, XA_WINDOW
, 32, PropModeReplace
, (unsigned char *) wins
, n
);
163 XFlush(globalconf
.display
);
167 ewmh_update_net_numbers_of_desktop(int phys_screen
)
172 for(tag
= globalconf
.screens
[phys_screen
].tags
; tag
; tag
= tag
->next
)
175 XChangeProperty(globalconf
.display
, RootWindow(globalconf
.display
, phys_screen
),
176 net_number_of_desktops
, XA_CARDINAL
, 32, PropModeReplace
, (unsigned char *) &count
, 1);
180 ewmh_update_net_current_desktop(int phys_screen
)
183 Tag
*tag
, **curtags
= get_current_tags(phys_screen
);
185 for(tag
= globalconf
.screens
[phys_screen
].tags
; tag
!= curtags
[0]; tag
= tag
->next
)
188 XChangeProperty(globalconf
.display
, RootWindow(globalconf
.display
, phys_screen
),
189 net_current_desktop
, XA_CARDINAL
, 32, PropModeReplace
, (unsigned char *) &count
, 1);
195 ewmh_update_net_desktop_names(int phys_screen
)
197 char buf
[1024], *pos
;
198 ssize_t len
, curr_size
;
203 for(tag
= globalconf
.screens
[phys_screen
].tags
; tag
; tag
= tag
->next
)
205 curr_size
= a_strlen(tag
->name
);
206 a_strcpy(pos
, sizeof(buf
), tag
->name
);
207 pos
+= curr_size
+ 1;
208 len
+= curr_size
+ 1;
211 XChangeProperty(globalconf
.display
, RootWindow(globalconf
.display
, phys_screen
),
212 net_desktop_names
, utf8_string
, 8, PropModeReplace
, (unsigned char *) buf
, len
);
216 ewmh_update_net_active_window(int phys_screen
)
219 Client
*sel
= focus_get_current_client(phys_screen
);
221 win
= sel
? sel
->win
: None
;
223 XChangeProperty(globalconf
.display
, RootWindow(globalconf
.display
, phys_screen
),
224 net_active_window
, XA_WINDOW
, 32, PropModeReplace
, (unsigned char *) &win
, 1);
228 ewmh_process_state_atom(Client
*c
, Atom state
, int set
)
230 if(state
== net_wm_state_sticky
)
233 for(tag
= globalconf
.screens
[c
->screen
].tags
; tag
; tag
= tag
->next
)
236 else if(state
== net_wm_state_skip_taskbar
)
238 if(set
== _NET_WM_STATE_REMOVE
)
240 else if(set
== _NET_WM_STATE_ADD
)
243 else if(state
== net_wm_state_fullscreen
)
246 if(set
== _NET_WM_STATE_REMOVE
)
248 /* restore geometry */
249 geometry
= c
->m_geometry
;
250 c
->border
= c
->oldborder
;
252 c
->isfloating
= c
->wasfloating
;
254 else if(set
== _NET_WM_STATE_ADD
)
256 geometry
= get_screen_area(c
->screen
, NULL
, NULL
);
258 c
->m_geometry
= c
->geometry
;
259 c
->wasfloating
= c
->isfloating
;
260 c
->oldborder
= c
->border
;
263 c
->isfloating
= True
;
265 statusbar_draw_all(c
->screen
);
266 client_resize(c
, geometry
, False
);
267 XRaiseWindow(globalconf
.display
, c
->win
);
272 ewmh_process_window_type_atom(Client
*c
, Atom state
)
274 if(state
== net_wm_window_type_normal
)
278 else if(state
== net_wm_window_type_dock
279 || state
== net_wm_window_type_splash
)
284 c
->isfloating
= True
;
288 ewmh_process_client_message(XClientMessageEvent
*ev
)
293 if(ev
->message_type
== net_current_desktop
)
294 for(screen
= 0; screen
< ScreenCount(globalconf
.display
); screen
++)
295 if(ev
->window
== RootWindow(globalconf
.display
, screen
))
296 tag_view(screen
, ev
->data
.l
[0]);
298 if(ev
->message_type
== net_close_window
)
300 if((c
= get_client_bywin(globalconf
.clients
, ev
->window
)))
303 else if(ev
->message_type
== net_wm_state
)
305 if((c
= get_client_bywin(globalconf
.clients
, ev
->window
)))
307 ewmh_process_state_atom(c
, (Atom
) ev
->data
.l
[1], ev
->data
.l
[0]);
309 ewmh_process_state_atom(c
, (Atom
) ev
->data
.l
[2], ev
->data
.l
[0]);
315 ewmh_check_client_hints(Client
*c
)
319 unsigned char *data
= NULL
;
320 unsigned long i
, n
, extra
;
322 if(XGetWindowProperty(globalconf
.display
, c
->win
, net_wm_state
, 0L, LONG_MAX
, False
,
323 XA_ATOM
, &real
, &format
, &n
, &extra
,
324 (unsigned char **) &data
) == Success
&& data
)
326 state
= (Atom
*) data
;
327 for(i
= 0; i
< n
; i
++)
328 ewmh_process_state_atom(c
, state
[i
], _NET_WM_STATE_ADD
);
333 if(XGetWindowProperty(globalconf
.display
, c
->win
, net_wm_window_type
, 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_window_type_atom(c
, state
[i
]);
346 ewmh_get_window_icon(Window w
)
351 unsigned long items
, rest
, *data
, pixel
;
352 unsigned char *imgdata
, *wdata
;
354 if(XGetWindowProperty(globalconf
.display
, w
,
355 net_wm_icon
, 0L, LONG_MAX
, False
, XA_CARDINAL
, &type
, &format
,
356 &items
, &rest
, &wdata
) != Success
360 if(type
!= XA_CARDINAL
|| format
!= 32 || items
< 2)
366 icon
= p_new(NetWMIcon
, 1);
368 data
= (unsigned long *) wdata
;
370 icon
->width
= data
[0];
371 icon
->height
= data
[1];
372 size
= icon
->width
* icon
->height
;
381 icon
->image
= p_new(unsigned char, size
* 4);
382 for(imgdata
= icon
->image
, i
= 2; i
< size
+ 2; i
++, imgdata
+= 4)
385 imgdata
[3] = (pixel
>> 24) & 0xff; /* A */
386 imgdata
[0] = (pixel
>> 16) & 0xff; /* R */
387 imgdata
[1] = (pixel
>> 8) & 0xff; /* G */
388 imgdata
[2] = pixel
& 0xff; /* B */
396 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80