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