1 /* wmspec.c-- support for the wm-spec Hints
3 * Window Maker window manager
5 * Copyright (c) 1998, 2001 Alfredo K. Kojima
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
27 #include <X11/Xatom.h>
29 #include "WindowMaker.h"
36 static Atom net_supported
;
37 static Atom net_client_list
;
38 static Atom net_client_list_stacking
;
39 static Atom net_number_of_desktops
;
40 static Atom net_desktop_geometry
;
41 static Atom net_desktop_viewport
;
42 static Atom net_current_desktop
;
43 static Atom net_active_window
;
44 static Atom net_workarea
;
45 static Atom net_supporting_wm_check
;
46 /* net_virtual_roots N/A */
49 * _NET_WM_VISIBLE_NAME
51 * _NET_WM_VISIBLE_ICON_NAME
54 static Atom net_wm_desktop
;
55 static Atom net_wm_state
;
57 static Atom net_wm_strut
;
59 * _NET_WM_ICON_GEOMETRY
62 * _NET_WM_HANDLED_ICONS
66 static Atom net_wm_state_modal
;
67 static Atom net_wm_state_sticky
;
68 static Atom net_wm_state_maximized_vert
;
69 static Atom net_wm_state_maximized_horz
;
70 static Atom net_wm_state_shaded
;
71 static Atom net_wm_state_skip_taskbar
;
72 static Atom net_wm_state_skip_pager
;
79 static char *atomNames
[] = {
82 "_NET_NUMBER_OF_DESKTOPS",
83 "_NET_DESKTOP_GEOMETRY",
84 "_NET_DESKTOP_VIEWPORT",
85 "_NET_CURRENT_DESKTOP",
88 "_NET_SUPPORTING_WM_CHECK",
95 "_NET_WM_STATE_MODAL",
96 "_NET_WM_STATE_STICKY",
97 "_NET_WM_STATE_MAXIMIZED_VERT",
98 "_NET_WM_STATE_MAXIMIZED_HORZ",
99 "_NET_WM_STATE_SHADED",
100 "_NET_WM_STATE_SKIP_TASKBAR",
101 "_NET_WM_STATE_SKIP_PAGER"
104 static void observer(void *self
, WMNotification
*notif
);
105 static void wsobserver(void *self
, WMNotification
*notif
);
108 typedef struct NetData
{
110 Window
*client_windows
;
119 static void setSupportedHints(WScreen
*scr
)
123 unsigned int sizes
[2];
125 /* set supported hints list */
127 atom
[i
++] = net_client_list
;
130 XChangeProperty(dpy
, scr
->root_win
,
131 net_supported
, XA_ATOM
, 32,
132 PropModeReplace
, (unsigned char*)atom
, i
);
134 /* set supporting wm hint */
135 XChangeProperty(dpy
, scr
->root_win
,
136 net_supporting_wm_check
, XA_WINDOW
, 32,
138 (unsigned char*)&scr
->info_window
, 1);
140 XChangeProperty(dpy
, scr
->info_window
,
141 net_supporting_wm_check
, XA_WINDOW
, 32,
143 (unsigned char*)&scr
->info_window
, 1);
146 /* set desktop geometry. dynamic change is not supported */
147 sizes
[0] = scr
->scr_width
;
148 sizes
[1] = scr
->scr_height
;
150 XChangeProperty(dpy
, scr
->root_win
,
151 net_desktop_geometry
, XA_CARDINAL
, 32,
153 (unsigned char*)&sizes
, 2);
155 /* set desktop viewport. dynamic change is not supported */
159 XChangeProperty(dpy
, scr
->root_win
,
160 net_desktop_viewport
, XA_CARDINAL
, 32,
162 (unsigned char*)&sizes
, 2);
167 void netwmInitialize(WScreen
*scr
)
172 #ifdef HAVE_XINTERNATOMS
173 XInternAtoms(dpy
, atomNames
, sizeof(atomNames
)/sizeof(char*),
178 for (i
= 0; i
< sizeof(atomNames
)/sizeof(char*); i
++) {
179 atom
[i
] = XInternAtom(dpy
, atomNames
[i
], False
);
183 net_supported
= atom
[0];
184 net_client_list
= atom
[1];
186 setSupportedHints(scr
);
188 data
= wmalloc(sizeof(NetData
));
190 data
->client_windows
= NULL
;
191 data
->client_count
= 0;
192 data
->client_size
= 0;
194 WMAddNotificationObserver(observer
, data
, WMNManaged
, NULL
);
195 WMAddNotificationObserver(observer
, data
, WMNUnmanaged
, NULL
);
196 WMAddNotificationObserver(observer
, data
, WMNChangedWorkspace
, NULL
);
197 WMAddNotificationObserver(observer
, data
, WMNChangedState
, NULL
);
198 WMAddNotificationObserver(observer
, data
, WMNChangedFocus
, NULL
);
199 WMAddNotificationObserver(observer
, data
, WMNChangedStacking
, NULL
);
200 WMAddNotificationObserver(observer
, data
, WMNChangedName
, NULL
);
202 WMAddNotificationObserver(wsobserver
, data
, WMNWorkspaceCreated
, NULL
);
203 WMAddNotificationObserver(wsobserver
, data
, WMNWorkspaceDestroyed
, NULL
);
204 WMAddNotificationObserver(wsobserver
, data
, WMNWorkspaceChanged
, NULL
);
205 WMAddNotificationObserver(wsobserver
, data
, WMNWorkspaceNameChanged
, NULL
);
210 netwmUpdateWorkarea(WScreen
*scr
)
212 unsigned int area
[4];
216 XChangeProperty(dpy
, scr
->root_win
, net_workarea
, XA_CARDINAL
, 32,
218 (unsigned char*)area
, 4);
224 updateClientList(WScreen
*scr
, WWindow
*wwin
, Bool added
)
226 NetData
*data
= scr
->netdata
;
229 if (data
->client_count
== data
->client_size
) {
230 data
->client_size
+= 20;
231 data
->client_windows
= wrealloc(data
->client_windows
,
232 sizeof(Window
)*data
->client_size
);
235 data
->client_windows
[data
->client_count
++] = wwin
->client_win
;
237 XChangeProperty(dpy
, scr
->root_win
, net_client_list
, XA_WINDOW
, 32,
238 PropModeAppend
, (unsigned char*)&wwin
->client_win
, 1);
241 for (i
= 0; i
< data
->client_count
; i
++) {
242 if (data
->client_windows
[i
] == wwin
->client_win
) {
243 if (data
->client_count
-1 > i
) {
244 memmove(data
->client_windows
+i
,
245 data
->client_windows
+i
+1,
246 (data
->client_count
-i
-1)*sizeof(Window
));
248 data
->client_count
--;
253 /* update client list */
254 XChangeProperty(dpy
, scr
->root_win
, net_client_list
, XA_WINDOW
, 32,
256 (unsigned char *)data
->client_windows
,
265 updateClientListStacking(WScreen
*scr
)
273 /* update client list */
275 client_list
= (Window
*)malloc(sizeof(Window
)*scr
->window_count
);
277 wwarning(_("out of memory while updating wm hints"));
281 WM_ETARETI_BAG(scr
->stacking_list
, tmp
, iter
) {
283 client_list
[client_count
++] = tmp
->window
;
284 tmp
= tmp
->stacking
->under
;
288 XChangeProperty(dpy
, scr
->root_win
,
289 net_client_list_stacking
, XA_WINDOW
, 32,
291 (unsigned char *)client_list
, client_count
);
301 updateWorkspaceCount(WScreen
*scr
) /* changeable */
303 unsigned int count
= scr
->workspace_count
;
305 XChangeProperty(dpy
, scr
->root_win
,
306 net_number_of_desktops
, XA_CARDINAL
, 32,
308 (unsigned char*)&count
, 1);
313 updateCurrentWorkspace(WScreen
*scr
) /* changeable */
315 unsigned int count
= scr
->current_workspace
;
317 XChangeProperty(dpy
, scr
->root_win
,
318 net_current_desktop
, XA_CARDINAL
, 32,
320 (unsigned char*)&count
, 1);
325 updateWorkspaceNames(WScreen
*scr
, int workspace
)
332 updateFocusHint(WScreen
*scr
, WWindow
*wwin
) /* changeable */
334 Window window
= None
;
337 window
= wwin
->client_win
;
339 XChangeProperty(dpy
, scr
->root_win
,
340 net_active_window
, XA_WINDOW
, 32,
342 (unsigned char*)&window
, 1);
347 updateWorkspaceHint(WWindow
*wwin
, Bool del
)
350 XDeleteProperty(dpy
, wwin
->client_win
, net_wm_desktop
);
352 XChangeProperty(dpy
, wwin
->screen_ptr
->root_win
,
353 net_wm_desktop
, XA_CARDINAL
, 32,
355 (unsigned char*)&wwin
->frame
->workspace
, 1);
361 updateStateHint(WWindow
*wwin
, Bool del
) /* changeable */
364 if (!wwin
->flags
.net_state_from_client
)
365 XDeleteProperty(dpy
, wwin
->client_win
, net_wm_state
);
370 if (wwin
->flags
.omnipresent
)
371 state
[i
++] = net_wm_state_sticky
;
372 if (wwin
->flags
.maximized
& MAX_HORIZONTAL
)
373 state
[i
++] = net_wm_state_maximized_horz
;
374 if (wwin
->flags
.maximized
& MAX_VERTICAL
)
375 state
[i
++] = net_wm_state_maximized_vert
;
376 if (wwin
->flags
.shaded
)
377 state
[i
++] = net_wm_state_shaded
;
378 if (WFLAGP(wwin
, skip_window_list
) || wwin
->flags
.net_skip_taskbar
)
379 state
[i
++] = net_wm_state_skip_taskbar
;
380 if (wwin
->flags
.net_skip_pager
)
381 state
[i
++] = net_wm_state_skip_pager
;
387 updateStrut(WWindow
*wwin
, Bool adding
)
390 // XGetWindowProperty(dpy, wwin->client_win,
392 /* XXX add property observer */
399 observer(void *self
, WMNotification
*notif
)
401 WWindow
*wwin
= (WWindow
*)WMGetNotificationObject(notif
);
402 const char *name
= WMGetNotificationName(notif
);
403 void *data
= WMGetNotificationClientData(notif
);
404 NetData
*ndata
= (NetData
*)self
;
407 if (strcmp(name
, WMNManaged
) == 0 && wwin
) {
408 updateClientList(wwin
->screen_ptr
, wwin
, True
);
410 updateStrut(wwin
, True
);
412 } else if (strcmp(name
, WMNUnmanaged
) == 0 && wwin
) {
413 updateClientList(wwin
->screen_ptr
, wwin
, False
);
414 updateWorkspaceHint(wwin
, True
);
415 updateStateHint(wwin
, True
);
417 updateStrut(wwin
, False
);
419 } else if (strcmp(name
, WMNResetStacking
) == 0 && wwin
) {
420 updateClientListStacking(wwin
->screen_ptr
);
422 } else if (strcmp(name
, WMNChangedStacking
) == 0 && wwin
) {
423 updateClientListStacking(wwin
->screen_ptr
);
425 } else if (strcmp(name
, WMNChangedFocus
) == 0) {
426 updateFocusHint(ndata
->scr
, wwin
);
428 } else if (strcmp(name
, WMNChangedWorkspace
) == 0 && wwin
) {
429 updateWorkspaceHint(wwin
, False
);
431 } else if (strcmp(name
, WMNChangedState
) == 0 && wwin
) {
432 updateStateHint(wwin
, False
);
438 wsobserver(void *self
, WMNotification
*notif
)
440 WScreen
*scr
= (WScreen
*)WMGetNotificationObject(notif
);
441 const char *name
= WMGetNotificationName(notif
);
442 void *data
= WMGetNotificationClientData(notif
);
444 if (strcmp(name
, WMNWorkspaceCreated
) == 0) {
445 updateWorkspaceCount(scr
);
446 } else if (strcmp(name
, WMNWorkspaceDestroyed
) == 0) {
447 updateWorkspaceCount(scr
);
448 } else if (strcmp(name
, WMNWorkspaceChanged
) == 0) {
449 updateCurrentWorkspace(scr
);
450 } else if (strcmp(name
, WMNWorkspaceNameChanged
) == 0) {
451 updateWorkspaceNames(scr
, (int)data
);