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