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