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