Remove/mark some unused functions and parameters
[notion.git] / ioncore / netwm.c
blob61c16e1c347f37d78aebacc1704bfe31591763a5
1 /*
2 * ion/ioncore/netwm.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <X11/Xatom.h>
10 #include <X11/Xmd.h>
12 #include <libtu/util.h>
13 #include "common.h"
14 #include "global.h"
15 #include "fullscreen.h"
16 #include "clientwin.h"
17 #include "netwm.h"
18 #include "property.h"
19 #include "activity.h"
20 #include "focus.h"
21 #include "xwindow.h"
22 #include "extlconv.h"
23 #include "group.h"
24 #include "event.h"
27 /*{{{ Atoms */
29 static Atom atom_net_wm_name=0;
30 static Atom atom_net_wm_state=0;
31 static Atom atom_net_wm_state_fullscreen=0;
32 static Atom atom_net_wm_state_demands_attention=0;
33 static Atom atom_net_supporting_wm_check=0;
34 static Atom atom_net_virtual_roots=0;
35 static Atom atom_net_active_window=0;
36 static Atom atom_net_wm_user_time=0;
37 static Atom atom_net_wm_allowed_actions=0;
38 static Atom atom_net_wm_moveresize=0;
40 #define N_NETWM 9
42 static Atom atom_net_supported=0;
44 #define SOURCE_UNKNOWN 0
45 #define SOURCE_APPLICATION 1
46 #define SOURCE_PAGER 2
48 /*}}}*/
51 /*{{{ Initialisation */
54 void netwm_init()
56 atom_net_wm_name=XInternAtom(ioncore_g.dpy, "_NET_WM_NAME", False);
57 atom_net_wm_state=XInternAtom(ioncore_g.dpy, "_NET_WM_STATE", False);
58 atom_net_wm_state_fullscreen=XInternAtom(ioncore_g.dpy, "_NET_WM_STATE_FULLSCREEN", False);
59 atom_net_wm_state_demands_attention=XInternAtom(ioncore_g.dpy, "_NET_WM_STATE_DEMANDS_ATTENTION", False);
60 atom_net_supported=XInternAtom(ioncore_g.dpy, "_NET_SUPPORTED", False);
61 atom_net_supporting_wm_check=XInternAtom(ioncore_g.dpy, "_NET_SUPPORTING_WM_CHECK", False);
62 atom_net_virtual_roots=XInternAtom(ioncore_g.dpy, "_NET_VIRTUAL_ROOTS", False);
63 atom_net_active_window=XInternAtom(ioncore_g.dpy, "_NET_ACTIVE_WINDOW", False);
64 atom_net_wm_user_time=XInternAtom(ioncore_g.dpy, "_NET_WM_USER_TIME", False);
65 atom_net_wm_allowed_actions=XInternAtom(ioncore_g.dpy, "_NET_WM_ALLOWED_ACTIONS", False);
66 atom_net_wm_moveresize=XInternAtom(ioncore_g.dpy, "_NET_WM_MOVERESIZE", False);
70 void netwm_init_rootwin(WRootWin *rw)
72 Atom atoms[N_NETWM];
73 const char *p[1];
75 atoms[0]=atom_net_wm_name;
76 atoms[1]=atom_net_wm_state;
77 atoms[2]=atom_net_wm_state_fullscreen;
78 atoms[3]=atom_net_wm_state_demands_attention;
79 atoms[4]=atom_net_supporting_wm_check;
80 atoms[5]=atom_net_virtual_roots;
81 atoms[6]=atom_net_active_window;
82 atoms[7]=atom_net_wm_allowed_actions;
83 atoms[8]=atom_net_wm_moveresize;
85 XChangeProperty(ioncore_g.dpy, WROOTWIN_ROOT(rw),
86 atom_net_supporting_wm_check, XA_WINDOW,
87 32, PropModeReplace, (uchar*)&(rw->dummy_win), 1);
88 XChangeProperty(ioncore_g.dpy, rw->dummy_win,
89 atom_net_supporting_wm_check, XA_WINDOW,
90 32, PropModeReplace, (uchar*)&(rw->dummy_win), 1);
91 XChangeProperty(ioncore_g.dpy, WROOTWIN_ROOT(rw),
92 atom_net_supported, XA_ATOM,
93 32, PropModeReplace, (uchar*)atoms, N_NETWM);
95 p[0]=libtu_progbasename();
96 /**
97 * Unfortunately we cannot determine the charset of libtu_progbasename()
98 * so we'll just have to guess it makes sense in the current locale charset
100 xwindow_set_utf8_property(rw->dummy_win, atom_net_wm_name, p, 1);
104 /*}}}*/
107 /*{{{ _NET_WM_STATE */
110 bool netwm_check_initial_fullscreen(WClientWin *cwin)
113 int i, n;
114 long *data;
116 n=xwindow_get_property(cwin->win, atom_net_wm_state, XA_ATOM,
117 1, TRUE, (uchar**)&data);
119 if(n<0)
120 return FALSE;
122 for(i=0; i<n; i++){
123 if(data[i]==(long)atom_net_wm_state_fullscreen)
124 return TRUE;
127 XFree((void*)data);
129 return FALSE;
132 /*EXTL_DOC
133 * refresh \_NET\_WM\_STATE markers for this window
135 EXTL_SAFE
136 EXTL_EXPORT
137 void ioncore_update_net_state(WClientWin *cwin)
139 netwm_update_state(cwin);
142 void netwm_update_state(WClientWin *cwin)
144 CARD32 data[2];
145 int n=0;
147 if(REGION_IS_FULLSCREEN(cwin))
148 data[n++]=atom_net_wm_state_fullscreen;
149 if(region_is_activity_r(&(cwin->region)))
150 data[n++]=atom_net_wm_state_demands_attention;
152 XChangeProperty(ioncore_g.dpy, cwin->win, atom_net_wm_state,
153 XA_ATOM, 32, PropModeReplace, (uchar*)data, n);
156 void netwm_update_allowed_actions(WClientWin *cwin)
158 CARD32 data[1];
159 int n=0;
161 /* TODO add support for 'resize' and list it here */
162 /* TODO add support for 'minimize' and list it here */
163 /* TODO add support for 'maximize_horz' and list it here */
164 /* TODO add support for 'maximize_vert' and list it here */
165 /* TODO add support for 'fullscreen' and list it here */
166 /* TODO add support for 'change desktop' and list it here */
167 /* TODO add support for 'close' and list it here */
168 /* TODO add support for 'above' and list it here */
169 /* TODO add support for 'below' and list it here */
171 XChangeProperty(ioncore_g.dpy, cwin->win, atom_net_wm_allowed_actions,
172 XA_ATOM, 32, PropModeReplace, (uchar*)data, n);
176 void netwm_delete_state(WClientWin *cwin)
178 XDeleteProperty(ioncore_g.dpy, cwin->win, atom_net_wm_state);
183 static void netwm_state_change_rq(WClientWin *cwin,
184 const XClientMessageEvent *ev)
186 if((ev->data.l[1]==0 ||
187 ev->data.l[1]!=(long)atom_net_wm_state_fullscreen) &&
188 (ev->data.l[2]==0 ||
189 ev->data.l[2]!=(long)atom_net_wm_state_fullscreen)){
190 return;
193 /* Ok, full screen add/remove/toggle */
194 if(!REGION_IS_FULLSCREEN(cwin)){
195 if(ev->data.l[0]==_NET_WM_STATE_ADD ||
196 ev->data.l[0]==_NET_WM_STATE_TOGGLE){
197 WRegion *grp=region_groupleader_of((WRegion*)cwin);
198 bool sw=clientwin_fullscreen_may_switchto(cwin);
199 cwin->flags|=CLIENTWIN_FS_RQ;
200 if(!region_enter_fullscreen(grp, sw))
201 cwin->flags&=~CLIENTWIN_FS_RQ;
202 }else{
203 /* Should not be set.. */
204 cwin->flags&=~CLIENTWIN_FS_RQ;
206 }else{
207 if(ev->data.l[0]==_NET_WM_STATE_REMOVE ||
208 ev->data.l[0]==_NET_WM_STATE_TOGGLE){
209 WRegion *grp=region_groupleader_of((WRegion*)cwin);
210 bool sw=clientwin_fullscreen_may_switchto(cwin);
211 cwin->flags&=~CLIENTWIN_FS_RQ;
212 region_leave_fullscreen(grp, sw);
213 }else{
214 /* Set the flag */
215 cwin->flags|=CLIENTWIN_FS_RQ;
221 /*}}}*/
224 /*{{{ _NET_ACTIVE_WINDOW */
227 void netwm_set_active(WRegion *reg)
229 CARD32 data[1]={None};
231 if(OBJ_IS(reg, WClientWin))
232 data[0]=region_xwindow(reg);
234 /* The spec doesn't say how multihead should be handled, so
235 * we just update the root window the window is on.
237 XChangeProperty(ioncore_g.dpy, region_root_of(reg),
238 atom_net_active_window, XA_WINDOW,
239 32, PropModeReplace, (uchar*)data, 1);
243 static void netwm_active_window_rq(WClientWin *cwin,
244 const XClientMessageEvent *ev)
246 long source=ev->data.l[0];
248 * By default we ignore non-pager activity requests, as they're known to
249 * steal focus from newly-created windows :(
251 bool ignore=source!=SOURCE_PAGER;
253 extl_table_gets_b(cwin->proptab, "ignore_net_active_window", &ignore);
255 if(!ignore)
256 region_goto((WRegion*)cwin);
257 else
258 region_set_activity((WRegion*)cwin, SETPARAM_SET);
262 /*}}}*/
265 /*{{{ _NET_WM_NAME */
268 char **netwm_get_name(WClientWin *cwin)
270 return xwindow_get_text_property(cwin->win, atom_net_wm_name, NULL);
274 /*}}}*/
277 /*{{{ netwm_handle_client_message */
280 void netwm_handle_client_message(const XClientMessageEvent *ev)
282 /* Check _NET_WM_STATE fullscreen request */
283 if(ev->message_type==atom_net_wm_state && ev->format==32){
284 WClientWin *cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
285 if(cwin!=NULL)
286 netwm_state_change_rq(cwin, ev);
288 /* Check _NET_ACTIVE_WINDOW request */
289 else if(ev->message_type==atom_net_active_window && ev->format==32){
290 WClientWin *cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
291 if(cwin!=NULL)
292 netwm_active_window_rq(cwin, ev);
297 /*}}}*/
300 /*{{{ netwm_handle_property */
303 bool netwm_handle_property(WClientWin *cwin, const XPropertyEvent *ev)
305 if(ev->atom!=atom_net_wm_name)
306 return FALSE;
308 clientwin_get_set_name(cwin);
309 return TRUE;
313 /*}}}*/
316 /*{{{ user time */
318 /** When a new window is mapped, look at the netwm user time to find out
319 * whether the new window should be switched to and get the focus.
321 * It is unclear what the desired behavior would be, and how we should takee
322 * into consideration ioncore_g.usertime_diff_new and IONCORE_CLOCK_SKEW_MS,
323 * so for now we deny raising the new window only in the special case where
324 * its user time is set to 0, specifically preventing it from being raised.
326 void netwm_check_manage_user_time(WClientWin *cwin, WManageParams *param)
328 /* the currently focussed window */
329 WClientWin *cur=OBJ_CAST(ioncore_g.focus_current, WClientWin);
330 /* the new window */
331 Window win=region_xwindow((WRegion*)cwin);
332 /* user time */
333 CARD32 ut=0;
334 /* whether the new (got) and current (gotcut) windows had their usertime
335 * set */
336 bool got=FALSE, gotcut=FALSE;
337 bool nofocus=FALSE;
339 if(cur!=NULL){
340 Window curwin;
341 /* current window user time */
342 CARD32 cut;
343 if(param->tfor==cur)
344 return;
345 curwin=region_xwindow((WRegion*)cur);
346 gotcut=xwindow_get_cardinal_property(curwin, atom_net_wm_user_time, &cut);
349 got=xwindow_get_cardinal_property(win, atom_net_wm_user_time, &ut);
351 /* The special value of zero on a newly mapped window can be used to
352 * request that the window not be initially focused when it is mapped */
353 if (got && ut == 0)
354 nofocus = TRUE;
356 /* there was some other logic here, but it was not clear how it was meant
357 * to work and prevented newly created windows from receiving the focus
358 * in some cases
359 * (https://sourceforge.net/tracker/?func=detail&aid=3109576&group_id=314802&atid=1324528)
360 * Stripped until we decide how this is supposed to behave.
363 if(nofocus){
364 param->switchto=FALSE;
365 param->jumpto=FALSE;
370 /*}}}*/
372 /*{{{ _NET_WM_VIRTUAL_ROOTS */
374 int count_screens()
376 int result = 0;
377 WScreen *scr;
379 FOR_ALL_SCREENS(scr){
380 result++;
383 return result;
386 /*EXTL_DOC
387 * refresh \_NET\_WM\_VIRTUAL\_ROOTS
389 EXTL_SAFE
390 EXTL_EXPORT
391 void ioncore_screens_updated(WRootWin *rw)
393 int current_screen = 0;
394 int n_screens;
396 long *virtualroots;
397 WScreen *scr;
399 n_screens = count_screens();
400 virtualroots = (long*)malloc(n_screens * sizeof(long));
402 FOR_ALL_SCREENS(scr){
403 virtualroots[current_screen] = region_xwindow((WRegion *)scr);
404 current_screen++;
407 XChangeProperty(ioncore_g.dpy, WROOTWIN_ROOT(rw),
408 atom_net_virtual_roots, XA_WINDOW,
409 32, PropModeReplace, (uchar*)virtualroots, n_screens);
411 free(virtualroots);
414 /*}}}*/