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