]> git.decadent.org.uk Git - ion3.git/blob - mod_statusbar/main.c
bf0e1d0034c101fe1ef823d7a2dc24976945a6b8
[ion3.git] / mod_statusbar / main.c
1 /*
2  * ion/mod_statusbar/main.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 <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     
98     if(gettimeofday(&endtime, NULL)!=0){
99         warn_err();
100         return FALSE;
101     }
102     
103     now=endtime;
104     endtime.tv_sec+=CF_STATUSD_TIMEOUT_SEC;
105     
106     while(1){
107         FD_ZERO(&rfds);
108
109         /* Calculate remaining time */
110         if(now.tv_sec>endtime.tv_sec){
111             goto timeout;
112         }else if(now.tv_sec==endtime.tv_sec){
113             if(now.tv_usec>=endtime.tv_usec)
114                 goto timeout;
115             tv.tv_sec=0;
116             tv.tv_usec=endtime.tv_usec-now.tv_usec;
117         }else{
118             tv.tv_usec=USEC+endtime.tv_usec-now.tv_usec;
119             tv.tv_sec=-1+endtime.tv_sec-now.tv_sec;
120             /* Kernel lameness tuner: */
121             tv.tv_sec+=tv.tv_usec/USEC;
122             tv.tv_usec%=USEC;
123         }
124         
125         FD_SET(outfd, &rfds);
126         FD_SET(errfd, &rfds);
127     
128         retval=select(nfds+1, &rfds, NULL, NULL, &tv);
129         if(retval>0){
130             if(FD_ISSET(errfd, &rfds)){
131                 if(!process_pipe(errfd, eh, &dummy, &eagain))
132                     return FALSE;
133             }
134             if(FD_ISSET(outfd, &rfds)){
135                 if(!process_pipe(outfd, dh, &doneseen, &eagain))
136                     return FALSE;
137                 if(doneseen){
138                     /* Read rest of errors. */
139                     bool ok;
140                     do{
141                         ok=process_pipe(errfd, eh, &dummy, &eagain);
142                     }while(ok && !eagain);
143                     return TRUE;
144                 }
145             }
146         }else if(retval==0){
147             goto timeout;
148         }
149         
150         if(gettimeofday(&now, NULL)!=0){
151             warn_err();
152             return FALSE;
153         }
154     }
155     
156     return TRUE;
157     
158 timeout:
159     warn(TR("ion-statusd timed out."));
160     return FALSE;
161 }
162
163
164 EXTL_EXPORT
165 int mod_statusbar__launch_statusd(const char *cmd,
166                                   ExtlFn initdatahandler,
167                                   ExtlFn initerrhandler,
168                                   ExtlFn datahandler,
169                                   ExtlFn errhandler)
170 {
171     pid_t pid;
172     int outfd=-1, errfd=-1;
173     
174     if(cmd==NULL)
175         return -1;
176     
177     pid=mainloop_do_spawn(cmd, NULL, NULL,
178                           NULL, &outfd, &errfd);
179     
180     if(pid<0)
181         return -1;
182     
183     if(!wait_statusd_init(outfd, errfd, initdatahandler, initerrhandler))
184         goto err;
185     
186     if(!mainloop_register_input_fd_extlfn(outfd, datahandler))
187         goto err;
188     
189     if(!mainloop_register_input_fd_extlfn(errfd, errhandler))
190         goto err2;
191
192     return pid;
193     
194 err2:    
195     mainloop_unregister_input_fd(outfd);
196 err:    
197     close(outfd);
198     close(errfd);
199     return -1;
200 }
201
202
203 /*}}}*/
204
205
206 /*{{{ Systray */
207
208
209 static bool is_systray(WClientWin *cwin)
210 {
211     static Atom atom__kde_net_wm_system_tray_window_for=None;
212     Atom actual_type=None;
213     int actual_format;
214     unsigned long nitems;
215     unsigned long bytes_after;
216     unsigned char *prop;
217     char *dummy;
218     bool is=FALSE;
219
220     if(extl_table_gets_s(cwin->proptab, "statusbar", &dummy)){
221         free(dummy);
222         return TRUE;
223     }
224     
225     if(atom__kde_net_wm_system_tray_window_for==None){
226         atom__kde_net_wm_system_tray_window_for=XInternAtom(ioncore_g.dpy,
227                                                             "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR",
228                                                             False);
229     }
230     if(XGetWindowProperty(ioncore_g.dpy, cwin->win,
231                           atom__kde_net_wm_system_tray_window_for, 0,
232                           sizeof(Atom), False, AnyPropertyType, 
233                           &actual_type, &actual_format, &nitems,
234                           &bytes_after, &prop)==Success){
235         if(actual_type!=None){
236             is=TRUE;
237         }
238         XFree(prop);
239     }
240     
241     return is;
242 }
243
244
245 static bool clientwin_do_manage_hook(WClientWin *cwin, const WManageParams *param)
246 {
247     WStatusBar *sb=NULL;
248     
249     if(!is_systray(cwin))
250         return FALSE;
251     
252     sb=mod_statusbar_find_suitable(cwin, param);
253     if(sb==NULL)
254         return FALSE;
255
256     return region_manage_clientwin((WRegion*)sb, cwin, param,
257                                    MANAGE_REDIR_PREFER_NO);
258 }
259
260     
261 /*}}}*/
262
263
264 /*{{{ Init & deinit */
265
266
267 void mod_statusbar_deinit()
268 {
269     hook_remove(clientwin_do_manage_alt, 
270                 (WHookDummy*)clientwin_do_manage_hook);
271
272     if(mod_statusbar_statusbar_bindmap!=NULL){
273         ioncore_free_bindmap("WStatusBar", mod_statusbar_statusbar_bindmap);
274         mod_statusbar_statusbar_bindmap=NULL;
275     }
276
277     ioncore_unregister_regclass(&CLASSDESCR(WStatusBar));
278
279     mod_statusbar_unregister_exports();
280 }
281
282
283 bool mod_statusbar_init()
284 {
285     mod_statusbar_statusbar_bindmap=ioncore_alloc_bindmap("WStatusBar", NULL);
286     
287     if(mod_statusbar_statusbar_bindmap==NULL)
288         return FALSE;
289
290     if(!ioncore_register_regclass(&CLASSDESCR(WStatusBar),
291                                   (WRegionLoadCreateFn*) statusbar_load)){
292         mod_statusbar_deinit();
293         return FALSE;
294     }
295
296     if(!mod_statusbar_register_exports()){
297         mod_statusbar_deinit();
298         return FALSE;
299     }
300     
301     hook_add(clientwin_do_manage_alt, 
302              (WHookDummy*)clientwin_do_manage_hook);
303
304     /*ioncore_read_config("cfg_statusbar", NULL, TRUE);*/
305     
306     return TRUE;
307 }
308
309
310 /*}}}*/
311