]> git.decadent.org.uk Git - ion3.git/blob - mod_statusbar/main.c
[svn-upgrade] Integrating new upstream version, ion3 (20070506)
[ion3.git] / mod_statusbar / main.c
1 /*
2  * ion/mod_statusbar/main.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2007. 
5  *
6  * See the included file LICENSE for details.
7  */
8
9 #include <sys/time.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12 #include <time.h>
13 #include <errno.h>
14
15 #include <libtu/minmax.h>
16 #include <libextl/readconfig.h>
17 #include <libmainloop/exec.h>
18 #include <libmainloop/select.h>
19 #include <ioncore/saveload.h>
20 #include <ioncore/bindmaps.h>
21 #include <ioncore/global.h>
22
23 #include "statusbar.h"
24 #include "exports.h"
25
26
27 #define CF_STATUSD_TIMEOUT_SEC 5
28
29
30 /*{{{ Module information */
31
32
33 #include "../version.h"
34
35 char mod_statusbar_ion_api_version[]=ION_API_VERSION;
36
37
38 /*}}}*/
39
40
41 /*{{{ Bindmaps */
42
43
44 WBindmap *mod_statusbar_statusbar_bindmap=NULL;
45
46
47 /*}}}*/
48
49
50 /*{{{ Statusd launch helper */
51
52
53 #define BL 1024
54
55
56 static bool process_pipe(int fd, ExtlFn fn, 
57                          bool *doneseen, bool *eagain)
58 {
59     char buf[BL];
60     int n;
61     bool fnret;
62     
63     *eagain=FALSE;
64     
65     n=read(fd, buf, BL-1);
66     
67     if(n<0){
68         if(errno==EAGAIN || errno==EINTR){
69             *eagain=(errno==EAGAIN);
70             return TRUE;
71         }
72         warn_err_obj(TR("reading a pipe"));
73         return FALSE;
74     }else if(n>0){
75         buf[n]='\0';
76         *doneseen=FALSE;
77         return extl_call(fn, "s", "b", &buf, doneseen);
78     }
79     
80     return FALSE;
81 }
82
83
84 #define USEC 1000000
85
86
87 static bool wait_statusd_init(int outfd, int errfd, ExtlFn dh, ExtlFn eh)
88 {
89     fd_set rfds;
90     struct timeval tv, endtime, now;
91     int nfds=maxof(outfd, errfd);
92     int retval;
93     bool dummy, doneseen, eagain=FALSE;
94     
95     if(gettimeofday(&endtime, NULL)!=0){
96         warn_err();
97         return FALSE;
98     }
99     
100     now=endtime;
101     endtime.tv_sec+=CF_STATUSD_TIMEOUT_SEC;
102     
103     while(1){
104         FD_ZERO(&rfds);
105
106         /* Calculate remaining time */
107         if(now.tv_sec>endtime.tv_sec){
108             goto timeout;
109         }else if(now.tv_sec==endtime.tv_sec){
110             if(now.tv_usec>=endtime.tv_usec)
111                 goto timeout;
112             tv.tv_sec=0;
113             tv.tv_usec=endtime.tv_usec-now.tv_usec;
114         }else{
115             tv.tv_usec=USEC+endtime.tv_usec-now.tv_usec;
116             tv.tv_sec=-1+endtime.tv_sec-now.tv_sec;
117             /* Kernel lameness tuner: */
118             tv.tv_sec+=tv.tv_usec/USEC;
119             tv.tv_usec%=USEC;
120         }
121         
122         FD_SET(outfd, &rfds);
123         FD_SET(errfd, &rfds);
124     
125         retval=select(nfds+1, &rfds, NULL, NULL, &tv);
126         if(retval>0){
127             if(FD_ISSET(errfd, &rfds)){
128                 if(!process_pipe(errfd, eh, &dummy, &eagain))
129                     return FALSE;
130             }
131             if(FD_ISSET(outfd, &rfds)){
132                 if(!process_pipe(outfd, dh, &doneseen, &eagain))
133                     return FALSE;
134                 if(doneseen){
135                     /* Read rest of errors. */
136                     bool ok;
137                     do{
138                         ok=process_pipe(errfd, eh, &dummy, &eagain);
139                     }while(ok && !eagain);
140                     return TRUE;
141                 }
142             }
143         }else if(retval==0){
144             goto timeout;
145         }
146         
147         if(gettimeofday(&now, NULL)!=0){
148             warn_err();
149             return FALSE;
150         }
151     }
152     
153     return TRUE;
154     
155 timeout:
156     warn(TR("ion-statusd timed out."));
157     return FALSE;
158 }
159
160
161 EXTL_EXPORT
162 int mod_statusbar__launch_statusd(const char *cmd,
163                                   ExtlFn initdatahandler,
164                                   ExtlFn initerrhandler,
165                                   ExtlFn datahandler,
166                                   ExtlFn errhandler)
167 {
168     pid_t pid;
169     int outfd=-1, errfd=-1;
170     
171     if(cmd==NULL)
172         return -1;
173     
174     pid=mainloop_do_spawn(cmd, NULL, NULL,
175                           NULL, &outfd, &errfd);
176     
177     if(pid<0)
178         return -1;
179     
180     if(!wait_statusd_init(outfd, errfd, initdatahandler, initerrhandler))
181         goto err;
182     
183     if(!mainloop_register_input_fd_extlfn(outfd, datahandler))
184         goto err;
185     
186     if(!mainloop_register_input_fd_extlfn(errfd, errhandler))
187         goto err2;
188
189     return pid;
190     
191 err2:    
192     mainloop_unregister_input_fd(outfd);
193 err:    
194     close(outfd);
195     close(errfd);
196     return -1;
197 }
198
199
200 /*}}}*/
201
202
203 /*{{{ Systray */
204
205
206 static bool is_systray(WClientWin *cwin)
207 {
208     static Atom atom__kde_net_wm_system_tray_window_for=None;
209     Atom actual_type=None;
210     int actual_format;
211     unsigned long nitems;
212     unsigned long bytes_after;
213     unsigned char *prop;
214     char *dummy;
215     bool is=FALSE;
216
217     if(extl_table_gets_s(cwin->proptab, "statusbar", &dummy)){
218         free(dummy);
219         return TRUE;
220     }
221     
222     if(atom__kde_net_wm_system_tray_window_for==None){
223         atom__kde_net_wm_system_tray_window_for=XInternAtom(ioncore_g.dpy,
224                                                             "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR",
225                                                             False);
226     }
227     if(XGetWindowProperty(ioncore_g.dpy, cwin->win,
228                           atom__kde_net_wm_system_tray_window_for, 0,
229                           sizeof(Atom), False, AnyPropertyType, 
230                           &actual_type, &actual_format, &nitems,
231                           &bytes_after, &prop)==Success){
232         if(actual_type!=None){
233             is=TRUE;
234         }
235         XFree(prop);
236     }
237     
238     return is;
239 }
240
241
242 static bool clientwin_do_manage_hook(WClientWin *cwin, const WManageParams *param)
243 {
244     WStatusBar *sb=NULL;
245     
246     if(!is_systray(cwin))
247         return FALSE;
248     
249     sb=mod_statusbar_find_suitable(cwin, param);
250     if(sb==NULL)
251         return FALSE;
252
253     return region_manage_clientwin((WRegion*)sb, cwin, param,
254                                    MANAGE_PRIORITY_NONE);
255 }
256
257     
258 /*}}}*/
259
260
261 /*{{{ Init & deinit */
262
263
264 void mod_statusbar_deinit()
265 {
266     hook_remove(clientwin_do_manage_alt, 
267                 (WHookDummy*)clientwin_do_manage_hook);
268
269     if(mod_statusbar_statusbar_bindmap!=NULL){
270         ioncore_free_bindmap("WStatusBar", mod_statusbar_statusbar_bindmap);
271         mod_statusbar_statusbar_bindmap=NULL;
272     }
273
274     ioncore_unregister_regclass(&CLASSDESCR(WStatusBar));
275
276     mod_statusbar_unregister_exports();
277 }
278
279
280 bool mod_statusbar_init()
281 {
282     mod_statusbar_statusbar_bindmap=ioncore_alloc_bindmap("WStatusBar", NULL);
283     
284     if(mod_statusbar_statusbar_bindmap==NULL)
285         return FALSE;
286
287     if(!ioncore_register_regclass(&CLASSDESCR(WStatusBar),
288                                   (WRegionLoadCreateFn*) statusbar_load)){
289         mod_statusbar_deinit();
290         return FALSE;
291     }
292
293     if(!mod_statusbar_register_exports()){
294         mod_statusbar_deinit();
295         return FALSE;
296     }
297     
298     hook_add(clientwin_do_manage_alt, 
299              (WHookDummy*)clientwin_do_manage_hook);
300
301     /*ioncore_read_config("cfg_statusbar", NULL, TRUE);*/
302     
303     return TRUE;
304 }
305
306
307 /*}}}*/
308