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