]> git.decadent.org.uk Git - ion3.git/blob - ioncore/netwm.c
Merge commit '20070203' into HEAD
[ion3.git] / ioncore / netwm.c
1 /*
2  * ion/ioncore/netwm.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2007. 
5  *
6  * Ion is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  */
11
12 #include <X11/Xatom.h>
13 #include <X11/Xmd.h>
14
15 #include <libtu/util.h>
16 #include "common.h"
17 #include "global.h"
18 #include "fullscreen.h"
19 #include "clientwin.h"
20 #include "netwm.h"
21 #include "property.h"
22 #include "focus.h"
23 #include "xwindow.h"
24 #include "extlconv.h"
25
26
27 /*{{{ Atoms */
28
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_supporting_wm_check=0;
33 static Atom atom_net_virtual_roots=0;
34 static Atom atom_net_active_window=0;
35
36 #define N_NETWM 6
37
38 static Atom atom_net_supported=0;
39
40 /*}}}*/
41
42
43 /*{{{ Initialisation */
44
45
46 void netwm_init()
47 {
48     atom_net_wm_name=XInternAtom(ioncore_g.dpy, "_NET_WM_NAME", False);
49     atom_net_wm_state=XInternAtom(ioncore_g.dpy, "_NET_WM_STATE", False);
50     atom_net_wm_state_fullscreen=XInternAtom(ioncore_g.dpy, "_NET_WM_STATE_FULLSCREEN", False);
51     atom_net_supported=XInternAtom(ioncore_g.dpy, "_NET_SUPPORTED", False);
52     atom_net_supporting_wm_check=XInternAtom(ioncore_g.dpy, "_NET_SUPPORTING_WM_CHECK", False);
53     atom_net_virtual_roots=XInternAtom(ioncore_g.dpy, "_NET_VIRTUAL_ROOTS", False);
54     atom_net_active_window=XInternAtom(ioncore_g.dpy, "_NET_ACTIVE_WINDOW", False);
55 }
56
57
58 void netwm_init_rootwin(WRootWin *rw)
59 {
60     Atom atoms[N_NETWM];
61         const char *p[1];
62
63     atoms[0]=atom_net_wm_name;
64     atoms[1]=atom_net_wm_state;
65     atoms[2]=atom_net_wm_state_fullscreen;
66     atoms[3]=atom_net_supporting_wm_check;
67     atoms[4]=atom_net_virtual_roots;
68     atoms[5]=atom_net_active_window;
69     
70     XChangeProperty(ioncore_g.dpy, WROOTWIN_ROOT(rw),
71                     atom_net_supporting_wm_check, XA_WINDOW,
72                     32, PropModeReplace, (uchar*)&(rw->dummy_win), 1);
73     XChangeProperty(ioncore_g.dpy, WROOTWIN_ROOT(rw),
74                     atom_net_supported, XA_ATOM,
75                     32, PropModeReplace, (uchar*)atoms, N_NETWM);
76     /* Something else should probably be used as WM name here. */
77     p[0]=prog_execname();
78     xwindow_set_text_property(rw->dummy_win, atom_net_wm_name, p, 1);
79 }
80
81
82 /*}}}*/
83
84
85 /*{{{ _NET_WM_STATE */
86
87
88 int netwm_check_initial_fullscreen(WClientWin *cwin, bool sw)
89 {
90
91     int i, n;
92     int ret=0;
93     long *data;
94     
95     n=xwindow_get_property(cwin->win, atom_net_wm_state, XA_ATOM,
96                    1, TRUE, (uchar**)&data);
97     
98     if(n<0)
99         return -1;
100     
101     for(i=0; i<n; i++){
102         if(data[i]==(long)atom_net_wm_state_fullscreen){
103             ret=region_enter_fullscreen((WRegion*)cwin, sw);
104             break;
105         }
106     }
107     
108     XFree((void*)data);
109
110     return ret;
111 }
112
113
114 void netwm_update_state(WClientWin *cwin)
115 {
116     CARD32 data[1];
117     int n=0;
118     
119     if(REGION_IS_FULLSCREEN(cwin))
120         data[n++]=atom_net_wm_state_fullscreen;
121
122     XChangeProperty(ioncore_g.dpy, cwin->win, atom_net_wm_state, 
123                     XA_ATOM, 32, PropModeReplace, (uchar*)data, n);
124 }
125
126
127 void netwm_delete_state(WClientWin *cwin)
128 {
129     XDeleteProperty(ioncore_g.dpy, cwin->win, atom_net_wm_state);
130 }
131
132
133
134 static void netwm_state_change_rq(WClientWin *cwin, 
135                                   const XClientMessageEvent *ev)
136 {
137     if((ev->data.l[1]==0 ||
138         ev->data.l[1]!=(long)atom_net_wm_state_fullscreen) &&
139        (ev->data.l[2]==0 ||
140         ev->data.l[2]!=(long)atom_net_wm_state_fullscreen)){
141         return;
142     }
143     
144     /* Ok, full screen add/remove/toggle */
145     if(!REGION_IS_FULLSCREEN(cwin)){
146         if(ev->data.l[0]==_NET_WM_STATE_ADD || 
147            ev->data.l[0]==_NET_WM_STATE_TOGGLE){
148             bool sw=clientwin_fullscreen_may_switchto(cwin);
149             cwin->flags|=CLIENTWIN_FS_RQ;
150             if(!region_enter_fullscreen((WRegion*)cwin, sw))
151                 cwin->flags&=~CLIENTWIN_FS_RQ;
152         }else{
153             /* Should not be set.. */
154             cwin->flags&=~CLIENTWIN_FS_RQ;
155         }
156     }else{
157         if(ev->data.l[0]==_NET_WM_STATE_REMOVE || 
158            ev->data.l[0]==_NET_WM_STATE_TOGGLE){
159             bool sw=clientwin_fullscreen_may_switchto(cwin);
160             cwin->flags&=~CLIENTWIN_FS_RQ;
161             region_leave_fullscreen((WRegion*)cwin, sw);
162         }else{
163             /* Set the flag */
164             cwin->flags|=CLIENTWIN_FS_RQ;
165         }
166     }
167 }
168
169
170 /*}}}*/
171
172
173 /*{{{ _NET_ACTIVE_WINDOW */
174
175
176 void netwm_set_active(WRegion *reg)
177 {
178     CARD32 data[1]={None};
179     
180     if(OBJ_IS(reg, WClientWin))
181         data[0]=region_xwindow(reg);
182
183     /* The spec doesn't say how multihead should be handled, so
184      * we just update the root window the window is on.
185      */
186     XChangeProperty(ioncore_g.dpy, region_root_of(reg), 
187                     atom_net_active_window, XA_WINDOW, 
188                     32, PropModeReplace, (uchar*)data, 1);
189 }
190
191
192 static void netwm_active_window_rq(WClientWin *cwin, 
193                                    const XClientMessageEvent *ev)
194 {
195     bool ignore=TRUE;
196     
197     extl_table_gets_b(cwin->proptab, "ignore_net_active_window", &ignore);
198     
199     if(!ignore)
200         region_goto((WRegion*)cwin);
201 }
202
203
204 /*}}}*/
205
206
207 /*{{{ _NET_WM_NAME */
208
209
210 char **netwm_get_name(WClientWin *cwin)
211 {
212     return xwindow_get_text_property(cwin->win, atom_net_wm_name, NULL);
213 }
214
215
216 /*}}}*/
217
218
219 /*{{{ netwm_handle_client_message */
220
221
222 void netwm_handle_client_message(const XClientMessageEvent *ev)
223 {
224     /* Check _NET_WM_STATE fullscreen request */
225     if(ev->message_type==atom_net_wm_state && ev->format==32){
226         WClientWin *cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
227         if(cwin!=NULL)
228             netwm_state_change_rq(cwin, ev);
229     }
230     /* Check _NET_ACTIVE_WINDOW request */
231     else if(ev->message_type==atom_net_active_window && ev->format==32){
232         WClientWin *cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
233         if(cwin!=NULL)
234             netwm_active_window_rq(cwin, ev);
235     }
236 }
237
238
239 /*}}}*/
240
241
242 /*{{{ netwm_handle_property */
243
244
245 bool netwm_handle_property(WClientWin *cwin, const XPropertyEvent *ev)
246 {
247     if(ev->atom!=atom_net_wm_name)
248         return FALSE;
249     
250     clientwin_get_set_name(cwin);
251     return TRUE;
252 }
253
254
255 /*}}}*/