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