1 /* evilwm - Minimalist Window Manager for X
2 * Copyright (C) 1999-2009 Ciaran Anscomb <evilwm@6809.org.uk>
3 * see README for license and other details. */
10 /* Root Window Properties (and Related Messages) */
11 static Atom xa_net_supported
;
12 static Atom xa_net_client_list
;
13 static Atom xa_net_client_list_stacking
;
15 static Atom xa_net_number_of_desktops
;
17 static Atom xa_net_desktop_geometry
;
18 static Atom xa_net_desktop_viewport
;
20 Atom xa_net_current_desktop
;
22 Atom xa_net_active_window
;
23 static Atom xa_net_workarea
;
24 static Atom xa_net_supporting_wm_check
;
26 /* Other Root Window Messages */
27 Atom xa_net_close_window
;
28 Atom xa_net_moveresize_window
;
29 Atom xa_net_restack_window
;
30 Atom xa_net_request_frame_extents
;
32 /* Application Window Properties */
33 static Atom xa_net_wm_name
;
35 Atom xa_net_wm_desktop
;
37 Atom xa_net_wm_window_type
;
38 Atom xa_net_wm_window_type_dock
;
40 Atom xa_net_wm_state_maximized_vert
;
41 Atom xa_net_wm_state_maximized_horz
;
42 Atom xa_net_wm_state_fullscreen
;
43 static Atom xa_net_wm_allowed_actions
;
44 static Atom xa_net_wm_action_move
;
45 static Atom xa_net_wm_action_resize
;
46 static Atom xa_net_wm_action_maximize_horz
;
47 static Atom xa_net_wm_action_maximize_vert
;
48 static Atom xa_net_wm_action_fullscreen
;
49 static Atom xa_net_wm_action_change_desktop
;
50 static Atom xa_net_wm_action_close
;
51 static Atom xa_net_wm_pid
;
52 Atom xa_net_frame_extents
;
54 /* Maintain a reasonably sized allocated block of memory for lists
55 * of windows (for feeding to XChangeProperty in one hit). */
56 static Window
*window_array
= NULL
;
57 static Window
*alloc_window_array(void);
59 void ewmh_init(void) {
60 /* Root Window Properties (and Related Messages) */
61 xa_net_supported
= XInternAtom(dpy
, "_NET_SUPPORTED", False
);
62 xa_net_client_list
= XInternAtom(dpy
, "_NET_CLIENT_LIST", False
);
63 xa_net_client_list_stacking
= XInternAtom(dpy
, "_NET_CLIENT_LIST_STACKING", False
);
65 xa_net_number_of_desktops
= XInternAtom(dpy
, "_NET_NUMBER_OF_DESKTOPS", False
);
67 xa_net_desktop_geometry
= XInternAtom(dpy
, "_NET_DESKTOP_GEOMETRY", False
);
68 xa_net_desktop_viewport
= XInternAtom(dpy
, "_NET_DESKTOP_VIEWPORT", False
);
70 xa_net_current_desktop
= XInternAtom(dpy
, "_NET_CURRENT_DESKTOP", False
);
72 xa_net_active_window
= XInternAtom(dpy
, "_NET_ACTIVE_WINDOW", False
);
73 xa_net_workarea
= XInternAtom(dpy
, "_NET_WORKAREA", False
);
74 xa_net_supporting_wm_check
= XInternAtom(dpy
, "_NET_SUPPORTING_WM_CHECK", False
);
76 /* Other Root Window Messages */
77 xa_net_close_window
= XInternAtom(dpy
, "_NET_CLOSE_WINDOW", False
);
78 xa_net_moveresize_window
= XInternAtom(dpy
, "_NET_MOVERESIZE_WINDOW", False
);
79 xa_net_restack_window
= XInternAtom(dpy
, "_NET_RESTACK_WINDOW", False
);
80 xa_net_request_frame_extents
= XInternAtom(dpy
, "_NET_REQUEST_FRAME_EXTENTS", False
);
82 /* Application Window Properties */
83 xa_net_wm_name
= XInternAtom(dpy
, "_NET_WM_NAME", False
);
85 xa_net_wm_desktop
= XInternAtom(dpy
, "_NET_WM_DESKTOP", False
);
87 xa_net_wm_window_type
= XInternAtom(dpy
, "_NET_WM_WINDOW_TYPE", False
);
88 xa_net_wm_window_type_dock
= XInternAtom(dpy
, "_NET_WM_WINDOW_TYPE_DOCK", False
);
89 xa_net_wm_state
= XInternAtom(dpy
, "_NET_WM_STATE", False
);
90 xa_net_wm_state_maximized_vert
= XInternAtom(dpy
, "_NET_WM_STATE_MAXIMIZED_VERT", False
);
91 xa_net_wm_state_maximized_horz
= XInternAtom(dpy
, "_NET_WM_STATE_MAXIMIZED_HORZ", False
);
92 xa_net_wm_state_fullscreen
= XInternAtom(dpy
, "_NET_WM_STATE_FULLSCREEN", False
);
93 xa_net_wm_allowed_actions
= XInternAtom(dpy
, "_NET_WM_ALLOWED_ACTIONS", False
);
94 xa_net_wm_action_move
= XInternAtom(dpy
, "_NET_WM_ACTION_MOVE", False
);
95 xa_net_wm_action_resize
= XInternAtom(dpy
, "_NET_WM_ACTION_RESIZE", False
);
96 xa_net_wm_action_maximize_horz
= XInternAtom(dpy
, "_NET_WM_ACTION_MAXIMIZE_HORZ", False
);
97 xa_net_wm_action_maximize_vert
= XInternAtom(dpy
, "_NET_WM_ACTION_MAXIMIZE_VERT", False
);
98 xa_net_wm_action_fullscreen
= XInternAtom(dpy
, "_NET_WM_ACTION_FULLSCREEN", False
);
99 xa_net_wm_action_change_desktop
= XInternAtom(dpy
, "_NET_WM_ACTION_CHANGE_DESKTOP", False
);
100 xa_net_wm_action_close
= XInternAtom(dpy
, "_NET_WM_ACTION_CLOSE", False
);
101 xa_net_wm_pid
= XInternAtom(dpy
, "_NET_WM_PID", False
);
102 xa_net_frame_extents
= XInternAtom(dpy
, "_NET_FRAME_EXTENTS", False
);
105 void ewmh_init_screen(ScreenInfo
*s
) {
106 unsigned long pid
= getpid();
109 xa_net_client_list_stacking
,
111 xa_net_number_of_desktops
,
113 xa_net_desktop_geometry
,
114 xa_net_desktop_viewport
,
116 xa_net_current_desktop
,
118 xa_net_active_window
,
120 xa_net_supporting_wm_check
,
123 xa_net_moveresize_window
,
124 xa_net_restack_window
,
125 xa_net_request_frame_extents
,
130 xa_net_wm_window_type
,
131 xa_net_wm_window_type_dock
,
133 xa_net_wm_state_maximized_vert
,
134 xa_net_wm_state_maximized_horz
,
135 xa_net_wm_state_fullscreen
,
136 xa_net_wm_allowed_actions
,
137 /* Not sure if it makes any sense including every action here
138 * as they'll already be listed per-client in the
139 * _NET_WM_ALOWED_ACTIONS property, but EWMH spec is unclear.
141 xa_net_wm_action_move
,
142 xa_net_wm_action_resize
,
143 xa_net_wm_action_maximize_horz
,
144 xa_net_wm_action_maximize_vert
,
145 xa_net_wm_action_fullscreen
,
146 xa_net_wm_action_change_desktop
,
147 xa_net_wm_action_close
,
148 xa_net_frame_extents
,
151 unsigned long num_desktops
= 8;
152 unsigned long vdesk
= s
->vdesk
;
154 unsigned long workarea
[4] = {
156 DisplayWidth(dpy
, s
->screen
), DisplayHeight(dpy
, s
->screen
)
158 s
->supporting
= XCreateSimpleWindow(dpy
, s
->root
, 0, 0, 1, 1, 0, 0, 0);
159 XChangeProperty(dpy
, s
->root
, xa_net_supported
,
160 XA_ATOM
, 32, PropModeReplace
,
161 (unsigned char *)&supported
,
162 sizeof(supported
) / sizeof(Atom
));
164 XChangeProperty(dpy
, s
->root
, xa_net_number_of_desktops
,
165 XA_CARDINAL
, 32, PropModeReplace
,
166 (unsigned char *)&num_desktops
, 1);
168 XChangeProperty(dpy
, s
->root
, xa_net_desktop_geometry
,
169 XA_CARDINAL
, 32, PropModeReplace
,
170 (unsigned char *)&workarea
[2], 2);
171 XChangeProperty(dpy
, s
->root
, xa_net_desktop_viewport
,
172 XA_CARDINAL
, 32, PropModeReplace
,
173 (unsigned char *)&workarea
[0], 2);
175 XChangeProperty(dpy
, s
->root
, xa_net_current_desktop
,
176 XA_CARDINAL
, 32, PropModeReplace
,
177 (unsigned char *)&vdesk
, 1);
179 XChangeProperty(dpy
, s
->root
, xa_net_workarea
,
180 XA_CARDINAL
, 32, PropModeReplace
,
181 (unsigned char *)&workarea
, 4);
182 XChangeProperty(dpy
, s
->root
, xa_net_supporting_wm_check
,
183 XA_WINDOW
, 32, PropModeReplace
,
184 (unsigned char *)&s
->supporting
, 1);
185 XChangeProperty(dpy
, s
->supporting
, xa_net_supporting_wm_check
,
186 XA_WINDOW
, 32, PropModeReplace
,
187 (unsigned char *)&s
->supporting
, 1);
188 XChangeProperty(dpy
, s
->supporting
, xa_net_wm_name
,
189 XA_STRING
, 8, PropModeReplace
,
190 (const unsigned char *)"evilwm", 6);
191 XChangeProperty(dpy
, s
->supporting
, xa_net_wm_pid
,
192 XA_CARDINAL
, 32, PropModeReplace
,
193 (unsigned char *)&pid
, 1);
196 void ewmh_deinit_screen(ScreenInfo
*s
) {
197 XDeleteProperty(dpy
, s
->root
, xa_net_supported
);
198 XDeleteProperty(dpy
, s
->root
, xa_net_client_list
);
199 XDeleteProperty(dpy
, s
->root
, xa_net_client_list_stacking
);
201 XDeleteProperty(dpy
, s
->root
, xa_net_number_of_desktops
);
203 XDeleteProperty(dpy
, s
->root
, xa_net_desktop_geometry
);
204 XDeleteProperty(dpy
, s
->root
, xa_net_desktop_viewport
);
206 XDeleteProperty(dpy
, s
->root
, xa_net_current_desktop
);
208 XDeleteProperty(dpy
, s
->root
, xa_net_active_window
);
209 XDeleteProperty(dpy
, s
->root
, xa_net_workarea
);
210 XDeleteProperty(dpy
, s
->root
, xa_net_supporting_wm_check
);
211 XDestroyWindow(dpy
, s
->supporting
);
214 void ewmh_init_client(Client
*c
) {
215 Atom allowed_actions
[] = {
216 xa_net_wm_action_move
,
217 xa_net_wm_action_maximize_horz
,
218 xa_net_wm_action_maximize_vert
,
219 xa_net_wm_action_fullscreen
,
220 xa_net_wm_action_change_desktop
,
221 xa_net_wm_action_close
,
222 /* nelements reduced to omit this if not possible: */
223 xa_net_wm_action_resize
,
225 int nelements
= sizeof(allowed_actions
) / sizeof(Atom
);
226 /* Omit resize element if resizing not possible: */
227 if (c
->max_width
&& c
->max_width
== c
->min_width
228 && c
->max_height
&& c
->max_height
== c
->min_height
)
230 XChangeProperty(dpy
, c
->window
, xa_net_wm_allowed_actions
,
231 XA_ATOM
, 32, PropModeReplace
,
232 (unsigned char *)&allowed_actions
,
236 void ewmh_deinit_client(Client
*c
) {
237 XDeleteProperty(dpy
, c
->window
, xa_net_wm_allowed_actions
);
240 void ewmh_withdraw_client(Client
*c
) {
242 XDeleteProperty(dpy
, c
->window
, xa_net_wm_desktop
);
244 XDeleteProperty(dpy
, c
->window
, xa_net_wm_state
);
247 void ewmh_select_client(Client
*c
) {
248 clients_tab_order
= list_to_head(clients_tab_order
, c
);
251 void ewmh_set_net_client_list(ScreenInfo
*s
) {
252 Window
*windows
= alloc_window_array();
255 for (iter
= clients_mapping_order
; iter
; iter
= iter
->next
) {
256 Client
*c
= iter
->data
;
257 if (c
->screen
== s
) {
258 windows
[i
++] = c
->window
;
261 XChangeProperty(dpy
, s
->root
, xa_net_client_list
,
262 XA_WINDOW
, 32, PropModeReplace
,
263 (unsigned char *)windows
, i
);
266 void ewmh_set_net_client_list_stacking(ScreenInfo
*s
) {
267 Window
*windows
= alloc_window_array();
270 for (iter
= clients_stacking_order
; iter
; iter
= iter
->next
) {
271 Client
*c
= iter
->data
;
272 if (c
->screen
== s
) {
273 windows
[i
++] = c
->window
;
276 XChangeProperty(dpy
, s
->root
, xa_net_client_list_stacking
,
277 XA_WINDOW
, 32, PropModeReplace
,
278 (unsigned char *)windows
, i
);
282 void ewmh_set_net_current_desktop(ScreenInfo
*s
) {
283 unsigned long vdesk
= s
->vdesk
;
284 XChangeProperty(dpy
, s
->root
, xa_net_current_desktop
,
285 XA_CARDINAL
, 32, PropModeReplace
,
286 (unsigned char *)&vdesk
, 1);
290 void ewmh_set_net_active_window(Client
*c
) {
292 for (i
= 0; i
< num_screens
; i
++) {
294 if (c
&& i
== c
->screen
->screen
) {
299 XChangeProperty(dpy
, screens
[i
].root
, xa_net_active_window
,
300 XA_WINDOW
, 32, PropModeReplace
,
301 (unsigned char *)&w
, 1);
306 void ewmh_set_net_wm_desktop(Client
*c
) {
307 XChangeProperty(dpy
, c
->window
, xa_net_wm_desktop
,
308 XA_CARDINAL
, 32, PropModeReplace
,
309 (unsigned char *)&c
->vdesk
, 1);
313 void ewmh_set_net_wm_state(Client
*c
) {
317 state
[i
++] = xa_net_wm_state_maximized_vert
;
319 state
[i
++] = xa_net_wm_state_maximized_horz
;
320 if (c
->oldh
&& c
->oldw
)
321 state
[i
++] = xa_net_wm_state_fullscreen
;
322 XChangeProperty(dpy
, c
->window
, xa_net_wm_state
,
323 XA_ATOM
, 32, PropModeReplace
,
324 (unsigned char *)&state
, i
);
327 void ewmh_set_net_frame_extents(Window w
) {
328 unsigned long extents
[4];
329 extents
[0] = extents
[1] = extents
[2] = extents
[3] = opt_bw
;
330 XChangeProperty(dpy
, w
, xa_net_frame_extents
,
331 XA_CARDINAL
, 32, PropModeReplace
,
332 (unsigned char *)&extents
, 4);
335 static Window
*alloc_window_array(void) {
337 unsigned int count
= 0;
338 for (iter
= clients_mapping_order
; iter
; iter
= iter
->next
) {
341 if (count
== 0) count
++;
342 /* Round up to next block of 128 */
343 count
= (count
+ 127) & ~127;
344 window_array
= realloc(window_array
, count
* sizeof(Window
));