audacious support added
[monky] / src / conky.c
1 /*
2  * Conky, a system monitor, based on torsmo
3  *
4  * This program is licensed under BSD license, read COPYING
5  *
6  *  $Id$
7  */
8
9 #include "conky.h"
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
14 #include <time.h>
15 #include <locale.h>
16 #include <signal.h>
17 #include <unistd.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <pthread.h>
21 #include <string.h>
22 #include <limits.h>
23 #if HAVE_DIRENT_H
24 #include <dirent.h>
25 #endif
26 #include <sys/time.h>
27 #ifdef X11
28 #include <X11/Xutil.h>
29 #endif /* X11 */
30 #include <sys/types.h>
31 #include <sys/stat.h>
32
33 #define CONFIG_FILE "$HOME/.conkyrc"
34 #define MAIL_FILE "$MAIL"
35 #define MAX_IF_BLOCK_DEPTH 5
36
37 /* #define SIGNAL_BLOCKING */
38 #undef SIGNAL_BLOCKING
39
40 #ifdef X11
41
42 /* alignments */
43 enum alignment {
44         TOP_LEFT = 1,
45         TOP_RIGHT,
46         BOTTOM_LEFT,
47         BOTTOM_RIGHT,
48         NONE
49 };
50
51
52 /* for fonts */
53 struct font_list {
54
55         char name[TEXT_BUFFER_SIZE];
56         int num;
57         XFontStruct *font;
58
59 #ifdef XFT
60         XftFont *xftfont;
61         int font_alpha;
62 #endif  
63
64 };
65 static int selected_font = 0;
66 static int font_count = -1;
67 struct font_list *fonts = NULL;
68
69 #ifdef XFT
70
71 #define font_height() use_xft ? (fonts[selected_font].xftfont->ascent + fonts[selected_font].xftfont->descent) : \
72 (fonts[selected_font].font->max_bounds.ascent + fonts[selected_font].font->max_bounds.descent)
73 #define font_ascent() use_xft ? fonts[selected_font].xftfont->ascent : fonts[selected_font].font->max_bounds.ascent
74 #define font_descent() use_xft ? fonts[selected_font].xftfont->descent : fonts[selected_font].font->max_bounds.descent
75
76 #else
77
78 #define font_height() (fonts[selected_font].font->max_bounds.ascent + fonts[selected_font].font->max_bounds.descent)
79 #define font_ascent() fonts[selected_font].font->max_bounds.ascent
80 #define font_descent() fonts[selected_font].font->max_bounds.descent
81
82 #endif
83
84 #define MAX_FONTS 64 // hmm, no particular reason, just makes sense.
85
86
87 static void set_font();
88
89 int addfont(const char *data_in)
90 {
91         if (font_count > MAX_FONTS) {
92                 CRIT_ERR("you don't need that many fonts, sorry.");
93         }
94         font_count++;
95         if (font_count == 0) {
96                 if (fonts != NULL) {
97                         free(fonts);
98                 }
99                 if ((fonts = (struct font_list*)malloc(sizeof(struct font_list))) == NULL) {
100                         CRIT_ERR("malloc");
101                 }
102         }
103         fonts = realloc(fonts, (sizeof(struct font_list) * (font_count+1)));
104         if (fonts == NULL) {
105                 CRIT_ERR("realloc in addfont");
106         }
107         if (strlen(data_in) < TEXT_BUFFER_SIZE) { // must account for null terminator
108                 strncpy(fonts[font_count].name, data_in, TEXT_BUFFER_SIZE);
109 #ifdef XFT
110                 fonts[font_count].font_alpha = 0xffff;
111 #endif
112         } else {
113                 CRIT_ERR("Oops...looks like something overflowed in addfont().");
114         }
115         return font_count;
116 }
117
118 void set_first_font(const char *data_in)
119 {
120         if (font_count < 0) {
121                 if ((fonts = (struct font_list*)malloc(sizeof(struct font_list))) == NULL) {
122                         CRIT_ERR("malloc");
123                 }
124                 font_count++;
125         }
126         if (strlen(data_in) > 1) {
127                 strncpy(fonts[0].name, data_in, TEXT_BUFFER_SIZE-1);
128 #ifdef XFT
129                 fonts[0].font_alpha = 0xffff;
130 #endif
131         }
132 }
133
134 void free_fonts()
135 {
136         int i;
137         for (i=0;i<=font_count;i++) {
138 #ifdef XFT
139                 if (use_xft) {
140                         XftFontClose(display, fonts[i].xftfont);
141                 } else
142 #endif
143                 {
144                         XFreeFont(display, fonts[i].font);
145                 }
146 }
147         free(fonts);
148         fonts = NULL;
149         font_count = -1;
150         selected_font = 0;
151         set_first_font("6x10");
152 }
153
154
155 static void load_fonts()
156 {
157         int i;
158         for (i=0;i<=font_count;i++) {
159 #ifdef XFT
160         /* load Xft font */
161         if (use_xft) {
162         /*if (fonts[i].xftfont != NULL && selected_font == 0) {
163                         XftFontClose(display, fonts[i].xftfont);
164         }*/
165                 if ((fonts[i].xftfont =
166                         XftFontOpenName(display, screen, fonts[i].name)) != NULL)
167                         continue;
168                 
169                 ERR("can't load Xft font '%s'", fonts[i].name);
170                 if ((fonts[i].xftfont =
171                         XftFontOpenName(display, screen,
172                                         "courier-12")) != NULL)
173                         continue;
174                 
175                 ERR("can't load Xft font '%s'", "courier-12");
176                 
177                 if ((fonts[i].font = XLoadQueryFont(display, "fixed")) == NULL) {
178                         CRIT_ERR("can't load font '%s'", "fixed");
179                 }
180                 use_xft = 0;
181                 
182                 continue;
183         }
184 #endif
185         /* load normal font */
186 /*      if (fonts[i].font != NULL)
187                 XFreeFont(display, fonts[i].font);*/
188         
189         if ((fonts[i].font = XLoadQueryFont(display, fonts[i].name)) == NULL) {
190                 ERR("can't load font '%s'", fonts[i].name);
191                 if ((fonts[i].font = XLoadQueryFont(display, "fixed")) == NULL) {
192                         CRIT_ERR("can't load font '%s'", "fixed");
193                         printf("loaded fixed?\n");
194                 }
195         }
196         }
197 }
198
199 #endif /* X11 */
200
201 /* default config file */
202 static char *current_config;
203
204 /* set to 1 if you want all text to be in uppercase */
205 static unsigned int stuff_in_upper_case;
206
207 /* Update interval */
208 static double update_interval;
209
210 /* Run how many times? */
211 static unsigned long total_run_times;
212
213 /* fork? */
214 static int fork_to_background;
215
216 static int cpu_avg_samples, net_avg_samples;
217
218 #ifdef X11
219
220 /* Always on bottom */
221 static int on_bottom;
222
223 /* Position on the screen */
224 static int text_alignment;
225 static int gap_x, gap_y;
226
227 /* border */
228 static int draw_borders;
229 static int draw_graph_borders;
230 static int stippled_borders;
231
232 static int draw_shades, draw_outline;
233
234 static int border_margin, border_width;
235
236 static long default_fg_color, default_bg_color, default_out_color;
237
238 /* create own window or draw stuff to root? */
239 static int set_transparent = 0;
240
241
242 #ifdef OWN_WINDOW
243 static int own_window = 0;
244 static int background_colour = 0;
245 static char wm_class_name[256];
246 /* fixed size/pos is set if wm/user changes them */
247 static int fixed_size = 0, fixed_pos = 0;
248 #endif
249
250 static int minimum_width, minimum_height;
251 static int maximum_width;
252
253 /* UTF-8 */
254 int utf8_mode = 0;
255
256 #endif /* X11 */
257
258 /* no buffers in used memory? */
259 int no_buffers;
260
261 /* pad percentages to decimals? */
262 static int pad_percents = 0;
263
264 #ifdef TCP_PORT_MONITOR
265 tcp_port_monitor_collection_args_t      tcp_port_monitor_collection_args;
266 tcp_port_monitor_args_t                 tcp_port_monitor_args;
267 #endif
268
269 /* Text that is shown */
270 static char original_text[] =
271     "$nodename - $sysname $kernel on $machine\n"
272     "$hr\n"
273     "${color grey}Uptime:$color $uptime\n"
274     "${color grey}Frequency (in MHz):$color $freq\n"
275     "${color grey}Frequency (in GHz):$color $freq_g\n"
276     "${color grey}RAM Usage:$color $mem/$memmax - $memperc% ${membar 4}\n"
277     "${color grey}Swap Usage:$color $swap/$swapmax - $swapperc% ${swapbar 4}\n"
278     "${color grey}CPU Usage:$color $cpu% ${cpubar 4}\n"
279     "${color grey}Processes:$color $processes  ${color grey}Running:$color $running_processes\n"
280     "$hr\n"
281     "${color grey}File systems:\n"
282     " / $color${fs_free /}/${fs_size /} ${fs_bar 6 /}\n"
283     "${color grey}Networking:\n"
284     " Up:$color ${upspeed eth0} k/s${color grey} - Down:$color ${downspeed eth0} k/s\n"
285     "${color grey}Temperatures:\n"
286     " CPU:$color ${i2c temp 1}°C${color grey} - MB:$color ${i2c temp 2}°C\n"
287     "$hr\n"
288 #ifdef SETI
289     "${color grey}SETI@Home Statistics:\n"
290     "${color grey}Seti Unit Number:$color $seti_credit\n"
291     "${color grey}Seti Progress:$color $seti_prog% $seti_progbar\n"
292 #endif
293 #ifdef MPD
294     "${color grey}MPD: $mpd_status $mpd_artist - $mpd_title from $mpd_album at $mpd_vol\n"
295     "Bitrate: $mpd_bitrate\n" "Progress: $mpd_bar\n"
296 #endif
297     "${color grey}Name          PID     CPU%    MEM%\n"
298     " ${color lightgrey} ${top name 1} ${top pid 1} ${top cpu 1} ${top mem 1}\n"
299     " ${color lightgrey} ${top name 2} ${top pid 2} ${top cpu 2} ${top mem 2}\n"
300     " ${color lightgrey} ${top name 3} ${top pid 3} ${top cpu 3} ${top mem 3}\n"
301     " ${color lightgrey} ${top name 4} ${top pid 4} ${top cpu 4} ${top mem 4}\n"
302     "${tail /var/log/Xorg.0.log 3}";
303
304 static char *text = original_text;
305
306 static int total_updates;
307
308 /* if-blocks */
309 static int blockdepth = 0;
310 static int if_jumped = 0;
311 static int blockstart[MAX_IF_BLOCK_DEPTH];
312
313 int check_mount(char *s)
314 {
315 #if defined(__linux__)
316         int ret = 0;
317         FILE *mtab = fopen("/etc/mtab", "r");
318         if (mtab) {
319                 char buf1[256], buf2[128];
320                 while (fgets(buf1, 256, mtab)) {
321                         sscanf(buf1, "%*s %128s", buf2);
322                         if (!strcmp(s, buf2)) {
323                                 ret = 1;
324                                 break;
325                         }
326                 }
327                 fclose(mtab);
328         } else {
329                 ERR("Could not open mtab");
330         }
331         return ret;
332 #elif defined(__FreeBSD__)
333         struct statfs *mntbuf;
334         int i, mntsize;
335
336         mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
337         for (i = mntsize - 1; i >= 0; i--)
338                 if (strcmp(mntbuf[i].f_mntonname, s) == 0)
339                         return 1;
340
341         return 0;
342 #endif
343 }
344
345
346 #ifdef X11
347 static inline int calc_text_width(const char *s, int l)
348 {
349 #ifdef XFT
350         if (use_xft) {
351                 XGlyphInfo gi;
352                 if (utf8_mode) {
353                         XftTextExtentsUtf8(display, fonts[selected_font].xftfont, s, l, &gi);
354                 } else {
355                         XftTextExtents8(display, fonts[selected_font].xftfont, s, l, &gi);
356                 }
357                 return gi.xOff;
358         } else
359 #endif
360         {
361                 return XTextWidth(fonts[selected_font].font, s, l);
362         }
363 }
364 #endif /* X11 */
365
366 /* formatted text to render on screen, generated in generate_text(),
367  * drawn in draw_stuff() */
368
369 static char text_buffer[TEXT_BUFFER_SIZE * 4];
370
371 /* special stuff in text_buffer */
372
373 #define SPECIAL_CHAR '\x01'
374
375 enum {
376         HORIZONTAL_LINE,
377         STIPPLED_HR,
378         BAR,
379         FG,
380         BG,
381         OUTLINE,
382         ALIGNR,
383         ALIGNC,
384         GRAPH,
385         OFFSET,
386         VOFFSET,
387         FONT,
388 };
389
390 static struct special_t {
391         int type;
392         short height;
393         short width;
394         long arg;
395         double *graph;
396         double graph_scale;
397         int graph_width;
398         int scaled;
399         short font_added;
400         unsigned long first_colour; // for graph gradient
401         unsigned long last_colour;
402 } specials[128];
403
404 static int special_count;
405 #ifdef X11
406 static int special_index;       /* used when drawing */
407 #endif /* X11 */
408
409 #define MAX_GRAPH_DEPTH 256     /* why 256? cause an array of more then 256 doubles seems excessive, and who needs that kind of precision anyway? */
410
411 static struct special_t *new_special(char *buf, int t)
412 {
413         if (special_count >= 128)
414                 CRIT_ERR("too many special things in text");
415
416         buf[0] = SPECIAL_CHAR;
417         buf[1] = '\0';
418         specials[special_count].type = t;
419         return &specials[special_count++];
420 }
421
422 typedef struct tailstring_list {
423         char data[TEXT_BUFFER_SIZE];
424         struct tailstring_list *next;
425         struct tailstring_list *first;
426 } tailstring;
427
428 void addtail(tailstring ** head, char *data_in)
429 {
430         tailstring *tmp;
431         if ((tmp = malloc(sizeof(*tmp))) == NULL) {
432                 CRIT_ERR("malloc");
433         }
434         if (*head == NULL) {
435                 tmp->first = tmp;
436         } else {
437                 tmp->first = (*head)->first;
438         }
439         strncpy(tmp->data, data_in, TEXT_BUFFER_SIZE);
440         tmp->next = *head;
441         *head = tmp;
442 }
443
444 void freetail(tailstring * head)
445 {
446         tailstring *tmp;
447         while (head != NULL) {
448                 tmp = head->next;
449                 free(head);
450                 head = tmp;
451         }
452 }
453
454 void freelasttail(tailstring * head)
455 {
456         tailstring * tmp = head;
457         while(tmp != NULL) {
458                 if (tmp->next == head->first) {
459                         tmp->next = NULL;
460                         break;
461                 }
462                 tmp = tmp->next;
463         }
464         free(head->first);
465         while(head != NULL && tmp != NULL) {
466                 head->first = tmp;
467                 head = head->next;
468         }
469 }
470
471 static void new_bar(char *buf, int w, int h, int usage)
472 {
473         struct special_t *s = new_special(buf, BAR);
474         s->arg = (usage > 255) ? 255 : ((usage < 0) ? 0 : usage);
475         s->width = w;
476         s->height = h;
477 }
478
479 static const char *scan_bar(const char *args, int *w, int *h)
480 {
481         *w = 0;                 /* zero width means all space that is available */
482         *h = 6;
483         /* bar's argument is either height or height,width */
484         if (args) {
485                 int n = 0;
486                 if (sscanf(args, "%d,%d %n", h, w, &n) <= 1)
487                         sscanf(args, "%d %n", h, &n);
488                 args += n;
489         }
490
491         return args;
492 }
493
494 static char *scan_font(const char *args)
495 {
496         if (args && sizeof(args) < 127) {
497                 return strdup(args);
498         }
499         else {
500                 ERR("font scan failed, lets hope it doesn't mess stuff up");
501         }
502         return NULL;
503 }
504
505 #ifdef X11
506 static void new_font(char *buf, char * args) {
507         struct special_t *s = new_special(buf, FONT);
508         if (!s->font_added || strcmp(args, fonts[s->font_added].name)) {
509                 int tmp = selected_font;
510                 selected_font = s->font_added = addfont(args);
511                 load_fonts();
512 //              set_font();
513                 selected_font = tmp;
514         }
515 }
516 #endif
517
518 inline void graph_append(struct special_t *graph, double f)
519 {
520         if (!graph->scaled && f > graph->graph_scale) {
521                 f = graph->graph_scale;
522         }
523         int i;
524         if (graph->scaled) {
525                 graph->graph_scale = 1;
526         }
527         graph->graph[graph->graph_width - 1] = f; /* add new data */
528         for (i = 0; i < graph->graph_width - 1; i++) { /* shift all the data by 1 */
529                 graph->graph[i] = graph->graph[i + 1];
530                 if (graph->scaled && graph->graph[i] > graph->graph_scale) {
531                         graph->graph_scale = graph->graph[i]; /* check if we need to update the scale */
532                 }
533         }
534 }
535
536 short colour_depth = 0;
537 void set_up_gradient();
538
539 /* precalculated: 31/255, and 63/255 */
540 #define CONST_8_TO_5_BITS 0.12156862745098
541 #define CONST_8_TO_6_BITS 0.247058823529412
542
543 /* adjust color values depending on color depth*/
544 static unsigned int adjust_colors(unsigned int color)
545 {
546         double r, g, b;
547         if (colour_depth == 0) {
548                 set_up_gradient();
549         }
550         if (colour_depth == 16) {
551                 r = (color & 0xff0000) >> 16;
552                 g = (color & 0xff00) >> 8;
553                 b =  color & 0xff;
554                 color  = (int)(r * CONST_8_TO_5_BITS) << 11;
555                 color |= (int)(g * CONST_8_TO_6_BITS) << 5;
556                 color |= (int)(b * CONST_8_TO_5_BITS);
557         }
558         return color;
559 }
560
561 static void new_graph(char *buf, int w, int h, unsigned int first_colour, unsigned int second_colour, double i, int scale, int append)
562 {
563         struct special_t *s = new_special(buf, GRAPH);
564         s->width = w;
565         if (s->graph == NULL) {
566                 if (s->width > 0 && s->width < MAX_GRAPH_DEPTH) {
567                         s->graph_width = s->width - 3;  // subtract 3 for the box
568                 } else {
569                         s->graph_width = MAX_GRAPH_DEPTH - 3;
570                 }
571                 s->graph = malloc(s->graph_width * sizeof(double));
572                 memset(s->graph, 0, s->graph_width * sizeof(double));
573                 s->graph_scale = 100;
574         }
575         s->height = h;
576         s->first_colour = adjust_colors(first_colour);
577         s->last_colour = adjust_colors(second_colour);
578         if (scale != 0) {
579                 s->scaled = 0;
580         } else {
581                 s->scaled = 1;
582         }
583         /*if (s->width) {
584                 s->graph_width = s->width - 3;  // subtract 3 for rectangle around
585         }*/
586         if (s->scaled) {
587                 s->graph_scale = 1;
588         } else {
589                 s->graph_scale = scale;
590         }
591         if (append) {
592                 graph_append(s, i);
593         }
594 }
595
596 static const char *scan_graph(const char *args, int *w, int *h, unsigned int *first_colour, unsigned int *last_colour, unsigned int *scale)
597 {
598         *w = 0;                 /* zero width means all space that is available */
599         *h = 25;
600         *first_colour = 0;
601         *last_colour = 0;
602         /* graph's argument is either height or height,width */
603         if (args) {
604                 if (sscanf(args, "%*s %d,%d %x %x %i", h, w, first_colour, last_colour, scale) < 5) {
605                         if (sscanf(args, "%*s %d,%d %x %x", h, w, first_colour, last_colour) < 4) {
606                                 *scale = 0;
607                                 if (sscanf(args, "%d,%d %x %x %i", h, w, first_colour, last_colour, scale) < 5) {
608                                         *scale = 0;
609                                         if (sscanf(args, "%d,%d %x %x", h, w, first_colour, last_colour) < 4) {
610                                                 *w = 0;
611                                 *h = 25;                        
612                                 if (sscanf(args, "%*s %x %x %i", first_colour, last_colour, scale) < 3) {
613                                 *w = 0;
614                                 *h = 25;
615                                 *scale = 0;
616                                 if (sscanf(args, "%*s %x %x", first_colour, last_colour) < 2) {
617                                         *w = 0;
618                                         *h = 25;
619                                         if (sscanf(args, "%x %x %i", first_colour, last_colour, scale) < 3) {
620                                                 *first_colour = 0;
621                                                 *last_colour = 0;
622                                                 *scale = 0;
623                                                 if (sscanf(args, "%x %x", first_colour, last_colour) < 2) {
624                                         *first_colour = 0;
625                                         *last_colour = 0;
626                                         if (sscanf(args, "%d,%d %i", h, w, scale) < 3) {
627                                                 *first_colour = 0;
628                                                 *last_colour = 0;
629                                                 *scale = 0;
630                                                 if (sscanf(args, "%d,%d", h, w) < 2) {
631                                                         *first_colour = 0;
632                                                         *last_colour = 0;
633                                                         sscanf(args, "%*s %d,%d", h, w);
634         }}}}}}}}}}} // haha
635         return args;
636 }
637
638
639 static inline void new_hr(char *buf, int a)
640 {
641         new_special(buf, HORIZONTAL_LINE)->height = a;
642 }
643
644 static inline void new_stippled_hr(char *buf, int a, int b)
645 {
646         struct special_t *s = new_special(buf, STIPPLED_HR);
647         s->height = b;
648         s->arg = a;
649 }
650
651 static inline void new_fg(char *buf, long c)
652 {
653         new_special(buf, FG)->arg = c;
654 }
655
656 static inline void new_bg(char *buf, long c)
657 {
658         new_special(buf, BG)->arg = c;
659 }
660
661 static inline void new_outline(char *buf, long c)
662 {
663         new_special(buf, OUTLINE)->arg = c;
664 }
665
666 static inline void new_offset(char *buf, long c)
667 {
668         new_special(buf, OFFSET)->arg = c;
669 }
670
671 static inline void new_voffset(char *buf, long c)
672 {
673         new_special(buf, VOFFSET)->arg = c;
674 }
675
676 static inline void new_alignr(char *buf, long c)
677 {
678         new_special(buf, ALIGNR)->arg = c;
679 }
680
681 static inline void new_alignc(char *buf, long c)
682 {
683         new_special(buf, ALIGNC)->arg = c;
684 }
685
686 /* quite boring functions */
687
688 static inline void for_each_line(char *b, void (*f) (char *))
689 {
690         char *ps, *pe;
691
692         for (ps = b, pe = b; *pe; pe++) {
693                 if (*pe == '\n') {
694                         *pe = '\0';
695                         f(ps);
696                         *pe = '\n';
697                         ps = pe + 1;
698                 }
699         }
700
701         if (ps < pe)
702                 f(ps);
703 }
704
705 static void convert_escapes(char *buf)
706 {
707         char *p = buf, *s = buf;
708
709         while (*s) {
710                 if (*s == '\\') {
711                         s++;
712                         if (*s == 'n')
713                                 *p++ = '\n';
714                         else if (*s == '\\')
715                                 *p++ = '\\';
716                         s++;
717                 } else
718                         *p++ = *s++;
719         }
720         *p = '\0';
721 }
722
723 /* converts from bytes to human readable format (k, M, G, T) */
724 static void human_readable(long long a, char *buf, int size)
725 {
726         // Strange conditional due to possible overflows
727         if(a / 1024 / 1024 / 1024.0 > 1024.0){
728                 snprintf(buf, size, "%.2fT", (a / 1024 / 1024 / 1024) / 1024.0);
729         }
730         else if (a >= 1024 * 1024 * 1024) {
731                 snprintf(buf, size, "%.2fG", (a / 1024 / 1024) / 1024.0);
732         }
733         else if (a >= 1024 * 1024) {
734                 double m = (a / 1024) / 1024.0;
735                 if (m >= 100.0)
736                         snprintf(buf, size, "%.0fM", m);
737                 else
738                         snprintf(buf, size, "%.1fM", m);
739         } else if (a >= 1024)
740                 snprintf(buf, size, "%Ldk", a / (long long) 1024);
741         else
742                 snprintf(buf, size, "%Ld", a);
743 }
744
745 /* text handling */
746
747 enum text_object_type {
748         OBJ_acpiacadapter,
749         OBJ_adt746xcpu,
750         OBJ_adt746xfan,
751         OBJ_acpifan,
752         OBJ_addr,
753         OBJ_linkstatus,
754         OBJ_acpitemp,
755         OBJ_acpitempf,
756         OBJ_battery,
757         OBJ_buffers,
758         OBJ_cached,
759         OBJ_color,
760         OBJ_font,
761         OBJ_cpu,
762         OBJ_cpubar,
763         OBJ_cpugraph,
764         OBJ_diskio,
765         OBJ_diskiograph,
766         OBJ_downspeed,
767         OBJ_downspeedf,
768         OBJ_downspeedgraph,
769         OBJ_else,
770         OBJ_endif,
771         OBJ_exec,
772         OBJ_execi,
773         OBJ_texeci,
774         OBJ_execbar,
775         OBJ_execgraph,
776         OBJ_execibar,
777         OBJ_execigraph,
778         OBJ_freq,
779         OBJ_freq_g,
780         OBJ_freq_dyn,
781         OBJ_freq_dyn_g,
782         OBJ_fs_bar,
783         OBJ_fs_bar_free,
784         OBJ_fs_free,
785         OBJ_fs_free_perc,
786         OBJ_fs_size,
787         OBJ_fs_used,
788         OBJ_fs_used_perc,
789         OBJ_hr,
790         OBJ_offset,
791         OBJ_voffset,
792         OBJ_alignr,
793         OBJ_alignc,
794         OBJ_i2c,
795 #if defined(__linux__)
796         OBJ_i8k_version,
797         OBJ_i8k_bios,
798         OBJ_i8k_serial,
799         OBJ_i8k_cpu_temp,
800         OBJ_i8k_cpu_tempf,
801         OBJ_i8k_left_fan_status,
802         OBJ_i8k_right_fan_status,
803         OBJ_i8k_left_fan_rpm,
804         OBJ_i8k_right_fan_rpm,
805         OBJ_i8k_ac_status,      
806         OBJ_i8k_buttons_status,
807 #endif /* __linux__ */
808         OBJ_if_existing,
809         OBJ_if_mounted,
810         OBJ_if_running,
811         OBJ_top,
812         OBJ_top_mem,
813         OBJ_tail,
814         OBJ_head,
815         OBJ_kernel,
816         OBJ_loadavg,
817         OBJ_machine,
818         OBJ_mails,
819         OBJ_mem,
820         OBJ_membar,
821         OBJ_memgraph,
822         OBJ_memmax,
823         OBJ_memperc,
824         OBJ_mixer,
825         OBJ_mixerl,
826         OBJ_mixerr,
827         OBJ_mixerbar,
828         OBJ_mixerlbar,
829         OBJ_mixerrbar,
830         OBJ_new_mails,
831         OBJ_nodename,
832         OBJ_pre_exec,
833 #ifdef MLDONKEY
834         OBJ_ml_upload_counter,
835         OBJ_ml_download_counter,
836         OBJ_ml_nshared_files,
837         OBJ_ml_shared_counter,
838         OBJ_ml_tcp_upload_rate,
839         OBJ_ml_tcp_download_rate,
840         OBJ_ml_udp_upload_rate,
841         OBJ_ml_udp_download_rate,
842         OBJ_ml_ndownloaded_files,
843         OBJ_ml_ndownloading_files,
844 #endif
845         OBJ_processes,
846         OBJ_running_processes,
847         OBJ_shadecolor,
848         OBJ_outlinecolor,
849         OBJ_stippled_hr,
850         OBJ_swap,
851         OBJ_swapbar,
852         OBJ_swapmax,
853         OBJ_swapperc,
854         OBJ_sysname,
855         OBJ_temp1,              /* i2c is used instead in these */
856         OBJ_temp2,
857         OBJ_text,
858         OBJ_time,
859         OBJ_utime,
860         OBJ_totaldown,
861         OBJ_totalup,
862         OBJ_updates,
863         OBJ_upspeed,
864         OBJ_upspeedf,
865         OBJ_upspeedgraph,
866         OBJ_uptime,
867         OBJ_uptime_short,
868 #if defined(__FreeBSD__) && (defined(i386) || defined(__i386__))
869         OBJ_apm_adapter,
870         OBJ_apm_battery_time,
871         OBJ_apm_battery_life,
872 #endif /* __FreeBSD__ */
873 #ifdef SETI
874         OBJ_seti_prog,
875         OBJ_seti_progbar,
876         OBJ_seti_credit,
877 #endif
878 #ifdef MPD
879         OBJ_mpd_title,
880         OBJ_mpd_artist,
881         OBJ_mpd_album,
882         OBJ_mpd_random,
883         OBJ_mpd_repeat,
884         OBJ_mpd_vol,
885         OBJ_mpd_bitrate,
886         OBJ_mpd_status,
887         OBJ_mpd_host,
888         OBJ_mpd_port,
889         OBJ_mpd_bar,
890         OBJ_mpd_elapsed,
891         OBJ_mpd_length,
892         OBJ_mpd_track,
893         OBJ_mpd_percent,
894 #endif
895 #ifdef AUDACIOUS
896         OBJ_audacious_status,
897         OBJ_audacious_song,
898         OBJ_audacious_song_length,
899         OBJ_audacious_song_length_seconds,
900         OBJ_audacious_song_length_frames,
901         OBJ_audacious_song_output_length,
902         OBJ_audacious_song_output_length_seconds,
903         OBJ_audacious_song_output_length_frames,
904         OBJ_audacious_song_bitrate,
905         OBJ_audacious_song_frequency,
906         OBJ_audacious_song_channels,
907         OBJ_audacious_bar,
908 #endif
909 #ifdef BMPX
910         OBJ_bmpx_title,
911         OBJ_bmpx_artist,
912         OBJ_bmpx_album,
913         OBJ_bmpx_track,
914         OBJ_bmpx_uri,
915         OBJ_bmpx_bitrate,
916 #endif
917 #ifdef INFOPIPE
918         OBJ_infopipe_protocol,
919         OBJ_infopipe_version,
920         OBJ_infopipe_status,
921         OBJ_infopipe_playlist_tunes,
922         OBJ_infopipe_playlist_currtune,
923         OBJ_infopipe_usec_position,
924         OBJ_infopipe_position,
925         OBJ_infopipe_usec_time,
926         OBJ_infopipe_time,
927         OBJ_infopipe_bitrate,
928         OBJ_infopipe_frequency,
929         OBJ_infopipe_channels,
930         OBJ_infopipe_title,
931         OBJ_infopipe_file,
932         OBJ_infopipe_bar,
933 #endif
934 #ifdef TCP_PORT_MONITOR
935         OBJ_tcp_portmon,
936 #endif
937 };
938
939 struct text_object {
940         int type;
941         int a, b;
942         unsigned int c, d, e;
943         float f;
944         union {
945                 char *s;        /* some string */
946                 int i;          /* some integer */
947                 long l;         /* some other integer */
948                 struct net_stat *net;
949                 struct fs_stat *fs;
950                 unsigned char loadavg[3];
951                 //unsigned int diskio;
952                 unsigned int cpu_index;
953                 struct {
954                         struct fs_stat *fs;
955                         int w, h;
956                 } fsbar;        /* 3 */
957
958                 struct {
959                         int l;
960                         int w, h;
961                 } mixerbar;     /* 3 */
962
963                 struct {
964                         int fd;
965                         int arg;
966                         char devtype[256];
967                         char type[64];
968                 } i2c;          /* 2 */
969                 struct {
970                         int pos;
971                         char *s;
972                 } ifblock;
973                 struct {
974                         int num;
975                         int type;
976                 } top;
977
978                 struct {
979                         int wantedlines;
980                         int readlines;
981                         char *logfile;
982                         double last_update;
983                         float interval;
984                         char *buffer;
985                 } tail;
986
987                 struct {
988                         double last_update;
989                         float interval;
990                         char *cmd;
991                         char *buffer;
992                         double data;
993                 } execi;        /* 5 */
994
995                 struct {
996                         int a, b;
997                 } pair;         /* 2 */
998 #ifdef TCP_PORT_MONITOR
999                 struct {
1000                         in_port_t  port_range_begin;  /* starting port to monitor */
1001                         in_port_t  port_range_end;    /* ending port to monitor */
1002                         int        item;              /* enum value from libtcp-portmon.h, e.g. COUNT, REMOTEIP, etc. */
1003                         int        connection_index;  /* 0 to n-1 connections. */
1004                } tcp_port_monitor;
1005 #endif
1006         } data;
1007 };
1008
1009 struct text_object_list {
1010   unsigned int text_object_count;
1011   struct text_object *text_objects;
1012 };
1013
1014 static unsigned int text_object_count;
1015 static struct text_object *text_objects;
1016 static void generate_text_internal(char *p, int p_max_size, struct text_object *objs, unsigned int object_count, struct information *cur);
1017
1018 pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
1019
1020 void *threaded_exec( struct text_object *obj ) {
1021         char *p2 = obj->data.execi.buffer;
1022         FILE *fp = popen(obj->data.execi.cmd,"r");
1023         pthread_mutex_lock( &mutex1 );
1024         int n2 = fread(p2, 1, TEXT_BUFFER_SIZE, fp);
1025         (void) pclose(fp);      
1026         p2[n2] = '\0';
1027         if (n2 && p2[n2 - 1] == '\n')
1028                 p2[n2 - 1] = '\0';
1029         
1030         while (*p2) {
1031                 if (*p2 == '\001')
1032                         *p2 = ' ';
1033                 p2++;
1034         }
1035         pthread_mutex_unlock( &mutex1 );
1036         return NULL;
1037 }
1038
1039 static struct text_object *new_text_object_internal()
1040 {
1041   struct text_object *obj = malloc(sizeof(struct text_object));
1042   memset(obj, 0, sizeof(struct text_object));    
1043   return obj;
1044 }
1045
1046 #ifdef MLDONKEY
1047 void ml_cleanup()
1048 {
1049         if (mlconfig.mldonkey_hostname) {
1050                 free(mlconfig.mldonkey_hostname);
1051                 mlconfig.mldonkey_hostname = NULL;
1052         }
1053 }
1054 #endif
1055
1056 static void free_text_objects(unsigned int count, struct text_object *objs)
1057 {
1058         unsigned int i;
1059         for (i = 0; i < count; i++) {
1060             switch (objs[i].type) {
1061                 case OBJ_acpitemp:
1062                         close(objs[i].data.i);
1063                         break;
1064                 case OBJ_acpitempf:
1065                         close(objs[i].data.i);
1066                         break;
1067                 case OBJ_i2c:
1068                         close(objs[i].data.i2c.fd);
1069                         break;
1070                 case OBJ_time:
1071                         free(objs[i].data.s);
1072                         break;
1073                 case OBJ_utime:
1074                 case OBJ_if_existing:
1075                 case OBJ_if_mounted:
1076                 case OBJ_if_running:
1077                         free(objs[i].data.ifblock.s);
1078                         break;
1079                 case OBJ_tail:
1080                         free(objs[i].data.tail.logfile);
1081                         free(objs[i].data.tail.buffer);
1082                         break;
1083                 case OBJ_text: case OBJ_font:
1084                         free(objs[i].data.s);
1085                         break;
1086                 case OBJ_exec:
1087                         free(objs[i].data.s);
1088                         break;
1089                 case OBJ_execbar:
1090                         free(objs[i].data.s);
1091                         break;
1092                 case OBJ_execgraph:
1093                         free(objs[i].data.s);
1094                         break;
1095 /*              case OBJ_execibar:
1096                         free(objs[i].data.s);
1097                         break;
1098                 case OBJ_execigraph:
1099                         free(objs[i].data.s);
1100                         break;*/
1101 #ifdef MPD
1102                 case OBJ_mpd_title:
1103                 case OBJ_mpd_artist:
1104                 case OBJ_mpd_album:
1105                 case OBJ_mpd_random:
1106                 case OBJ_mpd_repeat:
1107                 case OBJ_mpd_track:
1108                 case OBJ_mpd_status:
1109                 case OBJ_mpd_host:
1110 #endif
1111 #ifdef BMPX
1112                 case OBJ_bmpx_title:
1113                 case OBJ_bmpx_artist:
1114                 case OBJ_bmpx_album:
1115                 case OBJ_bmpx_track:
1116                 case OBJ_bmpx_uri:
1117                 case OBJ_bmpx_bitrate:
1118 #endif
1119                 case OBJ_pre_exec:
1120                 case OBJ_battery:
1121                         free(objs[i].data.s);
1122                         break;
1123
1124                 case OBJ_execi:
1125                         free(objs[i].data.execi.cmd);
1126                         free(objs[i].data.execi.buffer);
1127                         break;
1128                 case OBJ_texeci:
1129                         free(objs[i].data.execi.cmd);
1130                         free(objs[i].data.execi.buffer);
1131                         break;
1132                 case OBJ_top:
1133                         if (info.first_process) {
1134                                 free_all_processes();
1135                                 info.first_process = NULL;
1136                         }
1137                         break;
1138                 case OBJ_top_mem:
1139                         if (info.first_process) {
1140                                 free_all_processes();
1141                                 info.first_process = NULL;
1142                         }
1143                         break;
1144                 }
1145         }
1146         free(objs);
1147         //text_objects = NULL;
1148         //text_object_count = 0;
1149 }
1150
1151 void scan_mixer_bar(const char *arg, int *a, int *w, int *h)
1152 {
1153         char buf1[64];
1154         int n;
1155
1156         if (arg && sscanf(arg, "%63s %n", buf1, &n) >= 1) {
1157                 *a = mixer_init(buf1);
1158                 (void) scan_bar(arg + n, w, h);
1159         } else {
1160                 *a = mixer_init(0);
1161                 (void) scan_bar(arg, w, h);
1162         }
1163 }
1164
1165
1166 /* construct_text_object() creates a new text_object */
1167 static struct text_object *construct_text_object(const char *s, const char *arg)
1168 {
1169     //struct text_object *obj = new_text_object();
1170     struct text_object *obj = new_text_object_internal();
1171
1172 #define OBJ(a, n) if (strcmp(s, #a) == 0) { obj->type = OBJ_##a; need_mask |= (1 << n); {
1173 #define END ; } } else
1174
1175 #ifdef X11      
1176 if (s[0] == '#') {
1177                 obj->type = OBJ_color;
1178                 obj->data.l = get_x11_color(s);
1179         } else
1180 #endif /* X11 */
1181         OBJ(acpitemp, 0) obj->data.i = open_acpi_temperature(arg);
1182         END OBJ(acpitempf, 0) obj->data.i = open_acpi_temperature(arg);
1183         END OBJ(acpiacadapter, 0)
1184         END OBJ(freq, 0);
1185         END OBJ(freq_g, 0);
1186         END OBJ(freq_dyn, 0);
1187         END OBJ(freq_dyn_g, 0);
1188         END OBJ(acpifan, 0);
1189         END OBJ(battery, 0);
1190         char bat[64];
1191         if (arg)
1192                 sscanf(arg, "%63s", bat);
1193         else
1194                 strcpy(bat, "BAT0");
1195         obj->data.s = strdup(bat);
1196 #if defined(__linux__)
1197         END OBJ(i8k_version, INFO_I8K)
1198         END OBJ(i8k_bios, INFO_I8K)
1199         END OBJ(i8k_serial, INFO_I8K)
1200         END OBJ(i8k_cpu_temp, INFO_I8K)
1201         END OBJ(i8k_cpu_tempf, INFO_I8K)
1202         END OBJ(i8k_left_fan_status, INFO_I8K)  
1203         END OBJ(i8k_right_fan_status, INFO_I8K)
1204         END OBJ(i8k_left_fan_rpm, INFO_I8K)
1205         END OBJ(i8k_right_fan_rpm, INFO_I8K)
1206         END OBJ(i8k_ac_status, INFO_I8K)
1207         END OBJ(i8k_buttons_status, INFO_I8K)
1208 #endif /* __linux__ */
1209         END OBJ(buffers, INFO_BUFFERS)
1210         END OBJ(cached, INFO_BUFFERS)
1211         END OBJ(cpu, INFO_CPU)
1212                 if (arg) {
1213                 if (strncmp(arg, "cpu", 3) == 0 && isdigit(arg[3])) {
1214                         obj->data.cpu_index = atoi(&arg[3]);
1215                         arg += 4;
1216                 } else {obj->data.cpu_index = 0; }
1217                 } else {
1218                                 obj->data.cpu_index = 0;
1219                         }
1220         END OBJ(cpubar, INFO_CPU)
1221                 if (arg) {
1222                 if (strncmp(arg, "cpu", 3) == 0 && isdigit(arg[3])) {
1223                         obj->data.cpu_index = atoi(&arg[3]);
1224                         arg += 4;
1225                 }
1226                 else {obj->data.cpu_index = 0;}
1227                 (void) scan_bar(arg, &obj->a, &obj->b);
1228                 } else {
1229                                 (void) scan_bar(arg, &obj->a, &obj->b);
1230                                 obj->data.cpu_index = 0;
1231                         }
1232         END OBJ(cpugraph, INFO_CPU)
1233                         if (arg) {
1234                 if (strncmp(arg, "cpu", 3) == 0 && isdigit(arg[3])) {
1235                         obj->data.cpu_index = atoi(&arg[3]);
1236                         arg += 4;
1237                 }
1238                                 (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
1239                         } else {
1240         (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
1241         obj->data.cpu_index = 0;
1242                         }
1243         END OBJ(diskio, INFO_DISKIO)
1244         END OBJ(diskiograph, INFO_DISKIO) (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
1245         END OBJ(color, 0) 
1246 #ifdef X11
1247                         obj->data.l = arg ? get_x11_color(arg) : default_fg_color;
1248 #endif /* X11 */
1249         END
1250         OBJ(font, 0)
1251                         obj->data.s = scan_font(arg);
1252         END
1253                 OBJ(downspeed, INFO_NET) 
1254                 if(arg) {
1255                         obj->data.net = get_net_stat(arg);
1256                 }
1257                 else {
1258                         CRIT_ERR("downspeed needs argument");
1259                 }
1260         END OBJ(downspeedf, INFO_NET)
1261                 if(arg) {
1262                         obj->data.net = get_net_stat(arg);
1263                 }
1264                 else {
1265                         CRIT_ERR("downspeedf needs argument");
1266                 }
1267         END OBJ(downspeedgraph, INFO_NET)
1268                         (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
1269         char buf[64];
1270         sscanf(arg, "%63s %*i,%*i %*i", buf);
1271         obj->data.net = get_net_stat(buf);
1272         if (sscanf(arg, "%*s %d,%d %*d", &obj->b, &obj->a) <= 1) {
1273                 if (sscanf(arg, "%*s %d,%d", &obj->b, &obj->a) <= 1) {
1274                         obj->a = 0;
1275                         obj->b = 25;
1276                 }
1277         }
1278         END OBJ(
1279                        else
1280                        , 0)
1281         if (blockdepth) {
1282                 text_objects[blockstart[blockdepth - 1] -
1283                              1].data.ifblock.pos = text_object_count;
1284                 blockstart[blockdepth - 1] = text_object_count;
1285                 obj->data.ifblock.pos = text_object_count + 2;
1286         } else {
1287                 ERR("$else: no matching $if_*");
1288         }
1289         END OBJ(endif, 0)
1290         if (blockdepth) {
1291                 blockdepth--;
1292                 text_objects[blockstart[blockdepth] - 1].data.ifblock.pos =
1293                     text_object_count;
1294         } else {
1295                 ERR("$endif: no matching $if_*");
1296         }
1297         END
1298 #ifdef HAVE_POPEN
1299             OBJ(exec, 0) obj->data.s = strdup(arg ? arg : "");
1300         END OBJ(execbar, 0) obj->data.s = strdup(arg ? arg : "");
1301         END OBJ(execgraph, 0) obj->data.s = strdup(arg ? arg : "");
1302         END OBJ(execibar, 0) unsigned int n;
1303         if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
1304                 char buf[256];
1305                 ERR("${execibar <interval> command}");
1306                 obj->type = OBJ_text;
1307                 snprintf(buf, 256, "${%s}", s);
1308                 obj->data.s = strdup(buf);
1309                 } else {
1310                         obj->data.execi.cmd = strdup(arg + n);
1311                     }
1312         END OBJ(execigraph, 0) unsigned int n;
1313         if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
1314                 char buf[256];
1315                 ERR("${execigraph <interval> command}");
1316                 obj->type = OBJ_text;
1317                 snprintf(buf, 256, "${%s}", s);
1318                 obj->data.s = strdup(buf);
1319         } else {
1320                 obj->data.execi.cmd = strdup(arg + n);
1321         }
1322         END OBJ(execi, 0) unsigned int n;
1323
1324         if (!arg
1325             || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
1326                 char buf[256];
1327                 ERR("${execi <interval> command}");
1328                 obj->type = OBJ_text;
1329                 snprintf(buf, 256, "${%s}", s);
1330                 obj->data.s = strdup(buf);
1331         } else {
1332                 obj->data.execi.cmd = strdup(arg + n);
1333                 obj->data.execi.buffer =
1334                     (char *) calloc(1, TEXT_BUFFER_SIZE);
1335         }
1336         END OBJ(texeci, 0) unsigned int n;
1337
1338         if (!arg
1339                     || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
1340                 char buf[256];
1341                 ERR("${texeci <interval> command}");
1342                 obj->type = OBJ_text;
1343                 snprintf(buf, 256, "${%s}", s);
1344                 obj->data.s = strdup(buf);
1345                     } else {
1346                             obj->data.execi.cmd = strdup(arg + n);
1347                             obj->data.execi.buffer =
1348                                             (char *) calloc(1, TEXT_BUFFER_SIZE);
1349                     }
1350         END OBJ(pre_exec, 0) obj->type = OBJ_text;
1351         if (arg) {
1352                 FILE *fp = popen(arg, "r");
1353                 unsigned int n;
1354                 char buf[2048];
1355
1356                 n = fread(buf, 1, 2048, fp);
1357                 buf[n] = '\0';
1358
1359                 if (n && buf[n - 1] == '\n')
1360                         buf[n - 1] = '\0';
1361
1362                 (void) pclose(fp);
1363
1364                 obj->data.s = strdup(buf);
1365         } else
1366                 obj->data.s = strdup("");
1367         END
1368 #endif
1369             OBJ(fs_bar, INFO_FS) obj->data.fsbar.h = 4;
1370         arg = scan_bar(arg, &obj->data.fsbar.w, &obj->data.fsbar.h);
1371         if (arg) {
1372                 while (isspace(*arg))
1373                         arg++;
1374                 if (*arg == '\0')
1375                         arg = "/";
1376         } else
1377                 arg = "/";
1378         obj->data.fsbar.fs = prepare_fs_stat(arg);
1379         END OBJ(fs_bar_free, INFO_FS) obj->data.fsbar.h = 4;
1380         if (arg) {
1381                 unsigned int n;
1382                 if (sscanf(arg, "%d %n", &obj->data.fsbar.h, &n) >= 1)
1383                         arg += n;
1384         } else
1385                 arg = "/";
1386         obj->data.fsbar.fs = prepare_fs_stat(arg);
1387         END OBJ(fs_free, INFO_FS) if (!arg)
1388                  arg = "/";
1389         obj->data.fs = prepare_fs_stat(arg);
1390         END OBJ(fs_used_perc, INFO_FS) if (!arg)
1391                  arg = "/";
1392         obj->data.fs = prepare_fs_stat(arg);
1393         END OBJ(fs_free_perc, INFO_FS) if (!arg)
1394                  arg = "/";
1395         obj->data.fs = prepare_fs_stat(arg);
1396         END OBJ(fs_size, INFO_FS) if (!arg)
1397                  arg = "/";
1398         obj->data.fs = prepare_fs_stat(arg);
1399         END OBJ(fs_used, INFO_FS) if (!arg)
1400                  arg = "/";
1401         obj->data.fs = prepare_fs_stat(arg);
1402         END OBJ(hr, 0) obj->data.i = arg ? atoi(arg) : 1;
1403         END OBJ(offset, 0) obj->data.i = arg ? atoi(arg) : 1;
1404         END OBJ(voffset, 0) obj->data.i = arg ? atoi(arg) : 1;
1405         END OBJ(i2c, INFO_I2C) char buf1[64], buf2[64];
1406         int n;
1407
1408         if (!arg) {
1409                 ERR("i2c needs arguments");
1410                 obj->type = OBJ_text;
1411                 //obj->data.s = strdup("${i2c}");
1412                 return NULL;
1413         }
1414
1415         if (sscanf(arg, "%63s %63s %d", buf1, buf2, &n) != 3) {
1416                 /* if scanf couldn't read three values, read type and num and use
1417                  * default device */
1418                 sscanf(arg, "%63s %d", buf2, &n);
1419                 obj->data.i2c.fd =
1420                     open_i2c_sensor(0, buf2, n, &obj->data.i2c.arg,
1421                                     obj->data.i2c.devtype);
1422                 strncpy(obj->data.i2c.type, buf2, 63);
1423         } else {
1424                 obj->data.i2c.fd =
1425                     open_i2c_sensor(buf1, buf2, n, &obj->data.i2c.arg,
1426                                     obj->data.i2c.devtype);
1427                 strncpy(obj->data.i2c.type, buf2, 63);
1428         }
1429
1430         END OBJ(top, INFO_TOP)
1431         char buf[64];
1432         int n;
1433         if (!arg) {
1434                 ERR("top needs arguments");
1435                 obj->type = OBJ_text;
1436                 //obj->data.s = strdup("${top}");
1437                 return NULL;
1438         }
1439         if (sscanf(arg, "%63s %i", buf, &n) == 2) {
1440                 if (strcmp(buf, "name") == 0) {
1441                         obj->data.top.type = TOP_NAME;
1442                 } else if (strcmp(buf, "cpu") == 0) {
1443                         obj->data.top.type = TOP_CPU;
1444                 } else if (strcmp(buf, "pid") == 0) {
1445                         obj->data.top.type = TOP_PID;
1446                 } else if (strcmp(buf, "mem") == 0) {
1447                         obj->data.top.type = TOP_MEM;
1448                 } else {
1449                         ERR("invalid arg for top");
1450                         return NULL;
1451                 }
1452                 if (n < 1 || n > 10) {
1453                         CRIT_ERR("invalid arg for top");
1454                         return NULL;
1455                 } else {
1456                         obj->data.top.num = n - 1;
1457                         top_cpu = 1;
1458                 }
1459         } else {
1460                 ERR("invalid args given for top");
1461                 return NULL;
1462         }
1463         END OBJ(top_mem, INFO_TOP)
1464         char buf[64];
1465         int n;
1466         if (!arg) {
1467                 ERR("top_mem needs arguments");
1468                 obj->type = OBJ_text;
1469                 obj->data.s = strdup("${top_mem}");
1470                 return NULL;
1471         }
1472         if (sscanf(arg, "%63s %i", buf, &n) == 2) {
1473                 if (strcmp(buf, "name") == 0) {
1474                         obj->data.top.type = TOP_NAME;
1475                 } else if (strcmp(buf, "cpu") == 0) {
1476                         obj->data.top.type = TOP_CPU;
1477                 } else if (strcmp(buf, "pid") == 0) {
1478                         obj->data.top.type = TOP_PID;
1479                 } else if (strcmp(buf, "mem") == 0) {
1480                         obj->data.top.type = TOP_MEM;
1481                 } else {
1482                         ERR("invalid arg for top");
1483                         return NULL;
1484                 }
1485                 if (n < 1 || n > 10) {
1486                         CRIT_ERR("invalid arg for top");
1487                         return NULL;
1488                 } else {
1489                         obj->data.top.num = n - 1;
1490                         top_mem = 1;
1491                 }
1492         } else {
1493                 ERR("invalid args given for top");
1494                 return NULL;
1495         }
1496         END OBJ(addr, INFO_NET)
1497                 if(arg) {
1498                         obj->data.net = get_net_stat(arg);
1499                 }
1500                 else {
1501                         CRIT_ERR("addr needs argument");
1502                 }
1503         END OBJ(linkstatus, INFO_WIFI) 
1504                 if(arg) {
1505                         obj->data.net = get_net_stat(arg);
1506                 }
1507                 else {
1508                         CRIT_ERR("linkstatus needs argument");
1509                 }
1510         END OBJ(tail, 0)
1511         char buf[64];
1512         int n1, n2;
1513         if (!arg) {
1514                 ERR("tail needs arguments");
1515                 obj->type = OBJ_text;
1516                 obj->data.s = strdup("${tail}");
1517                 return NULL;
1518         }
1519         if (sscanf(arg, "%63s %i %i", buf, &n1, &n2) == 2) {
1520                 if (n1 < 1 || n1 > 30) {
1521                         CRIT_ERR("invalid arg for tail, number of lines must be between 1 and 30");
1522                         return NULL;
1523                 } else {
1524                         FILE *fp = NULL;
1525                         fp = fopen(buf, "r");
1526                         if (fp) {
1527                                 obj->data.tail.logfile =
1528                                     malloc(TEXT_BUFFER_SIZE);
1529                                 strcpy(obj->data.tail.logfile, buf);
1530                                 obj->data.tail.wantedlines = n1 - 1;
1531                                 obj->data.tail.interval =
1532                                     update_interval * 2;
1533                                 fclose(fp);
1534                         } else {
1535                                 //fclose (fp);
1536                                 CRIT_ERR("tail logfile does not exist, or you do not have correct permissions");
1537                         }
1538                 }
1539         } else if (sscanf(arg, "%63s %i %i", buf, &n1, &n2) == 3) {
1540                 if (n1 < 1 || n1 > 30) {
1541                         CRIT_ERR
1542                             ("invalid arg for tail, number of lines must be between 1 and 30");
1543                         return NULL;
1544                 } else if (n2 < 1 || n2 < update_interval) {
1545                         CRIT_ERR
1546                             ("invalid arg for tail, interval must be greater than 0 and Conky's interval");
1547                         return NULL;
1548                 } else {
1549                         FILE *fp;
1550                         fp = fopen(buf, "r");
1551                         if (fp != NULL) {
1552                                 obj->data.tail.logfile =
1553                                     malloc(TEXT_BUFFER_SIZE);
1554                                 strcpy(obj->data.tail.logfile, buf);
1555                                 obj->data.tail.wantedlines = n1 - 1;
1556                                 obj->data.tail.interval = n2;
1557                                 fclose(fp);
1558                         } else {
1559                                 //fclose (fp);
1560                                 CRIT_ERR("tail logfile does not exist, or you do not have correct permissions");
1561                         }
1562                 }
1563         }
1564
1565         else {
1566                 ERR("invalid args given for tail");
1567                 return NULL;
1568         }
1569         obj->data.tail.buffer = malloc(TEXT_BUFFER_SIZE * 20); /* asumming all else worked */
1570         END OBJ(head, 0)
1571                         char buf[64];
1572         int n1, n2;
1573         if (!arg) {
1574                 ERR("head needs arguments");
1575                 obj->type = OBJ_text;
1576                 obj->data.s = strdup("${head}");
1577                 return NULL;
1578         }
1579         if (sscanf(arg, "%63s %i %i", buf, &n1, &n2) == 2) {
1580                 if (n1 < 1 || n1 > 30) {
1581                         CRIT_ERR("invalid arg for head, number of lines must be between 1 and 30");
1582                         return NULL;
1583                 } else {
1584                         FILE *fp;
1585                         fp = fopen(buf, "r");
1586                         if (fp != NULL) {
1587                                 obj->data.tail.logfile =
1588                                                 malloc(TEXT_BUFFER_SIZE);
1589                                 strcpy(obj->data.tail.logfile, buf);
1590                                 obj->data.tail.wantedlines = n1 - 1;
1591                                 obj->data.tail.interval =
1592                                                 update_interval * 2;
1593                                 fclose(fp);
1594                         } else {
1595                                 //fclose (fp);
1596                                 CRIT_ERR("head logfile does not exist, or you do not have correct permissions");
1597                         }
1598                 }
1599         } else if (sscanf(arg, "%63s %i %i", buf, &n1, &n2) == 3) {
1600                 if (n1 < 1 || n1 > 30) {
1601                         CRIT_ERR
1602                                         ("invalid arg for head, number of lines must be between 1 and 30");
1603                         return NULL;
1604                 } else if (n2 < 1 || n2 < update_interval) {
1605                         CRIT_ERR
1606                                         ("invalid arg for head, interval must be greater than 0 and Conky's interval");
1607                         return NULL;
1608                 } else {
1609                         FILE *fp;
1610                         fp = fopen(buf, "r");
1611                         if (fp != NULL) {
1612                                 obj->data.tail.logfile =
1613                                                 malloc(TEXT_BUFFER_SIZE);
1614                                 strcpy(obj->data.tail.logfile, buf);
1615                                 obj->data.tail.wantedlines = n1 - 1;
1616                                 obj->data.tail.interval = n2;
1617                                 fclose(fp);
1618                         } else {
1619                                 //fclose (fp);
1620                                 CRIT_ERR("head logfile does not exist, or you do not have correct permissions");
1621                         }
1622                 }
1623         }
1624
1625         else {
1626                 ERR("invalid args given for head");
1627                 return NULL;
1628         }
1629         obj->data.tail.buffer = malloc(TEXT_BUFFER_SIZE * 20); /* asumming all else worked */
1630         END OBJ(loadavg, INFO_LOADAVG) int a = 1, b = 2, c = 3, r = 3;
1631         if (arg) {
1632                 r = sscanf(arg, "%d %d %d", &a, &b, &c);
1633                 if (r >= 3 && (c < 1 || c > 3))
1634                         r--;
1635                 if (r >= 2 && (b < 1 || b > 3))
1636                         r--, b = c;
1637                 if (r >= 1 && (a < 1 || a > 3))
1638                         r--, a = b, b = c;
1639         }
1640         obj->data.loadavg[0] = (r >= 1) ? (unsigned char) a : 0;
1641         obj->data.loadavg[1] = (r >= 2) ? (unsigned char) b : 0;
1642         obj->data.loadavg[2] = (r >= 3) ? (unsigned char) c : 0;
1643         END OBJ(if_existing, 0)
1644         if (blockdepth >= MAX_IF_BLOCK_DEPTH) {
1645                 CRIT_ERR("MAX_IF_BLOCK_DEPTH exceeded");
1646         }
1647         if (!arg) {
1648                 ERR("if_existing needs an argument");
1649                 obj->data.ifblock.s = 0;
1650         } else
1651                 obj->data.ifblock.s = strdup(arg);
1652         blockstart[blockdepth] = text_object_count;
1653         obj->data.ifblock.pos = text_object_count + 2;
1654         blockdepth++;
1655         END OBJ(if_mounted, 0)
1656         if (blockdepth >= MAX_IF_BLOCK_DEPTH) {
1657                 CRIT_ERR("MAX_IF_BLOCK_DEPTH exceeded");
1658         }
1659         if (!arg) {
1660                 ERR("if_mounted needs an argument");
1661                 obj->data.ifblock.s = 0;
1662         } else
1663                 obj->data.ifblock.s = strdup(arg);
1664         blockstart[blockdepth] = text_object_count;
1665         obj->data.ifblock.pos = text_object_count + 2;
1666         blockdepth++;
1667         END OBJ(if_running, 0)
1668         if (blockdepth >= MAX_IF_BLOCK_DEPTH) {
1669                 CRIT_ERR("MAX_IF_BLOCK_DEPTH exceeded");
1670         }
1671         if (arg) {
1672                 char buf[256];
1673                 snprintf(buf, 256, "pidof %s >/dev/null", arg);
1674                 obj->data.ifblock.s = strdup(buf);
1675         } else {
1676                 ERR("if_running needs an argument");
1677                 obj->data.ifblock.s = 0;
1678         }
1679         blockstart[blockdepth] = text_object_count;
1680         obj->data.ifblock.pos = text_object_count + 2;
1681         blockdepth++;
1682         END OBJ(kernel, 0)
1683         END OBJ(machine, 0)
1684         END OBJ(mails, INFO_MAIL)
1685         END OBJ(mem, INFO_MEM)
1686         END OBJ(memmax, INFO_MEM)
1687         END OBJ(memperc, INFO_MEM)
1688         END OBJ(membar, INFO_MEM)
1689          (void) scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
1690         END OBJ(memgraph, INFO_MEM)
1691                         (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
1692         END OBJ(mixer, INFO_MIXER) obj->data.l = mixer_init(arg);
1693         END OBJ(mixerl, INFO_MIXER) obj->data.l = mixer_init(arg);
1694         END OBJ(mixerr, INFO_MIXER) obj->data.l = mixer_init(arg);
1695         END OBJ(mixerbar, INFO_MIXER)
1696             scan_mixer_bar(arg, &obj->data.mixerbar.l,
1697                            &obj->data.mixerbar.w, &obj->data.mixerbar.h);
1698         END OBJ(mixerlbar, INFO_MIXER)
1699             scan_mixer_bar(arg, &obj->data.mixerbar.l,
1700                            &obj->data.mixerbar.w, &obj->data.mixerbar.h);
1701         END OBJ(mixerrbar, INFO_MIXER)
1702             scan_mixer_bar(arg, &obj->data.mixerbar.l,
1703                            &obj->data.mixerbar.w, &obj->data.mixerbar.h);
1704         END
1705 #ifdef MLDONKEY
1706             OBJ(ml_upload_counter, INFO_MLDONKEY)
1707         END OBJ(ml_download_counter, INFO_MLDONKEY)
1708         END OBJ(ml_nshared_files, INFO_MLDONKEY)
1709         END OBJ(ml_shared_counter, INFO_MLDONKEY)
1710         END OBJ(ml_tcp_upload_rate, INFO_MLDONKEY)
1711         END OBJ(ml_tcp_download_rate, INFO_MLDONKEY)
1712         END OBJ(ml_udp_upload_rate, INFO_MLDONKEY)
1713         END OBJ(ml_udp_download_rate, INFO_MLDONKEY)
1714         END OBJ(ml_ndownloaded_files, INFO_MLDONKEY)
1715         END OBJ(ml_ndownloading_files, INFO_MLDONKEY) END
1716 #endif
1717          OBJ(new_mails, INFO_MAIL)
1718         END OBJ(nodename, 0)
1719         END OBJ(processes, INFO_PROCS)
1720         END OBJ(running_processes, INFO_RUN_PROCS)
1721         END OBJ(shadecolor, 0)
1722 #ifdef X11
1723             obj->data.l = arg ? get_x11_color(arg) : default_bg_color;
1724 #endif /* X11 */
1725         END OBJ(outlinecolor, 0)
1726 #ifdef X11
1727             obj->data.l = arg ? get_x11_color(arg) : default_out_color;
1728 #endif /* X11 */
1729         END OBJ(stippled_hr, 0)
1730 #ifdef X11
1731 int a = stippled_borders, b = 1;
1732         if (arg) {
1733                 if (sscanf(arg, "%d %d", &a, &b) != 2)
1734                         sscanf(arg, "%d", &b);
1735         }
1736         if (a <= 0)
1737                 a = 1;
1738         obj->data.pair.a = a;
1739         obj->data.pair.b = b;
1740 #endif /* X11 */
1741         END OBJ(swap, INFO_MEM)
1742         END OBJ(swapmax, INFO_MEM)
1743         END OBJ(swapperc, INFO_MEM)
1744         END OBJ(swapbar, INFO_MEM)
1745          (void) scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
1746         END OBJ(sysname, 0) END OBJ(temp1, INFO_I2C) obj->type = OBJ_i2c;
1747         obj->data.i2c.fd =
1748             open_i2c_sensor(0, "temp", 1, &obj->data.i2c.arg,
1749                             obj->data.i2c.devtype);
1750         END OBJ(temp2, INFO_I2C) obj->type = OBJ_i2c;
1751         obj->data.i2c.fd =
1752             open_i2c_sensor(0, "temp", 2, &obj->data.i2c.arg,
1753                             obj->data.i2c.devtype);
1754         END OBJ(time, 0) obj->data.s = strdup(arg ? arg : "%F %T");
1755         END OBJ(utime, 0) obj->data.s = strdup(arg ? arg : "%F %T");
1756         END OBJ(totaldown, INFO_NET)
1757                 if(arg) {
1758                         obj->data.net = get_net_stat(arg);
1759                 }
1760                 else {
1761                         CRIT_ERR("totaldown needs argument");
1762                 }
1763         END OBJ(totalup, INFO_NET) obj->data.net = get_net_stat(arg);
1764                 if(arg) {
1765                         obj->data.net = get_net_stat(arg);
1766                 }
1767                 else {
1768                         CRIT_ERR("totalup needs argument");
1769                 }
1770         END OBJ(updates, 0)
1771         END OBJ(alignr, 0) obj->data.i = arg ? atoi(arg) : 0;
1772         END OBJ(alignc, 0) obj->data.i = arg ? atoi(arg) : 0;
1773         END OBJ(upspeed, INFO_NET)
1774                 if(arg) {
1775                         obj->data.net = get_net_stat(arg);
1776                 }
1777                 else {
1778                         CRIT_ERR("upspeed needs argument");
1779                 }
1780         END OBJ(upspeedf, INFO_NET) 
1781                 if(arg) {
1782                         obj->data.net = get_net_stat(arg);
1783                 }
1784                 else {
1785                         CRIT_ERR("upspeedf needs argument");
1786                 }
1787
1788         END OBJ(upspeedgraph, INFO_NET)
1789                         (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
1790         char buf[64];
1791         sscanf(arg, "%63s %*i,%*i %*i", buf);
1792         obj->data.net = get_net_stat(buf);
1793         if (sscanf(arg, "%*s %d,%d %*d", &obj->b, &obj->a) <= 1) {
1794                 if (sscanf(arg, "%*s %d,%d", &obj->a, &obj->a) <= 1) {
1795                         obj->a = 0;
1796                         obj->b = 25;
1797                 }
1798         }
1799         END OBJ(uptime_short, INFO_UPTIME) END OBJ(uptime, INFO_UPTIME) END
1800             OBJ(adt746xcpu, 0) END OBJ(adt746xfan, 0) END
1801 #if defined(__FreeBSD__) && (defined(i386) || defined(__i386__))
1802         OBJ(apm_adapter, 0) END
1803         OBJ(apm_battery_life, 0) END
1804         OBJ(apm_battery_time, 0) END
1805 #endif /* __FreeBSD__ */
1806 #ifdef SETI
1807          OBJ(seti_prog, INFO_SETI) END OBJ(seti_progbar, INFO_SETI)
1808          (void) scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
1809         END OBJ(seti_credit, INFO_SETI) END
1810 #endif
1811 #ifdef MPD
1812          OBJ(mpd_artist, INFO_MPD)
1813         END OBJ(mpd_title, INFO_MPD)
1814         END OBJ(mpd_random, INFO_MPD)
1815         END OBJ(mpd_repeat, INFO_MPD)
1816         END OBJ(mpd_elapsed, INFO_MPD)
1817         END OBJ(mpd_length, INFO_MPD)
1818         END OBJ(mpd_track, INFO_MPD)
1819         END OBJ(mpd_percent, INFO_MPD)
1820         END OBJ(mpd_album, INFO_MPD) END OBJ(mpd_vol,
1821                                              INFO_MPD) END OBJ(mpd_bitrate,
1822                                                                INFO_MPD)
1823         END OBJ(mpd_status, INFO_MPD)
1824         END OBJ(mpd_bar, INFO_MPD)
1825          (void) scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
1826         END
1827 #endif
1828 #ifdef AUDACIOUS
1829         OBJ(audacious_status, INFO_AUDACIOUS) END
1830         OBJ(audacious_song, INFO_AUDACIOUS) END
1831         OBJ(audacious_song_length, INFO_AUDACIOUS) END
1832         OBJ(audacious_song_length_seconds, INFO_AUDACIOUS) END
1833         OBJ(audacious_song_length_frames, INFO_AUDACIOUS) END
1834         OBJ(audacious_song_output_length, INFO_AUDACIOUS) END
1835         OBJ(audacious_song_output_length_seconds, INFO_AUDACIOUS) END
1836         OBJ(audacious_song_output_length_frames, INFO_AUDACIOUS) END
1837         OBJ(audacious_song_bitrate, INFO_AUDACIOUS) END
1838         OBJ(audacious_song_frequency, INFO_AUDACIOUS) END
1839         OBJ(audacious_song_channels, INFO_AUDACIOUS) END
1840         OBJ(audacious_bar, INFO_AUDACIOUS)
1841             (void) scan_bar(arg, &obj->a, &obj->b);
1842         END
1843 #endif
1844 #ifdef BMPX
1845         OBJ(bmpx_title, INFO_BMPX)
1846                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
1847         END
1848         OBJ(bmpx_artist, INFO_BMPX)
1849                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
1850         END
1851         OBJ(bmpx_album, INFO_BMPX)
1852                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
1853         END
1854         OBJ(bmpx_track, INFO_BMPX)
1855                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
1856         END
1857         OBJ(bmpx_uri, INFO_BMPX)
1858                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
1859         END
1860         OBJ(bmpx_bitrate, INFO_BMPX)
1861                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
1862         END
1863 #endif
1864 #ifdef INFOPIPE
1865         OBJ(infopipe_protocol, INFO_INFOPIPE) END
1866         OBJ(infopipe_version, INFO_INFOPIPE) END
1867         OBJ(infopipe_status, INFO_INFOPIPE) END
1868         OBJ(infopipe_playlist_tunes, INFO_INFOPIPE) END
1869         OBJ(infopipe_playlist_currtune, INFO_INFOPIPE) END
1870         OBJ(infopipe_usec_position, INFO_INFOPIPE) END
1871         OBJ(infopipe_position, INFO_INFOPIPE) END
1872         OBJ(infopipe_usec_time, INFO_INFOPIPE) END
1873         OBJ(infopipe_time, INFO_INFOPIPE) END
1874         OBJ(infopipe_bitrate, INFO_INFOPIPE) END
1875         OBJ(infopipe_frequency, INFO_INFOPIPE) END
1876         OBJ(infopipe_channels, INFO_INFOPIPE) END
1877         OBJ(infopipe_title, INFO_INFOPIPE) END
1878         OBJ(infopipe_file, INFO_INFOPIPE) END
1879         OBJ(infopipe_bar, INFO_INFOPIPE) 
1880             (void) scan_bar(arg, &obj->a, &obj->b);
1881         END
1882 #endif
1883 #ifdef TCP_PORT_MONITOR
1884         OBJ(tcp_portmon, INFO_TCP_PORT_MONITOR) 
1885                 int argc, port_begin, port_end, item, connection_index;
1886                 char itembuf[32];
1887                 memset(itembuf,0,sizeof(itembuf));
1888                 connection_index=0;
1889                 /* massive argument checking */
1890                 if (!arg) {
1891                         CRIT_ERR("tcp_portmon: needs arguments");
1892                 }
1893                 argc=sscanf(arg, "%d %d %31s %d", &port_begin, &port_end, itembuf, &connection_index);
1894                 if ( (argc != 3) && (argc != 4) ) 
1895                 {
1896                         CRIT_ERR("tcp_portmon: requires 3 or 4 arguments");
1897                 }
1898                 if ( (port_begin<1) || (port_begin>65535) || (port_end<1) || (port_end>65535) )
1899                 {
1900                         CRIT_ERR("tcp_portmon: port values must be from 1 to 65535");
1901                 }
1902                 if ( port_begin > port_end )
1903                 {
1904                         CRIT_ERR("tcp_portmon: starting port must be <= ending port");
1905                 }
1906                 if ( strncmp(itembuf,"count",31) == 0 )
1907                         item=COUNT;
1908                 else if ( strncmp(itembuf,"rip",31) == 0 )
1909                         item=REMOTEIP;
1910                 else if ( strncmp(itembuf,"rhost",31) == 0 )
1911                         item=REMOTEHOST;
1912                 else if ( strncmp(itembuf,"rport",31) == 0 )
1913                         item=REMOTEPORT;
1914                 else if ( strncmp(itembuf,"lip",31) == 0 )
1915                         item=LOCALIP;
1916                 else if ( strncmp(itembuf,"lhost",31) == 0 )
1917                         item=LOCALHOST;
1918                 else if ( strncmp(itembuf,"lport",31) == 0 )
1919                         item=LOCALPORT;
1920                 else if ( strncmp(itembuf,"lservice",31) == 0 )
1921                         item=LOCALSERVICE;
1922                 else
1923                 {
1924                         CRIT_ERR("tcp_portmon: invalid item specified"); 
1925                 }
1926                 if ( (argc==3) && (item!=COUNT) )
1927                 {
1928                         CRIT_ERR("tcp_portmon: 3 argument form valid only for \"count\" item");
1929                 }
1930                 if ( (argc==4) && (connection_index<0) )
1931                 {
1932                         CRIT_ERR("tcp_portmon: connection index must be non-negative");
1933                 }
1934                 /* ok, args looks good. save the text object data */
1935                 obj->data.tcp_port_monitor.port_range_begin = (in_addr_t)port_begin;
1936                 obj->data.tcp_port_monitor.port_range_end = (in_addr_t)port_end;
1937                 obj->data.tcp_port_monitor.item = item;
1938                 obj->data.tcp_port_monitor.connection_index = connection_index;
1939
1940                 /* if the port monitor collection hasn't been created, we must create it */
1941                 if ( !info.p_tcp_port_monitor_collection )
1942                 {
1943                         info.p_tcp_port_monitor_collection = 
1944                                 create_tcp_port_monitor_collection( &tcp_port_monitor_collection_args );
1945                         if ( !info.p_tcp_port_monitor_collection )
1946                         {
1947                                 CRIT_ERR("tcp_portmon: unable to create port monitor collection");
1948                         }
1949                 }
1950
1951                 /* if a port monitor for this port does not exist, create one and add it to the collection */
1952                 if ( find_tcp_port_monitor( info.p_tcp_port_monitor_collection, port_begin, port_end ) == NULL )
1953                 {
1954                         tcp_port_monitor_t * p_monitor = 
1955                                 create_tcp_port_monitor( port_begin, port_end, &tcp_port_monitor_args );
1956                         if ( !p_monitor )
1957                         {
1958                                 CRIT_ERR("tcp_portmon: unable to create port monitor");
1959                         }
1960                         /* add the newly created monitor to the collection */
1961                         if ( insert_tcp_port_monitor_into_collection( info.p_tcp_port_monitor_collection,
1962                                                                       p_monitor ) != 0 )
1963                         {
1964                                 CRIT_ERR("tcp_portmon: unable to add port monitor to collection");
1965                         }
1966                 }
1967         END
1968 #endif
1969         {
1970                 char buf[256];
1971                 ERR("unknown variable %s", s);
1972                 obj->type = OBJ_text;
1973                 snprintf(buf, 256, "${%s}", s);
1974                 obj->data.s = strdup(buf);
1975         }
1976 #undef OBJ
1977
1978         return obj;
1979 }
1980
1981 static struct text_object *create_plain_text(const char *s)
1982 {
1983   struct text_object *obj;
1984
1985   if (s == NULL || *s == '\0') {
1986       return NULL;
1987   }
1988   
1989   obj = new_text_object_internal();
1990
1991   obj->type = OBJ_text;
1992   obj->data.s = strdup(s);
1993   return obj;
1994 }
1995
1996 static struct text_object_list *extract_variable_text_internal(const char *p)
1997 {
1998     struct text_object_list *retval;
1999     struct text_object *obj;
2000     const char *s = p;
2001     
2002     retval = malloc(sizeof(struct text_object_list));
2003     memset(retval, 0, sizeof(struct text_object_list));
2004     retval->text_object_count = 0;
2005         
2006         while (*p) {
2007                 if (*p == '$') {
2008                         *(char *) p = '\0';
2009                         obj = create_plain_text(s);
2010                         if(obj != NULL) {
2011                             // allocate memory for the object
2012                             retval->text_objects = realloc(retval->text_objects, 
2013                                                            sizeof(struct text_object) * (retval->text_object_count+1));
2014                             // assign the new object to the end of the list.
2015                             memcpy(&retval->text_objects[retval->text_object_count++],
2016                                    obj, sizeof(struct text_object));
2017                             free(obj);
2018                         }
2019                         *(char *) p = '$';
2020                         p++;
2021                         s = p;
2022
2023                         if (*p != '$') {
2024                                 char buf[256];
2025                                 const char *var;
2026                                 unsigned int len;
2027
2028                                 /* variable is either $foo or ${foo} */
2029                                 if (*p == '{') {
2030                                         p++;
2031                                         s = p;
2032                                         while (*p && *p != '}')
2033                                                 p++;
2034                                 } else {
2035                                         s = p;
2036                                         if (*p == '#')
2037                                                 p++;
2038                                         while (*p && (isalnum((int) *p)
2039                                                       || *p == '_'))
2040                                                 p++;
2041                                 }
2042
2043                                 /* copy variable to buffer */
2044                                 len = (p - s > 255) ? 255 : (p - s);
2045                                 strncpy(buf, s, len);
2046                                 buf[len] = '\0';
2047
2048                                 if (*p == '}')
2049                                         p++;
2050                                 s = p;
2051
2052                                 var = getenv(buf);
2053
2054                                 /* if variable wasn't found from environment, use some special */
2055                                 if (!var) {
2056                                         char *p;
2057                                         char *arg = 0;
2058
2059                                         /* split arg */
2060                                         if (strchr(buf, ' ')) {
2061                                                 arg = strchr(buf, ' ');
2062                                                 *arg = '\0';
2063                                                 arg++;
2064                                                 while (isspace((int) *arg))
2065                                                         arg++;
2066                                                 if (!*arg)
2067                                                         arg = 0;
2068                                         }
2069
2070                                         /* lowercase variable name */
2071                                         p = buf;
2072                                         while (*p) {
2073                                                 *p = tolower(*p);
2074                                                 p++;
2075                                         }
2076
2077                                         // create new object
2078                                         obj = construct_text_object(buf, arg);
2079                                         if(obj != NULL) {
2080                                             // allocate memory for the object
2081                                             retval->text_objects = realloc(retval->text_objects, 
2082                                                                            sizeof(struct text_object) * (retval->text_object_count+1));
2083                                             // assign the new object to the end of the list.
2084                                             memcpy(&retval->text_objects[retval->text_object_count++],
2085                                                    obj, sizeof(struct text_object));
2086                                             free(obj);
2087                                         }
2088                                 }
2089                                 continue;
2090                         } else {
2091                             obj = create_plain_text("$");
2092                             if(obj != NULL) {
2093                                 // allocate memory for the object
2094                                 retval->text_objects = realloc(retval->text_objects, 
2095                                                                sizeof(struct text_object) * (retval->text_object_count+1));
2096                                 // assign the new object to the end of the list.
2097                                 memcpy(&retval->text_objects[retval->text_object_count++],
2098                                        obj, sizeof(struct text_object));
2099                                 free(obj);
2100                             }
2101                         }
2102                 }
2103                 p++;
2104         }
2105         obj = create_plain_text(s);
2106         if(obj != NULL) {
2107             // allocate memory for the object
2108             retval->text_objects = realloc(retval->text_objects,
2109                                            sizeof(struct text_object) * (retval->text_object_count+1));
2110             // assign the new object to the end of the list.
2111             memcpy(&retval->text_objects[retval->text_object_count++],
2112                    obj, sizeof(struct text_object));
2113             free(obj);
2114         }
2115
2116         if (blockdepth) {
2117                 ERR("one or more $endif's are missing");
2118         }
2119
2120         return retval;
2121 }
2122
2123 static void extract_variable_text(const char *p)
2124 {
2125   struct text_object_list *list;
2126
2127   free_text_objects(text_object_count, text_objects);
2128   text_object_count = 0;
2129   text_objects = NULL;
2130
2131 #ifdef MLDONKEY 
2132   ml_cleanup();
2133 #endif /* MLDONKEY */
2134          
2135   list = extract_variable_text_internal(p);
2136   text_objects = list->text_objects;
2137   text_object_count = list->text_object_count;
2138
2139   free(list);
2140
2141   return;
2142 }
2143
2144 void parse_conky_vars(char * text, char * p, struct information *cur) { 
2145         struct text_object_list *object_list = extract_variable_text_internal(text);
2146         generate_text_internal(p, P_MAX_SIZE, object_list->text_objects, object_list->text_object_count, cur);
2147         free(object_list);
2148 }
2149
2150 static void generate_text_internal(char *p, int p_max_size, struct text_object *objs, unsigned int object_count, struct information *cur)
2151 {
2152     unsigned int i;
2153
2154         for (i = 0; i < object_count; i++) {
2155                 struct text_object *obj = &objs[i];
2156
2157 #define OBJ(a) break; case OBJ_##a:
2158
2159                 switch (obj->type) {
2160                 default:
2161                         {
2162                                 ERR("not implemented obj type %d",
2163                                     obj->type);
2164                         }
2165                         OBJ(acpitemp) {
2166                                 /* does anyone have decimals in acpi temperature? */
2167                                 if (!use_spacer)
2168                                         snprintf(p, p_max_size, "%d", (int)
2169                                                         get_acpi_temperature(obj->
2170                                                                         data.
2171                                                                         i));
2172                                 else
2173                                         snprintf(p, 5, "%d    ", (int)
2174                                                         get_acpi_temperature(obj->
2175                                                                         data.
2176                                                                         i));
2177                         }
2178                         OBJ(acpitempf) {
2179                                 /* does anyone have decimals in acpi temperature? */
2180                                 if (!use_spacer)
2181                                         snprintf(p, p_max_size, "%d", (int)
2182                                                         ((get_acpi_temperature(obj->
2183                                                                         data.
2184                                                                         i)+ 40) * 9.0 / 5 - 40));
2185                                 else
2186                                         snprintf(p, 5, "%d    ", (int)
2187                                                         ((get_acpi_temperature(obj->
2188                                                                         data.
2189                                                                         i)+ 40) * 9.0 / 5 - 40));
2190                         }
2191                         OBJ(freq) {
2192                                 get_freq(p, p_max_size, "%.0f", 1); /* pk */
2193                         }
2194                         OBJ(freq_g) {
2195                                 get_freq(p, p_max_size, "%'.2f", 1000); /* pk */
2196                         }
2197                         OBJ(freq_dyn) {
2198                                 if (use_spacer) {
2199                                         get_freq_dynamic(p, 6, "%.0f     ", 1 ); /* pk */
2200                                 } else {
2201                                         get_freq_dynamic(p, p_max_size, "%.0f", 1 ); /* pk */
2202                                 }
2203                         }
2204                         OBJ(freq_dyn_g) {
2205                                 if (use_spacer) {
2206                                         get_freq_dynamic(p, 6, "%'.2f     ", 1000); /* pk */
2207                                 } else {
2208                                         get_freq_dynamic(p, p_max_size, "%'.2f", 1000); /* pk */
2209                                 }
2210                         }
2211                         OBJ(adt746xcpu) {
2212                                 get_adt746x_cpu(p, p_max_size); /* pk */
2213                         }
2214                         OBJ(adt746xfan) {
2215                                 get_adt746x_fan(p, p_max_size); /* pk */
2216                         }
2217                         OBJ(acpifan) {
2218                                 get_acpi_fan(p, p_max_size);  /* pk */
2219                         }
2220                         OBJ(acpiacadapter) {
2221                                 get_acpi_ac_adapter(p, p_max_size); /* pk */
2222                         }
2223                         OBJ(battery) {
2224                                 get_battery_stuff(p, p_max_size, obj->data.s);
2225                         }
2226                         OBJ(buffers) {
2227                                 human_readable(cur->buffers * 1024, p, 255);
2228                         }
2229                         OBJ(cached) {
2230                                 human_readable(cur->cached * 1024, p, 255);
2231                         }
2232                         OBJ(cpu) {
2233                                 if (obj->data.cpu_index > info.cpu_count) {
2234                                         printf("obj->data.cpu_index %i info.cpu_count %i", obj->data.cpu_index, info.cpu_count);
2235                                         CRIT_ERR("attempting to use more CPUs then you have!");
2236                                 }
2237                                 if (!use_spacer)
2238                                         snprintf(p, p_max_size, "%*d", pad_percents,
2239                                                 (int) round_to_int(cur->cpu_usage[obj->data.cpu_index] *
2240                                                         100.0));
2241                                 else
2242                                         snprintf(p, 4, "%*d    ",
2243                                                  pad_percents,
2244                                                  (int) round_to_int(cur->cpu_usage[obj->data.cpu_index] *
2245                                                         100.0));
2246                         }
2247                         OBJ(cpubar) {
2248                                 new_bar(p, obj->a,
2249                                         obj->b,
2250                                         (int) round_to_int(cur->cpu_usage[obj->data.cpu_index] * 255.0));
2251                         }
2252                         OBJ(cpugraph) {
2253                                 new_graph(p, obj->a,
2254                                           obj->b, obj->c, obj->d,
2255                                           (unsigned int) round_to_int(cur->cpu_usage[obj->data.cpu_index] *
2256                                                           100), 100, 1);
2257                         }
2258                         OBJ(color) {
2259                                 new_fg(p, obj->data.l);
2260                         }
2261 #if defined(__linux__)
2262                         OBJ(i8k_version) {
2263                                 snprintf(p, p_max_size, "%s", i8k.version);
2264                         }
2265                         OBJ(i8k_bios) {
2266                                 snprintf(p, p_max_size, "%s", i8k.bios);
2267                         }
2268                         OBJ(i8k_serial) { 
2269                                 snprintf(p, p_max_size, "%s", i8k.serial);
2270                         }
2271                         OBJ(i8k_cpu_temp) { 
2272                                 snprintf(p, p_max_size, "%s", i8k.cpu_temp);
2273                         }
2274                         OBJ(i8k_cpu_tempf) { 
2275                                 int cpu_temp;
2276                                 sscanf(i8k.cpu_temp, "%d", &cpu_temp);
2277                                 snprintf(p, p_max_size, "%.1f", cpu_temp*(9.0/5.0)+32.0);
2278                         }
2279                         OBJ(i8k_left_fan_status) { 
2280                                 int left_fan_status;
2281                                 sscanf(i8k.left_fan_status, "%d", &left_fan_status);
2282                                 if(left_fan_status == 0) {
2283                                         snprintf(p, p_max_size,"off");
2284                                 } if(left_fan_status == 1) {
2285                                         snprintf(p, p_max_size, "low");
2286                                 }       if(left_fan_status == 2) {
2287                                         snprintf(p, p_max_size, "high");
2288                                 }
2289
2290                         }
2291                         OBJ(i8k_right_fan_status) { 
2292                                 int right_fan_status;
2293                                 sscanf(i8k.right_fan_status, "%d", &right_fan_status);
2294                                 if(right_fan_status == 0) {
2295                                         snprintf(p, p_max_size,"off");
2296                                 } if(right_fan_status == 1) {
2297                                         snprintf(p, p_max_size, "low");
2298                                 }       if(right_fan_status == 2) {
2299                                         snprintf(p, p_max_size, "high");
2300                                 }
2301                         }
2302                         OBJ(i8k_left_fan_rpm) { 
2303                                 snprintf(p, p_max_size, "%s", i8k.left_fan_rpm);
2304                         }
2305                         OBJ(i8k_right_fan_rpm) { 
2306                                 snprintf(p, p_max_size, "%s", i8k.right_fan_rpm);
2307                         }
2308                         OBJ(i8k_ac_status) { 
2309                                 int ac_status;
2310                                 sscanf(i8k.ac_status, "%d", &ac_status);
2311                                 if(ac_status == -1) {
2312                                         snprintf(p, p_max_size,"disabled (read i8k docs)");
2313                                 } if(ac_status == 0) {
2314                                         snprintf(p, p_max_size, "off");
2315                                 }       if(ac_status == 1) {
2316                                         snprintf(p, p_max_size, "on");
2317                                 }
2318                         }
2319                         OBJ(i8k_buttons_status) {
2320                                 snprintf(p, p_max_size, "%s", i8k.buttons_status); 
2321
2322                         }
2323 #endif /* __linux__ */
2324
2325 #ifdef X11
2326                         OBJ(font) {
2327                                 new_font(p, obj->data.s);
2328                         }
2329 #endif /* X11 */
2330                         OBJ(diskio) {
2331                                 if (!use_spacer) {
2332                                         if (diskio_value > 1024*1024) {
2333                                                 snprintf(p, p_max_size, "%.1fG",
2334                                                                 (double)diskio_value/1024/1024);
2335                                         } else if (diskio_value > 1024) {
2336                                                 snprintf(p, p_max_size, "%.1fM",
2337                                                                 (double)diskio_value/1024);
2338                                         } else if (diskio_value > 0) {
2339                                                 snprintf(p, p_max_size, "%dK", diskio_value);
2340                                         } else {
2341                                                 snprintf(p, p_max_size, "%d", diskio_value);
2342                                         }
2343                                 } else {
2344                                         if (diskio_value > 1024*1024) {
2345                                                 snprintf(p, 6, "%.1fG   ",
2346                                                                 (double)diskio_value/1024/1024);
2347                                         } else if (diskio_value > 1024) {
2348                                                 snprintf(p, 6, "%.1fM   ",
2349                                                                 (double)diskio_value/1024);
2350                                         } else if (diskio_value > 0) {
2351                                                 snprintf(p, 6, "%dK ", diskio_value);
2352                                         } else {
2353                                                 snprintf(p, 6, "%d     ", diskio_value);
2354                                         }
2355                                 }
2356                         }
2357                         OBJ(diskiograph) {
2358                                 new_graph(p, obj->a,
2359                                           obj->b, obj->c, obj->d,
2360                                           diskio_value, obj->e, 1);
2361                         }
2362         
2363                         OBJ(downspeed) {
2364                                 if (!use_spacer) {
2365                                         snprintf(p, p_max_size, "%d",
2366                                                  (int) (obj->data.net->
2367                                                         recv_speed /
2368                                                         1024));
2369                                 } else
2370                                         snprintf(p, 6, "%d     ",
2371                                                  (int) (obj->data.net->
2372                                                         recv_speed /
2373                                                         1024));
2374                         }
2375                         OBJ(downspeedf) {
2376                                 if (!use_spacer)
2377                                         snprintf(p, p_max_size, "%.1f",
2378                                                  obj->data.net->
2379                                                  recv_speed / 1024.0);
2380                                 else
2381                                         snprintf(p, 8, "%.1f       ",
2382                                                  obj->data.net->
2383                                                  recv_speed / 1024.0);
2384                         }
2385                         OBJ(downspeedgraph) {
2386                                 if (obj->data.net->recv_speed == 0)     // this is just to make the ugliness at start go away
2387                                         obj->data.net->recv_speed = 0.01;
2388                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
2389                                           (obj->data.net->recv_speed /
2390                                 1024.0), obj->e, 1);
2391                         }
2392                         OBJ(
2393                                    else
2394                         ) {
2395                                 if (!if_jumped) {
2396                                         i = obj->data.ifblock.pos - 2;
2397                                 } else {
2398                                         if_jumped = 0;
2399                                 }
2400                         }
2401                         OBJ(endif) {
2402                                 if_jumped = 0;
2403                         }
2404 #ifdef HAVE_POPEN
2405                         OBJ(addr) {
2406                                 snprintf(p, p_max_size, "%u.%u.%u.%u",
2407                                          obj->data.net->addr.
2408                                          sa_data[2] & 255,
2409                                          obj->data.net->addr.
2410                                          sa_data[3] & 255,
2411                                          obj->data.net->addr.
2412                                          sa_data[4] & 255,
2413                                          obj->data.net->addr.
2414                                          sa_data[5] & 255);
2415
2416                         }
2417                         OBJ(linkstatus) {
2418                                 snprintf(p, p_max_size, "%d",
2419                                          obj->data.net->linkstatus);
2420                         }
2421
2422                         OBJ(exec) {
2423                                 FILE *fp = popen(obj->data.s, "r");
2424                                 int length = fread(p, 1, p_max_size, fp);
2425                                 (void) pclose(fp);
2426
2427                                 /*output[length] = '\0';
2428                                 if (length > 0 && output[length - 1] == '\n') {
2429                                         output[length - 1] = '\0';
2430                                 }*/
2431                                         p[length] = '\0';
2432                                         if (length > 0 && p[length - 1] == '\n') {
2433                                                 p[length - 1] = '\0';
2434                                         }
2435                                     
2436                                 //parse_conky_vars(output, p, cur);
2437                         }
2438                         OBJ(execbar) {
2439                                 char *p2 = p;
2440                                 FILE *fp = popen(obj->data.s, "r");
2441                                 int n2 = fread(p, 1, p_max_size, fp);
2442                                 (void) pclose(fp);
2443
2444                                 p[n2] = '\0';
2445                                 if (n2 && p[n2 - 1] == '\n')
2446                                         p[n2 - 1] = '\0';
2447
2448                                 while (*p2) {
2449                                         if (*p2 == '\001')
2450                                                 *p2 = ' ';
2451                                         p2++;
2452                                 }
2453                                 double barnum;
2454                                 if (sscanf(p, "%lf", &barnum) == 0) {
2455                                         ERR("reading execbar value failed (perhaps it's not the correct format?)");
2456                                 }
2457                                 if (barnum > 100 || barnum < 0) {
2458                                         ERR("your execbar value is not between 0 and 100, therefore it will be ignored");
2459                                 } else {
2460                                         barnum = barnum / 100.0;
2461                                         new_bar(p, 0, 4, (int) (barnum * 255.0));
2462                                 }
2463
2464                         }
2465                         OBJ(execgraph) {
2466                                 char *p2 = p;
2467                                 FILE *fp = popen(obj->data.s, "r");
2468                                 int n2 = fread(p, 1, p_max_size, fp);
2469                                 (void) pclose(fp);
2470
2471                                 p[n2] = '\0';
2472                                 if (n2 && p[n2 - 1] == '\n')
2473                                         p[n2 - 1] = '\0';
2474
2475                                 while (*p2) {
2476                                         if (*p2 == '\001')
2477                                                 *p2 = ' ';
2478                                         p2++;
2479                                 }
2480                                 double barnum;
2481                                 if (sscanf(p, "%lf", &barnum) == 0) {
2482                                         ERR("reading execgraph value failed (perhaps it's not the correct format?)");
2483                                 }
2484                                 if (barnum > 100 || barnum < 0) {
2485                                         ERR("your execgraph value is not between 0 and 100, therefore it will be ignored");
2486                                 } else {
2487                                         new_graph(p, 0,
2488                                         25, obj->c, obj->d, (int) (barnum), obj->e, 1);
2489                                 }
2490
2491                         }
2492                         OBJ(execibar) {
2493                                 if (current_update_time - obj->data.execi.last_update < obj->data.execi.interval) {
2494                                         new_bar(p, 0, 4, (int) obj->f);
2495                                 } else {
2496                                         char *p2 = p;
2497                                         FILE *fp = popen(obj->data.execi.cmd, "r");
2498                                         int n2 = fread(p, 1, p_max_size, fp);
2499                                         (void) pclose(fp);
2500                                         p[n2] = '\0';
2501                                         if (n2 && p[n2 - 1] == '\n')
2502                                                 p[n2 - 1] = '\0';
2503
2504                                         while (*p2) {
2505                                                 if (*p2 == '\001')
2506                                                         *p2 = ' ';
2507                                                 p2++;
2508                                         }
2509                                         float barnum;
2510                                         if (sscanf(p, "%f", &barnum) == 0) {
2511                                                 ERR("reading execibar value failed (perhaps it's not the correct format?)");
2512                                         }
2513                                         if (barnum > 100 || barnum < 0) {
2514                                                 ERR("your execibar value is not between 0 and 100, therefore it will be ignored");
2515                                         } else {
2516                                                 obj->f = 255 * barnum / 100.0;
2517                                                 new_bar(p, 0, 4, (int) obj->f);
2518                                         }
2519                                         obj->data.execi.last_update =
2520                                                         current_update_time;
2521                                 }
2522                         }
2523                         OBJ(execigraph) {
2524                                 if (current_update_time - obj->data.execi.last_update < obj->data.execi.interval) {
2525                                         new_graph(p, 0, 25, obj->c, obj->d, (int) (obj->f), 100, 0);
2526                                 } else {
2527                                         char *p2 = p;
2528                                         FILE *fp = popen(obj->data.execi.cmd, "r");
2529                                         int n2 = fread(p, 1, p_max_size, fp);
2530                                         (void) pclose(fp);
2531                                         p[n2] = '\0';
2532                                         if (n2 && p[n2 - 1] == '\n')
2533                                                 p[n2 - 1] = '\0';
2534
2535                                         while (*p2) {
2536                                                 if (*p2 == '\001')
2537                                                         *p2 = ' ';
2538                                                 p2++;
2539                                         }
2540                                         float barnum;
2541                                         if (sscanf(p, "%f", &barnum) == 0) {
2542                                                 ERR("reading execigraph value failed (perhaps it's not the correct format?)");
2543                                         }
2544                                         if (barnum > 100 || barnum < 0) {
2545                                                 ERR("your execigraph value is not between 0 and 100, therefore it will be ignored");
2546                                         } else {
2547                                                 obj->f = barnum;
2548                                                 new_graph(p, 0, 25, obj->c, obj->d, (int) (obj->f), 100, 1);
2549                                         }
2550                                         obj->data.execi.last_update = current_update_time;
2551         
2552                                 }
2553
2554                         }
2555                         OBJ(execi) {
2556                                 if (current_update_time - obj->data.execi.last_update < obj->data.execi.interval || obj->data.execi.interval == 0) {
2557                                         snprintf(p, p_max_size, "%s", obj->data.execi.buffer);
2558                                 } else {
2559                                         char *output = obj->data.execi.buffer;
2560                                         FILE *fp = popen(obj->data.execi.cmd, "r");
2561                                         //int length = fread(output, 1, TEXT_BUFFER_SIZE, fp);
2562                                         int length = fread(output, 1, TEXT_BUFFER_SIZE, fp);
2563                                         (void) pclose(fp);
2564                                     
2565                                         output[length] = '\0';
2566                                         if (length > 0 && output[length - 1] == '\n') {
2567                                                 output[length - 1] = '\0';
2568                                         }
2569                                         obj->data.execi.last_update = current_update_time;
2570                                         snprintf(p, p_max_size, "%s", output);
2571                                 }
2572                                 //parse_conky_vars(output, p, cur);
2573                         }
2574                         OBJ(texeci) {
2575                                 static int running = 0;
2576                                 if (current_update_time - obj->data.execi.last_update < obj->data.execi.interval) {
2577                                         snprintf(p, p_max_size, "%s", obj->data.execi.buffer);
2578                                 } else {
2579                                         static pthread_t execthread;
2580                                         if (running) {
2581                                                 pthread_join( execthread, NULL);
2582                                                 running = 0;
2583                                         }
2584                                         if (!running) {
2585                                                 running = 1;
2586                                                 pthread_create( &execthread, NULL, (void*)threaded_exec, (void*) obj);
2587                                                 pthread_mutex_lock( &mutex1 );
2588                                                 obj->data.execi.last_update = current_update_time;
2589                                                 pthread_mutex_unlock( &mutex1 );
2590                                         }
2591                                         snprintf(p, p_max_size, "%s", obj->data.execi.buffer);
2592                                 }
2593                                 //parse_conky_vars(obj->data.execi.buffer, p, cur);
2594                         }
2595 #endif
2596                         OBJ(fs_bar) {
2597                                 if (obj->data.fs != NULL) {
2598                                         if (obj->data.fs->size == 0)
2599                                                 new_bar(p,
2600                                                         obj->data.fsbar.w,
2601                                                         obj->data.fsbar.h,
2602                                                         255);
2603                                         else
2604                                                 new_bar(p,
2605                                                         obj->data.fsbar.w,
2606                                                         obj->data.fsbar.h,
2607                                                         (int) (255 -
2608                                                                obj->data.
2609                                                                fsbar.fs->
2610                                                                avail *
2611                                                                255 /
2612                                                                obj->data.
2613                                                                fs->size));
2614                                 }
2615                         }
2616                         OBJ(fs_free) {
2617                                 if (obj->data.fs != NULL)
2618                                         human_readable(obj->data.fs->avail,
2619                                                        p, 255);
2620                         }
2621                         OBJ(fs_free_perc) {
2622                                 if (obj->data.fs != NULL) {
2623                                         if (obj->data.fs->size)
2624                                                 snprintf(p, p_max_size, "%*d",
2625                                                          pad_percents,
2626                                                          (int) ((obj->data.
2627                                                                  fs->
2628                                                                  avail *
2629                                                                  100) /
2630                                                                 obj->data.
2631                                                                 fs->size));
2632                                         else
2633                                                 snprintf(p, p_max_size, "0");
2634                                 }
2635                         }
2636                         OBJ(fs_size) {
2637                                 if (obj->data.fs != NULL)
2638                                         human_readable(obj->data.fs->size,
2639                                                        p, 255);
2640                         }
2641                         OBJ(fs_used) {
2642                                 if (obj->data.fs != NULL)
2643                                         human_readable(obj->data.fs->size -
2644                                                        (obj->data.fs->free ? obj->data.fs->free :obj->data.fs->avail),
2645                                                        p, 255);
2646                         }
2647                         OBJ(fs_bar_free) {
2648                                 if (obj->data.fs != NULL) {
2649                                         if (obj->data.fs->size == 0)
2650                                                 new_bar(p,
2651                                                         obj->data.fsbar.w,
2652                                                         obj->data.fsbar.h,
2653                                                         255);
2654                                         else
2655                                                 new_bar(p,
2656                                                         obj->data.fsbar.w,
2657                                                         obj->data.fsbar.h,
2658                                                         (int) (obj->data.
2659                                                                fsbar.fs->
2660                                                                avail *
2661                                                                255 /
2662                                                                obj->data.
2663                                                                fs->size));
2664                                 }
2665                         }
2666                         OBJ(fs_used_perc) {
2667                                 if (obj->data.fs != NULL) {
2668                                         if (obj->data.fs->size)
2669                                                 snprintf(p, 4, "%d",
2670                                                          100 - ((int)
2671                                                                 ((obj->
2672                                                                   data.fs->
2673                                                                   avail *
2674                                                                   100) /
2675                                                                  obj->data.
2676                                                                  fs->
2677                                                                  size)));
2678                                         else
2679                                                 snprintf(p, p_max_size, "0");
2680                                 }
2681                         }
2682                         OBJ(loadavg) {
2683                                 float *v = info.loadavg;
2684
2685                                 if (obj->data.loadavg[2])
2686                                         snprintf(p, p_max_size, "%.2f %.2f %.2f",
2687                                                  v[obj->data.loadavg[0] -
2688                                                    1],
2689                                                  v[obj->data.loadavg[1] -
2690                                                    1],
2691                                                  v[obj->data.loadavg[2] -
2692                                                    1]);
2693                                 else if (obj->data.loadavg[1])
2694                                         snprintf(p, p_max_size, "%.2f %.2f",
2695                                                  v[obj->data.loadavg[0] -
2696                                                    1],
2697                                                  v[obj->data.loadavg[1] -
2698                                                    1]);
2699                                 else if (obj->data.loadavg[0])
2700                                         snprintf(p, p_max_size, "%.2f",
2701                                                  v[obj->data.loadavg[0] -
2702                                                    1]);
2703                         }
2704                         OBJ(hr) {
2705                                 new_hr(p, obj->data.i);
2706                         }
2707                         OBJ(offset) {
2708                                 new_offset(p, obj->data.i);
2709                         }
2710                         OBJ(voffset) {
2711                                 new_voffset(p, obj->data.i);
2712                         }
2713                         OBJ(i2c) {
2714                                 double r;
2715
2716                                 r = get_i2c_info(&obj->data.i2c.fd,
2717                                                  obj->data.i2c.arg,
2718                                                  obj->data.i2c.devtype,
2719                                                  obj->data.i2c.type);
2720
2721                                 if (r >= 100.0 || r == 0)
2722                                         snprintf(p, p_max_size, "%d", (int) r);
2723                                 else
2724                                         snprintf(p, p_max_size, "%.1f", r);
2725                         }
2726                         OBJ(alignr) {
2727                                 new_alignr(p, obj->data.i);
2728                         }
2729                         OBJ(alignc) {
2730                                 new_alignc(p, obj->data.i);
2731                         }
2732                         OBJ(if_existing) {
2733                                 struct stat tmp;
2734                                 if ((obj->data.ifblock.s)
2735                                     && (stat(obj->data.ifblock.s, &tmp) ==
2736                                         -1)) {
2737                                         i = obj->data.ifblock.pos - 2;
2738                                         if_jumped = 1;
2739                                 } else
2740                                         if_jumped = 0;
2741                         }
2742                         OBJ(if_mounted) {
2743                                 if ((obj->data.ifblock.s)
2744                                     && (!check_mount(obj->data.ifblock.s))) {
2745                                         i = obj->data.ifblock.pos - 2;
2746                                         if_jumped = 1;
2747                                 } else
2748                                         if_jumped = 0;
2749                         }
2750                         OBJ(if_running) {
2751                                 if ((obj->data.ifblock.s)
2752                                     && system(obj->data.ifblock.s)) {
2753                                         i = obj->data.ifblock.pos - 2;
2754                                         if_jumped = 1;
2755                                 } else
2756                                         if_jumped = 0;
2757                         }
2758                         OBJ(kernel) {
2759                                 snprintf(p, p_max_size, "%s", cur->uname_s.release);
2760                         }
2761                         OBJ(machine) {
2762                                 snprintf(p, p_max_size, "%s", cur->uname_s.machine);
2763                         }
2764
2765                         /* memory stuff */
2766                         OBJ(mem) {
2767                                 human_readable(cur->mem * 1024, p, 6);
2768                         }
2769                         OBJ(memmax) {
2770                                 human_readable(cur->memmax * 1024, p, 255);
2771                         }
2772                         OBJ(memperc) {
2773                                 if (cur->memmax) {
2774                                         if (!use_spacer)
2775                                                 snprintf(p, p_max_size, "%*lu",
2776                                                          pad_percents,
2777                                                          (cur->mem * 100) /
2778                                                          (cur->memmax));
2779                                         else
2780                                                 snprintf(p, 4, "%*lu   ",
2781                                                          pad_percents,
2782                                                          (cur->mem * 100) /
2783                                                          (cur->memmax));
2784                                 }
2785                         }
2786                         OBJ(membar) {
2787                                 new_bar(p, obj->data.pair.a,
2788                                         obj->data.pair.b,
2789                                         cur->memmax ? (cur->mem * 255) /
2790                                         (cur->memmax) : 0);
2791                         }
2792
2793                         OBJ(memgraph) {
2794                                 new_graph(p, obj->a,
2795                                 obj->b, obj->c, obj->d,
2796                                 cur->memmax ? (cur->mem * 100.0) /
2797                                                 (cur->memmax) : 0.0, 100, 1);
2798                         }
2799                         /* mixer stuff */
2800                         OBJ(mixer) {
2801                                 snprintf(p, p_max_size, "%d",
2802                                          mixer_get_avg(obj->data.l));
2803                         }
2804                         OBJ(mixerl) {
2805                                 snprintf(p, p_max_size, "%d",
2806                                          mixer_get_left(obj->data.l));
2807                         }
2808                         OBJ(mixerr) {
2809                                 snprintf(p, p_max_size, "%d",
2810                                          mixer_get_right(obj->data.l));
2811                         }
2812                         OBJ(mixerbar) {
2813                                 new_bar(p, obj->data.mixerbar.w,
2814                                         obj->data.mixerbar.h,
2815                                         mixer_get_avg(obj->data.mixerbar.
2816                                                       l) * 255 / 100);
2817                         }
2818                         OBJ(mixerlbar) {
2819                                 new_bar(p, obj->data.mixerbar.w,
2820                                         obj->data.mixerbar.h,
2821                                         mixer_get_left(obj->data.mixerbar.
2822                                                        l) * 255 / 100);
2823                         }
2824                         OBJ(mixerrbar) {
2825                                 new_bar(p, obj->data.mixerbar.w,
2826                                         obj->data.mixerbar.h,
2827                                         mixer_get_right(obj->data.mixerbar.
2828                                                         l) * 255 / 100);
2829                         }
2830
2831                         /* mail stuff */
2832                         OBJ(mails) {
2833                                 snprintf(p, p_max_size, "%d", cur->mail_count);
2834                         }
2835                         OBJ(new_mails) {
2836                                 snprintf(p, p_max_size, "%d", cur->new_mail_count);
2837                         }
2838 #ifdef MLDONKEY
2839                         OBJ(ml_upload_counter) {
2840                                 snprintf(p, p_max_size, "%lld",
2841                                          mlinfo.upload_counter / 1048576);
2842                         }
2843                         OBJ(ml_download_counter) {
2844                                 snprintf(p, p_max_size, "%lld",
2845                                          mlinfo.download_counter /
2846                                          1048576);
2847                         }
2848                         OBJ(ml_nshared_files) {
2849                                 snprintf(p, p_max_size, "%i", mlinfo.nshared_files);
2850                         }
2851                         OBJ(ml_shared_counter) {
2852                                 snprintf(p, p_max_size, "%lld",
2853                                          mlinfo.shared_counter / 1048576);
2854                         }
2855                         OBJ(ml_tcp_upload_rate) {
2856                                 snprintf(p, p_max_size, "%.2f",
2857                                          (float) mlinfo.tcp_upload_rate /
2858                                          1024);
2859                         }
2860                         OBJ(ml_tcp_download_rate) {
2861                                 snprintf(p, p_max_size, "%.2f",
2862                                          (float) mlinfo.tcp_download_rate /
2863                                          1024);
2864                         }
2865                         OBJ(ml_udp_upload_rate) {
2866                                 snprintf(p, p_max_size, "%.2f",
2867                                          (float) mlinfo.udp_upload_rate /
2868                                          1024);
2869                         }
2870                         OBJ(ml_udp_download_rate) {
2871                                 snprintf(p, p_max_size, "%.2f",
2872                                          (float) mlinfo.udp_download_rate /
2873                                          1024);
2874                         }
2875                         OBJ(ml_ndownloaded_files) {
2876                                 snprintf(p, p_max_size, "%i",
2877                                          mlinfo.ndownloaded_files);
2878                         }
2879                         OBJ(ml_ndownloading_files) {
2880                                 snprintf(p, p_max_size, "%i",
2881                                          mlinfo.ndownloading_files);
2882                         }
2883 #endif
2884
2885                         OBJ(nodename) {
2886                                 snprintf(p, p_max_size, "%s",
2887                                          cur->uname_s.nodename);
2888                         }
2889                         OBJ(outlinecolor) {
2890                                 new_outline(p, obj->data.l);
2891                         }
2892                         OBJ(processes) {
2893                                 if (!use_spacer)
2894                                         snprintf(p, p_max_size, "%hu", cur->procs);
2895                                 else
2896                                         snprintf(p, 5, "%hu    ",
2897                                                  cur->procs);
2898                         }
2899                         OBJ(running_processes) {
2900                                 if (!use_spacer)
2901                                         snprintf(p, p_max_size, "%hu",
2902                                                  cur->run_procs);
2903                                 else
2904                                         snprintf(p, 3, "%hu     ",
2905                                                  cur->run_procs);
2906                         }
2907                         OBJ(text) {
2908                                 snprintf(p, p_max_size, "%s", obj->data.s);
2909                         }
2910                         OBJ(shadecolor) {
2911                                 new_bg(p, obj->data.l);
2912                         }
2913                         OBJ(stippled_hr) {
2914                                 new_stippled_hr(p, obj->data.pair.a,
2915                                                 obj->data.pair.b);
2916                         }
2917                         OBJ(swap) {
2918                                 human_readable(cur->swap * 1024, p, 255);
2919                         }
2920                         OBJ(swapmax) {
2921                                 human_readable(cur->swapmax * 1024, p,
2922                                                255);
2923                         }
2924                         OBJ(swapperc) {
2925                                 if (cur->swapmax == 0) {
2926                                         strncpy(p, "No swap", 255);
2927                                 } else {
2928                                         if (!use_spacer)
2929                                                 snprintf(p, 255, "%*lu",
2930                                                          pad_percents,
2931                                                          (cur->swap *
2932                                                           100) /
2933                                                          cur->swapmax);
2934                                         else
2935                                                 snprintf(p, 4, "%*lu   ",
2936                                                          pad_percents,
2937                                                          (cur->swap *
2938                                                           100) /
2939                                                          cur->swapmax);
2940                                 }
2941                         }
2942                         OBJ(swapbar) {
2943                                 new_bar(p, obj->data.pair.a,
2944                                         obj->data.pair.b,
2945                                         cur->swapmax ? (cur->swap * 255) /
2946                                         (cur->swapmax) : 0);
2947                         }
2948                         OBJ(sysname) {
2949                                 snprintf(p, p_max_size, "%s", cur->uname_s.sysname);
2950                         }
2951                         OBJ(time) {
2952                                 time_t t = time(NULL);
2953                                 struct tm *tm = localtime(&t);
2954                                 setlocale(LC_TIME, "");
2955                                 strftime(p, p_max_size, obj->data.s, tm);
2956                         }
2957                         OBJ(utime) {
2958                                 time_t t = time(NULL);
2959                                 struct tm *tm = gmtime(&t);
2960                                 strftime(p, p_max_size, obj->data.s, tm);
2961                         }
2962                         OBJ(totaldown) {
2963                                 human_readable(obj->data.net->recv, p,
2964                                                255);
2965                         }
2966                         OBJ(totalup) {
2967                                 human_readable(obj->data.net->trans, p,
2968                                                255);
2969                         }
2970                         OBJ(updates) {
2971                                 snprintf(p, p_max_size, "%d", total_updates);
2972                         }
2973                         OBJ(upspeed) {
2974                                 if (!use_spacer)
2975                                         snprintf(p, p_max_size, "%d",
2976                                                  (int) (obj->data.net->
2977                                                         trans_speed /
2978                                                         1024));
2979                                 else
2980                                         snprintf(p, 5, "%d     ",
2981                                                  (int) (obj->data.net->
2982                                                         trans_speed /
2983                                                         1024));
2984                         }
2985                         OBJ(upspeedf) {
2986                                 if (!use_spacer)
2987                                         snprintf(p, p_max_size, "%.1f",
2988                                                  obj->data.net->
2989                                                  trans_speed / 1024.0);
2990                                 else
2991                                         snprintf(p, 8, "%.1f       ",
2992                                                  obj->data.net->
2993                                                  trans_speed / 1024.0);
2994                         }
2995                         OBJ(upspeedgraph) {
2996                                 if (obj->data.net->trans_speed == 0)    // this is just to make the ugliness at start go away
2997                                         obj->data.net->trans_speed = 0.01;
2998                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
2999                                           (obj->data.net->trans_speed /
3000                                 1024.0), obj->e, 1);
3001                         }
3002                         OBJ(uptime_short) {
3003                                 format_seconds_short(p, p_max_size,
3004                                                      (int) cur->uptime);
3005                         }
3006                         OBJ(uptime) {
3007                                 format_seconds(p, p_max_size, (int) cur->uptime);
3008                         }
3009
3010 #if defined(__FreeBSD__) && (defined(i386) || defined(__i386__))
3011                         OBJ(apm_adapter) {
3012                                 snprintf(p, p_max_size, "%s", get_apm_adapter());
3013                         }
3014                         OBJ(apm_battery_life) {
3015                                 char    *msg;
3016                                 msg = get_apm_battery_life();
3017                                 snprintf(p, p_max_size, "%s", msg);
3018                                 free(msg);
3019                         }
3020                         OBJ(apm_battery_time) {
3021                                 char    *msg;
3022                                 msg = get_apm_battery_time();
3023                                 snprintf(p, p_max_size, "%s", msg);
3024                                 free(msg);
3025                         }
3026 #endif /* __FreeBSD__ */
3027 #ifdef SETI
3028                         OBJ(seti_prog) {
3029                                 snprintf(p, p_max_size, "%.2f",
3030                                          cur->seti_prog * 100.0f);
3031                         }
3032                         OBJ(seti_progbar) {
3033                                 new_bar(p, obj->data.pair.a,
3034                                         obj->data.pair.b,
3035                                         (int) (cur->seti_prog * 255.0f));
3036                         }
3037                         OBJ(seti_credit) {
3038                                 snprintf(p, p_max_size, "%.0f", cur->seti_credit);
3039                         }
3040 #endif
3041
3042 #ifdef MPD
3043                         OBJ(mpd_title) {
3044                                 snprintf(p, p_max_size, "%s", cur->mpd.title);
3045                         }
3046                         OBJ(mpd_artist) {
3047                                 snprintf(p, p_max_size, "%s", cur->mpd.artist);
3048                         }
3049                         OBJ(mpd_album) {
3050                                 snprintf(p, p_max_size, "%s", cur->mpd.album);
3051                         }
3052                         OBJ(mpd_random) {
3053                                 snprintf(p, p_max_size, "%s", cur->mpd.random);
3054                         }
3055                         OBJ(mpd_repeat) {
3056                                 snprintf(p, p_max_size, "%s", cur->mpd.repeat);
3057                         }
3058                         OBJ(mpd_track) {
3059                                 snprintf(p, p_max_size, "%s", cur->mpd.track);
3060                         }
3061                         OBJ(mpd_vol) {
3062                                 snprintf(p, p_max_size, "%i", cur->mpd.volume);
3063                         }
3064                         OBJ(mpd_bitrate) {
3065                                 snprintf(p, p_max_size, "%i", cur->mpd.bitrate);
3066                         }
3067                         OBJ(mpd_status) {
3068                                 snprintf(p, p_max_size, "%s", cur->mpd.status);
3069                         }
3070                         OBJ(mpd_elapsed) {
3071                                 int days = 0, hours = 0, minutes =
3072                                     0, seconds = 0;
3073                                 int tmp = cur->mpd.elapsed;
3074                                 while (tmp >= 86400) {
3075                                         tmp -= 86400;
3076                                         days++;
3077                                 }
3078                                 while (tmp >= 3600) {
3079                                         tmp -= 3600;
3080                                         hours++;
3081                                 }
3082                                 while (tmp >= 60) {
3083                                         tmp -= 60;
3084                                         minutes++;
3085                                 }
3086                                 seconds = tmp;
3087                                 if (days > 0)
3088                                         snprintf(p, p_max_size, "%i days %i:%02i:%02i",
3089                                                  days, hours, minutes,
3090                                                  seconds);
3091                                 else if (hours > 0)
3092                                         snprintf(p, p_max_size, "%i:%02i:%02i", hours,
3093                                                  minutes, seconds);
3094                                 else
3095                                         snprintf(p, p_max_size, "%i:%02i", minutes,
3096                                                  seconds);
3097                         }
3098                         OBJ(mpd_length) {
3099                                 int days = 0, hours = 0, minutes =
3100                                     0, seconds = 0;
3101                                 int tmp = cur->mpd.length;
3102                                 while (tmp >= 86400) {
3103                                         tmp -= 86400;
3104                                         days++;
3105                                 }
3106                                 while (tmp >= 3600) {
3107                                         tmp -= 3600;
3108                                         hours++;
3109                                 }
3110                                 while (tmp >= 60) {
3111                                         tmp -= 60;
3112                                         minutes++;
3113                                 }
3114                                 seconds = tmp;
3115                                 if (days > 0)
3116                                         snprintf(p, p_max_size,
3117                                                  "%i days %i:%02i:%02i",
3118                                                  days, hours, minutes,
3119                                                  seconds);
3120                                 else if (hours > 0)
3121                                         snprintf(p, p_max_size, "%i:%02i:%02i", hours,
3122                                                  minutes, seconds);
3123                                 else
3124                                         snprintf(p, p_max_size, "%i:%02i", minutes,
3125                                                  seconds);
3126                         }
3127                         OBJ(mpd_percent) {
3128                                 snprintf(p, p_max_size, "%2.0f",
3129                                          cur->mpd.progress * 100);
3130                         }
3131                         OBJ(mpd_bar) {
3132                                 new_bar(p, obj->data.pair.a,
3133                                         obj->data.pair.b,
3134                                         (int) (cur->mpd.progress *
3135                                                255.0f));
3136                         }
3137 #endif
3138 #ifdef AUDACIOUS
3139                         OBJ(audacious_status) {
3140                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_STATUS]);
3141                         }
3142                         OBJ(audacious_song) {
3143                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_SONG]);
3144                         }
3145                         OBJ(audacious_song_length) {
3146                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_SONG_LENGTH]);
3147                         }
3148                         OBJ(audacious_song_length_seconds) {
3149                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_SONG_LENGTH_SECONDS]);
3150                         }
3151                         OBJ(audacious_song_length_frames) {
3152                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_SONG_LENGTH_FRAMES]);
3153                         }
3154                         OBJ(audacious_song_output_length) {
3155                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_SONG_OUTPUT_LENGTH]);
3156                         }
3157                         OBJ(audacious_song_output_length_seconds) {
3158                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_SONG_OUTPUT_LENGTH_SECONDS]);
3159                         }
3160                         OBJ(audacious_song_output_length_frames) {
3161                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_SONG_OUTPUT_LENGTH_FRAMES]);
3162                         }
3163                         OBJ(audacious_song_bitrate) {
3164                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_SONG_BITRATE]);
3165                         }
3166                         OBJ(audacious_song_frequency) {
3167                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_SONG_FREQUENCY]);
3168                         }
3169                         OBJ(audacious_song_channels) {
3170                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_STATUS]);
3171                         }
3172                         OBJ(audacious_bar) {
3173                             double progress;
3174                             progress= atof(cur->audacious.items[AUDACIOUS_SONG_OUTPUT_LENGTH_SECONDS]) /
3175                                       atof(cur->audacious.items[AUDACIOUS_SONG_LENGTH_SECONDS]);
3176                             new_bar(p,obj->a,obj->b,(int)(progress*255.0f));
3177
3178                         }
3179 #endif
3180 #ifdef BMPX
3181                         OBJ(bmpx_title) {
3182                                 snprintf(p, p_max_size, "%s", cur->bmpx.title);
3183                         }
3184                         OBJ(bmpx_artist) {
3185                                 snprintf(p, p_max_size, "%s", cur->bmpx.artist);
3186                         }
3187                         OBJ(bmpx_album) {
3188                                 snprintf(p, p_max_size, "%s", cur->bmpx.album);
3189                         }
3190                         OBJ(bmpx_uri) {
3191                                 snprintf(p, p_max_size, "%s", cur->bmpx.uri);
3192                         }
3193                         OBJ(bmpx_track) {
3194                                  snprintf(p, p_max_size, "%i", cur->bmpx.track);
3195                         }
3196                         OBJ(bmpx_bitrate) {
3197                                 snprintf(p, p_max_size, "%i", cur->bmpx.bitrate);
3198                         }
3199 #endif
3200 #ifdef INFOPIPE
3201                         OBJ(infopipe_protocol) {
3202                                 snprintf(p, p_max_size, "%s", cur->infopipe.items[INFOPIPE_PROTOCOL]);
3203                         }
3204                         OBJ(infopipe_version) {
3205                                 snprintf(p, p_max_size, "%s", cur->infopipe.items[INFOPIPE_VERSION]);
3206                         }
3207                         OBJ(infopipe_status) {
3208                                 snprintf(p, p_max_size, "%s", cur->infopipe.items[INFOPIPE_STATUS]);
3209                         }
3210                         OBJ(infopipe_playlist_tunes) {
3211                                 snprintf(p, p_max_size, "%s", cur->infopipe.items[INFOPIPE_PLAYLIST_TUNES]);
3212                         }
3213                         OBJ(infopipe_playlist_currtune) {
3214                                 snprintf(p, p_max_size, "%s", cur->infopipe.items[INFOPIPE_PLAYLIST_CURRTUNE]);
3215                         }
3216                         OBJ(infopipe_usec_position) {
3217                                 snprintf(p, p_max_size, "%s", cur->infopipe.items[INFOPIPE_USEC_POSITION]);
3218                         }
3219                         OBJ(infopipe_position) {
3220                                 snprintf(p, p_max_size, "%s", cur->infopipe.items[INFOPIPE_POSITION]);
3221                         }
3222                         OBJ(infopipe_usec_time) {
3223                                 snprintf(p, p_max_size, "%s", cur->infopipe.items[INFOPIPE_USEC_TIME]);
3224                         }
3225                         OBJ(infopipe_time) {
3226                                 snprintf(p, p_max_size, "%s", cur->infopipe.items[INFOPIPE_TIME]);
3227                         }
3228                         OBJ(infopipe_bitrate) {
3229                                 snprintf(p, p_max_size, "%s", cur->infopipe.items[INFOPIPE_BITRATE]);
3230                         }
3231                         OBJ(infopipe_frequency) {
3232                                 snprintf(p, p_max_size, "%s", cur->infopipe.items[INFOPIPE_FREQUENCY]);
3233                         }
3234                         OBJ(infopipe_channels) {
3235                                 snprintf(p, p_max_size, "%s", cur->infopipe.items[INFOPIPE_CHANNELS]);
3236                         }
3237                         OBJ(infopipe_title) {
3238                                 snprintf(p, p_max_size, "%s", cur->infopipe.items[INFOPIPE_TITLE]);
3239                         }
3240                         OBJ(infopipe_file) {
3241                                 snprintf(p, p_max_size, "%s", cur->infopipe.items[INFOPIPE_FILE]);
3242                         }
3243                         OBJ(infopipe_bar) {
3244                                 double progress;
3245                                 progress= atof(cur->infopipe.items[INFOPIPE_USEC_POSITION]) /
3246                                           atof(cur->infopipe.items[INFOPIPE_USEC_TIME]);
3247                                 new_bar(p,obj->a,obj->b,(int)(progress*255.0f));
3248                         }
3249 #endif
3250                         OBJ(top) {
3251                                 if (obj->data.top.type == TOP_NAME
3252                                     && obj->data.top.num >= 0
3253                                     && obj->data.top.num < 10) {
3254                                         // if we limit the buffer and add a bunch of space after, it stops the thing from
3255                                         // moving other shit around, which is really fucking annoying
3256                                         snprintf(p, 17, "%s                              ", cur->cpu[obj->data.top.num]->name);
3257                                 } else if (obj->data.top.type == TOP_CPU
3258                                            && obj->data.top.num >= 0
3259                                            && obj->data.top.num < 10) {
3260                                         snprintf(p, 7, "%3.2f      ",
3261                                                  cur->cpu[obj->data.top.
3262                                                           num]->amount);
3263                                 } else if (obj->data.top.type == TOP_PID
3264                                            && obj->data.top.num >= 0
3265                                            && obj->data.top.num < 10) {
3266                                         snprintf(p, 8, "%i           ",
3267                                                  cur->cpu[obj->data.top.
3268                                                           num]->pid);
3269                                 } else if (obj->data.top.type == TOP_MEM
3270                                            && obj->data.top.num >= 0
3271                                            && obj->data.top.num < 10) {
3272                                         snprintf(p, 7, "%3.2f       ",
3273                                                  cur->cpu[obj->data.top.
3274                                                           num]->totalmem);
3275                                 }
3276                         }
3277                         OBJ(top_mem) {
3278                                 if (obj->data.top.type == TOP_NAME
3279                                     && obj->data.top.num >= 0
3280                                     && obj->data.top.num < 10) {
3281                                         // if we limit the buffer and add a bunch of space after, it stops the thing from
3282                                         // moving other shit around, which is really fucking annoying
3283                                         snprintf(p, 17,
3284                                                  "%s                              ",
3285                                                  cur->memu[obj->data.top.
3286                                                            num]->name);
3287                                 } else if (obj->data.top.type == TOP_CPU
3288                                            && obj->data.top.num >= 0
3289                                            && obj->data.top.num < 10) {
3290                                         snprintf(p, 7, "%3.2f      ",
3291                                                  cur->memu[obj->data.top.
3292                                                            num]->amount);
3293                                 } else if (obj->data.top.type == TOP_PID
3294                                            && obj->data.top.num >= 0
3295                                            && obj->data.top.num < 10) {
3296                                         snprintf(p, 8, "%i           ",
3297                                                  cur->memu[obj->data.top.
3298                                                            num]->pid);
3299                                 } else if (obj->data.top.type == TOP_MEM
3300                                            && obj->data.top.num >= 0
3301                                            && obj->data.top.num < 10) {
3302                                         snprintf(p, 7, "%3.2f       ",
3303                                                  cur->memu[obj->data.top.
3304                                                            num]->totalmem);
3305                                 }
3306                         }
3307
3308
3309                         OBJ(tail) {
3310                                 if (current_update_time -obj->data.tail.last_update < obj->data.tail.interval) {
3311                                                         snprintf(p, p_max_size, "%s", obj->data.tail.buffer);
3312                                 } else {
3313                                         obj->data.tail.last_update = current_update_time;
3314                                         FILE *fp;
3315                                         int i;
3316                                         int added = 0;
3317                                         tailstring *head = NULL;
3318                                         tailstring *headtmp = NULL;
3319                                         tailstring *freetmp = NULL;
3320                                         fp = fopen(obj->data.tail.logfile, "rt");
3321                                         if (fp == NULL) {
3322                                                 ERR("tail logfile failed to open");
3323                                         }
3324                                         else {
3325                                                 obj->data.tail.readlines = 0;
3326
3327                                                 while (fgets(obj->data.tail.buffer, TEXT_BUFFER_SIZE*20, fp) != NULL) {
3328                                                         if (added >= 30) {
3329                                                                 freelasttail(head);
3330                                                         }
3331                                                         else {
3332                                                                 added++;
3333                                                         }
3334                                                         addtail(&head, obj->data.tail.buffer);
3335                                                         obj->data.tail.readlines++;
3336                                                 }
3337
3338                                                 fclose(fp);
3339                                                 freetmp = head;
3340
3341                                                 if (obj->data.tail.readlines > 0) {
3342                                                         for (i = 0;i < obj->data.tail.wantedlines + 1 && i < obj->data.tail.readlines; i++) {
3343                                                                 addtail(&headtmp, head->data);
3344                                                                 head = head->next;
3345                                                         }
3346                                                         freetail(freetmp);
3347                                                         freetmp = headtmp;
3348                                                         strcpy(obj->data.tail.buffer, headtmp->data);
3349                                                         headtmp = headtmp->next;
3350                                                         for (i = 1;i < obj->data.tail.wantedlines + 1 && i < obj->data.tail.readlines; i++) {
3351                                                                 if (headtmp) {
3352                                                                         strncat(obj->data.tail.buffer, headtmp->data, (TEXT_BUFFER_SIZE * 20) - strlen(obj->data.tail.buffer)); /* without strlen() at the end this becomes a possible */
3353                                                                         headtmp = headtmp->next;
3354                                                                 }
3355                                                         }
3356
3357                                                         /* get rid of any ugly newlines at the end */
3358                                                         if (obj->data.tail.buffer[strlen(obj->data.tail.buffer)-1] == '\n') {
3359                                                                 obj->data.tail.buffer[strlen(obj->data.tail.buffer)-1] = '\0';
3360                                                         }
3361                                                         snprintf(p, p_max_size, "%s", obj->data.tail.buffer);
3362
3363                                                         freetail(freetmp);
3364                                                 } else {
3365                                                         strcpy(obj->data.tail.buffer, "Logfile Empty");
3366                                                         snprintf(p, p_max_size, "Logfile Empty");
3367                                                 }  /* if readlines */
3368                                         } /*  fp == NULL  */
3369                                 } /* if cur_upd_time >= */
3370         
3371                                 //parse_conky_vars(obj->data.tail.buffer, p, cur);
3372
3373                         }
3374                         OBJ(head) {
3375                                 if (current_update_time -obj->data.tail.last_update < obj->data.tail.interval) {
3376                                                         snprintf(p, p_max_size, "%s", obj->data.tail.buffer);
3377                                 } else {
3378                                         obj->data.tail.last_update = current_update_time;
3379                                         FILE *fp;
3380                                         tailstring *head = NULL;
3381                                         tailstring *headtmp = NULL;
3382                                         tailstring *freetmp = NULL;
3383                                         fp = fopen(obj->data.tail.logfile, "rt");
3384                                         if (fp == NULL) {
3385                                                 ERR("head logfile failed to open");
3386                                         } else {
3387                                                 obj->data.tail.readlines = 0;
3388                                                 while (fgets(obj->data.tail.buffer, TEXT_BUFFER_SIZE*20, fp) != NULL && obj->data.tail.readlines <= obj->data.tail.wantedlines) {
3389                                                         addtail(&head, obj->data.tail.buffer);
3390                                                         obj->data.tail.readlines++;
3391                                                 }
3392                                                 fclose(fp);
3393                                                 freetmp = head;
3394                                                 if (obj->data.tail.readlines > 0) {
3395                                                         while (head) {
3396                                                                 addtail(&headtmp, head->data);
3397                                                                 head = head->next;
3398                                                         }
3399                                                         freetail(freetmp);
3400                                                         freetmp = headtmp;
3401                                                         strcpy(obj->data.tail.buffer, headtmp->data);
3402                                                         headtmp = headtmp->next;
3403                                                         while (headtmp) {
3404                                                                 strncat(obj->data.tail.buffer, headtmp->data, (TEXT_BUFFER_SIZE * 20) - strlen(obj->data.tail.buffer)); /* without strlen() at the end this becomes a possible */
3405                                                                 headtmp = headtmp->next;
3406                                                         }
3407                                                         freetail(freetmp);
3408                                                         /* get rid of any ugly newlines at the end */
3409                                                         if (obj->data.tail.buffer[strlen(obj->data.tail.buffer)-1] == '\n') {
3410                                                                 obj->data.tail.buffer[strlen(obj->data.tail.buffer)-1] = '\0';
3411                                                         }
3412                                                         snprintf(p, p_max_size, "%s", obj->data.tail.buffer);
3413                                                 } else {
3414                                                         strcpy(obj->data.tail.buffer, "Logfile Empty");
3415                                                         snprintf(p, p_max_size, "Logfile Empty");
3416                                                 } /* if readlines > 0 */
3417                                         } /* if fp == null */
3418                                 } /* cur_upd_time >= */
3419
3420                                 //parse_conky_vars(obj->data.tail.buffer, p, cur);
3421
3422                         }
3423 #ifdef TCP_PORT_MONITOR
3424                         OBJ(tcp_portmon)
3425                         {
3426                                 /* grab a pointer to this port monitor */
3427                                 tcp_port_monitor_t * p_monitor = 
3428                                         find_tcp_port_monitor( info.p_tcp_port_monitor_collection,
3429                                                                 obj->data.tcp_port_monitor.port_range_begin,
3430                                                                 obj->data.tcp_port_monitor.port_range_end );
3431                                 if ( !p_monitor ) {
3432                                         snprintf(p, p_max_size, "monitor not found");
3433                                         break;
3434                                 }
3435
3436                                 /* now grab the text of interest */
3437                                 if ( peek_tcp_port_monitor( p_monitor, 
3438                                                             obj->data.tcp_port_monitor.item, 
3439                                                             obj->data.tcp_port_monitor.connection_index,
3440                                                             p, p_max_size ) != 0 )
3441                                 {
3442                                         snprintf(p, p_max_size, "monitor peek error");
3443                                         break;
3444                                 }
3445                         }
3446 #endif
3447
3448                         break;
3449                 }
3450
3451                 {
3452                         unsigned int a = strlen(p);
3453                         p += a;
3454                         p_max_size -= a;
3455                 }
3456         }
3457 }
3458
3459
3460 double current_update_time, last_update_time;
3461
3462 static void generate_text()
3463 {
3464         struct information *cur = &info;
3465         char *p;
3466
3467         special_count = 0;
3468
3469         /* update info */
3470
3471         current_update_time = get_time();
3472
3473         update_stuff(cur);
3474
3475         /* add things to the buffer */
3476
3477         /* generate text */
3478
3479         p = text_buffer;
3480
3481         generate_text_internal(p, P_MAX_SIZE, text_objects, text_object_count, cur);
3482
3483         if (stuff_in_upper_case) {
3484                 char *p;
3485
3486                 p = text_buffer;
3487                 while (*p) {
3488                         *p = toupper(*p);
3489                         p++;
3490                 }
3491         }
3492
3493         last_update_time = current_update_time;
3494         total_updates++;
3495         //free(p);
3496 }
3497
3498
3499 #ifdef X11
3500 static void set_font()
3501 {
3502 #ifdef XFT
3503         if (use_xft) {
3504                         if (window.xftdraw != NULL) {
3505                                 XftDrawDestroy(window.xftdraw);
3506                         }
3507                         window.xftdraw = XftDrawCreate(display, window.drawable,
3508                                         DefaultVisual(display,
3509                                                         screen),
3510                                         DefaultColormap(display,
3511                                                         screen));
3512                 } else
3513 #endif
3514 {
3515         XSetFont(display, window.gc, fonts[selected_font].font->fid);
3516 }
3517 }
3518
3519
3520 /*
3521  * text size
3522  */
3523
3524 static int text_start_x, text_start_y;  /* text start position in window */
3525 static int text_width, text_height;
3526
3527 #endif /* X11 */
3528
3529 static inline int get_string_width(const char *s)
3530 {
3531 #ifdef X11
3532         return *s ? calc_text_width(s, strlen(s)) : 0;
3533 #else
3534         return strlen(s);
3535 #endif /* X11 */
3536 }
3537
3538 static inline int get_string_width_special(char *s)
3539 {
3540         if (!s) {
3541                 return 0;
3542         }
3543 #ifdef X11
3544         char *p, *final;
3545         p = strdup(s);
3546         final = p;
3547         int index = 1;
3548         int width = 0;
3549         unsigned int i;
3550         while (*p) {
3551                 if (*p == SPECIAL_CHAR) {
3552                         /* shift everything over by 1 so that the special char doesn't mess up the size calculation */
3553                         for (i = 0; i < strlen(p); i++) {
3554                                 *(p + i) = *(p + i + 1);
3555                         }
3556                         if (specials[special_index+index].type == GRAPH || specials[special_index+index].type == BAR) {
3557                                 width += specials[special_index+index].width;
3558                         }
3559                         index++;
3560                 } else {
3561                         p++;
3562                 }
3563         }
3564         if (strlen(final) > 1) {
3565                 width += calc_text_width(final, strlen(final));
3566         }
3567         free(final);
3568         return width;
3569 #else
3570         return strlen(s);
3571 #endif /* X11 */
3572 }
3573
3574 int fontchange = 0;
3575
3576 #ifdef X11
3577 static void text_size_updater(char *s)
3578 {
3579         int w = 0;
3580         char *p;
3581         int h = font_height();
3582         /* get string widths and skip specials */
3583         p = s;
3584         while (*p) {
3585                 if (*p == SPECIAL_CHAR) {
3586                         *p = '\0';
3587                         w += get_string_width(s);
3588                         *p = SPECIAL_CHAR;
3589
3590                         if (specials[special_index].type == BAR
3591                             || specials[special_index].type == GRAPH) {
3592                                 w += specials[special_index].width;
3593                                 if (specials[special_index].height > h) {
3594                                         h = specials[special_index].height;
3595                                         h += font_ascent();
3596                                 }
3597                         }
3598                         
3599                         else if (specials[special_index].type == OFFSET) {
3600                                 w += specials[special_index].arg + get_string_width("a"); /* filthy, but works */
3601                         }
3602                         else if (specials[special_index].type == VOFFSET) {
3603                                 h += specials[special_index].arg;
3604                         }
3605                         else if (specials[special_index].type == FONT) {
3606                                 fontchange = specials[special_index].font_added;
3607                                 selected_font = specials[special_index].font_added;
3608                                 h = font_height();
3609                         }
3610
3611                         
3612                         special_index++;
3613                         s = p + 1;
3614                 }
3615                 p++;
3616         }
3617                 w += get_string_width(s);
3618         if (w > text_width)
3619                 text_width = w;
3620         if (text_width > maximum_width && maximum_width)
3621                 text_width = maximum_width;
3622
3623         text_height += h;
3624         if (fontchange) {
3625                 selected_font = 0;
3626         }
3627 }
3628 #endif /* X11 */
3629
3630
3631 #ifdef X11
3632 static void update_text_area()
3633 {
3634         int x, y;
3635
3636         /* update text size if it isn't fixed */
3637 #ifdef OWN_WINDOW
3638         if (!fixed_size)
3639 #endif
3640         {
3641                 text_width = minimum_width;
3642                 text_height = 0;
3643                 special_index = 0;
3644                 for_each_line(text_buffer, text_size_updater);
3645                 text_width += 1;
3646                 if (text_height < minimum_height)
3647                         text_height = minimum_height;
3648                 if (text_width > maximum_width && maximum_width > 0)
3649                         text_width = maximum_width;
3650         }
3651
3652         /* get text position on workarea */
3653         switch (text_alignment) {
3654         case TOP_LEFT:
3655                 x = gap_x;
3656                 y = gap_y;
3657                 break;
3658
3659         case TOP_RIGHT:
3660                 x = workarea[2] - text_width - gap_x;
3661                 y = gap_y;
3662                 break;
3663
3664         default:
3665         case BOTTOM_LEFT:
3666                 x = gap_x;
3667                 y = workarea[3] - text_height - gap_y;
3668                 break;
3669
3670         case BOTTOM_RIGHT:
3671                 x = workarea[2] - text_width - gap_x;
3672                 y = workarea[3] - text_height - gap_y;
3673                 break;
3674         
3675 #ifdef OWN_WINDOW
3676         case NONE: // Let the WM manage the window
3677                 x = window.x;
3678                 y = window.y;
3679
3680                 fixed_pos  = 1;
3681                 fixed_size = 1;
3682                 break;
3683 #endif
3684         }
3685 #ifdef OWN_WINDOW
3686
3687         if (own_window && !fixed_pos) {
3688                 x += workarea[0];
3689                 y += workarea[1];
3690                 text_start_x = border_margin + 1;
3691                 text_start_y = border_margin + 1;
3692                 window.x = x - border_margin - 1;
3693                 window.y = y - border_margin - 1;
3694         } else
3695 #endif
3696         {
3697                 /* If window size doesn't match to workarea's size, then window
3698                  * probably includes panels (gnome).
3699                  * Blah, doesn't work on KDE. */
3700                 if (workarea[2] != window.width
3701                     || workarea[3] != window.height) {
3702                         y += workarea[1];
3703                         x += workarea[0];
3704                 }
3705
3706                 text_start_x = x;
3707                 text_start_y = y;
3708         }
3709 }
3710
3711 /*
3712  * drawing stuff
3713  */
3714
3715 static int cur_x, cur_y;        /* current x and y for drawing */
3716 static int draw_mode;           /* FG, BG or OUTLINE */
3717 static long current_color;
3718
3719 static inline void set_foreground_color(long c)
3720 {
3721         current_color = c;
3722         XSetForeground(display, window.gc, c);
3723 }
3724 #endif /* X11 */
3725
3726 static void draw_string(const char *s)
3727 {
3728         if (s[0] == '\0')
3729                 return;
3730         int i, i2, pos, width_of_s;
3731         int max=0;
3732         int added;
3733         width_of_s = get_string_width(s);
3734         if (out_to_console) {
3735                 printf("%s\n", s);
3736                 fflush(stdout);   /* output immediately, don't buffer */
3737         }
3738         /* daemon_run(s);  the daemon can be called here, but we need to have a buffer in daemon_run() and we need to tell it when everything is ready to be sent */
3739         memset(tmpstring1,0,TEXT_BUFFER_SIZE);
3740         memset(tmpstring2,0,TEXT_BUFFER_SIZE);
3741         strncpy(tmpstring1, s, TEXT_BUFFER_SIZE-1);
3742         pos = 0;
3743         added = 0;
3744         char space[2];
3745         snprintf(space, 2, " ");
3746 #ifdef X11
3747         max = ((text_width - width_of_s) / get_string_width(space));
3748 #endif /* X11 */
3749         /*
3750          * This code looks for tabs in the text and coverts them to spaces.
3751          * The trick is getting the correct number of spaces,
3752          * and not going over the window's size without forcing
3753          * the window larger.
3754          */
3755         for (i = 0; i < TEXT_BUFFER_SIZE; i++) {
3756                 if (tmpstring1[i] == '\t')      // 9 is ascii tab
3757                 {
3758                         i2 = 0;
3759                         for (i2 = 0;
3760                              i2 < (8 - (1 + pos) % 8) && added <= max;
3761                              i2++) {
3762                                 /*
3763                                 if ( pos + i2 > TEXT_BUFFER_SIZE-1 )
3764                                         fprintf(stderr,"buffer overrun detected\n");
3765                                 */
3766                                 tmpstring2[ MIN(pos + i2, TEXT_BUFFER_SIZE-1) ] = ' '; /* guard against overrun */
3767                                 added++;
3768                         }
3769                         pos += i2;
3770                 } else {
3771                         if (tmpstring1[i] != 9) {
3772                                 /*
3773                                 if ( pos > TEXT_BUFFER_SIZE-1 )
3774                                          fprintf(stderr,"buffer overrun detected\n");
3775                                 */
3776                                 tmpstring2[ MIN(pos, TEXT_BUFFER_SIZE-1) ] = tmpstring1[i]; /* guard against overrun */
3777                                 pos++;
3778                         }
3779                 }
3780         }
3781 #ifdef X11
3782         if (text_width == maximum_width) {
3783                 /* this means the text is probably pushing the limit, so we'll chop it */
3784                 while (cur_x + get_string_width(tmpstring2) - text_start_x > maximum_width && strlen(tmpstring2) > 0) {
3785                         tmpstring2[strlen(tmpstring2)-1] = '\0';
3786                 }
3787         }
3788 #endif /* X11 */
3789         s = tmpstring2;
3790 #ifdef X11
3791 #ifdef XFT
3792         if (use_xft) {
3793                 XColor c;
3794                 XftColor c2;
3795                 c.pixel = current_color;
3796                 XQueryColor(display, DefaultColormap(display, screen), &c);
3797
3798                 c2.pixel = c.pixel;
3799                 c2.color.red = c.red;
3800                 c2.color.green = c.green;
3801                 c2.color.blue = c.blue;
3802                 c2.color.alpha = fonts[selected_font].font_alpha;
3803                 if (utf8_mode) {
3804                         XftDrawStringUtf8(window.xftdraw, &c2, fonts[selected_font].xftfont,
3805                                           cur_x, cur_y, (XftChar8 *) s,
3806                                           strlen(s));
3807                 } else {
3808                         XftDrawString8(window.xftdraw, &c2, fonts[selected_font].xftfont,
3809                                        cur_x, cur_y, (XftChar8 *) s,
3810                                        strlen(s));
3811                 }
3812         } else
3813 #endif
3814         {
3815                 XDrawString(display, window.drawable, window.gc,
3816                             cur_x, cur_y, s, strlen(s));
3817         }
3818         cur_x += width_of_s;
3819 #endif /* X11 */
3820         memcpy(tmpstring1, s, TEXT_BUFFER_SIZE);
3821 }
3822
3823 long redmask, greenmask, bluemask;
3824
3825 void set_up_gradient()
3826 {
3827 #ifdef X11
3828         colour_depth = DisplayPlanes(display, screen);
3829 #else
3830         colour_depth = 16;
3831 #endif /* X11 */
3832         if (colour_depth != 24 && colour_depth != 16) {
3833                 ERR("using non-standard colour depth, gradients may look like a lolly-pop");
3834         }
3835         int i;
3836         redmask = 0;
3837         greenmask = 0;
3838         bluemask = 0;
3839         for(i = (colour_depth / 3)-1; i>=0; i--) {
3840                 redmask |= 1 << i;
3841                 greenmask |= 1 << i;
3842                 bluemask |= 1 << i;
3843         }
3844         if (colour_depth%3 == 1) {
3845                 greenmask |= 1 << (colour_depth / 3);
3846         }
3847         redmask = redmask << (2*colour_depth / 3 + colour_depth%3);
3848         greenmask = greenmask << (colour_depth / 3);
3849 }
3850
3851 inline unsigned long do_gradient(unsigned long first_colour, unsigned long last_colour) { /* this function returns the next colour between two colours for a gradient */
3852         int tmp_color = 0;
3853         int red1, green1, blue1; // first colour
3854         int red2, green2, blue2; // second colour
3855         int red3 = 0, green3 = 0, blue3 = 0; // difference
3856         short redshift = (2*colour_depth / 3 + colour_depth%3);
3857         short greenshift = (colour_depth / 3);
3858         red1 = (first_colour & redmask) >> redshift;
3859         green1 = (first_colour & greenmask) >> greenshift;
3860         blue1 = first_colour & bluemask;
3861         red2 = (last_colour & redmask) >> redshift;
3862         green2 = (last_colour & greenmask) >> greenshift;
3863         blue2 = last_colour & bluemask;
3864         if (red1 > red2) {
3865                 red3 = -1;
3866         }
3867         if (red1 < red2) {
3868                 red3 = 1;
3869         }
3870         if (green1 > green2) {
3871                 green3 = -1;
3872         }
3873         if (green1 < green2) {
3874                 green3 = 1;
3875         }
3876         if (blue1 > blue2) {
3877                 blue3 = -1;
3878         }
3879         if (blue1 < blue2) {
3880                 blue3 = 1;
3881         }
3882         red1 += red3;
3883         green1 += green3;
3884         blue1 += blue3;
3885         if (red1 < 0) {
3886                 red1 = 0;
3887         }
3888         if (green1 < 0) {
3889                 green1 = 0;
3890         }
3891         if (blue1 < 0) {
3892                 blue1 = 0;
3893         }
3894         if (red1 > bluemask) {
3895                 red1 = bluemask;
3896         }
3897         if (green1 > bluemask) {
3898                 green1 = bluemask;
3899         }
3900         if (blue1 > bluemask) {
3901                 blue1 = bluemask;
3902         }
3903         tmp_color = (red1 << redshift) | (green1 << greenshift) | blue1;
3904         return tmp_color;
3905 }
3906
3907 inline unsigned long gradient_max(unsigned long first_colour, unsigned long last_colour) { /* this function returns the max diff for a gradient */
3908         if (colour_depth == 0) {
3909                 set_up_gradient();
3910         }
3911         int red1, green1, blue1; // first colour
3912         int red2, green2, blue2; // second colour
3913         long redshift = (2*colour_depth / 3 + colour_depth%3);
3914         long greenshift = (colour_depth / 3);
3915         int red3 = 0, green3 = 0, blue3 = 0; // difference
3916         red1 = (first_colour & redmask) >> redshift;
3917         green1 = (first_colour & greenmask) >> greenshift;
3918         blue1 = first_colour & bluemask;
3919         red2 = (last_colour & redmask) >> redshift;
3920         green2 = (last_colour & greenmask) >> greenshift;
3921         blue2 = last_colour & bluemask;
3922         red3 = abs(red1 - red2);
3923         green3 = abs(green1 - green2);
3924         blue3 = abs(blue1 - blue2);
3925         int max = red3;
3926         if (green3 > max)
3927                 max = green3;
3928         if (blue3 > max)
3929                 max = blue3;
3930         return max;
3931 }
3932
3933 static void draw_line(char *s)
3934 {
3935 #ifdef X11
3936         char *p;
3937         cur_x = text_start_x;
3938         cur_y += font_ascent();
3939         int cur_y_add = 0;
3940         short font_h = font_height();
3941
3942         /* find specials and draw stuff */
3943         p = s;
3944         while (*p) {
3945                 if (*p == SPECIAL_CHAR) {
3946                         int w = 0;
3947
3948                         /* draw string before special */
3949                         *p = '\0';
3950                         draw_string(s);
3951                         *p = SPECIAL_CHAR;
3952                         s = p + 1;
3953
3954                         /* draw special */
3955                         switch (specials[special_index].type) {
3956                         case HORIZONTAL_LINE:
3957                                 {
3958                                         int h =
3959                                             specials[special_index].height;
3960                                         int mid = font_ascent() / 2;
3961                                         w = text_start_x + text_width -
3962                                             cur_x;
3963
3964                                         XSetLineAttributes(display,
3965                                                            window.gc, h,
3966                                                            LineSolid,
3967                                                            CapButt,
3968                                                            JoinMiter);
3969                                         XDrawLine(display, window.drawable,
3970                                                   window.gc, cur_x,
3971                                                   cur_y - mid / 2,
3972                                                   cur_x + w,
3973                                                   cur_y - mid / 2);
3974                                 }
3975                                 break;
3976
3977                         case STIPPLED_HR:
3978                                 {
3979                                         int h =
3980                                             specials[special_index].height;
3981                                         int s =
3982                                             specials[special_index].arg;
3983                                         int mid = font_ascent() / 2;
3984                                         char ss[2] = { s, s };
3985                                         w = text_start_x + text_width -
3986                                             cur_x - 1;
3987
3988                                         XSetLineAttributes(display,
3989                                                            window.gc, h,
3990                                                            LineOnOffDash,
3991                                                            CapButt,
3992                                                            JoinMiter);
3993                                         XSetDashes(display, window.gc, 0,
3994                                                    ss, 2);
3995                                         XDrawLine(display, window.drawable,
3996                                                   window.gc, cur_x,
3997                                                   cur_y - mid / 2,
3998                                                   cur_x + w,
3999                                                   cur_y - mid / 2);
4000                                 }
4001                                 break;
4002
4003                         case BAR:
4004                                 {
4005                                         if (cur_x - text_start_x > maximum_width && maximum_width > 0) {
4006                                                 break;
4007                                         }
4008                                         int h =
4009                                             specials[special_index].height;
4010                                         int bar_usage =
4011                                             specials[special_index].arg;
4012                                         int by;
4013
4014 #ifdef XFT
4015                                         if (use_xft) {
4016                                                 by = cur_y - (font_ascent() + h) / 2 - 1;
4017                                         } else 
4018 #endif
4019                                         {
4020                                                 by = cur_y - (font_ascent()/2) - 1;
4021                                         }
4022                                         if (h < (font_height())) {
4023                                                 by -= h / 2 - 1;
4024                                         }
4025                                         w = specials[special_index].width;
4026                                         if (w == 0)
4027                                                 w = text_start_x +
4028                                                     text_width - cur_x - 1;
4029                                         if (w < 0)
4030                                                 w = 0;
4031
4032                                         XSetLineAttributes(display,
4033                                                            window.gc, 1,
4034                                                            LineSolid,
4035                                                            CapButt,
4036                                                            JoinMiter);
4037
4038                                         XDrawRectangle(display,
4039                                                        window.drawable,
4040                                                        window.gc, cur_x,
4041                                                        by, w, h);
4042                                         XFillRectangle(display,
4043                                                        window.drawable,
4044                                                        window.gc, cur_x,
4045                                                        by,
4046                                                        w * bar_usage / 255,
4047                                                        h);
4048                                         if (specials[special_index].
4049                                             height > cur_y_add
4050                                             && specials[special_index].
4051                                             height > font_h) {
4052                                                 cur_y_add =
4053                                                     specials
4054                                                     [special_index].height;
4055                                         }
4056                                 }
4057                                 break;
4058
4059                         case GRAPH:
4060                         {
4061                                         if (cur_x - text_start_x > maximum_width && maximum_width > 0) {
4062                                                 break;
4063                                         }
4064                                         int h =
4065                                             specials[special_index].height;
4066                                         int by;
4067 #ifdef XFT
4068                                         if (use_xft) {
4069                                             by = cur_y - (font_ascent() + h) / 2 - 1;
4070                                         } else
4071 #endif
4072                                         {
4073                                                 by = cur_y - (font_ascent()/2) - 1;
4074                                         }
4075                                         if (h < (font_height())) {
4076                                                 by -= h / 2 - 1;
4077                                         }
4078                                         w = specials[special_index].width;
4079                                         if (w == 0)
4080                                                 w = text_start_x + text_width - cur_x - 1;
4081                                         if (w < 0)
4082                                                 w = 0;
4083                                         if (draw_graph_borders) {
4084                                                 XSetLineAttributes(display, window.gc, 1, LineSolid, CapButt, JoinMiter);
4085                                                 XDrawRectangle(display,window.drawable, window.gc, cur_x, by, w, h);
4086                                         }
4087                                         XSetLineAttributes(display,
4088                                                            window.gc, 1,
4089                                                            LineSolid,
4090                                                            CapButt,
4091                                                            JoinMiter);
4092         int i;
4093         int j = 0;
4094         int gradient_size = 0;
4095         float gradient_factor = 0;
4096         float gradient_update = 0;
4097         unsigned long tmpcolour = current_color;
4098         if (specials[special_index].first_colour != specials[special_index].last_colour) {
4099                 tmpcolour = specials[special_index].first_colour;
4100                 gradient_size = gradient_max(specials[special_index].first_colour, specials[special_index].last_colour);
4101                 gradient_factor = (float)gradient_size / (w - 3);
4102         }
4103         for (i = 0; i < w - 3; i++) {
4104                 if (specials[special_index].first_colour != specials[special_index].last_colour) {
4105                         XSetForeground(display, window.gc, tmpcolour);
4106                         gradient_update += gradient_factor;
4107                         while (gradient_update > 0) {
4108                                 tmpcolour = do_gradient(tmpcolour, specials[special_index].last_colour);
4109                                 gradient_update--;
4110                         }
4111                 }
4112                 if (i / ((float) (w - 3) / (specials[special_index].graph_width)) > j) {
4113                         j++;
4114                                                 }
4115                                                 XDrawLine(display,  window.drawable, window.gc, cur_x + i + 2, by + h, cur_x + i + 2, by + h - specials[special_index].graph[j] * (h - 1) / specials[special_index].graph_scale);       /* this is mugfugly, but it works */
4116                                         }
4117                                         if (specials[special_index].
4118                                             height > cur_y_add
4119                                             && specials[special_index].
4120                                             height > font_h) {
4121                                                 cur_y_add =
4122                                                     specials
4123                                                     [special_index].height;
4124                                         }
4125                                 }
4126                                 if (draw_mode == BG) {
4127                                         set_foreground_color(default_bg_color);
4128                                 }
4129                                 else if (draw_mode == OUTLINE) {
4130                                         set_foreground_color(default_out_color);
4131                                 } else {
4132                                         set_foreground_color(default_fg_color);
4133                                 }
4134                                 break;
4135                         
4136                                 case FONT:
4137                                 if (fontchange) {
4138                                         cur_y -= font_ascent();
4139                                         selected_font = specials[special_index].font_added;
4140                                         cur_y += font_ascent();
4141 #ifdef XFT
4142                                         if (!use_xft || use_xdbe)
4143 #endif
4144                                         {
4145                                                 set_font();
4146                                         }
4147                                 }
4148                                 break;
4149                         case FG:
4150                                 if (draw_mode == FG)
4151                                         set_foreground_color(specials
4152                                                              [special_index].
4153                                                              arg);
4154                                 break;
4155
4156                         case BG:
4157                                 if (draw_mode == BG)
4158                                         set_foreground_color(specials
4159                                                              [special_index].
4160                                                              arg);
4161                                 break;
4162
4163                         case OUTLINE:
4164                                 if (draw_mode == OUTLINE)
4165                                         set_foreground_color(specials
4166                                                              [special_index].
4167                                                              arg);
4168                                 break;
4169
4170                                 case OFFSET:
4171                                 {
4172                                         w += specials[special_index].arg;
4173                                 }
4174                                 break;
4175                                 case VOFFSET:
4176                                 {
4177                                         cur_y += specials[special_index].arg;
4178                                 }
4179                                 break;
4180
4181                         case ALIGNR:
4182                                 {
4183                                         int pos_x = text_start_x + text_width - get_string_width_special(s) /*+ border_margin*/;
4184                                         /*printf("pos_x %i text_start_x %i text_width %i cur_x %i get_string_width(p) %i gap_x %i specials[special_index].arg %i border_margin %i border_width %i\n", pos_x, text_start_x, text_width, cur_x, get_string_width_special(s), gap_x, specials[special_index].arg, border_margin, border_width);*/
4185                                         if (pos_x > specials[special_index].arg && pos_x > cur_x) {
4186                                                 cur_x = pos_x - specials[special_index].arg;
4187                                 }
4188                                 }
4189                                 break;
4190
4191                         case ALIGNC:
4192                                 {
4193                                         int pos_x = (text_width)/2 - get_string_width_special(s)/2 - (cur_x - text_start_x);
4194                                         /*int pos_x = text_start_x + text_width/2 - get_string_width_special(s)/2;*/
4195                                         /*printf("pos_x %i text_start_x %i text_width %i cur_x %i get_string_width(p) %i gap_x %i specials[special_index].arg %i\n", pos_x, text_start_x, text_width, cur_x, get_string_width(s), gap_x, specials[special_index].arg);*/
4196                                         if (pos_x >
4197                                             specials[special_index].arg)
4198                                                 w = pos_x -
4199                                                     specials
4200                                                     [special_index].arg;
4201                                 }
4202                                 break;
4203
4204                         }
4205
4206                         cur_x += w;
4207
4208                         special_index++;
4209                 }
4210
4211                 p++;
4212         }
4213 #else
4214         draw_string(s);
4215 #endif
4216 #ifdef X11
4217         if (cur_y_add > 0) {
4218                 cur_y += cur_y_add;
4219                 cur_y -= font_descent();
4220         }
4221
4222         draw_string(s);
4223
4224         cur_y += font_descent();
4225         if (fontchange) {
4226                 selected_font = 0;
4227         }
4228 #endif /* X11 */
4229 }
4230
4231 static void draw_text()
4232 {
4233 #ifdef X11
4234         cur_y = text_start_y;
4235
4236         /* draw borders */
4237         if (draw_borders && border_width > 0) {
4238                 unsigned int b = (border_width + 1) / 2;
4239
4240                 if (stippled_borders) {
4241                         char ss[2] =
4242                             { stippled_borders, stippled_borders };
4243                         XSetLineAttributes(display, window.gc,
4244                                            border_width, LineOnOffDash,
4245                                            CapButt, JoinMiter);
4246                         XSetDashes(display, window.gc, 0, ss, 2);
4247                 } else {
4248                         XSetLineAttributes(display, window.gc,
4249                                            border_width, LineSolid,
4250                                            CapButt, JoinMiter);
4251                 }
4252
4253                 XDrawRectangle(display, window.drawable, window.gc,
4254                                text_start_x - border_margin + b,
4255                                text_start_y - border_margin + b,
4256                                text_width + border_margin * 2 - 1 - b * 2,
4257                                text_height + border_margin * 2 - 1 -
4258                                b * 2);
4259         }
4260
4261         /* draw text */
4262         special_index = 0;
4263 #endif /* X11 */
4264         for_each_line(text_buffer, draw_line);
4265 }
4266
4267 static void draw_stuff()
4268 {
4269 #ifdef X11
4270         if (draw_shades && !draw_outline) {
4271                 text_start_x++;
4272                 text_start_y++;
4273                 set_foreground_color(default_bg_color);
4274                 draw_mode = BG;
4275                 draw_text();
4276                 text_start_x--;
4277                 text_start_y--;
4278         }
4279
4280         if (draw_outline) {
4281                 int i, j;
4282                 for (i = -1; i < 2; i++)
4283                         for (j = -1; j < 2; j++) {
4284                                 if (i == 0 && j == 0)
4285                                         continue;
4286                                 text_start_x += i;
4287                                 text_start_y += j;
4288                                 set_foreground_color(default_out_color);
4289                                 draw_mode = OUTLINE;
4290                                 draw_text();
4291                                 text_start_x -= i;
4292                                 text_start_y -= j;
4293                         }
4294         }
4295
4296         set_foreground_color(default_fg_color);
4297         draw_mode = FG;
4298 #endif /* X11 */
4299         draw_text();
4300 #ifdef X11
4301 #ifdef XDBE
4302         if (use_xdbe) {
4303                 XdbeSwapInfo swap;
4304                 swap.swap_window = window.window;
4305                 swap.swap_action = XdbeBackground;
4306                 XdbeSwapBuffers(display, &swap, 1);
4307         }
4308 #endif
4309 #endif /* X11 */
4310 }
4311 #ifdef X11
4312 static void clear_text(int exposures)
4313 {
4314 #ifdef XDBE
4315         if (use_xdbe) {
4316                 return;         /* The swap action is XdbeBackground, which clears */
4317         } else
4318 #endif
4319         {
4320         /* there is some extra space for borders and outlines */
4321         XClearArea(display, window.drawable,
4322                    text_start_x - border_margin - 1,
4323                    text_start_y - border_margin - 1,
4324                    text_width + border_margin * 2 + 2,
4325                    text_height + border_margin * 2 + 2,
4326                    exposures ? True : 0);
4327         }
4328 }
4329 #endif /* X11 */
4330
4331 static int need_to_update;
4332
4333 /* update_text() generates new text and clears old text area */
4334 static void update_text()
4335 {
4336         generate_text();
4337 #ifdef X11
4338         clear_text(1);
4339 #endif /* X11 */
4340         need_to_update = 1;
4341 }
4342
4343 static void main_loop()
4344 {
4345 #ifdef SIGNAL_BLOCKING
4346         sigset_t  newmask, oldmask;
4347
4348         sigemptyset(&newmask);
4349         sigaddset(&newmask,SIGINT);
4350         sigaddset(&newmask,SIGTERM);
4351         sigaddset(&newmask,SIGUSR1);
4352 #endif
4353
4354 #ifdef X11
4355         Region region = XCreateRegion();
4356 #endif /* X11 */
4357
4358         info.looped = 0;
4359         while (total_run_times == 0 || info.looped < total_run_times - 1) {
4360                 info.looped++;
4361
4362 #ifdef SIGNAL_BLOCKING
4363                 /* block signals.  we will inspect for pending signals later */
4364                 if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
4365                         CRIT_ERR("unable to sigprocmask()");
4366 #endif
4367
4368 #ifdef X11
4369                 XFlush(display);
4370
4371                 /* wait for X event or timeout */
4372
4373                 if (!XPending(display)) {
4374                         fd_set fdsr;
4375                         struct timeval tv;
4376                         int s;
4377                         double t =
4378                             update_interval - (get_time() -
4379                                                last_update_time);
4380
4381                         if (t < 0)
4382                                 t = 0;
4383
4384                         tv.tv_sec = (long) t;
4385                         tv.tv_usec = (long) (t * 1000000) % 1000000;
4386                         FD_ZERO(&fdsr);
4387                         FD_SET(ConnectionNumber(display), &fdsr);
4388
4389
4390                         s = select(ConnectionNumber(display) + 1, &fdsr, 0,
4391                                    0, &tv);
4392 #else
4393                         usleep(update_interval*1000000); /* FIXME just sleep for the interval time if no X11 */
4394 #endif /* X11 */
4395 #ifdef X11
4396                         if (s == -1) {
4397                                 if (errno != EINTR)
4398                                         ERR("can't select(): %s",
4399                                             strerror(errno));
4400                         } else {
4401                                 /* timeout */
4402                                 if (s == 0)
4403 #endif /* X11 */
4404                                         update_text();
4405 #ifdef X11
4406                         }
4407 #ifdef OWN_WINDOW
4408                         if (own_window) {
4409                                 set_transparent_background(window.window);
4410                         }
4411 #endif
4412                 }
4413                 
4414                 if (need_to_update) {
4415 #ifdef OWN_WINDOW
4416                         int wx = window.x, wy = window.y;
4417 #endif
4418
4419                         need_to_update = 0;
4420
4421                         update_text_area();
4422 #ifdef OWN_WINDOW
4423                         if (own_window) {
4424                                 /* resize window if it isn't right size */
4425                                 if (!fixed_size &&
4426                                     (text_width + border_margin * 2 !=
4427                                      window.width
4428                                      || text_height + border_margin * 2 !=
4429                                      window.height)) {
4430                                         window.width =
4431                                             text_width +
4432                                             border_margin * 2 + 1;
4433                                         window.height =
4434                                             text_height +
4435                                             border_margin * 2 + 1;
4436                                         XResizeWindow(display,
4437                                                       window.window,
4438                                                       window.width,
4439                                                       window.height);
4440                                      }
4441
4442                                 /* move window if it isn't in right position */
4443                                 if (!fixed_pos
4444                                     && (window.x != wx
4445                                         || window.y != wy)) {
4446                                         XMoveWindow(display, window.window,
4447                                                     window.x, window.y);
4448                                 }
4449                         }
4450 #endif
4451
4452                         clear_text(1);
4453
4454 #ifdef XDBE
4455                         if (use_xdbe) {
4456                                 XRectangle r;
4457                                 r.x = text_start_x - border_margin;
4458                                 r.y = text_start_y - border_margin;
4459                                 r.width = text_width + border_margin * 2;
4460                                 r.height = text_height + border_margin * 2;
4461                                 XUnionRectWithRegion(&r, region, region);
4462                         }
4463 #endif
4464                 }
4465
4466                 /* handle X events */
4467
4468                 while (XPending(display)) {
4469                         XEvent ev;
4470                         XNextEvent(display, &ev);
4471                         switch (ev.type) {
4472                         case Expose:
4473                                 {
4474                                         XRectangle r;
4475                                         r.x = ev.xexpose.x;
4476                                         r.y = ev.xexpose.y;
4477                                         r.width = ev.xexpose.width;
4478                                         r.height = ev.xexpose.height;
4479                                         XUnionRectWithRegion(&r, region,
4480                                                              region);
4481                                 }
4482                                 break;
4483
4484 #ifdef OWN_WINDOW
4485                         case ReparentNotify:
4486                                 /* set background to ParentRelative for all parents */
4487                                 if (own_window) {
4488                                         set_transparent_background(window.
4489                                         window);
4490                                 }
4491                                 break;
4492
4493                         case ConfigureNotify:
4494                                 if (own_window) {
4495                                         /* if window size isn't what expected, set fixed size */
4496                                         if (ev.xconfigure.width !=
4497                                             window.width
4498                                             || ev.xconfigure.height !=
4499                                             window.height) {
4500                                                 if (window.width != 0
4501                                                     && window.height != 0)
4502                                                         fixed_size = 1;
4503
4504                                                 /* clear old stuff before screwing up size and pos */
4505                                                 clear_text(1);
4506
4507                                                 {
4508                                                         XWindowAttributes
4509                                                             attrs;
4510                                                         if (XGetWindowAttributes(display, window.window, &attrs)) {
4511                                                                 window.
4512                                                                     width =
4513                                                                     attrs.
4514                                                                     width;
4515                                                                 window.
4516                                                                     height
4517                                                                     =
4518                                                                     attrs.
4519                                                                     height;
4520                                                         }
4521                                                 }
4522
4523                                                 text_width =
4524                                                     window.width -
4525                                                     border_margin * 2 - 1;
4526                                                 text_height =
4527                                                     window.height -
4528                                                     border_margin * 2 - 1;
4529                                                 if (text_width > maximum_width && maximum_width > 0)
4530                                                         text_width = maximum_width;
4531                                         }
4532
4533                                         /* if position isn't what expected, set fixed pos, total_updates
4534                                          * avoids setting fixed_pos when window is set to weird locations
4535                                          * when started */
4536                                         /*if (total_updates >= 2 this is broken
4537                                             && !fixed_pos
4538                                             && (window.x != ev.xconfigure.x
4539                                                 || window.y !=
4540                                                 ev.xconfigure.y)
4541                                             && (ev.xconfigure.x != 0
4542                                                 || ev.xconfigure.y != 0)) {
4543                                                 fixed_pos = 1;
4544                                 }*/
4545                                         set_font();
4546                                 }
4547                                 break;
4548 #endif
4549
4550                         default:
4551                                 break;
4552                         }
4553                 }
4554
4555                 /* XDBE doesn't seem to provide a way to clear the back buffer without
4556                  * interfering with the front buffer, other than passing XdbeBackground
4557                  * to XdbeSwapBuffers. That means that if we're using XDBE, we need to
4558                  * redraw the text even if it wasn't part of the exposed area. OTOH,
4559                  * if we're not going to call draw_stuff at all, then no swap happens
4560                  * and we can safely do nothing.
4561                  */
4562
4563                 if (!XEmptyRegion(region)) {
4564 #ifdef XDBE
4565                         if (use_xdbe) {
4566                                 XRectangle r;
4567                                 r.x = text_start_x - border_margin;
4568                                 r.y = text_start_y - border_margin;
4569                                 r.width = text_width + border_margin * 2;
4570                                 r.height = text_height + border_margin * 2;
4571                                 XUnionRectWithRegion(&r, region, region);
4572                 }
4573 #endif
4574                         XSetRegion(display, window.gc, region);
4575 #ifdef XFT
4576                         if (use_xft) {
4577                                 XftDrawSetClip(window.xftdraw, region);
4578                         }
4579 #endif
4580 #endif /* X11 */
4581                         draw_stuff();
4582 #ifdef X11
4583                         XDestroyRegion(region);
4584                         region = XCreateRegion();
4585                 }
4586 #endif /* X11 */
4587
4588 #ifdef SIGNAL_BLOCKING
4589                 /* unblock signals of interest and let handler fly */
4590                 if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
4591                         CRIT_ERR("unable to sigprocmask()");
4592 #endif
4593
4594                 switch(g_signal_pending) {
4595                 case SIGUSR1:
4596                         {
4597                         ERR("received SIGUSR1. reloading the config file.");
4598                         reload_config();
4599                         break;
4600                         }
4601                 case SIGINT:
4602                 case SIGTERM:
4603                         {
4604                         ERR("received SIGINT or SIGTERM to terminate. bye!");
4605                         clean_up();
4606 #ifdef X11
4607                         XDestroyRegion(region);
4608                         region = NULL;
4609 #endif /* X11 */
4610                         return;  /* return from main_loop */
4611                         /*break;*/
4612                         }
4613                 default:
4614                         {
4615                         /* Reaching here means someone set a signal( SIGXXXX, signal_handler )
4616                          * but didn't write any code to deal with it.   if you don't want to
4617                          * handle a signal, don't set a handler on it in the first place. */
4618                         if (g_signal_pending)
4619                                 ERR("ignoring signal (%d)", g_signal_pending);
4620                         break;
4621                         }
4622                 }
4623                 g_signal_pending=0;
4624         
4625         }
4626 #ifdef X11
4627         XDestroyRegion(region);
4628         region = NULL;
4629 #endif /* X11 */
4630 }
4631
4632 static void load_config_file(const char *);
4633
4634 /* reload the config file */
4635 void reload_config(void)
4636 {
4637         if (current_config) {
4638                 clear_fs_stats();
4639                 load_config_file(current_config);
4640 #ifdef X11
4641                 load_fonts();
4642                 set_font();
4643                 XClearWindow(display, RootWindow(display, screen)); // clear the window first
4644
4645 #endif /* X11 */
4646 #ifdef TCP_PORT_MONITOR
4647                 destroy_tcp_port_monitor_collection( info.p_tcp_port_monitor_collection );
4648                 info.p_tcp_port_monitor_collection = NULL; 
4649 #endif
4650                 extract_variable_text(text);
4651                 free(text);
4652                 text = NULL;
4653                 update_text();
4654         }
4655 }
4656
4657 void clean_up(void)
4658 {
4659 #ifdef X11
4660 #ifdef XDBE
4661         if (use_xdbe) {
4662                 XdbeDeallocateBackBufferName(display, window.back_buffer);
4663         }
4664 #endif
4665 #ifdef OWN_WINDOW
4666         if (own_window)
4667                 XDestroyWindow(display, window.window);
4668         else
4669 #endif
4670         {
4671                 XClearWindow(display, RootWindow(display, screen));
4672                 clear_text(1);
4673                 XFlush(display);
4674         }
4675
4676         XFreeGC(display, window.gc);
4677 #endif /* X11 */
4678
4679
4680         /* it is really pointless to free() memory at the end of program but ak|ra
4681          * wants me to do this */
4682
4683         free_text_objects(text_object_count, text_objects);
4684         text_object_count = 0;
4685         text_objects = NULL;
4686
4687 #ifdef MLDONKEY 
4688         ml_cleanup();
4689 #endif /* MLDONKEY */
4690
4691         if (text != original_text)
4692                 free(text);
4693
4694         free(current_config);
4695         free(current_mail_spool);
4696 #ifdef SETI
4697         free(seti_dir);
4698 #endif
4699 #ifdef TCP_PORT_MONITOR
4700         destroy_tcp_port_monitor_collection( info.p_tcp_port_monitor_collection );
4701         info.p_tcp_port_monitor_collection = NULL;
4702 #endif
4703 }
4704
4705 static int string_to_bool(const char *s)
4706 {
4707         if (!s)
4708                 return 1;
4709         if (strcasecmp(s, "yes") == 0)
4710                 return 1;
4711         if (strcasecmp(s, "true") == 0)
4712                 return 1;
4713         if (strcasecmp(s, "1") == 0)
4714                 return 1;
4715         return 0;
4716 }
4717 #ifdef X11
4718 static enum alignment string_to_alignment(const char *s)
4719 {
4720         if (strcasecmp(s, "top_left") == 0)
4721                 return TOP_LEFT;
4722         else if (strcasecmp(s, "top_right") == 0)
4723                 return TOP_RIGHT;
4724         else if (strcasecmp(s, "bottom_left") == 0)
4725                 return BOTTOM_LEFT;
4726         else if (strcasecmp(s, "bottom_right") == 0)
4727                 return BOTTOM_RIGHT;
4728         else if (strcasecmp(s, "tl") == 0)
4729                 return TOP_LEFT;
4730         else if (strcasecmp(s, "tr") == 0)
4731                 return TOP_RIGHT;
4732         else if (strcasecmp(s, "bl") == 0)
4733                 return BOTTOM_LEFT;
4734         else if (strcasecmp(s, "br") == 0)
4735                 return BOTTOM_RIGHT;
4736         else if (strcasecmp(s, "none") == 0)
4737                 return NONE;
4738         return TOP_LEFT;
4739 }
4740 #endif /* X11 */
4741
4742
4743 static void set_default_configurations(void)
4744 {
4745         fork_to_background = 0;
4746         total_run_times = 0;
4747         info.cpu_avg_samples = 2;
4748         info.net_avg_samples = 2;
4749         info.memmax = 0;
4750         top_cpu = 0;
4751         top_mem = 0;
4752 #ifdef MPD
4753         strcpy(info.mpd.host, "localhost");
4754         info.mpd.port = 6600;
4755         info.mpd.status = "Checking status...";
4756 #endif
4757         use_spacer = 0;
4758 #ifdef X11
4759         out_to_console = 0;
4760 #else
4761         out_to_console = 1;
4762 #endif
4763 #ifdef X11
4764         default_fg_color = WhitePixel(display, screen);
4765         default_bg_color = BlackPixel(display, screen);
4766         default_out_color = BlackPixel(display, screen);
4767         draw_shades = 1;
4768         draw_borders = 0;
4769         draw_graph_borders = 1;
4770         draw_outline = 0;
4771         set_first_font("6x10");
4772         gap_x = 5;
4773         gap_y = 5;
4774         minimum_width = 5;
4775         minimum_height = 5;
4776         maximum_width = 0;
4777 #ifdef OWN_WINDOW
4778         own_window = 0;
4779         strcpy(wm_class_name, "conky"); 
4780 #endif
4781         stippled_borders = 0;
4782         border_margin = 3;
4783         border_width = 1;
4784         text_alignment = BOTTOM_LEFT;
4785         on_bottom = 1;
4786 #endif /* X11 */
4787
4788         free(current_mail_spool);
4789         {
4790                 char buf[256];
4791                 variable_substitute(MAIL_FILE, buf, 256);
4792                 if (buf[0] != '\0')
4793                         current_mail_spool = strdup(buf);
4794         }
4795
4796         no_buffers = 1;
4797         update_interval = 10.0;
4798         stuff_in_upper_case = 0;
4799 #ifdef MLDONKEY
4800         mlconfig.mldonkey_hostname = strdup("127.0.0.1");
4801         mlconfig.mldonkey_port = 4001;
4802         mlconfig.mldonkey_login = NULL;
4803         mlconfig.mldonkey_password = NULL;
4804 #endif
4805
4806 #ifdef TCP_PORT_MONITOR
4807         tcp_port_monitor_collection_args.min_port_monitors = MIN_PORT_MONITORS_DEFAULT;
4808         tcp_port_monitor_args.min_port_monitor_connections = MIN_PORT_MONITOR_CONNECTIONS_DEFAULT;
4809 #endif
4810 }
4811
4812 static void load_config_file(const char *f)
4813 {
4814 #define CONF_ERR ERR("%s: %d: config file error", f, line)
4815         int line = 0;
4816         FILE *fp;
4817
4818         set_default_configurations();
4819         fp = fopen(f, "r");
4820         if (!fp)
4821                 return;
4822
4823         while (!feof(fp)) {
4824                 char buf[256], *p, *p2, *name, *value;
4825                 line++;
4826                 if (fgets(buf, 256, fp) == NULL)
4827                         break;
4828
4829                 p = buf;
4830
4831                 /* break at comment */
4832                 p2 = strchr(p, '#');
4833                 if (p2)
4834                         *p2 = '\0';
4835
4836                 /* skip spaces */
4837                 while (*p && isspace((int) *p))
4838                         p++;
4839                 if (*p == '\0')
4840                         continue;       /* empty line */
4841
4842                 name = p;
4843
4844                 /* skip name */
4845                 p2 = p;
4846                 while (*p2 && !isspace((int) *p2))
4847                         p2++;
4848                 if (*p2 != '\0') {
4849                         *p2 = '\0';     /* break at name's end */
4850                         p2++;
4851                 }
4852
4853                 /* get value */
4854                 if (*p2) {
4855                         p = p2;
4856                         while (*p && isspace((int) *p))
4857                                 p++;
4858
4859                         value = p;
4860
4861                         p2 = value + strlen(value);
4862                         while (isspace((int) *(p2 - 1)))
4863                                 *--p2 = '\0';
4864                 } else {
4865                         value = 0;
4866                 }
4867
4868 #define CONF2(a) if (strcasecmp(name, a) == 0)
4869 #define CONF(a) else CONF2(a)
4870 #define CONF3(a,b) \
4871 else if (strcasecmp(name, a) == 0 || strcasecmp(name, b) == 0)
4872
4873
4874 #ifdef X11
4875                 CONF2("alignment") {
4876         if (value) {
4877                 int a = string_to_alignment(value);
4878                 if (a <= 0)
4879                         CONF_ERR;
4880                 else
4881                         text_alignment = a;
4882         } else
4883                 CONF_ERR;
4884                 }
4885                 CONF("on_bottom") {
4886                         if(value)
4887                                 on_bottom = string_to_bool(value);
4888                         else
4889                                 CONF_ERR;
4890                 }
4891                 CONF("background") {
4892                         fork_to_background = string_to_bool(value);
4893                 }
4894
4895 #else
4896                 CONF2("background") {
4897         fork_to_background = string_to_bool(value);
4898                 }
4899 #endif /* X11 */
4900 #ifdef X11
4901                 CONF("border_margin") {
4902                         if (value)
4903                                 border_margin = strtol(value, 0, 0);
4904                         else
4905                                 CONF_ERR;
4906                 }
4907                 CONF("border_width") {
4908                         if (value)
4909                                 border_width = strtol(value, 0, 0);
4910                         else
4911                                 CONF_ERR;
4912                 }
4913                 CONF("default_color") {
4914                         if (value)
4915                                 default_fg_color = get_x11_color(value);
4916                         else
4917                                 CONF_ERR;
4918                 }
4919                 CONF3("default_shade_color", "default_shadecolor") {
4920                         if (value)
4921                                 default_bg_color = get_x11_color(value);
4922                         else
4923                                 CONF_ERR;
4924                 }
4925                 CONF3("default_outline_color", "default_outlinecolor") {
4926                         if (value)
4927                                 default_out_color = get_x11_color(value);
4928                         else
4929                                 CONF_ERR;
4930                 }
4931 #endif /* X11 */
4932 #ifdef MPD
4933                 CONF("mpd_host") {
4934                         if (value)
4935                                 strcpy(info.mpd.host, value);
4936                         else
4937                                 CONF_ERR;
4938                 }
4939                 CONF("mpd_port") {
4940                         if (value) {
4941                                 info.mpd.port = strtol(value, 0, 0);
4942                                 if (info.mpd.port < 1
4943                                     || info.mpd.port > 0xffff)
4944                                         CONF_ERR;
4945                         }
4946                 }
4947 #endif
4948                 CONF("cpu_avg_samples") {
4949                         if (value) {
4950                                 cpu_avg_samples = strtol(value, 0, 0);
4951                                 if (cpu_avg_samples < 1
4952                                     || cpu_avg_samples > 14)
4953                                         CONF_ERR;
4954                                 else
4955                                         info.
4956                                             cpu_avg_samples
4957                                             = cpu_avg_samples;
4958                         } else
4959                                 CONF_ERR;
4960                 }
4961                 CONF("net_avg_samples") {
4962                         if (value) {
4963                                 net_avg_samples = strtol(value, 0, 0);
4964                                 if (net_avg_samples < 1
4965                                     || net_avg_samples > 14)
4966                                         CONF_ERR;
4967                                 else
4968                                         info.
4969                                             net_avg_samples
4970                                             = net_avg_samples;
4971                         } else
4972                                 CONF_ERR;
4973                 }
4974
4975
4976
4977
4978
4979
4980 #ifdef XDBE
4981                 CONF("double_buffer") {
4982                 use_xdbe = string_to_bool(value);
4983                 }
4984 #endif
4985 #ifdef X11
4986                 CONF("override_utf8_locale") {
4987         utf8_mode = string_to_bool(value);
4988                 }
4989
4990                 CONF("draw_borders") {
4991                         draw_borders = string_to_bool(value);
4992                 }
4993                 CONF("draw_graph_borders") {
4994                         draw_graph_borders = string_to_bool(value);
4995                 }
4996                 CONF("draw_shades") {
4997                         draw_shades = string_to_bool(value);
4998                 }
4999                 CONF("draw_outline") {
5000                         draw_outline = string_to_bool(value);
5001                 }
5002 #endif /* X11 */
5003                 CONF("out_to_console") {
5004                         out_to_console = string_to_bool(value);
5005                 }
5006                 CONF("use_spacer") {
5007                         use_spacer = string_to_bool(value);
5008                 }
5009 #ifdef X11
5010 #ifdef XFT
5011                 CONF("use_xft") {
5012                         use_xft = string_to_bool(value);
5013                 }
5014                 CONF("font") {
5015                         if (value) {
5016                                 set_first_font(value);
5017                         } else
5018                                 CONF_ERR;
5019                 }
5020                 CONF("xftalpha") {
5021                         if (value && font_count >= 0)
5022                                 fonts[0].font_alpha = atof(value)
5023                                     * 65535.0;
5024                         else
5025                                 CONF_ERR;
5026                 }
5027                 CONF("xftfont") {
5028 #else
5029                 CONF("use_xft") {
5030                         if (string_to_bool(value))
5031                                 ERR("Xft not enabled");
5032                 }
5033                 CONF("xftfont") {
5034                         /* xftfont silently ignored when no Xft */
5035                 }
5036                 CONF("xftalpha") {
5037                         /* xftalpha is silently ignored when no Xft */
5038                 }
5039                 CONF("font") {
5040 #endif
5041                         if (use_xft) {
5042                                 if (value) {
5043                                         set_first_font(value);
5044                                 } else
5045                                         CONF_ERR;
5046                         }
5047                 }
5048                 CONF("gap_x") {
5049                         if (value)
5050                                 gap_x = atoi(value);
5051                         else
5052                                 CONF_ERR;
5053                 }
5054                 CONF("gap_y") {
5055                         if (value)
5056                                 gap_y = atoi(value);
5057                         else
5058                                 CONF_ERR;
5059                 }
5060 #endif /* X11 */
5061                 CONF("mail_spool") {
5062                         if (value) {
5063                                 char buf[256];
5064                                 variable_substitute(value, buf, 256);
5065
5066                                 if (buf[0]
5067                                     != '\0') {
5068                                         if (current_mail_spool)
5069                                                 free(current_mail_spool);
5070                                         current_mail_spool = strdup(buf);
5071                                 }
5072                         } else
5073                                 CONF_ERR;
5074                 }
5075 #ifdef X11
5076                 CONF("minimum_size") {
5077         if (value) {
5078                 if (sscanf
5079                                   (value, "%d %d", &minimum_width,
5080                                    &minimum_height) != 2)
5081                         if (sscanf
5082                                                  (value, "%d",
5083                                                    &minimum_width) != 1)
5084                                 CONF_ERR;
5085         } else
5086                 CONF_ERR;
5087                 }
5088                 CONF("maximum_width") {
5089                         if (value) {
5090                                 if (sscanf(value, "%d", &maximum_width) != 1)
5091                                         CONF_ERR;
5092                         } else
5093                                 CONF_ERR;
5094                 }
5095 #endif /* X11 */
5096                 CONF("no_buffers") {
5097                         no_buffers = string_to_bool(value);
5098                 }
5099 #ifdef MLDONKEY
5100                 CONF("mldonkey_hostname") {
5101                         if (value) {
5102                                 if (mlconfig.mldonkey_hostname != NULL) {
5103                                         free(mlconfig.mldonkey_hostname);
5104                                 }
5105                         mlconfig.mldonkey_hostname = strdup(value);
5106                         }
5107                         else
5108                                 CONF_ERR;
5109                 }
5110                 CONF("mldonkey_port") {
5111                         if (value)
5112                                 mlconfig.mldonkey_port = atoi(value);
5113                         else
5114                                 CONF_ERR;
5115                 }
5116                 CONF("mldonkey_login") {
5117                         if (value) {
5118                                 if (mlconfig.mldonkey_login != NULL) {
5119                                         free(mlconfig.mldonkey_login);
5120                                 }
5121                                 mlconfig.mldonkey_login = strdup(value);
5122                         }
5123                         else
5124                                 CONF_ERR;
5125                 }
5126                 CONF("mldonkey_password") {
5127                         if (value) {
5128                                 if (mlconfig.mldonkey_password != NULL) {
5129                                         free(mlconfig.mldonkey_password);
5130                                 }
5131                                 mlconfig.mldonkey_password = strdup(value);
5132                         }
5133                         else
5134                                 CONF_ERR;
5135                 }
5136 #endif
5137                 CONF("pad_percents") {
5138         pad_percents = atoi(value);
5139                 }
5140 #ifdef X11
5141 #ifdef OWN_WINDOW
5142                 CONF("own_window") {
5143                         own_window = string_to_bool(value);
5144                 }
5145                 CONF("wm_class_name") {
5146                         strncpy(wm_class_name, value, sizeof(wm_class_name)-1);
5147                         wm_class_name[sizeof(wm_class_name)-1] = 0;
5148                 }
5149                 CONF("own_window_transparent") {
5150                         set_transparent = string_to_bool(value);
5151                 }
5152                 CONF("own_window_colour") {
5153                         background_colour = get_x11_color(value);
5154                 }
5155 #endif
5156                 CONF("stippled_borders") {
5157                         if (value)
5158                                 stippled_borders = strtol(value, 0, 0);
5159                         else
5160                                 stippled_borders = 4;
5161                 }
5162 #endif /* X11 */
5163                 CONF("temp1") {
5164                         ERR("temp1 configuration is obsolete, use ${i2c <i2c device here> temp 1}");
5165                 }
5166                 CONF("temp1") {
5167                         ERR("temp2 configuration is obsolete, use ${i2c <i2c device here> temp 2}");
5168                 }
5169                 CONF("update_interval") {
5170                         if (value)
5171                                 update_interval = strtod(value, 0);
5172                         else
5173                                 CONF_ERR;
5174                 }
5175                 CONF("total_run_times") {
5176                         if (value)
5177                                 total_run_times = strtod(value, 0);
5178                         else
5179                                 CONF_ERR;
5180                 }
5181                 CONF("uppercase") {
5182                         stuff_in_upper_case = string_to_bool(value);
5183                 }
5184 #ifdef SETI
5185                 CONF("seti_dir") {
5186                         seti_dir = (char *)
5187                             malloc(strlen(value)
5188                                    + 1);
5189                         strcpy(seti_dir, value);
5190                 }
5191 #endif
5192                 CONF("text") {
5193                         if (text != original_text)
5194                                 free(text);
5195
5196                         text = (char *)
5197                             malloc(1);
5198                         text[0]
5199                             = '\0';
5200
5201                         while (!feof(fp)) {
5202                                 unsigned
5203                                 int l = strlen(text);
5204                                 if (fgets(buf, 256, fp) == NULL)
5205                                         break;
5206                                 text = (char *)
5207                                     realloc(text, l + strlen(buf)
5208                                             + 1);
5209                                 strcat(text, buf);
5210
5211                                 if (strlen(text) > 1024 * 8)
5212                                         break;
5213                         }
5214                         fclose(fp);
5215                         return;
5216                 }
5217 #ifdef TCP_PORT_MONITOR
5218                 CONF("min_port_monitors") 
5219                 {
5220                         if ( !value || 
5221                              (sscanf(value, "%d", &tcp_port_monitor_collection_args.min_port_monitors) != 1) || 
5222                              tcp_port_monitor_collection_args.min_port_monitors < 0 )
5223                         {
5224                                 /* an error. use default, warn and continue. */
5225                                 tcp_port_monitor_collection_args.min_port_monitors = MIN_PORT_MONITORS_DEFAULT;
5226                                 CONF_ERR;
5227                         }
5228                         else if ( tcp_port_monitor_collection_args.min_port_monitors == 0 )
5229                         {
5230                                 /* no error, just use default */
5231                                 tcp_port_monitor_collection_args.min_port_monitors = MIN_PORT_MONITORS_DEFAULT;
5232                         }
5233                         /* else tcp_port_monitor_collection_args.min_port_monitors > 0 as per config */
5234                 }
5235                 CONF("min_port_monitor_connections") 
5236                 {
5237                         if ( !value || 
5238                              (sscanf(value, "%d", &tcp_port_monitor_args.min_port_monitor_connections) != 1) 
5239                              || tcp_port_monitor_args.min_port_monitor_connections < 0 )
5240                         {
5241                                 /* an error. use default, warni and continue. */
5242                                 tcp_port_monitor_args.min_port_monitor_connections = MIN_PORT_MONITOR_CONNECTIONS_DEFAULT;
5243                                 CONF_ERR;
5244                         }
5245                         else if ( tcp_port_monitor_args.min_port_monitor_connections == 0 )
5246                         {
5247                                 /* no error, just use default */
5248                                 tcp_port_monitor_args.min_port_monitor_connections = MIN_PORT_MONITOR_CONNECTIONS_DEFAULT;
5249                         }
5250                         /* else tcp_port_monitor_args.min_port_monitor_connections > 0 as per config */
5251                 }
5252 #endif
5253                 else
5254                 ERR("%s: %d: no such configuration: '%s'", f, line, name);
5255
5256 #undef CONF
5257 #undef CONF2
5258         }
5259
5260         fclose(fp);
5261 #undef CONF_ERR
5262 }
5263
5264                                                                                                                                                                                         /* : means that character before that takes an argument */
5265 static const char *getopt_string = "vVdt:f:u:i:hc:w:x:y:a:"
5266 #ifdef X11
5267                 "x:y:w:a:f:"
5268 #ifdef OWN_WINDOW
5269     "o"
5270 #endif
5271 #ifdef XDBE
5272     "b"
5273 #endif
5274 #endif /* X11 */
5275     ;
5276
5277
5278 int main(int argc, char **argv)
5279 {
5280         struct sigaction act, oact;
5281
5282         g_signal_pending=0;
5283         memset(&info, 0, sizeof(info) );
5284
5285 #ifdef TCP_PORT_MONITOR
5286         tcp_port_monitor_collection_args.min_port_monitors = MIN_PORT_MONITORS_DEFAULT;
5287         tcp_port_monitor_args.min_port_monitor_connections = MIN_PORT_MONITOR_CONNECTIONS_DEFAULT;
5288 #endif
5289                 
5290         /* handle command line parameters that don't change configs */
5291 #ifdef X11
5292         char *s;
5293         char temp[10];
5294         unsigned int x;
5295
5296         if (((s = getenv("LC_ALL")) && *s) || ((s = getenv("LC_CTYPE")) && 
5297                      *s) || ((s = getenv("LANG")) && *s)) {
5298                 strcpy(temp, s);
5299                 for(x = 0; x < strlen(s) ; x++) {
5300                         temp[x] = tolower(s[x]);
5301                 }
5302                 if (strstr(temp, "utf-8") || strstr(temp, "utf8")) {
5303                         utf8_mode = 1;
5304                 }
5305         }
5306         if (!setlocale(LC_CTYPE, "")) {
5307                 ERR("Can't set the specified locale!\nCheck LANG, LC_CTYPE, LC_ALL.");
5308         }
5309 #endif /* X11 */
5310         while (1) {
5311                 int c = getopt(argc,
5312                                argv,
5313                                getopt_string);
5314                 if (c == -1)
5315                         break;
5316
5317                 switch (c) {
5318                 case 'v':
5319                 case 'V':
5320                         printf
5321                             ("Conky " VERSION " compiled " __DATE__ "\n");
5322                         return 0;
5323
5324                 case 'c':
5325                         /* if current_config is set to a strdup of CONFIG_FILE, free it (even
5326                          * though free() does the NULL check itself;), then load optarg value */
5327                         if (current_config)
5328                                 free(current_config);
5329                         current_config = strdup(optarg);
5330                         break;
5331
5332                 case 'h':
5333                         printf
5334                                         ("Usage: %s [OPTION]...\n"
5335                                         "Conky is a system monitor that renders text on desktop or to own transparent\n"
5336                                         "window. Command line options will override configurations defined in config\n"
5337                                         "file.\n"
5338                                         "   -V            version\n"
5339                                         "   -c FILE       config file to load instead of "
5340                                         CONFIG_FILE
5341                                         "\n"
5342                                         "   -d            daemonize, fork to background\n"
5343                                         "   -h            help\n"
5344 #ifdef X11
5345                                         "   -a ALIGNMENT  text alignment on screen, {top,bottom}_{left,right}\n"
5346                                         "   -f FONT       font to use\n"
5347 #ifdef OWN_WINDOW
5348                                         "   -o            create own window to draw\n"
5349 #endif
5350 #ifdef XDBE
5351                                         "   -b            double buffer (prevents flickering)\n"
5352 #endif
5353                                         "   -w WIN_ID     window id to draw\n"
5354                                         "   -x X          x position\n"
5355                                         "   -y Y          y position\n"
5356 #endif /* X11 */
5357                                         "   -t TEXT       text to render, remember single quotes, like -t '$uptime'\n"
5358                                         "   -u SECS       update interval\n"
5359                                         "   -i NUM        number of times to update Conky\n", argv[0]);
5360                         return 0;
5361 #ifdef X11
5362                 case 'w':
5363                         window.window = strtol(optarg, 0, 0);
5364                         break;
5365 #endif /* X11 */
5366
5367                 case '?':
5368                         exit(EXIT_FAILURE);
5369                 }
5370         }
5371 #ifdef X11
5372         /* initalize X BEFORE we load config. (we need to so that 'screen' is set) */
5373         init_X11();
5374 #endif /* X11 */
5375
5376         /* load current_config or CONFIG_FILE */
5377
5378 #ifdef CONFIG_FILE
5379         if (current_config == NULL) {
5380                 /* load default config file */
5381                 char buf[256];
5382
5383                 variable_substitute(CONFIG_FILE, buf, 256);
5384
5385                 if (buf[0] != '\0')
5386                         current_config = strdup(buf);
5387         }
5388 #endif
5389
5390         if (current_config != NULL && fopen((const char *)current_config, (const char *)"r"))
5391                 load_config_file(current_config);
5392         else { 
5393                 set_default_configurations();
5394         }
5395
5396 #ifdef MAIL_FILE
5397         if (current_mail_spool == NULL) {
5398                 char buf[256];
5399                 variable_substitute(MAIL_FILE, buf, 256);
5400
5401                 if (buf[0] != '\0')
5402                         current_mail_spool = strdup(buf);
5403         }
5404 #endif
5405
5406         /* handle other command line arguments */
5407
5408 #if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__NetBSD__)
5409         optind = optreset = 1;
5410 #else
5411         optind = 0;
5412 #endif
5413         
5414         while (1) {
5415                 int c = getopt(argc,
5416                                argv,
5417                                getopt_string);
5418                 if (c == -1)
5419                         break;
5420
5421                 switch (c) {
5422                 case 'd':
5423                         fork_to_background = 1;
5424                         break;
5425
5426 #ifdef X11
5427                         case 'f':
5428                         set_first_font(optarg);
5429                         break;
5430                         case 'a':
5431                                 text_alignment = string_to_alignment(optarg);
5432                                 break;
5433
5434 #ifdef OWN_WINDOW
5435                 case 'o':
5436                         own_window = 1;
5437                         break;
5438 #endif
5439 #ifdef XDBE
5440                 case 'b':
5441                                 use_xdbe = 1;
5442                         break;
5443 #endif
5444 #endif /* X11 */
5445                 case 't':
5446                         if (text != original_text)
5447                                 free(text);
5448                         text = strdup(optarg);
5449                         convert_escapes(text);
5450                         break;
5451
5452                 case 'u':
5453                         update_interval = strtod(optarg, 0);
5454                         break;
5455
5456                 case 'i':
5457                         total_run_times = strtod(optarg, 0);
5458                         break;
5459 #ifdef X11
5460                 case 'x':
5461                         gap_x = atoi(optarg);
5462                         break;
5463
5464                 case 'y':
5465                         gap_y = atoi(optarg);
5466                         break;
5467 #endif /* X11 */
5468
5469                 case '?':
5470                         exit(EXIT_FAILURE);
5471                 }
5472         }
5473
5474 #ifdef X11
5475         /* load font */
5476         load_fonts();
5477 #endif /* X11 */
5478
5479         /* generate text and get initial size */
5480         extract_variable_text(text);
5481         if (text != original_text) {
5482                 free(text);
5483         }
5484         text = NULL;
5485
5486         update_uname();
5487
5488         generate_text();
5489 #ifdef X11
5490         update_text_area();     /* to get initial size of the window */
5491
5492 #if defined OWN_WINDOW
5493         init_window
5494             (own_window,
5495              wm_class_name,
5496              text_width + border_margin * 2 + 1,
5497              text_height + border_margin * 2 + 1,
5498              on_bottom, fixed_pos, set_transparent, background_colour, info.uname_s.nodename);
5499 #else
5500         init_window
5501                 (own_window,
5502                  text_width + border_margin * 2 + 1,
5503                  text_height + border_margin * 2 + 1,
5504                  on_bottom, set_transparent, background_colour, info.uname_s.nodename);
5505         
5506 #endif
5507
5508         update_text_area();     /* to position text/window on screen */
5509 #endif /* X11 */
5510
5511 /*#ifdef CAIRO
5512 // why the fuck not?
5513 //do_it();
5514 #endif*/
5515
5516 #ifdef X11
5517 #ifdef OWN_WINDOW
5518         if (own_window && !fixed_pos) {
5519                 XMoveWindow(display, window.window, window.x, window.y);
5520         }
5521         if (own_window) {
5522                 set_transparent_background(window.window);
5523         }
5524 #endif
5525
5526         create_gc();
5527
5528         set_font();
5529         draw_stuff();
5530 #endif /* X11 */
5531
5532         /* fork */
5533         if (fork_to_background) {
5534                 int ret = fork();
5535                 switch (ret) {
5536                 case -1:
5537                         ERR("can't fork() to background: %s",
5538                             strerror(errno));
5539                         break;
5540
5541                 case 0:
5542                         break;
5543
5544                 default:
5545                         fprintf
5546                             (stderr,
5547                              "Conky: forked to background, pid is %d\n",
5548                              ret);
5549                         return 0;
5550                 }
5551         }
5552
5553         /* Set signal handlers */
5554         act.sa_handler = signal_handler;
5555         sigemptyset(&act.sa_mask);
5556         act.sa_flags = 0;
5557 #ifdef SA_RESTART
5558         act.sa_flags |= SA_RESTART;
5559 #endif
5560
5561         if ( sigaction(SIGINT,&act,&oact) < 0 ||
5562              sigaction(SIGUSR1,&act,&oact) < 0 ||
5563              sigaction(SIGTERM,&act,&oact) < 0 )
5564         {
5565                 ERR("error setting signal handler: %s", strerror(errno) );
5566         }
5567
5568 #ifdef AUDACIOUS
5569         /* joinable thread for audacious activity */
5570         pthread_attr_init(&info.audacious.thread_attr);
5571         pthread_attr_setdetachstate(&info.audacious.thread_attr, PTHREAD_CREATE_JOINABLE);
5572         /* init mutexex */
5573         pthread_mutex_init(&info.audacious.item_mutex, NULL);
5574         pthread_mutex_init(&info.audacious.runnable_mutex, NULL);
5575         /* init runnable condition for worker thread */
5576         pthread_mutex_lock(&info.audacious.runnable_mutex);
5577         info.audacious.runnable=1;
5578         pthread_mutex_unlock(&info.audacious.runnable_mutex);
5579         if (pthread_create(&info.audacious.thread, &info.audacious.thread_attr, audacious_thread_func, NULL))
5580         {
5581             CRIT_ERR("unable to create audacious thread!");
5582         }
5583 #endif
5584 #ifdef INFOPIPE
5585         /* joinable thread for infopipe activity */
5586         pthread_attr_init(&info.infopipe.thread_attr);
5587         pthread_attr_setdetachstate(&info.infopipe.thread_attr, PTHREAD_CREATE_JOINABLE);
5588         /* init mutexex */
5589         pthread_mutex_init(&info.infopipe.item_mutex, NULL);
5590         pthread_mutex_init(&info.infopipe.runnable_mutex, NULL);
5591         /* init runnable condition for worker thread */
5592         pthread_mutex_lock(&info.infopipe.runnable_mutex);
5593         info.infopipe.runnable=1;
5594         pthread_mutex_unlock(&info.infopipe.runnable_mutex);
5595         if (pthread_create(&info.infopipe.thread, &info.infopipe.thread_attr, infopipe_thread_func, NULL))
5596         {
5597             CRIT_ERR("unable to create infopipe thread!");
5598         }
5599 #endif
5600
5601         main_loop();
5602
5603 #ifdef AUDACIOUS
5604         /* signal audacious worker thread to terminate */
5605         pthread_mutex_lock(&info.audacious.runnable_mutex);
5606         info.audacious.runnable=0;
5607         pthread_mutex_unlock(&info.audacious.runnable_mutex);
5608         /* destroy thread attribute and wait for thread */
5609         pthread_attr_destroy(&info.audacious.thread_attr);
5610         if (pthread_join(info.audacious.thread, NULL))
5611         {
5612             ERR("error joining audacious thread");
5613         }
5614         /* destroy mutexes */
5615         pthread_mutex_destroy(&info.audacious.item_mutex);
5616         pthread_mutex_destroy(&info.audacious.runnable_mutex);
5617 #endif  
5618 #ifdef INFOPIPE
5619         /* signal infopipe worker thread to terminate */
5620         pthread_mutex_lock(&info.infopipe.runnable_mutex);
5621         info.infopipe.runnable=0;
5622         pthread_mutex_unlock(&info.infopipe.runnable_mutex);
5623         /* destroy thread attribute and wait for thread */
5624         pthread_attr_destroy(&info.infopipe.thread_attr);
5625         if (pthread_join(info.infopipe.thread, NULL))
5626         {
5627             ERR("error joining infopipe thread");
5628         }
5629         /* destroy mutexes */
5630         pthread_mutex_destroy(&info.infopipe.item_mutex);
5631         pthread_mutex_destroy(&info.infopipe.runnable_mutex);
5632 #endif
5633
5634         return 0;
5635 }
5636
5637 void signal_handler(int sig)
5638 {
5639         /* signal handler is light as a feather, as it should be. 
5640          * we will poll g_signal_pending with each loop of conky
5641          * and do any signal processing there, NOT here.  pkovacs. */
5642         g_signal_pending=sig;
5643 }