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