begin wmspec stuff
[wmaker-crm.git] / src / wmspec.c
blob92aaefdd521d4175d8ce7faaf1d1d4760eba32ca
1 /* wmspec.c-- support for the wm-spec Hints
2 *
3 * Window Maker window manager
4 *
5 * Copyright (c) 1998, 2001 Alfredo K. Kojima
6 *
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,
20 * USA.
24 #include "wconfig.h"
26 #include <X11/Xlib.h>
27 #include <X11/Xatom.h>
29 #include "WindowMaker.h"
30 #include "window.h"
31 #include "screen.h"
32 #include "framewin.h"
33 #include "actions.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 */
47 /* TODO
48 * _NET_WM_NAME
49 * _NET_WM_VISIBLE_NAME
50 * _NET_WM_ICON_NAME
51 * _NET_WM_VISIBLE_ICON_NAME
52 * _NET_WM_WINDOW_TYPE
54 static Atom net_wm_desktop;
55 static Atom net_wm_state;
57 static Atom net_wm_strut;
59 * _NET_WM_ICON_GEOMETRY
60 * _NET_WM_ICON
61 * _NET_WM_PID
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;
76 /* states */
79 static char *atomNames[] = {
80 "_NET_SUPPORTED",
81 "_NET_CLIENT_LIST",
82 "_NET_NUMBER_OF_DESKTOPS",
83 "_NET_DESKTOP_GEOMETRY",
84 "_NET_DESKTOP_VIEWPORT",
85 "_NET_CURRENT_DESKTOP",
86 "_NET_ACTIVE_WINDOW",
87 "_NET_WORKAREA",
88 "_NET_SUPPORTING_WM_CHECK",
89 "_NET_WM_DESKTOP",
90 "_NET_WM_STATE",
91 "_NET_WM_STRUT",
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 {
109 WScreen *scr;
110 Window *client_windows;
111 int client_count;
112 int client_size;
113 } NetData;
119 static void setSupportedHints(WScreen *scr)
121 Atom atom[32];
122 int i = 0;
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,
137 PropModeReplace,
138 (unsigned char*)&scr->info_window, 1);
140 XChangeProperty(dpy, scr->info_window,
141 net_supporting_wm_check, XA_WINDOW, 32,
142 PropModeReplace,
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,
152 PropModeReplace,
153 (unsigned char*)&sizes, 2);
155 /* set desktop viewport. dynamic change is not supported */
156 sizes[0] = 0;
157 sizes[1] = 0;
159 XChangeProperty(dpy, scr->root_win,
160 net_desktop_viewport, XA_CARDINAL, 32,
161 PropModeReplace,
162 (unsigned char*)&sizes, 2);
167 void netwmInitialize(WScreen *scr)
169 NetData *data;
170 Atom atom[32];
172 #ifdef HAVE_XINTERNATOMS
173 XInternAtoms(dpy, atomNames, sizeof(atomNames)/sizeof(char*),
174 False, atom);
175 #else
177 int i;
178 for (i = 0; i < sizeof(atomNames)/sizeof(char*); i++) {
179 atom[i] = XInternAtom(dpy, atomNames[i], False);
182 #endif
183 net_supported = atom[0];
184 net_client_list = atom[1];
186 setSupportedHints(scr);
188 data = wmalloc(sizeof(NetData));
189 data->scr = scr;
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);
209 void
210 netwmUpdateWorkarea(WScreen *scr)
212 unsigned int area[4];
214 /* XXX */
216 XChangeProperty(dpy, scr->root_win, net_workarea, XA_CARDINAL, 32,
217 PropModeReplace,
218 (unsigned char*)area, 4);
223 static void
224 updateClientList(WScreen *scr, WWindow *wwin, Bool added)
226 NetData *data = scr->netdata;
228 if (added) {
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);
239 } else {
240 int i;
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--;
249 break;
253 /* update client list */
254 XChangeProperty(dpy, scr->root_win, net_client_list, XA_WINDOW, 32,
255 PropModeReplace,
256 (unsigned char *)data->client_windows,
257 data->client_count);
259 XFlush(dpy);
264 static void
265 updateClientListStacking(WScreen *scr)
267 WWindow *wwin;
268 Window *client_list;
269 int client_count;
270 WCoreWindow *tmp;
271 WMBagIterator iter;
273 /* update client list */
275 client_list = (Window*)malloc(sizeof(Window)*scr->window_count);
276 if (!client_list) {
277 wwarning(_("out of memory while updating wm hints"));
278 return;
281 WM_ETARETI_BAG(scr->stacking_list, tmp, iter) {
282 while (tmp) {
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,
290 PropModeReplace,
291 (unsigned char *)client_list, client_count);
293 wfree(client_list);
295 XFlush(dpy);
300 static void
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,
307 PropModeReplace,
308 (unsigned char*)&count, 1);
312 static void
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,
319 PropModeReplace,
320 (unsigned char*)&count, 1);
324 static void
325 updateWorkspaceNames(WScreen *scr, int workspace)
327 /* XXX UTF 8 */
331 static void
332 updateFocusHint(WScreen *scr, WWindow *wwin) /* changeable */
334 Window window = None;
336 if (wwin)
337 window = wwin->client_win;
339 XChangeProperty(dpy, scr->root_win,
340 net_active_window, XA_WINDOW, 32,
341 PropModeReplace,
342 (unsigned char*)&window, 1);
346 static void
347 updateWorkspaceHint(WWindow *wwin, Bool del)
349 if (del) {
350 XDeleteProperty(dpy, wwin->client_win, net_wm_desktop);
351 } else {
352 XChangeProperty(dpy, wwin->screen_ptr->root_win,
353 net_wm_desktop, XA_CARDINAL, 32,
354 PropModeReplace,
355 (unsigned char*)&wwin->frame->workspace, 1);
360 static void
361 updateStateHint(WWindow *wwin, Bool del) /* changeable */
363 if (del) {
364 if (!wwin->flags.net_state_from_client)
365 XDeleteProperty(dpy, wwin->client_win, net_wm_state);
366 } else {
367 Atom state[8];
368 int i = 0;
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;
386 static void
387 updateStrut(WWindow *wwin, Bool adding)
389 if (adding) {
390 // XGetWindowProperty(dpy, wwin->client_win,
392 /* XXX add property observer */
393 } else {
398 static void
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);
437 static void
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);