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