2 * Conky, a system monitor, based on torsmo
4 * This program is licensed under BSD license, read COPYING
28 #include <X11/Xutil.h>
30 #include <sys/types.h>
33 #define CONFIG_FILE "$HOME/.conkyrc"
34 #define MAIL_FILE "$MAIL"
35 #define MAX_IF_BLOCK_DEPTH 5
52 char name[TEXT_BUFFER_SIZE];
62 static int selected_font = 0;
63 static int font_count = -1;
64 struct font_list *fonts = NULL;
68 #define font_height() use_xft ? (fonts[selected_font].xftfont->ascent + fonts[selected_font].xftfont->descent) : \
69 (fonts[selected_font].font->max_bounds.ascent + fonts[selected_font].font->max_bounds.descent)
70 #define font_ascent() use_xft ? fonts[selected_font].xftfont->ascent : fonts[selected_font].font->max_bounds.ascent
71 #define font_descent() use_xft ? fonts[selected_font].xftfont->descent : fonts[selected_font].font->max_bounds.descent
75 #define font_height() (fonts[selected_font].font->max_bounds.ascent + fonts[selected_font].font->max_bounds.descent)
76 #define font_ascent() fonts[selected_font].font->max_bounds.ascent
77 #define font_descent() fonts[selected_font].font->max_bounds.descent
81 #define MAX_FONTS 64 // hmm, no particular reason, just makes sense.
84 static void set_font();
87 int addfont(const char *data_in)
89 if (font_count > MAX_FONTS) {
90 CRIT_ERR("you don't need that many fonts, sorry.");
93 if (font_count == 0) {
97 if ((fonts = (struct font_list*)malloc(sizeof(struct font_list))) == NULL) {
101 fonts = realloc(fonts, (sizeof(struct font_list) * (font_count+1)));
103 CRIT_ERR("realloc in addfont");
105 if (strlen(data_in) < TEXT_BUFFER_SIZE) { // must account for null terminator
106 strncpy(fonts[font_count].name, data_in, TEXT_BUFFER_SIZE);
108 fonts[font_count].font_alpha = 0xffff;
111 CRIT_ERR("Oops...looks like something overflowed in addfont().");
116 void set_first_font(const char *data_in)
118 if (font_count < 0) {
119 if ((fonts = (struct font_list*)malloc(sizeof(struct font_list))) == NULL) {
124 if (strlen(data_in) > 1) {
125 strncpy(fonts[0].name, data_in, TEXT_BUFFER_SIZE-1);
127 fonts[0].font_alpha = 0xffff;
135 for (i=0;i<=font_count;i++) {
138 XftFontClose(display, fonts[i].xftfont);
142 XFreeFont(display, fonts[i].font);
149 set_first_font("6x10");
153 static void load_fonts()
156 for (i=0;i<=font_count;i++) {
160 /*if (fonts[i].xftfont != NULL && selected_font == 0) {
161 XftFontClose(display, fonts[i].xftfont);
163 if ((fonts[i].xftfont =
164 XftFontOpenName(display, screen, fonts[i].name)) != NULL)
167 ERR("can't load Xft font '%s'", fonts[i].name);
168 if ((fonts[i].xftfont =
169 XftFontOpenName(display, screen,
170 "courier-12")) != NULL)
173 ERR("can't load Xft font '%s'", "courier-12");
175 if ((fonts[i].font = XLoadQueryFont(display, "fixed")) == NULL) {
176 CRIT_ERR("can't load font '%s'", "fixed");
183 /* load normal font */
184 /* if (fonts[i].font != NULL)
185 XFreeFont(display, fonts[i].font);*/
187 if ((fonts[i].font = XLoadQueryFont(display, fonts[i].name)) == NULL) {
188 ERR("can't load font '%s'", fonts[i].name);
189 if ((fonts[i].font = XLoadQueryFont(display, "fixed")) == NULL) {
190 CRIT_ERR("can't load font '%s'", "fixed");
191 printf("loaded fixed?\n");
199 /* default config file */
200 static char *current_config;
202 /* set to 1 if you want all text to be in uppercase */
203 static unsigned int stuff_in_upper_case;
205 /* Update interval */
206 static double update_interval;
208 /* Run how many times? */
209 static unsigned long total_run_times;
212 static int fork_to_background;
214 static int cpu_avg_samples, net_avg_samples;
218 /* Always on bottom */
219 static int on_bottom;
221 /* Position on the screen */
222 static int text_alignment;
223 static int gap_x, gap_y;
226 static int draw_borders;
227 static int stippled_borders;
229 static int draw_shades, draw_outline;
231 static int border_margin, border_width;
233 static long default_fg_color, default_bg_color, default_out_color;
235 /* create own window or draw stuff to root? */
236 static int set_transparent = 0;
240 static int own_window = 0;
241 static int background_colour = 0;
242 /* fixed size/pos is set if wm/user changes them */
243 static int fixed_size = 0, fixed_pos = 0;
246 static int minimum_width, minimum_height;
247 static int maximum_width;
254 /* no buffers in used memory? */
257 /* pad percentages to decimals? */
258 static int pad_percents = 0;
260 /* Text that is shown */
261 static char original_text[] =
262 "$nodename - $sysname $kernel on $machine\n"
264 "${color grey}Uptime:$color $uptime\n"
265 "${color grey}Frequency (in MHz):$color $freq\n"
266 "${color grey}Frequency (in GHz):$color $freq_g\n"
267 "${color grey}RAM Usage:$color $mem/$memmax - $memperc% ${membar 4}\n"
268 "${color grey}Swap Usage:$color $swap/$swapmax - $swapperc% ${swapbar 4}\n"
269 "${color grey}CPU Usage:$color $cpu% ${cpubar 4}\n"
270 "${color grey}Processes:$color $processes ${color grey}Running:$color $running_processes\n"
272 "${color grey}File systems:\n"
273 " / $color${fs_free /}/${fs_size /} ${fs_bar 6 /}\n"
274 "${color grey}Networking:\n"
275 " Up:$color ${upspeed eth0} k/s${color grey} - Down:$color ${downspeed eth0} k/s\n"
276 "${color grey}Temperatures:\n"
277 " CPU:$color ${i2c temp 1}°C${color grey} - MB:$color ${i2c temp 2}°C\n"
280 "${color grey}SETI@Home Statistics:\n"
281 "${color grey}Seti Unit Number:$color $seti_credit\n"
282 "${color grey}Seti Progress:$color $seti_prog% $seti_progbar\n"
285 "${color grey}MPD: $mpd_status $mpd_artist - $mpd_title from $mpd_album at $mpd_vol\n"
286 "Bitrate: $mpd_bitrate\n" "Progress: $mpd_bar\n"
288 "${color grey}Name PID CPU% MEM%\n"
289 " ${color lightgrey} ${top name 1} ${top pid 1} ${top cpu 1} ${top mem 1}\n"
290 " ${color lightgrey} ${top name 2} ${top pid 2} ${top cpu 2} ${top mem 2}\n"
291 " ${color lightgrey} ${top name 3} ${top pid 3} ${top cpu 3} ${top mem 3}\n"
292 " ${color lightgrey} ${top name 4} ${top pid 4} ${top cpu 4} ${top mem 4}\n"
293 "${tail /var/log/Xorg.0.log 3}";
295 static char *text = original_text;
297 static int total_updates;
300 static int blockdepth = 0;
301 static int if_jumped = 0;
302 static int blockstart[MAX_IF_BLOCK_DEPTH];
304 int check_mount(char *s)
307 FILE *mtab = fopen("/etc/mtab", "r");
309 char buf1[256], buf2[128];
310 while (fgets(buf1, 256, mtab)) {
311 sscanf(buf1, "%*s %128s", buf2);
312 if (!strcmp(s, buf2)) {
319 ERR("Could not open mtab");
326 static inline int calc_text_width(const char *s, unsigned int l)
332 XftTextExtentsUtf8(display, fonts[selected_font].xftfont, s, l, &gi);
334 XftTextExtents8(display, fonts[selected_font].xftfont, s, l, &gi);
340 return XTextWidth(fonts[selected_font].font, s, l);
345 /* formatted text to render on screen, generated in generate_text(),
346 * drawn in draw_stuff() */
348 static char text_buffer[TEXT_BUFFER_SIZE * 4];
350 /* special stuff in text_buffer */
352 #define SPECIAL_CHAR '\x01'
369 static struct special_t {
379 unsigned long first_colour; // for graph gradient
380 unsigned long last_colour;
383 static int special_count;
385 static int special_index; /* used when drawing */
388 #define MAX_GRAPH_DEPTH 256 /* why 256? cause an array of more then 256 doubles seems excessive, and who needs that kind of precision anyway? */
390 static struct special_t *new_special(char *buf, int t)
392 if (special_count >= 128)
393 CRIT_ERR("too many special things in text");
395 buf[0] = SPECIAL_CHAR;
397 specials[special_count].type = t;
398 return &specials[special_count++];
401 typedef struct tailstring_list {
402 char data[TEXT_BUFFER_SIZE];
403 struct tailstring_list *next;
404 struct tailstring_list *first;
407 void addtail(tailstring ** head, char *data_in)
410 if ((tmp = malloc(sizeof(*tmp))) == NULL) {
416 tmp->first = (*head)->first;
418 strncpy(tmp->data, data_in, TEXT_BUFFER_SIZE);
423 void freetail(tailstring * head)
426 while (head != NULL) {
433 void freelasttail(tailstring * head)
435 tailstring * tmp = head;
437 if (tmp->next == head->first) {
444 while(head != NULL && tmp != NULL) {
450 static void new_bar(char *buf, int w, int h, int usage)
452 struct special_t *s = new_special(buf, BAR);
453 s->arg = (usage > 255) ? 255 : ((usage < 0) ? 0 : usage);
458 static const char *scan_bar(const char *args, int *w, int *h)
460 *w = 0; /* zero width means all space that is available */
462 /* bar's argument is either height or height,width */
465 if (sscanf(args, "%d,%d %n", h, w, &n) <= 1)
466 sscanf(args, "%d %n", h, &n);
473 static char *scan_font(const char *args)
475 if (args && sizeof(args) < 127) {
479 ERR("font scan failed, lets hope it doesn't mess stuff up");
485 static void new_font(char *buf, char * args) {
486 struct special_t *s = new_special(buf, FONT);
487 if (!s->font_added || strcmp(args, fonts[s->font_added].name)) {
488 int tmp = selected_font;
489 selected_font = s->font_added = addfont(args);
497 inline void graph_append(struct special_t *graph, double f)
499 if (!graph->scaled && f > graph->graph_scale) {
500 f = graph->graph_scale;
504 graph->graph_scale = 1;
506 graph->graph[graph->graph_width - 1] = f; /* add new data */
507 for (i = 0; i < graph->graph_width - 1; i++) { /* shift all the data by 1 */
508 graph->graph[i] = graph->graph[i + 1];
509 if (graph->scaled && graph->graph[i] > graph->graph_scale) {
510 graph->graph_scale = graph->graph[i]; /* check if we need to update the scale */
515 short colour_depth = 0;
516 void set_up_gradient();
518 /* precalculated: 31/255, and 63/255 */
519 #define CONST_8_TO_5_BITS 0.12156862745098
520 #define CONST_8_TO_6_BITS 0.247058823529412
522 /* adjust color values depending on color depth*/
523 static unsigned int adjust_colors(unsigned int color)
526 if (colour_depth == 0) {
529 if (colour_depth == 16) {
530 r = (color & 0xff0000) >> 16;
531 g = (color & 0xff00) >> 8;
533 color = (int)(r * CONST_8_TO_5_BITS) << 11;
534 color |= (int)(g * CONST_8_TO_6_BITS) << 5;
535 color |= (int)(b * CONST_8_TO_5_BITS);
540 static void new_graph(char *buf, int w, int h, unsigned int first_colour, unsigned int second_colour, double i, int scale, int append)
542 struct special_t *s = new_special(buf, GRAPH);
544 if (s->graph == NULL) {
545 if (s->width > 0 && s->width < MAX_GRAPH_DEPTH) {
546 s->graph_width = s->width - 3; // subtract 3 for the box
548 s->graph_width = MAX_GRAPH_DEPTH - 3;
550 s->graph = malloc(s->graph_width * sizeof(double));
551 memset(s->graph, 0, s->graph_width * sizeof(double));
552 s->graph_scale = 100;
555 s->first_colour = adjust_colors(first_colour);
556 s->last_colour = adjust_colors(second_colour);
563 s->graph_width = s->width - 3; // subtract 3 for rectangle around
568 s->graph_scale = scale;
575 static const char *scan_graph(const char *args, int *w, int *h, unsigned int *first_colour, unsigned int *last_colour, unsigned int *scale)
577 *w = 0; /* zero width means all space that is available */
581 /* graph's argument is either height or height,width */
583 if (sscanf(args, "%*s %d,%d %x %x %i", h, w, first_colour, last_colour, scale) < 5) {
584 if (sscanf(args, "%*s %d,%d %x %x", h, w, first_colour, last_colour) < 4) {
586 if (sscanf(args, "%d,%d %x %x %i", h, w, first_colour, last_colour, scale) < 5) {
588 if (sscanf(args, "%d,%d %x %x", h, w, first_colour, last_colour) < 4) {
591 if (sscanf(args, "%*s %x %x %i", first_colour, last_colour, scale) < 3) {
595 if (sscanf(args, "%*s %x %x", first_colour, last_colour) < 2) {
598 if (sscanf(args, "%x %x %i", first_colour, last_colour, scale) < 3) {
602 if (sscanf(args, "%x %x", first_colour, last_colour) < 2) {
605 if (sscanf(args, "%d,%d %i", h, w, scale) < 3) {
609 if (sscanf(args, "%d,%d", h, w) < 2) {
612 sscanf(args, "%*s %d,%d", h, w);
618 static inline void new_hr(char *buf, int a)
620 new_special(buf, HORIZONTAL_LINE)->height = a;
623 static inline void new_stippled_hr(char *buf, int a, int b)
625 struct special_t *s = new_special(buf, STIPPLED_HR);
630 static inline void new_fg(char *buf, long c)
632 new_special(buf, FG)->arg = c;
635 static inline void new_bg(char *buf, long c)
637 new_special(buf, BG)->arg = c;
640 static inline void new_outline(char *buf, long c)
642 new_special(buf, OUTLINE)->arg = c;
645 static inline void new_offset(char *buf, long c)
647 new_special(buf, OFFSET)->arg = c;
650 static inline void new_voffset(char *buf, long c)
652 new_special(buf, VOFFSET)->arg = c;
655 static inline void new_alignr(char *buf, long c)
657 new_special(buf, ALIGNR)->arg = c;
660 static inline void new_alignc(char *buf, long c)
662 new_special(buf, ALIGNC)->arg = c;
665 /* quite boring functions */
667 static inline void for_each_line(char *b, void (*f) (char *))
671 for (ps = b, pe = b; *pe; pe++) {
684 static void convert_escapes(char *buf)
686 char *p = buf, *s = buf;
702 /* converts from bytes to human readable format (k, M, G, T) */
703 static void human_readable(long long a, char *buf, int size)
705 // Strange conditional due to possible overflows
706 if(a / 1024 / 1024 / 1024.0 > 1024.0){
707 snprintf(buf, size, "%.2fT", (a / 1024 / 1024 / 1024) / 1024.0);
709 else if (a >= 1024 * 1024 * 1024) {
710 snprintf(buf, size, "%.2fG", (a / 1024 / 1024) / 1024.0);
712 else if (a >= 1024 * 1024) {
713 double m = (a / 1024) / 1024.0;
715 snprintf(buf, size, "%.0fM", m);
717 snprintf(buf, size, "%.1fM", m);
718 } else if (a >= 1024)
719 snprintf(buf, size, "%Ldk", a / (long long) 1024);
721 snprintf(buf, size, "%Ld", a);
726 enum text_object_type {
774 #if defined(__linux__)
780 OBJ_i8k_left_fan_status,
781 OBJ_i8k_right_fan_status,
782 OBJ_i8k_left_fan_rpm,
783 OBJ_i8k_right_fan_rpm,
785 OBJ_i8k_buttons_status,
786 #endif /* __linux__ */
813 OBJ_ml_upload_counter,
814 OBJ_ml_download_counter,
815 OBJ_ml_nshared_files,
816 OBJ_ml_shared_counter,
817 OBJ_ml_tcp_upload_rate,
818 OBJ_ml_tcp_download_rate,
819 OBJ_ml_udp_upload_rate,
820 OBJ_ml_udp_download_rate,
821 OBJ_ml_ndownloaded_files,
822 OBJ_ml_ndownloading_files,
825 OBJ_running_processes,
834 OBJ_temp1, /* i2c is used instead in these */
847 #if defined(__FreeBSD__) && (defined(i386) || defined(__i386__))
849 OBJ_apm_battery_time,
850 OBJ_apm_battery_life,
851 #endif /* __FreeBSD__ */
876 unsigned int c, d, e;
879 char *s; /* some string */
880 int i; /* some integer */
881 long l; /* some other integer */
882 struct net_stat *net;
884 unsigned char loadavg[3];
885 //unsigned int diskio;
886 unsigned int cpu_index;
935 static unsigned int text_object_count;
936 static struct text_object *text_objects;
938 pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
940 void *threaded_exec( struct text_object *obj ) {
941 char *p2 = obj->data.execi.buffer;
942 FILE *fp = popen(obj->data.execi.cmd,"r");
943 pthread_mutex_lock( &mutex1 );
944 int n2 = fread(p2, 1, TEXT_BUFFER_SIZE, fp);
947 if (n2 && p2[n2 - 1] == '\n')
955 pthread_mutex_unlock( &mutex1 );
959 /* new_text_object() allocates a new zeroed text_object */
960 static struct text_object *new_text_object()
963 text_objects = (struct text_object *) realloc(text_objects,
967 memset(&text_objects[text_object_count - 1], 0,
968 sizeof(struct text_object));
970 return &text_objects[text_object_count - 1];
973 static void free_text_objects()
976 for (i = 0; i < text_object_count; i++) {
977 switch (text_objects[i].type) {
979 close(text_objects[i].data.i);
982 close(text_objects[i].data.i);
985 close(text_objects[i].data.i2c.fd);
989 case OBJ_if_existing:
992 free(text_objects[i].data.ifblock.s);
996 free(text_objects[i].data.s);
999 free(text_objects[i].data.s);
1002 free(text_objects[i].data.s);
1005 free(text_objects[i].data.s);
1007 /* case OBJ_execibar:
1008 free(text_objects[i].data.s);
1010 case OBJ_execigraph:
1011 free(text_objects[i].data.s);
1015 case OBJ_mpd_artist:
1017 case OBJ_mpd_status:
1022 free(text_objects[i].data.s);
1026 free(text_objects[i].data.execi.cmd);
1027 free(text_objects[i].data.execi.buffer);
1030 free(text_objects[i].data.execi.cmd);
1031 free(text_objects[i].data.execi.buffer);
1037 text_objects = NULL;
1038 text_object_count = 0;
1041 void scan_mixer_bar(const char *arg, int *a, int *w, int *h)
1046 if (arg && sscanf(arg, "%63s %n", buf1, &n) >= 1) {
1047 *a = mixer_init(buf1);
1048 (void) scan_bar(arg + n, w, h);
1051 (void) scan_bar(arg, w, h);
1055 /* construct_text_object() creates a new text_object */
1056 static void construct_text_object(const char *s, const char *arg)
1058 struct text_object *obj = new_text_object();
1060 #define OBJ(a, n) if (strcmp(s, #a) == 0) { obj->type = OBJ_##a; need_mask |= (1 << n); {
1061 #define END ; } } else
1065 obj->type = OBJ_color;
1066 obj->data.l = get_x11_color(s);
1069 OBJ(acpitemp, 0) obj->data.i = open_acpi_temperature(arg);
1070 END OBJ(acpitempf, 0) obj->data.i = open_acpi_temperature(arg);
1071 END OBJ(acpiacadapter, 0)
1074 END OBJ(freq_dyn, 0);
1075 END OBJ(freq_dyn_g, 0);
1076 END OBJ(acpifan, 0);
1077 END OBJ(battery, 0);
1080 sscanf(arg, "%63s", bat);
1082 strcpy(bat, "BAT0");
1083 obj->data.s = strdup(bat);
1084 #if defined(__linux__)
1085 END OBJ(i8k_version, INFO_I8K)
1086 END OBJ(i8k_bios, INFO_I8K)
1087 END OBJ(i8k_serial, INFO_I8K)
1088 END OBJ(i8k_cpu_temp, INFO_I8K)
1089 END OBJ(i8k_cpu_tempf, INFO_I8K)
1090 END OBJ(i8k_left_fan_status, INFO_I8K)
1091 END OBJ(i8k_right_fan_status, INFO_I8K)
1092 END OBJ(i8k_left_fan_rpm, INFO_I8K)
1093 END OBJ(i8k_right_fan_rpm, INFO_I8K)
1094 END OBJ(i8k_ac_status, INFO_I8K)
1095 END OBJ(i8k_buttons_status, INFO_I8K)
1096 #endif /* __linux__ */
1097 END OBJ(buffers, INFO_BUFFERS)
1098 END OBJ(cached, INFO_BUFFERS)
1099 END OBJ(cpu, INFO_CPU)
1101 if (strncmp(arg, "cpu", 3) == 0 && isdigit(arg[3])) {
1102 obj->data.cpu_index = atoi(&arg[3]);
1104 } else {obj->data.cpu_index = 0; }
1106 obj->data.cpu_index = 0;
1108 END OBJ(cpubar, INFO_CPU)
1110 if (strncmp(arg, "cpu", 3) == 0 && isdigit(arg[3])) {
1111 obj->data.cpu_index = atoi(&arg[3]);
1114 else {obj->data.cpu_index = 0;}
1115 (void) scan_bar(arg, &obj->a, &obj->b);
1117 (void) scan_bar(arg, &obj->a, &obj->b);
1118 obj->data.cpu_index = 0;
1120 END OBJ(cpugraph, INFO_CPU)
1122 if (strncmp(arg, "cpu", 3) == 0 && isdigit(arg[3])) {
1123 obj->data.cpu_index = atoi(&arg[3]);
1126 (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
1128 (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
1129 obj->data.cpu_index = 0;
1131 END OBJ(diskio, INFO_DISKIO)
1132 END OBJ(diskiograph, INFO_DISKIO) (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
1135 obj->data.l = arg ? get_x11_color(arg) : default_fg_color;
1139 obj->data.s = scan_font(arg);
1141 OBJ(downspeed, INFO_NET)
1143 obj->data.net = get_net_stat(arg);
1146 CRIT_ERR("downspeed needs argument");
1148 END OBJ(downspeedf, INFO_NET)
1150 obj->data.net = get_net_stat(arg);
1153 CRIT_ERR("downspeedf needs argument");
1155 END OBJ(downspeedgraph, INFO_NET)
1156 (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
1158 sscanf(arg, "%63s %*i,%*i %*i", buf);
1159 obj->data.net = get_net_stat(buf);
1160 if (sscanf(arg, "%*s %d,%d %*d", &obj->b, &obj->a) <= 1) {
1161 if (sscanf(arg, "%*s %d,%d", &obj->b, &obj->a) <= 1) {
1170 text_objects[blockstart[blockdepth - 1] -
1171 1].data.ifblock.pos = text_object_count;
1172 blockstart[blockdepth - 1] = text_object_count;
1173 obj->data.ifblock.pos = text_object_count + 2;
1175 ERR("$else: no matching $if_*");
1180 text_objects[blockstart[blockdepth] - 1].data.ifblock.pos =
1183 ERR("$endif: no matching $if_*");
1187 OBJ(exec, 0) obj->data.s = strdup(arg ? arg : "");
1188 END OBJ(execbar, 0) obj->data.s = strdup(arg ? arg : "");
1189 END OBJ(execgraph, 0) obj->data.s = strdup(arg ? arg : "");
1190 END OBJ(execibar, 0) unsigned int n;
1191 if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
1193 ERR("${execibar <interval> command}");
1194 obj->type = OBJ_text;
1195 snprintf(buf, 256, "${%s}", s);
1196 obj->data.s = strdup(buf);
1198 obj->data.execi.cmd = strdup(arg + n);
1200 END OBJ(execigraph, 0) unsigned int n;
1201 if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
1203 ERR("${execigraph <interval> command}");
1204 obj->type = OBJ_text;
1205 snprintf(buf, 256, "${%s}", s);
1206 obj->data.s = strdup(buf);
1208 obj->data.execi.cmd = strdup(arg + n);
1210 END OBJ(execi, 0) unsigned int n;
1213 || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
1215 ERR("${execi <interval> command}");
1216 obj->type = OBJ_text;
1217 snprintf(buf, 256, "${%s}", s);
1218 obj->data.s = strdup(buf);
1220 obj->data.execi.cmd = strdup(arg + n);
1221 obj->data.execi.buffer =
1222 (char *) calloc(1, TEXT_BUFFER_SIZE);
1224 END OBJ(texeci, 0) unsigned int n;
1227 || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
1229 ERR("${texeci <interval> command}");
1230 obj->type = OBJ_text;
1231 snprintf(buf, 256, "${%s}", s);
1232 obj->data.s = strdup(buf);
1234 obj->data.execi.cmd = strdup(arg + n);
1235 obj->data.execi.buffer =
1236 (char *) calloc(1, TEXT_BUFFER_SIZE);
1238 END OBJ(pre_exec, 0) obj->type = OBJ_text;
1240 FILE *fp = popen(arg, "r");
1244 n = fread(buf, 1, 2048, fp);
1247 if (n && buf[n - 1] == '\n')
1252 obj->data.s = strdup(buf);
1254 obj->data.s = strdup("");
1257 OBJ(fs_bar, INFO_FS) obj->data.fsbar.h = 4;
1258 arg = scan_bar(arg, &obj->data.fsbar.w, &obj->data.fsbar.h);
1260 while (isspace(*arg))
1266 obj->data.fsbar.fs = prepare_fs_stat(arg);
1267 END OBJ(fs_bar_free, INFO_FS) obj->data.fsbar.h = 4;
1270 if (sscanf(arg, "%d %n", &obj->data.fsbar.h, &n) >= 1)
1274 obj->data.fsbar.fs = prepare_fs_stat(arg);
1275 END OBJ(fs_free, INFO_FS) if (!arg)
1277 obj->data.fs = prepare_fs_stat(arg);
1278 END OBJ(fs_used_perc, INFO_FS) if (!arg)
1280 obj->data.fs = prepare_fs_stat(arg);
1281 END OBJ(fs_free_perc, INFO_FS) if (!arg)
1283 obj->data.fs = prepare_fs_stat(arg);
1284 END OBJ(fs_size, INFO_FS) if (!arg)
1286 obj->data.fs = prepare_fs_stat(arg);
1287 END OBJ(fs_used, INFO_FS) if (!arg)
1289 obj->data.fs = prepare_fs_stat(arg);
1290 END OBJ(hr, 0) obj->data.i = arg ? atoi(arg) : 1;
1291 END OBJ(offset, 0) obj->data.i = arg ? atoi(arg) : 1;
1292 END OBJ(voffset, 0) obj->data.i = arg ? atoi(arg) : 1;
1293 END OBJ(i2c, INFO_I2C) char buf1[64], buf2[64];
1297 ERR("i2c needs arguments");
1298 obj->type = OBJ_text;
1299 //obj->data.s = strdup("${i2c}");
1303 if (sscanf(arg, "%63s %63s %d", buf1, buf2, &n) != 3) {
1304 /* if scanf couldn't read three values, read type and num and use
1306 sscanf(arg, "%63s %d", buf2, &n);
1308 open_i2c_sensor(0, buf2, n, &obj->data.i2c.arg,
1309 obj->data.i2c.devtype);
1310 strncpy(obj->data.i2c.type, buf2, 63);
1313 open_i2c_sensor(buf1, buf2, n, &obj->data.i2c.arg,
1314 obj->data.i2c.devtype);
1315 strncpy(obj->data.i2c.type, buf2, 63);
1318 END OBJ(top, INFO_TOP)
1322 ERR("top needs arguments");
1323 obj->type = OBJ_text;
1324 //obj->data.s = strdup("${top}");
1327 if (sscanf(arg, "%63s %i", buf, &n) == 2) {
1328 if (strcmp(buf, "name") == 0) {
1329 obj->data.top.type = TOP_NAME;
1330 } else if (strcmp(buf, "cpu") == 0) {
1331 obj->data.top.type = TOP_CPU;
1332 } else if (strcmp(buf, "pid") == 0) {
1333 obj->data.top.type = TOP_PID;
1334 } else if (strcmp(buf, "mem") == 0) {
1335 obj->data.top.type = TOP_MEM;
1337 ERR("invalid arg for top");
1340 if (n < 1 || n > 10) {
1341 CRIT_ERR("invalid arg for top");
1344 obj->data.top.num = n - 1;
1348 ERR("invalid args given for top");
1351 END OBJ(top_mem, INFO_TOP)
1355 ERR("top_mem needs arguments");
1356 obj->type = OBJ_text;
1357 obj->data.s = strdup("${top_mem}");
1360 if (sscanf(arg, "%63s %i", buf, &n) == 2) {
1361 if (strcmp(buf, "name") == 0) {
1362 obj->data.top.type = TOP_NAME;
1363 } else if (strcmp(buf, "cpu") == 0) {
1364 obj->data.top.type = TOP_CPU;
1365 } else if (strcmp(buf, "pid") == 0) {
1366 obj->data.top.type = TOP_PID;
1367 } else if (strcmp(buf, "mem") == 0) {
1368 obj->data.top.type = TOP_MEM;
1370 ERR("invalid arg for top");
1373 if (n < 1 || n > 10) {
1374 CRIT_ERR("invalid arg for top");
1377 obj->data.top.num = n - 1;
1381 ERR("invalid args given for top");
1384 END OBJ(addr, INFO_NET)
1386 obj->data.net = get_net_stat(arg);
1389 CRIT_ERR("addr needs argument");
1391 END OBJ(linkstatus, INFO_WIFI)
1393 obj->data.net = get_net_stat(arg);
1396 CRIT_ERR("linkstatus needs argument");
1402 ERR("tail needs arguments");
1403 obj->type = OBJ_text;
1404 obj->data.s = strdup("${tail}");
1407 if (sscanf(arg, "%63s %i %i", buf, &n1, &n2) == 2) {
1408 if (n1 < 1 || n1 > 30) {
1409 CRIT_ERR("invalid arg for tail, number of lines must be between 1 and 30");
1413 fp = fopen(buf, "rt");
1415 obj->data.tail.logfile =
1416 malloc(TEXT_BUFFER_SIZE);
1417 strcpy(obj->data.tail.logfile, buf);
1418 obj->data.tail.wantedlines = n1 - 1;
1419 obj->data.tail.interval =
1420 update_interval * 2;
1424 CRIT_ERR("tail logfile does not exist, or you do not have correct permissions");
1427 } else if (sscanf(arg, "%63s %i %i", buf, &n1, &n2) == 3) {
1428 if (n1 < 1 || n1 > 30) {
1430 ("invalid arg for tail, number of lines must be between 1 and 30");
1432 } else if (n2 < 1 || n2 < update_interval) {
1434 ("invalid arg for tail, interval must be greater than 0 and Conky's interval");
1438 fp = fopen(buf, "rt");
1440 obj->data.tail.logfile =
1441 malloc(TEXT_BUFFER_SIZE);
1442 strcpy(obj->data.tail.logfile, buf);
1443 obj->data.tail.wantedlines = n1 - 1;
1444 obj->data.tail.interval = n2;
1448 CRIT_ERR("tail logfile does not exist, or you do not have correct permissions");
1454 ERR("invalid args given for tail");
1457 obj->data.tail.buffer = malloc(TEXT_BUFFER_SIZE * 20); /* asumming all else worked */
1462 ERR("head needs arguments");
1463 obj->type = OBJ_text;
1464 obj->data.s = strdup("${head}");
1467 if (sscanf(arg, "%63s %i %i", buf, &n1, &n2) == 2) {
1468 if (n1 < 1 || n1 > 30) {
1469 CRIT_ERR("invalid arg for head, number of lines must be between 1 and 30");
1473 fp = fopen(buf, "rt");
1475 obj->data.tail.logfile =
1476 malloc(TEXT_BUFFER_SIZE);
1477 strcpy(obj->data.tail.logfile, buf);
1478 obj->data.tail.wantedlines = n1 - 1;
1479 obj->data.tail.interval =
1480 update_interval * 2;
1484 CRIT_ERR("head logfile does not exist, or you do not have correct permissions");
1487 } else if (sscanf(arg, "%63s %i %i", buf, &n1, &n2) == 3) {
1488 if (n1 < 1 || n1 > 30) {
1490 ("invalid arg for head, number of lines must be between 1 and 30");
1492 } else if (n2 < 1 || n2 < update_interval) {
1494 ("invalid arg for head, interval must be greater than 0 and Conky's interval");
1498 fp = fopen(buf, "rt");
1500 obj->data.tail.logfile =
1501 malloc(TEXT_BUFFER_SIZE);
1502 strcpy(obj->data.tail.logfile, buf);
1503 obj->data.tail.wantedlines = n1 - 1;
1504 obj->data.tail.interval = n2;
1508 CRIT_ERR("head logfile does not exist, or you do not have correct permissions");
1514 ERR("invalid args given for head");
1517 obj->data.tail.buffer = malloc(TEXT_BUFFER_SIZE * 20); /* asumming all else worked */
1518 END OBJ(loadavg, INFO_LOADAVG) int a = 1, b = 2, c = 3, r = 3;
1520 r = sscanf(arg, "%d %d %d", &a, &b, &c);
1521 if (r >= 3 && (c < 1 || c > 3))
1523 if (r >= 2 && (b < 1 || b > 3))
1525 if (r >= 1 && (a < 1 || a > 3))
1528 obj->data.loadavg[0] = (r >= 1) ? (unsigned char) a : 0;
1529 obj->data.loadavg[1] = (r >= 2) ? (unsigned char) b : 0;
1530 obj->data.loadavg[2] = (r >= 3) ? (unsigned char) c : 0;
1531 END OBJ(if_existing, 0)
1532 if (blockdepth >= MAX_IF_BLOCK_DEPTH) {
1533 CRIT_ERR("MAX_IF_BLOCK_DEPTH exceeded");
1536 ERR("if_existing needs an argument");
1537 obj->data.ifblock.s = 0;
1539 obj->data.ifblock.s = strdup(arg);
1540 blockstart[blockdepth] = text_object_count;
1541 obj->data.ifblock.pos = text_object_count + 2;
1543 END OBJ(if_mounted, 0)
1544 if (blockdepth >= MAX_IF_BLOCK_DEPTH) {
1545 CRIT_ERR("MAX_IF_BLOCK_DEPTH exceeded");
1548 ERR("if_mounted needs an argument");
1549 obj->data.ifblock.s = 0;
1551 obj->data.ifblock.s = strdup(arg);
1552 blockstart[blockdepth] = text_object_count;
1553 obj->data.ifblock.pos = text_object_count + 2;
1555 END OBJ(if_running, 0)
1556 if (blockdepth >= MAX_IF_BLOCK_DEPTH) {
1557 CRIT_ERR("MAX_IF_BLOCK_DEPTH exceeded");
1561 snprintf(buf, 256, "pidof %s >/dev/null", arg);
1562 obj->data.ifblock.s = strdup(buf);
1564 ERR("if_running needs an argument");
1565 obj->data.ifblock.s = 0;
1567 blockstart[blockdepth] = text_object_count;
1568 obj->data.ifblock.pos = text_object_count + 2;
1572 END OBJ(mails, INFO_MAIL)
1573 END OBJ(mem, INFO_MEM)
1574 END OBJ(memmax, INFO_MEM)
1575 END OBJ(memperc, INFO_MEM)
1576 END OBJ(membar, INFO_MEM)
1577 (void) scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
1578 END OBJ(memgraph, INFO_MEM)
1579 (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
1580 END OBJ(mixer, INFO_MIXER) obj->data.l = mixer_init(arg);
1581 END OBJ(mixerl, INFO_MIXER) obj->data.l = mixer_init(arg);
1582 END OBJ(mixerr, INFO_MIXER) obj->data.l = mixer_init(arg);
1583 END OBJ(mixerbar, INFO_MIXER)
1584 scan_mixer_bar(arg, &obj->data.mixerbar.l,
1585 &obj->data.mixerbar.w, &obj->data.mixerbar.h);
1586 END OBJ(mixerlbar, INFO_MIXER)
1587 scan_mixer_bar(arg, &obj->data.mixerbar.l,
1588 &obj->data.mixerbar.w, &obj->data.mixerbar.h);
1589 END OBJ(mixerrbar, INFO_MIXER)
1590 scan_mixer_bar(arg, &obj->data.mixerbar.l,
1591 &obj->data.mixerbar.w, &obj->data.mixerbar.h);
1594 OBJ(ml_upload_counter, INFO_MLDONKEY)
1595 END OBJ(ml_download_counter, INFO_MLDONKEY)
1596 END OBJ(ml_nshared_files, INFO_MLDONKEY)
1597 END OBJ(ml_shared_counter, INFO_MLDONKEY)
1598 END OBJ(ml_tcp_upload_rate, INFO_MLDONKEY)
1599 END OBJ(ml_tcp_download_rate, INFO_MLDONKEY)
1600 END OBJ(ml_udp_upload_rate, INFO_MLDONKEY)
1601 END OBJ(ml_udp_download_rate, INFO_MLDONKEY)
1602 END OBJ(ml_ndownloaded_files, INFO_MLDONKEY)
1603 END OBJ(ml_ndownloading_files, INFO_MLDONKEY) END
1605 OBJ(new_mails, INFO_MAIL)
1606 END OBJ(nodename, 0)
1607 END OBJ(processes, INFO_PROCS)
1608 END OBJ(running_processes, INFO_RUN_PROCS)
1609 END OBJ(shadecolor, 0)
1611 obj->data.l = arg ? get_x11_color(arg) : default_bg_color;
1613 END OBJ(outlinecolor, 0)
1615 obj->data.l = arg ? get_x11_color(arg) : default_out_color;
1617 END OBJ(stippled_hr, 0)
1619 int a = stippled_borders, b = 1;
1621 if (sscanf(arg, "%d %d", &a, &b) != 2)
1622 sscanf(arg, "%d", &b);
1626 obj->data.pair.a = a;
1627 obj->data.pair.b = b;
1629 END OBJ(swap, INFO_MEM)
1630 END OBJ(swapmax, INFO_MEM)
1631 END OBJ(swapperc, INFO_MEM)
1632 END OBJ(swapbar, INFO_MEM)
1633 (void) scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
1634 END OBJ(sysname, 0) END OBJ(temp1, INFO_I2C) obj->type = OBJ_i2c;
1636 open_i2c_sensor(0, "temp", 1, &obj->data.i2c.arg,
1637 obj->data.i2c.devtype);
1638 END OBJ(temp2, INFO_I2C) obj->type = OBJ_i2c;
1640 open_i2c_sensor(0, "temp", 2, &obj->data.i2c.arg,
1641 obj->data.i2c.devtype);
1642 END OBJ(time, 0) obj->data.s = strdup(arg ? arg : "%F %T");
1643 END OBJ(utime, 0) obj->data.s = strdup(arg ? arg : "%F %T");
1644 END OBJ(totaldown, INFO_NET)
1646 obj->data.net = get_net_stat(arg);
1649 CRIT_ERR("totaldown needs argument");
1651 END OBJ(totalup, INFO_NET) obj->data.net = get_net_stat(arg);
1653 obj->data.net = get_net_stat(arg);
1656 CRIT_ERR("totalup needs argument");
1659 END OBJ(alignr, 0) obj->data.i = arg ? atoi(arg) : 0;
1660 END OBJ(alignc, 0) obj->data.i = arg ? atoi(arg) : 0;
1661 END OBJ(upspeed, INFO_NET)
1663 obj->data.net = get_net_stat(arg);
1666 CRIT_ERR("upspeed needs argument");
1668 END OBJ(upspeedf, INFO_NET)
1670 obj->data.net = get_net_stat(arg);
1673 CRIT_ERR("upspeedf needs argument");
1676 END OBJ(upspeedgraph, INFO_NET)
1677 (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
1679 sscanf(arg, "%63s %*i,%*i %*i", buf);
1680 obj->data.net = get_net_stat(buf);
1681 if (sscanf(arg, "%*s %d,%d %*d", &obj->b, &obj->a) <= 1) {
1682 if (sscanf(arg, "%*s %d,%d", &obj->a, &obj->a) <= 1) {
1687 END OBJ(uptime_short, INFO_UPTIME) END OBJ(uptime, INFO_UPTIME) END
1688 OBJ(adt746xcpu, 0) END OBJ(adt746xfan, 0) END
1689 #if defined(__FreeBSD__) && (defined(i386) || defined(__i386__))
1690 OBJ(apm_adapter, 0) END
1691 OBJ(apm_battery_life, 0) END
1692 OBJ(apm_battery_time, 0) END
1693 #endif /* __FreeBSD__ */
1695 OBJ(seti_prog, INFO_SETI) END OBJ(seti_progbar, INFO_SETI)
1696 (void) scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
1697 END OBJ(seti_credit, INFO_SETI) END
1700 OBJ(mpd_artist, INFO_MPD)
1701 END OBJ(mpd_title, INFO_MPD)
1702 END OBJ(mpd_elapsed, INFO_MPD)
1703 END OBJ(mpd_length, INFO_MPD)
1704 END OBJ(mpd_percent, INFO_MPD)
1705 END OBJ(mpd_album, INFO_MPD) END OBJ(mpd_vol,
1706 INFO_MPD) END OBJ(mpd_bitrate,
1708 END OBJ(mpd_status, INFO_MPD) END OBJ(mpd_bar, INFO_MPD)
1709 (void) scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
1714 ERR("unknown variable %s", s);
1715 obj->type = OBJ_text;
1716 snprintf(buf, 256, "${%s}", s);
1717 obj->data.s = strdup(buf);
1722 /* append_text() appends text to last text_object if it's text, if it isn't
1723 * it creates a new text_object */
1724 static void append_text(const char *s)
1726 struct text_object *obj;
1728 if (s == NULL || *s == '\0')
1731 obj = text_object_count ? &text_objects[text_object_count - 1] : 0;
1733 /* create a new text object? */
1734 if (!obj || obj->type != OBJ_text) {
1735 obj = new_text_object();
1736 obj->type = OBJ_text;
1737 obj->data.s = strdup(s);
1740 obj->data.s = (char *) realloc(obj->data.s,
1741 strlen(obj->data.s) +
1743 strcat(obj->data.s, s);
1747 static void extract_variable_text(const char *p)
1751 free_text_objects();
1766 /* variable is either $foo or ${foo} */
1770 while (*p && *p != '}')
1776 while (*p && (isalnum((int) *p)
1781 /* copy variable to buffer */
1782 len = (p - s > 255) ? 255 : (p - s);
1783 strncpy(buf, s, len);
1792 /* if variable wasn't found from environment, use some special */
1798 if (strchr(buf, ' ')) {
1799 arg = strchr(buf, ' ');
1802 while (isspace((int) *arg))
1808 /* lowercase variable name */
1815 construct_text_object(buf, arg);
1826 ERR("one or more $endif's are missing");
1830 double current_update_time, last_update_time;
1832 static void generate_text()
1835 struct information *cur = &info;
1842 current_update_time = get_time();
1848 n = TEXT_BUFFER_SIZE * 4 - 2;
1851 for (i = 0; i < text_object_count; i++) {
1852 struct text_object *obj = &text_objects[i];
1854 #define OBJ(a) break; case OBJ_##a:
1856 switch (obj->type) {
1859 ERR("not implemented obj type %d",
1863 /* does anyone have decimals in acpi temperature? */
1865 snprintf(p, n, "%d", (int)
1866 get_acpi_temperature(obj->
1870 snprintf(p, 5, "%d ", (int)
1871 get_acpi_temperature(obj->
1876 /* does anyone have decimals in acpi temperature? */
1878 snprintf(p, n, "%d", (int)
1879 ((get_acpi_temperature(obj->
1881 i)+ 40) * 9.0 / 5 - 40));
1883 snprintf(p, 5, "%d ", (int)
1884 ((get_acpi_temperature(obj->
1886 i)+ 40) * 9.0 / 5 - 40));
1889 snprintf(p, n, "%.0f", get_freq());
1892 float ghz = (float)(get_freq()/1000);
1893 //printf("%f\n", ghz);
1894 snprintf(p, n, "%'.2f", ghz);
1897 snprintf(p, n, "%.0f", get_freq_dynamic());
1900 float ghz = (float)(get_freq_dynamic()/1000);
1901 snprintf(p, n, "%'.2f", ghz);
1904 snprintf(p, n, "%s", get_adt746x_cpu());
1907 snprintf(p, n, "%s", get_adt746x_fan());
1910 snprintf(p, n, "%s", get_acpi_fan());
1912 OBJ(acpiacadapter) {
1913 snprintf(p, n, "%s",
1914 get_acpi_ac_adapter());
1917 get_battery_stuff(p, n, obj->data.s);
1920 human_readable(cur->buffers * 1024, p,
1924 human_readable(cur->cached * 1024, p, 255);
1927 if (obj->data.cpu_index > info.cpu_count) {
1928 printf("obj->data.cpu_index %i info.cpu_count %i", obj->data.cpu_index, info.cpu_count);
1929 CRIT_ERR("attempting to use more CPUs then you have!");
1932 snprintf(p, n, "%*d", pad_percents,
1933 (int) round_to_int(cur->cpu_usage[obj->data.cpu_index] *
1936 snprintf(p, 4, "%*d ",
1938 (int) round_to_int(cur->cpu_usage[obj->data.cpu_index] *
1944 (int) round_to_int(cur->cpu_usage[obj->data.cpu_index] * 255.0));
1947 new_graph(p, obj->a,
1948 obj->b, obj->c, obj->d,
1949 (unsigned int) round_to_int(cur->cpu_usage[obj->data.cpu_index] *
1953 new_fg(p, obj->data.l);
1955 #if defined(__linux__)
1957 snprintf(p, n, "%s", i8k.version);
1960 snprintf(p, n, "%s", i8k.bios);
1963 snprintf(p, n, "%s", i8k.serial);
1966 snprintf(p, n, "%s", i8k.cpu_temp);
1968 OBJ(i8k_cpu_tempf) {
1970 sscanf(i8k.cpu_temp, "%d", &cpu_temp);
1971 snprintf(p, n, "%.1f", cpu_temp*(9.0/5.0)+32.0);
1973 OBJ(i8k_left_fan_status) {
1974 int left_fan_status;
1975 sscanf(i8k.left_fan_status, "%d", &left_fan_status);
1976 if(left_fan_status == 0) {
1977 snprintf(p, n,"off");
1978 } if(left_fan_status == 1) {
1979 snprintf(p, n, "low");
1980 } if(left_fan_status == 2) {
1981 snprintf(p, n, "high");
1985 OBJ(i8k_right_fan_status) {
1986 int right_fan_status;
1987 sscanf(i8k.right_fan_status, "%d", &right_fan_status);
1988 if(right_fan_status == 0) {
1989 snprintf(p, n,"off");
1990 } if(right_fan_status == 1) {
1991 snprintf(p, n, "low");
1992 } if(right_fan_status == 2) {
1993 snprintf(p, n, "high");
1996 OBJ(i8k_left_fan_rpm) {
1997 snprintf(p, n, "%s", i8k.left_fan_rpm);
1999 OBJ(i8k_right_fan_rpm) {
2000 snprintf(p, n, "%s", i8k.right_fan_rpm);
2002 OBJ(i8k_ac_status) {
2004 sscanf(i8k.ac_status, "%d", &ac_status);
2005 if(ac_status == -1) {
2006 snprintf(p, n,"disabled (read i8k docs)");
2007 } if(ac_status == 0) {
2008 snprintf(p, n, "off");
2009 } if(ac_status == 1) {
2010 snprintf(p, n, "on");
2013 OBJ(i8k_buttons_status) {
2014 snprintf(p, n, "%s", i8k.buttons_status);
2017 #endif /* __linux__ */
2021 new_font(p, obj->data.s);
2026 if (diskio_value > 1024*1024) {
2027 snprintf(p, n, "%.1fG",
2028 (double)diskio_value/1024/1024);
2029 } else if (diskio_value > 1024) {
2030 snprintf(p, n, "%.1fM",
2031 (double)diskio_value/1024);
2032 } else if (diskio_value > 0) {
2033 snprintf(p, n, "%dK", diskio_value);
2035 snprintf(p, n, "%d", diskio_value);
2038 if (diskio_value > 1024*1024) {
2039 snprintf(p, 6, "%.1fG ",
2040 (double)diskio_value/1024/1024);
2041 } else if (diskio_value > 1024) {
2042 snprintf(p, 6, "%.1fM ",
2043 (double)diskio_value/1024);
2044 } else if (diskio_value > 0) {
2045 snprintf(p, 6, "%dK ", diskio_value);
2047 snprintf(p, 6, "%d ", diskio_value);
2052 new_graph(p, obj->a,
2053 obj->b, obj->c, obj->d,
2054 diskio_value, obj->e, 1);
2059 snprintf(p, n, "%d",
2060 (int) (obj->data.net->
2064 snprintf(p, 6, "%d ",
2065 (int) (obj->data.net->
2071 snprintf(p, n, "%.1f",
2073 recv_speed / 1024.0);
2075 snprintf(p, 8, "%.1f ",
2077 recv_speed / 1024.0);
2079 OBJ(downspeedgraph) {
2080 if (obj->data.net->recv_speed == 0) // this is just to make the ugliness at start go away
2081 obj->data.net->recv_speed = 0.01;
2082 new_graph(p, obj->a, obj->b, obj->c, obj->d,
2083 (obj->data.net->recv_speed /
2084 1024.0), obj->e, 1);
2090 i = obj->data.ifblock.pos - 2;
2100 snprintf(p, n, "%u.%u.%u.%u",
2101 obj->data.net->addr.
2103 obj->data.net->addr.
2105 obj->data.net->addr.
2107 obj->data.net->addr.
2112 snprintf(p, n, "%d",
2113 obj->data.net->linkstatus);
2118 FILE *fp = popen(obj->data.s, "r");
2119 int n2 = fread(p, 1, n, fp);
2123 if (n2 && p[n2 - 1] == '\n')
2134 FILE *fp = popen(obj->data.s, "r");
2135 int n2 = fread(p, 1, n, fp);
2139 if (n2 && p[n2 - 1] == '\n')
2148 if (sscanf(p, "%lf", &barnum) == 0) {
2149 ERR("reading execbar value failed (perhaps it's not the correct format?)");
2151 if (barnum > 100 || barnum < 0) {
2152 ERR("your execbar value is not between 0 and 100, therefore it will be ignored");
2154 barnum = barnum / 100.0;
2155 new_bar(p, 0, 4, (int) (barnum * 255.0));
2161 FILE *fp = popen(obj->data.s, "r");
2162 int n2 = fread(p, 1, n, fp);
2166 if (n2 && p[n2 - 1] == '\n')
2175 if (sscanf(p, "%lf", &barnum) == 0) {
2176 ERR("reading execgraph value failed (perhaps it's not the correct format?)");
2178 if (barnum > 100 || barnum < 0) {
2179 ERR("your execgraph value is not between 0 and 100, therefore it will be ignored");
2182 25, obj->c, obj->d, (int) (barnum), obj->e, 1);
2187 if (current_update_time - obj->data.execi.last_update < obj->data.execi.interval) {
2188 new_bar(p, 0, 4, (int) obj->f);
2191 FILE *fp = popen(obj->data.execi.cmd, "r");
2192 int n2 = fread(p, 1, n, fp);
2195 if (n2 && p[n2 - 1] == '\n')
2204 if (sscanf(p, "%f", &barnum) == 0) {
2205 ERR("reading execibar value failed (perhaps it's not the correct format?)");
2207 if (barnum > 100 || barnum < 0) {
2208 ERR("your execibar value is not between 0 and 100, therefore it will be ignored");
2210 obj->f = 255 * barnum / 100.0;
2211 new_bar(p, 0, 4, (int) obj->f);
2213 obj->data.execi.last_update =
2214 current_update_time;
2218 if (current_update_time - obj->data.execi.last_update < obj->data.execi.interval) {
2219 new_graph(p, 0, 25, obj->c, obj->d, (int) (obj->f), 100, 0);
2222 FILE *fp = popen(obj->data.execi.cmd, "r");
2223 int n2 = fread(p, 1, n, fp);
2226 if (n2 && p[n2 - 1] == '\n')
2235 if (sscanf(p, "%f", &barnum) == 0) {
2236 ERR("reading execigraph value failed (perhaps it's not the correct format?)");
2238 if (barnum > 100 || barnum < 0) {
2239 ERR("your execigraph value is not between 0 and 100, therefore it will be ignored");
2242 new_graph(p, 0, 25, obj->c, obj->d, (int) (obj->f), 100, 1);
2244 obj->data.execi.last_update = current_update_time;
2250 if (current_update_time -
2251 obj->data.execi.last_update <
2252 obj->data.execi.interval) {
2253 snprintf(p, n, "%s",
2254 obj->data.execi.buffer);
2256 char *p2 = obj->data.execi.buffer;
2258 popen(obj->data.execi.cmd,
2261 fread(p2, 1, TEXT_BUFFER_SIZE,
2266 if (n2 && p2[n2 - 1] == '\n')
2275 snprintf(p, n, "%s",
2276 obj->data.execi.buffer);
2278 obj->data.execi.last_update =
2279 current_update_time;
2283 static int running = 0;
2284 if (current_update_time - obj->data.execi.last_update < obj->data.execi.interval) {
2285 snprintf(p, n, "%s", obj->data.execi.buffer);
2287 static pthread_t execthread;
2290 pthread_create( &execthread, NULL, (void*)threaded_exec, (void*) obj);
2291 pthread_mutex_lock( &mutex1 );
2292 obj->data.execi.last_update = current_update_time;
2293 pthread_mutex_unlock( &mutex1 );
2295 pthread_join( execthread, NULL);
2298 snprintf(p, n, "%s", obj->data.execi.buffer);
2303 if (obj->data.fs != NULL) {
2304 if (obj->data.fs->size == 0)
2323 if (obj->data.fs != NULL)
2324 human_readable(obj->data.fs->avail,
2328 if (obj->data.fs != NULL) {
2329 if (obj->data.fs->size)
2330 snprintf(p, n, "%*d",
2339 snprintf(p, n, "0");
2343 if (obj->data.fs != NULL)
2344 human_readable(obj->data.fs->size,
2348 if (obj->data.fs != NULL)
2349 human_readable(obj->data.fs->size -
2350 obj->data.fs->avail,
2354 if (obj->data.fs != NULL) {
2355 if (obj->data.fs->size == 0)
2373 if (obj->data.fs != NULL) {
2374 if (obj->data.fs->size)
2375 snprintf(p, 4, "%d",
2385 snprintf(p, n, "0");
2389 float *v = info.loadavg;
2391 if (obj->data.loadavg[2])
2392 snprintf(p, n, "%.2f %.2f %.2f",
2393 v[obj->data.loadavg[0] -
2395 v[obj->data.loadavg[1] -
2397 v[obj->data.loadavg[2] -
2399 else if (obj->data.loadavg[1])
2400 snprintf(p, n, "%.2f %.2f",
2401 v[obj->data.loadavg[0] -
2403 v[obj->data.loadavg[1] -
2405 else if (obj->data.loadavg[0])
2406 snprintf(p, n, "%.2f",
2407 v[obj->data.loadavg[0] -
2411 new_hr(p, obj->data.i);
2414 new_offset(p, obj->data.i);
2417 new_voffset(p, obj->data.i);
2422 r = get_i2c_info(&obj->data.i2c.fd,
2424 obj->data.i2c.devtype,
2425 obj->data.i2c.type);
2427 if (r >= 100.0 || r == 0)
2428 snprintf(p, n, "%d", (int) r);
2430 snprintf(p, n, "%.1f", r);
2433 new_alignr(p, obj->data.i);
2436 new_alignc(p, obj->data.i);
2440 if ((obj->data.ifblock.s)
2441 && (stat(obj->data.ifblock.s, &tmp) ==
2443 i = obj->data.ifblock.pos - 2;
2449 if ((obj->data.ifblock.s)
2450 && (!check_mount(obj->data.ifblock.s))) {
2451 i = obj->data.ifblock.pos - 2;
2457 if ((obj->data.ifblock.s)
2458 && system(obj->data.ifblock.s)) {
2459 i = obj->data.ifblock.pos - 2;
2465 snprintf(p, n, "%s", cur->uname_s.release);
2468 snprintf(p, n, "%s", cur->uname_s.machine);
2473 human_readable(cur->mem * 1024, p, 6);
2476 human_readable(cur->memmax * 1024, p, 255);
2481 snprintf(p, n, "%*d",
2486 snprintf(p, 4, "%*d ",
2493 new_bar(p, obj->data.pair.a,
2495 cur->memmax ? (cur->mem * 255) /
2500 new_graph(p, obj->a,
2501 obj->b, obj->c, obj->d,
2502 cur->memmax ? (cur->mem * 100.0) /
2503 (cur->memmax) : 0.0, 100, 1);
2507 snprintf(p, n, "%d",
2508 mixer_get_avg(obj->data.l));
2511 snprintf(p, n, "%d",
2512 mixer_get_left(obj->data.l));
2515 snprintf(p, n, "%d",
2516 mixer_get_right(obj->data.l));
2519 new_bar(p, obj->data.mixerbar.w,
2520 obj->data.mixerbar.h,
2521 mixer_get_avg(obj->data.mixerbar.
2525 new_bar(p, obj->data.mixerbar.w,
2526 obj->data.mixerbar.h,
2527 mixer_get_left(obj->data.mixerbar.
2531 new_bar(p, obj->data.mixerbar.w,
2532 obj->data.mixerbar.h,
2533 mixer_get_right(obj->data.mixerbar.
2539 snprintf(p, n, "%d", cur->mail_count);
2542 snprintf(p, n, "%d", cur->new_mail_count);
2545 OBJ(ml_upload_counter) {
2546 snprintf(p, n, "%lld",
2547 mlinfo.upload_counter / 1048576);
2549 OBJ(ml_download_counter) {
2550 snprintf(p, n, "%lld",
2551 mlinfo.download_counter /
2554 OBJ(ml_nshared_files) {
2555 snprintf(p, n, "%i", mlinfo.nshared_files);
2557 OBJ(ml_shared_counter) {
2558 snprintf(p, n, "%lld",
2559 mlinfo.shared_counter / 1048576);
2561 OBJ(ml_tcp_upload_rate) {
2562 snprintf(p, n, "%.2f",
2563 (float) mlinfo.tcp_upload_rate /
2566 OBJ(ml_tcp_download_rate) {
2567 snprintf(p, n, "%.2f",
2568 (float) mlinfo.tcp_download_rate /
2571 OBJ(ml_udp_upload_rate) {
2572 snprintf(p, n, "%.2f",
2573 (float) mlinfo.udp_upload_rate /
2576 OBJ(ml_udp_download_rate) {
2577 snprintf(p, n, "%.2f",
2578 (float) mlinfo.udp_download_rate /
2581 OBJ(ml_ndownloaded_files) {
2582 snprintf(p, n, "%i",
2583 mlinfo.ndownloaded_files);
2585 OBJ(ml_ndownloading_files) {
2586 snprintf(p, n, "%i",
2587 mlinfo.ndownloading_files);
2592 snprintf(p, n, "%s",
2593 cur->uname_s.nodename);
2596 new_outline(p, obj->data.l);
2600 snprintf(p, n, "%d", cur->procs);
2602 snprintf(p, 5, "%d ",
2605 OBJ(running_processes) {
2607 snprintf(p, n, "%d",
2610 snprintf(p, 3, "%d ",
2614 snprintf(p, n, "%s", obj->data.s);
2617 new_bg(p, obj->data.l);
2620 new_stippled_hr(p, obj->data.pair.a,
2624 human_readable(cur->swap * 1024, p, 255);
2627 human_readable(cur->swapmax * 1024, p,
2631 if (cur->swapmax == 0) {
2632 strncpy(p, "No swap", 255);
2635 snprintf(p, 255, "%*u",
2641 snprintf(p, 4, "%*u ",
2649 new_bar(p, obj->data.pair.a,
2651 cur->swapmax ? (cur->swap * 255) /
2652 (cur->swapmax) : 0);
2655 snprintf(p, n, "%s", cur->uname_s.sysname);
2658 time_t t = time(NULL);
2659 struct tm *tm = localtime(&t);
2660 setlocale(LC_TIME, "");
2661 strftime(p, n, obj->data.s, tm);
2664 time_t t = time(NULL);
2665 struct tm *tm = gmtime(&t);
2666 strftime(p, n, obj->data.s, tm);
2669 human_readable(obj->data.net->recv, p,
2673 human_readable(obj->data.net->trans, p,
2677 snprintf(p, n, "%d", total_updates);
2681 snprintf(p, n, "%d",
2682 (int) (obj->data.net->
2686 snprintf(p, 5, "%d ",
2687 (int) (obj->data.net->
2693 snprintf(p, n, "%.1f",
2695 trans_speed / 1024.0);
2697 snprintf(p, 8, "%.1f ",
2699 trans_speed / 1024.0);
2702 if (obj->data.net->trans_speed == 0) // this is just to make the ugliness at start go away
2703 obj->data.net->trans_speed = 0.01;
2704 new_graph(p, obj->a, obj->b, obj->c, obj->d,
2705 (obj->data.net->trans_speed /
2706 1024.0), obj->e, 1);
2709 format_seconds_short(p, n,
2713 format_seconds(p, n, (int) cur->uptime);
2716 #if defined(__FreeBSD__) && (defined(i386) || defined(__i386__))
2718 snprintf(p, n, "%s", get_apm_adapter());
2720 OBJ(apm_battery_life) {
2722 msg = get_apm_battery_life();
2723 snprintf(p, n, "%s", msg);
2726 OBJ(apm_battery_time) {
2728 msg = get_apm_battery_time();
2729 snprintf(p, n, "%s", msg);
2732 #endif /* __FreeBSD__ */
2735 snprintf(p, n, "%.2f",
2736 cur->seti_prog * 100.0f);
2739 new_bar(p, obj->data.pair.a,
2741 (int) (cur->seti_prog * 255.0f));
2744 snprintf(p, n, "%.0f", cur->seti_credit);
2750 snprintf(p, n, "%s", cur->mpd.title);
2753 snprintf(p, n, "%s", cur->mpd.artist);
2756 snprintf(p, n, "%s", cur->mpd.album);
2759 snprintf(p, n, "%i", cur->mpd.volume);
2762 snprintf(p, n, "%i", cur->mpd.bitrate);
2765 snprintf(p, n, "%s", cur->mpd.status);
2768 int days = 0, hours = 0, minutes =
2770 int tmp = cur->mpd.elapsed;
2771 while (tmp >= 86400) {
2775 while (tmp >= 3600) {
2785 snprintf(p, n, "%i days %i:%02i:%02i",
2786 days, hours, minutes,
2789 snprintf(p, n, "%i:%02i:%02i", hours,
2792 snprintf(p, n, "%i:%02i", minutes,
2796 int days = 0, hours = 0, minutes =
2798 int tmp = cur->mpd.length;
2799 while (tmp >= 86400) {
2803 while (tmp >= 3600) {
2814 "%i days %i:%02i:%02i",
2815 days, hours, minutes,
2818 snprintf(p, n, "%i:%02i:%02i", hours,
2821 snprintf(p, n, "%i:%02i", minutes,
2825 snprintf(p, n, "%2.0f",
2826 cur->mpd.progress * 100);
2829 new_bar(p, obj->data.pair.a,
2831 (int) (cur->mpd.progress *
2836 if (obj->data.top.type == TOP_NAME
2837 && obj->data.top.num >= 0
2838 && obj->data.top.num < 10) {
2839 // if we limit the buffer and add a bunch of space after, it stops the thing from
2840 // moving other shit around, which is really fucking annoying
2841 snprintf(p, 17, "%s ", cur->cpu[obj->data.top.num]->name);
2842 } else if (obj->data.top.type == TOP_CPU
2843 && obj->data.top.num >= 0
2844 && obj->data.top.num < 10) {
2845 snprintf(p, 7, "%3.2f ",
2846 cur->cpu[obj->data.top.
2848 } else if (obj->data.top.type == TOP_PID
2849 && obj->data.top.num >= 0
2850 && obj->data.top.num < 10) {
2851 snprintf(p, 8, "%i ",
2852 cur->cpu[obj->data.top.
2854 } else if (obj->data.top.type == TOP_MEM
2855 && obj->data.top.num >= 0
2856 && obj->data.top.num < 10) {
2857 snprintf(p, 7, "%3.2f ",
2858 cur->cpu[obj->data.top.
2863 if (obj->data.top.type == TOP_NAME
2864 && obj->data.top.num >= 0
2865 && obj->data.top.num < 10) {
2866 // if we limit the buffer and add a bunch of space after, it stops the thing from
2867 // moving other shit around, which is really fucking annoying
2870 cur->memu[obj->data.top.
2872 } else if (obj->data.top.type == TOP_CPU
2873 && obj->data.top.num >= 0
2874 && obj->data.top.num < 10) {
2875 snprintf(p, 7, "%3.2f ",
2876 cur->memu[obj->data.top.
2878 } else if (obj->data.top.type == TOP_PID
2879 && obj->data.top.num >= 0
2880 && obj->data.top.num < 10) {
2881 snprintf(p, 8, "%i ",
2882 cur->memu[obj->data.top.
2884 } else if (obj->data.top.type == TOP_MEM
2885 && obj->data.top.num >= 0
2886 && obj->data.top.num < 10) {
2887 snprintf(p, 7, "%3.2f ",
2888 cur->memu[obj->data.top.
2896 * I'm tired of everything being packed in
2903 if (current_update_time -obj->data.tail.last_update < obj->data.tail.interval) {
2904 snprintf(p, n, "%s", obj->data.tail.buffer);
2906 obj->data.tail.last_update = current_update_time;
2910 tailstring *head = NULL;
2911 tailstring *headtmp = NULL;
2912 tailstring *freetmp = NULL;
2913 fp = fopen(obj->data.tail.logfile, "rt");
2915 ERR("tail logfile failed to open");
2918 obj->data.tail.readlines = 0;
2920 while (fgets(obj->data.tail.buffer, TEXT_BUFFER_SIZE*20, fp) != NULL) {
2927 addtail(&head, obj->data.tail.buffer);
2928 obj->data.tail.readlines++;
2934 if (obj->data.tail.readlines > 0) {
2935 for (i = 0;i < obj->data.tail.wantedlines + 1 && i < obj->data.tail.readlines; i++) {
2936 addtail(&headtmp, head->data);
2941 strcpy(obj->data.tail.buffer, headtmp->data);
2942 headtmp = headtmp->next;
2943 for (i = 1;i < obj->data.tail.wantedlines + 1 && i < obj->data.tail.readlines; i++) {
2945 strncat(obj->data.tail.buffer, headtmp->data, (TEXT_BUFFER_SIZE * 20) - strlen(obj->data.tail.buffer)); /* without strlen() at the end this becomes a possible */
2946 headtmp = headtmp->next;
2950 /* get rid of any ugly newlines at the end */
2951 if (obj->data.tail.buffer[strlen(obj->data.tail.buffer)-1] == '\n') {
2952 obj->data.tail.buffer[strlen(obj->data.tail.buffer)-1] = '\0';
2954 snprintf(p, n, "%s", obj->data.tail.buffer);
2959 strcpy(obj->data.tail.buffer, "Logfile Empty");
2960 snprintf(p, n, "Logfile Empty");
2966 if (current_update_time -obj->data.tail.last_update < obj->data.tail.interval) {
2967 snprintf(p, n, "%s", obj->data.tail.buffer);
2969 obj->data.tail.last_update = current_update_time;
2971 tailstring *head = NULL;
2972 tailstring *headtmp = NULL;
2973 tailstring *freetmp = NULL;
2974 fp = fopen(obj->data.tail.logfile, "rt");
2976 ERR("head logfile failed to open");
2979 obj->data.tail.readlines = 0;
2980 while (fgets(obj->data.tail.buffer, TEXT_BUFFER_SIZE*20, fp) != NULL && obj->data.tail.readlines <= obj->data.tail.wantedlines) {
2981 addtail(&head, obj->data.tail.buffer);
2982 obj->data.tail.readlines++;
2986 if (obj->data.tail.readlines > 0) {
2988 addtail(&headtmp, head->data);
2993 strcpy(obj->data.tail.buffer, headtmp->data);
2994 headtmp = headtmp->next;
2996 strncat(obj->data.tail.buffer, headtmp->data, (TEXT_BUFFER_SIZE * 20) - strlen(obj->data.tail.buffer)); /* without strlen() at the end this becomes a possible */
2997 headtmp = headtmp->next;
3000 /* get rid of any ugly newlines at the end */
3001 if (obj->data.tail.buffer[strlen(obj->data.tail.buffer)-1] == '\n') {
3002 obj->data.tail.buffer[strlen(obj->data.tail.buffer)-1] = '\0';
3004 snprintf(p, n, "%s", obj->data.tail.buffer);
3007 strcpy(obj->data.tail.buffer, "Logfile Empty");
3008 snprintf(p, n, "Logfile Empty");
3018 unsigned int a = strlen(p);
3024 if (stuff_in_upper_case) {
3034 last_update_time = current_update_time;
3040 static void set_font()
3044 if (window.xftdraw != NULL) {
3045 XftDrawDestroy(window.xftdraw);
3047 window.xftdraw = XftDrawCreate(display, window.drawable,
3048 DefaultVisual(display,
3050 DefaultColormap(display,
3055 XSetFont(display, window.gc, fonts[selected_font].font->fid);
3064 static int text_start_x, text_start_y; /* text start position in window */
3065 static int text_width, text_height;
3069 static inline int get_string_width(const char *s)
3072 return *s ? calc_text_width(s, strlen(s)) : 0;
3078 static inline int get_string_width_special(char *s)
3091 if (*p == SPECIAL_CHAR) {
3092 /* shift everything over by 1 so that the special char doesn't mess up the size calculation */
3093 for (i = 0; i < strlen(p); i++) {
3094 *(p + i) = *(p + i + 1);
3096 if (specials[special_index+index].type == GRAPH || specials[special_index+index].type == BAR) {
3097 width += specials[special_index+index].width;
3104 if (strlen(final) > 1) {
3105 width += calc_text_width(final, strlen(final));
3117 static void text_size_updater(char *s)
3121 int h = font_height();
3122 /* get string widths and skip specials */
3125 if (*p == SPECIAL_CHAR) {
3127 w += get_string_width(s);
3130 if (specials[special_index].type == BAR
3131 || specials[special_index].type == GRAPH) {
3132 w += specials[special_index].width;
3133 if (specials[special_index].height > h) {
3134 h = specials[special_index].height;
3139 else if (specials[special_index].type == OFFSET) {
3140 w += specials[special_index].arg + get_string_width("a"); /* filthy, but works */
3142 else if (specials[special_index].type == VOFFSET) {
3143 h += specials[special_index].arg;
3145 else if (specials[special_index].type == FONT) {
3146 fontchange = specials[special_index].font_added;
3147 selected_font = specials[special_index].font_added;
3157 w += get_string_width(s);
3160 if (text_width > maximum_width && maximum_width)
3161 text_width = maximum_width;
3172 static void update_text_area()
3176 /* update text size if it isn't fixed */
3181 text_width = minimum_width;
3184 for_each_line(text_buffer, text_size_updater);
3186 if (text_height < minimum_height)
3187 text_height = minimum_height;
3188 if (text_width > maximum_width && maximum_width > 0)
3189 text_width = maximum_width;
3192 /* get text position on workarea */
3193 switch (text_alignment) {
3200 x = workarea[2] - text_width - gap_x;
3207 y = workarea[3] - text_height - gap_y;
3211 x = workarea[2] - text_width - gap_x;
3212 y = workarea[3] - text_height - gap_y;
3216 case NONE: // Let the WM manage the window
3227 if (own_window && !fixed_pos) {
3230 text_start_x = border_margin + 1;
3231 text_start_y = border_margin + 1;
3232 window.x = x - border_margin - 1;
3233 window.y = y - border_margin - 1;
3237 /* If window size doesn't match to workarea's size, then window
3238 * probably includes panels (gnome).
3239 * Blah, doesn't work on KDE. */
3240 if (workarea[2] != window.width
3241 || workarea[3] != window.height) {
3255 static int cur_x, cur_y; /* current x and y for drawing */
3256 static int draw_mode; /* FG, BG or OUTLINE */
3257 static long current_color;
3259 static inline void set_foreground_color(long c)
3262 XSetForeground(display, window.gc, c);
3266 static void draw_string(const char *s)
3270 int i, i2, pos, width_of_s;
3273 width_of_s = get_string_width(s);
3274 if (out_to_console) {
3277 /* 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 */
3278 strcpy(tmpstring1, s);
3282 snprintf(space, 2, " ");
3284 max = ((text_width - width_of_s) / get_string_width(space));
3287 * This code looks for tabs in the text and coverts them to spaces.
3288 * The trick is getting the correct number of spaces,
3289 * and not going over the window's size without forcing
3290 * the window larger.
3292 for (i = 0; i < TEXT_BUFFER_SIZE; i++) {
3293 if (tmpstring1[i] == '\t') // 9 is ascii tab
3297 i2 < (8 - (1 + pos) % 8) && added <= max;
3299 tmpstring2[pos + i2] = ' ';
3304 if (tmpstring1[i] != 9) {
3305 tmpstring2[pos] = tmpstring1[i];
3311 if (text_width == maximum_width) {
3312 /* this means the text is probably pushing the limit, so we'll chop it */
3313 while (cur_x + get_string_width(tmpstring2) - text_start_x > maximum_width && strlen(tmpstring2) > 0) {
3314 tmpstring2[strlen(tmpstring2)-1] = '\0';
3324 c.pixel = current_color;
3325 XQueryColor(display, DefaultColormap(display, screen), &c);
3328 c2.color.red = c.red;
3329 c2.color.green = c.green;
3330 c2.color.blue = c.blue;
3331 c2.color.alpha = fonts[selected_font].font_alpha;
3333 XftDrawStringUtf8(window.xftdraw, &c2, fonts[selected_font].xftfont,
3334 cur_x, cur_y, (XftChar8 *) s,
3337 XftDrawString8(window.xftdraw, &c2, fonts[selected_font].xftfont,
3338 cur_x, cur_y, (XftChar8 *) s,
3344 XDrawString(display, window.drawable, window.gc,
3345 cur_x, cur_y, s, strlen(s));
3347 cur_x += width_of_s;
3349 memcpy(tmpstring1, s, TEXT_BUFFER_SIZE);
3352 long redmask, greenmask, bluemask;
3354 void set_up_gradient()
3357 colour_depth = DisplayPlanes(display, screen);
3361 if (colour_depth != 24 && colour_depth != 16) {
3362 ERR("using non-standard colour depth, gradients may look like a lolly-pop");
3368 for(i = (colour_depth / 3)-1; i>=0; i--) {
3370 greenmask |= 1 << i;
3373 if (colour_depth%3 == 1) {
3374 greenmask |= 1 << (colour_depth / 3);
3376 redmask = redmask << (2*colour_depth / 3 + colour_depth%3);
3377 greenmask = greenmask << (colour_depth / 3);
3380 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 */
3382 int red1, green1, blue1; // first colour
3383 int red2, green2, blue2; // second colour
3384 int red3 = 0, green3 = 0, blue3 = 0; // difference
3385 short redshift = (2*colour_depth / 3 + colour_depth%3);
3386 short greenshift = (colour_depth / 3);
3387 red1 = (first_colour & redmask) >> redshift;
3388 green1 = (first_colour & greenmask) >> greenshift;
3389 blue1 = first_colour & bluemask;
3390 red2 = (last_colour & redmask) >> redshift;
3391 green2 = (last_colour & greenmask) >> greenshift;
3392 blue2 = last_colour & bluemask;
3399 if (green1 > green2) {
3402 if (green1 < green2) {
3405 if (blue1 > blue2) {
3408 if (blue1 < blue2) {
3423 if (red1 > bluemask) {
3426 if (green1 > bluemask) {
3429 if (blue1 > bluemask) {
3432 tmp_color = (red1 << redshift) | (green1 << greenshift) | blue1;
3436 inline unsigned long gradient_max(unsigned long first_colour, unsigned long last_colour) { /* this function returns the max diff for a gradient */
3437 if (colour_depth == 0) {
3440 int red1, green1, blue1; // first colour
3441 int red2, green2, blue2; // second colour
3442 long redshift = (2*colour_depth / 3 + colour_depth%3);
3443 long greenshift = (colour_depth / 3);
3444 int red3 = 0, green3 = 0, blue3 = 0; // difference
3445 red1 = (first_colour & redmask) >> redshift;
3446 green1 = (first_colour & greenmask) >> greenshift;
3447 blue1 = first_colour & bluemask;
3448 red2 = (last_colour & redmask) >> redshift;
3449 green2 = (last_colour & greenmask) >> greenshift;
3450 blue2 = last_colour & bluemask;
3451 red3 = abs(red1 - red2);
3452 green3 = abs(green1 - green2);
3453 blue3 = abs(blue1 - blue2);
3462 static void draw_line(char *s)
3466 cur_x = text_start_x;
3467 cur_y += font_ascent();
3469 short font_h = font_height();
3471 /* find specials and draw stuff */
3474 if (*p == SPECIAL_CHAR) {
3477 /* draw string before special */
3484 switch (specials[special_index].type) {
3485 case HORIZONTAL_LINE:
3488 specials[special_index].height;
3489 int mid = font_ascent() / 2;
3490 w = text_start_x + text_width -
3493 XSetLineAttributes(display,
3498 XDrawLine(display, window.drawable,
3509 specials[special_index].height;
3511 specials[special_index].arg;
3512 int mid = font_ascent() / 2;
3513 char ss[2] = { s, s };
3514 w = text_start_x + text_width -
3517 XSetLineAttributes(display,
3522 XSetDashes(display, window.gc, 0,
3524 XDrawLine(display, window.drawable,
3534 if (cur_x - text_start_x > maximum_width && maximum_width > 0) {
3538 specials[special_index].height;
3540 specials[special_index].arg;
3545 by = cur_y - (font_ascent() + h) / 2 - 1;
3549 by = cur_y - (font_ascent()/2) - 1;
3551 if (h < (font_height())) {
3554 w = specials[special_index].width;
3557 text_width - cur_x - 1;
3561 XSetLineAttributes(display,
3567 XDrawRectangle(display,
3571 XFillRectangle(display,
3575 w * bar_usage / 255,
3577 if (specials[special_index].
3579 && specials[special_index].
3583 [special_index].height;
3590 if (cur_x - text_start_x > maximum_width && maximum_width > 0) {
3594 specials[special_index].height;
3598 by = cur_y - (font_ascent() + h) / 2 - 1;
3602 by = cur_y - (font_ascent()/2) - 1;
3604 if (h < (font_height())) {
3607 w = specials[special_index].width;
3609 w = text_start_x + text_width - cur_x - 1;
3612 XSetLineAttributes(display,
3617 XDrawRectangle(display,
3621 XSetLineAttributes(display,
3628 int gradient_size = 0;
3629 float gradient_factor = 0;
3630 float gradient_update = 0;
3631 unsigned long tmpcolour = current_color;
3632 if (specials[special_index].first_colour != specials[special_index].last_colour) {
3633 tmpcolour = specials[special_index].first_colour;
3634 gradient_size = gradient_max(specials[special_index].first_colour, specials[special_index].last_colour);
3635 gradient_factor = (float)gradient_size / (w - 3);
3637 for (i = 0; i < w - 3; i++) {
3638 if (specials[special_index].first_colour != specials[special_index].last_colour) {
3639 XSetForeground(display, window.gc, tmpcolour);
3640 gradient_update += gradient_factor;
3641 while (gradient_update > 0) {
3642 tmpcolour = do_gradient(tmpcolour, specials[special_index].last_colour);
3646 if (i / ((float) (w - 3) / (specials[special_index].graph_width)) > j) {
3649 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 */
3651 if (specials[special_index].
3653 && specials[special_index].
3657 [special_index].height;
3660 if (draw_mode == BG) {
3661 set_foreground_color(default_bg_color);
3663 else if (draw_mode == OUTLINE) {
3664 set_foreground_color(default_out_color);
3666 set_foreground_color(default_fg_color);
3672 cur_y -= font_ascent();
3673 selected_font = specials[special_index].font_added;
3674 cur_y += font_ascent();
3676 if (!use_xft || use_xdbe)
3684 if (draw_mode == FG)
3685 set_foreground_color(specials
3691 if (draw_mode == BG)
3692 set_foreground_color(specials
3698 if (draw_mode == OUTLINE)
3699 set_foreground_color(specials
3706 w += specials[special_index].arg;
3711 cur_y += specials[special_index].arg;
3717 int pos_x = text_start_x + text_width - get_string_width_special(s) /*+ border_margin*/;
3718 /*printf("pos_x %i text_start_x %i text_width %i cur_x %i get_string_width(p) %i gap_x %i specials[special_index].arg %i border_margin %i border_width %i\n", pos_x, text_start_x, text_width, cur_x, get_string_width_special(s), gap_x, specials[special_index].arg, border_margin, border_width);*/
3719 if (pos_x > specials[special_index].arg && pos_x > cur_x) {
3720 cur_x = pos_x - specials[special_index].arg;
3727 int pos_x = (text_width)/2 - get_string_width_special(s)/2 - (cur_x - text_start_x);
3728 /*int pos_x = text_start_x + text_width/2 - get_string_width_special(s)/2;*/
3729 /*printf("pos_x %i text_start_x %i text_width %i cur_x %i get_string_width(p) %i gap_x %i specials[special_index].arg %i\n", pos_x, text_start_x, text_width, cur_x, get_string_width(s), gap_x, specials[special_index].arg);*/
3731 specials[special_index].arg)
3734 [special_index].arg;
3751 if (cur_y_add > 0) {
3753 cur_y -= font_descent();
3758 cur_y += font_descent();
3765 static void draw_text()
3768 cur_y = text_start_y;
3771 if (draw_borders && border_width > 0) {
3772 unsigned int b = (border_width + 1) / 2;
3774 if (stippled_borders) {
3776 { stippled_borders, stippled_borders };
3777 XSetLineAttributes(display, window.gc,
3778 border_width, LineOnOffDash,
3779 CapButt, JoinMiter);
3780 XSetDashes(display, window.gc, 0, ss, 2);
3782 XSetLineAttributes(display, window.gc,
3783 border_width, LineSolid,
3784 CapButt, JoinMiter);
3787 XDrawRectangle(display, window.drawable, window.gc,
3788 text_start_x - border_margin + b,
3789 text_start_y - border_margin + b,
3790 text_width + border_margin * 2 - 1 - b * 2,
3791 text_height + border_margin * 2 - 1 -
3798 for_each_line(text_buffer, draw_line);
3801 static void draw_stuff()
3804 if (draw_shades && !draw_outline) {
3807 set_foreground_color(default_bg_color);
3816 for (i = -1; i < 2; i++)
3817 for (j = -1; j < 2; j++) {
3818 if (i == 0 && j == 0)
3822 set_foreground_color(default_out_color);
3823 draw_mode = OUTLINE;
3830 set_foreground_color(default_fg_color);
3838 swap.swap_window = window.window;
3839 swap.swap_action = XdbeBackground;
3840 XdbeSwapBuffers(display, &swap, 1);
3846 static void clear_text(int exposures)
3850 return; /* The swap action is XdbeBackground, which clears */
3854 /* there is some extra space for borders and outlines */
3855 XClearArea(display, window.drawable,
3856 text_start_x - border_margin - 1,
3857 text_start_y - border_margin - 1,
3858 text_width + border_margin * 2 + 2,
3859 text_height + border_margin * 2 + 2,
3860 exposures ? True : 0);
3865 static int need_to_update;
3867 /* update_text() generates new text and clears old text area */
3868 static void update_text()
3877 static void main_loop()
3880 Region region = XCreateRegion();
3884 while (total_run_times == 0 || info.looped < total_run_times - 1) {
3889 /* wait for X event or timeout */
3891 if (!XPending(display)) {
3896 update_interval - (get_time() -
3902 tv.tv_sec = (long) t;
3903 tv.tv_usec = (long) (t * 1000000) % 1000000;
3905 FD_SET(ConnectionNumber(display), &fdsr);
3908 s = select(ConnectionNumber(display) + 1, &fdsr, 0,
3911 usleep(update_interval*1000000); /* FIXME just sleep for the interval time if no X11 */
3916 ERR("can't select(): %s",
3927 set_transparent_background(window.window);
3932 if (need_to_update) {
3934 int wx = window.x, wy = window.y;
3942 /* resize window if it isn't right size */
3944 (text_width + border_margin * 2 !=
3946 || text_height + border_margin * 2 !=
3950 border_margin * 2 + 1;
3953 border_margin * 2 + 1;
3954 XResizeWindow(display,
3960 /* move window if it isn't in right position */
3963 || window.y != wy)) {
3964 XMoveWindow(display, window.window,
3965 window.x, window.y);
3975 r.x = text_start_x - border_margin;
3976 r.y = text_start_y - border_margin;
3977 r.width = text_width + border_margin * 2;
3978 r.height = text_height + border_margin * 2;
3979 XUnionRectWithRegion(&r, region, region);
3984 /* handle X events */
3986 while (XPending(display)) {
3988 XNextEvent(display, &ev);
3995 r.width = ev.xexpose.width;
3996 r.height = ev.xexpose.height;
3997 XUnionRectWithRegion(&r, region,
4003 case ReparentNotify:
4004 /* set background to ParentRelative for all parents */
4006 set_transparent_background(window.
4011 case ConfigureNotify:
4013 /* if window size isn't what expected, set fixed size */
4014 if (ev.xconfigure.width !=
4016 || ev.xconfigure.height !=
4018 if (window.width != 0
4019 && window.height != 0)
4022 /* clear old stuff before screwing up size and pos */
4028 if (XGetWindowAttributes(display, window.window, &attrs)) {
4043 border_margin * 2 - 1;
4046 border_margin * 2 - 1;
4047 if (text_width > maximum_width && maximum_width > 0)
4048 text_width = maximum_width;
4051 /* if position isn't what expected, set fixed pos, total_updates
4052 * avoids setting fixed_pos when window is set to weird locations
4054 /*if (total_updates >= 2 this is broken
4056 && (window.x != ev.xconfigure.x
4059 && (ev.xconfigure.x != 0
4060 || ev.xconfigure.y != 0)) {
4073 /* XDBE doesn't seem to provide a way to clear the back buffer without
4074 * interfering with the front buffer, other than passing XdbeBackground
4075 * to XdbeSwapBuffers. That means that if we're using XDBE, we need to
4076 * redraw the text even if it wasn't part of the exposed area. OTOH,
4077 * if we're not going to call draw_stuff at all, then no swap happens
4078 * and we can safely do nothing.
4081 if (!XEmptyRegion(region)) {
4085 r.x = text_start_x - border_margin;
4086 r.y = text_start_y - border_margin;
4087 r.width = text_width + border_margin * 2;
4088 r.height = text_height + border_margin * 2;
4089 XUnionRectWithRegion(&r, region, region);
4092 XSetRegion(display, window.gc, region);
4095 XftDrawSetClip(window.xftdraw, region);
4101 XDestroyRegion(region);
4102 region = XCreateRegion();
4109 static void load_config_file(const char *);
4111 /* signal handler that reloads config file */
4112 static void reload_handler(int a)
4114 ERR("Conky: received signal %d, reloading config\n", a);
4116 if (current_config) {
4118 load_config_file(current_config);
4123 extract_variable_text(text);
4130 static void clean_up()
4135 XdbeDeallocateBackBufferName(display, window.back_buffer);
4140 XDestroyWindow(display, window.window);
4144 XClearWindow(display, RootWindow(display, screen));
4149 XFreeGC(display, window.gc);
4153 /* it is really pointless to free() memory at the end of program but ak|ra
4154 * wants me to do this */
4156 free_text_objects();
4158 if (text != original_text)
4161 free(current_config);
4162 free(current_mail_spool);
4168 static void term_handler(int a)
4170 a = a; /* to get rid of warning */
4175 static int string_to_bool(const char *s)
4179 if (strcasecmp(s, "yes") == 0)
4181 if (strcasecmp(s, "true") == 0)
4183 if (strcasecmp(s, "1") == 0)
4188 static enum alignment string_to_alignment(const char *s)
4190 if (strcasecmp(s, "top_left") == 0)
4192 else if (strcasecmp(s, "top_right") == 0)
4194 else if (strcasecmp(s, "bottom_left") == 0)
4196 else if (strcasecmp(s, "bottom_right") == 0)
4197 return BOTTOM_RIGHT;
4198 else if (strcasecmp(s, "tl") == 0)
4200 else if (strcasecmp(s, "tr") == 0)
4202 else if (strcasecmp(s, "bl") == 0)
4204 else if (strcasecmp(s, "br") == 0)
4205 return BOTTOM_RIGHT;
4206 else if (strcasecmp(s, "none") == 0)
4213 static void set_default_configurations(void)
4215 fork_to_background = 0;
4216 total_run_times = 0;
4217 info.cpu_avg_samples = 2;
4218 info.net_avg_samples = 2;
4223 strcpy(info.mpd.host, "localhost");
4224 info.mpd.port = 6600;
4225 info.mpd.status = "Checking status...";
4234 default_fg_color = WhitePixel(display, screen);
4235 default_bg_color = BlackPixel(display, screen);
4236 default_out_color = BlackPixel(display, screen);
4240 set_first_font("6x10");
4249 stippled_borders = 0;
4252 text_alignment = BOTTOM_LEFT;
4256 free(current_mail_spool);
4259 variable_substitute(MAIL_FILE, buf, 256);
4261 current_mail_spool = strdup(buf);
4265 update_interval = 10.0;
4266 stuff_in_upper_case = 0;
4268 mlconfig.mldonkey_hostname = strdup("127.0.0.1");
4269 mlconfig.mldonkey_port = 4001;
4270 mlconfig.mldonkey_login = NULL;
4271 mlconfig.mldonkey_password = NULL;
4275 static void load_config_file(const char *f)
4277 #define CONF_ERR ERR("%s: %d: config file error", f, line)
4281 set_default_configurations();
4283 fp = open_file(f, 0);
4288 char buf[256], *p, *p2, *name, *value;
4290 if (fgets(buf, 256, fp) == NULL)
4295 /* break at comment */
4296 p2 = strchr(p, '#');
4301 while (*p && isspace((int) *p))
4304 continue; /* empty line */
4310 while (*p2 && !isspace((int) *p2))
4313 *p2 = '\0'; /* break at name's end */
4320 while (*p && isspace((int) *p))
4325 p2 = value + strlen(value);
4326 while (isspace((int) *(p2 - 1)))
4332 #define CONF2(a) if (strcasecmp(name, a) == 0)
4333 #define CONF(a) else CONF2(a)
4334 #define CONF3(a,b) \
4335 else if (strcasecmp(name, a) == 0 || strcasecmp(name, b) == 0)
4339 CONF2("alignment") {
4341 int a = string_to_alignment(value);
4351 on_bottom = string_to_bool(value);
4355 CONF("background") {
4356 fork_to_background = string_to_bool(value);
4360 CONF2("background") {
4361 fork_to_background = string_to_bool(value);
4365 CONF("border_margin") {
4367 border_margin = strtol(value, 0, 0);
4371 CONF("border_width") {
4373 border_width = strtol(value, 0, 0);
4377 CONF("default_color") {
4379 default_fg_color = get_x11_color(value);
4383 CONF3("default_shade_color", "default_shadecolor") {
4385 default_bg_color = get_x11_color(value);
4389 CONF3("default_outline_color", "default_outlinecolor") {
4391 default_out_color = get_x11_color(value);
4399 strcpy(info.mpd.host, value);
4405 info.mpd.port = strtol(value, 0, 0);
4406 if (info.mpd.port < 1
4407 || info.mpd.port > 0xffff)
4412 CONF("cpu_avg_samples") {
4414 cpu_avg_samples = strtol(value, 0, 0);
4415 if (cpu_avg_samples < 1
4416 || cpu_avg_samples > 14)
4425 CONF("net_avg_samples") {
4427 net_avg_samples = strtol(value, 0, 0);
4428 if (net_avg_samples < 1
4429 || net_avg_samples > 14)
4445 CONF("double_buffer") {
4446 use_xdbe = string_to_bool(value);
4450 CONF("override_utf8_locale") {
4451 utf8_mode = string_to_bool(value);
4454 CONF("draw_borders") {
4455 draw_borders = string_to_bool(value);
4457 CONF("draw_shades") {
4458 draw_shades = string_to_bool(value);
4460 CONF("draw_outline") {
4461 draw_outline = string_to_bool(value);
4464 CONF("out_to_console") {
4465 out_to_console = string_to_bool(value);
4467 CONF("use_spacer") {
4468 use_spacer = string_to_bool(value);
4473 use_xft = string_to_bool(value);
4478 set_first_font(value);
4484 if (value && font_count >= 0)
4485 fonts[0].font_alpha = atof(value)
4493 if (string_to_bool(value))
4494 ERR("Xft not enabled");
4497 /* xftfont silently ignored when no Xft */
4500 /* xftalpha is silently ignored when no Xft */
4505 set_first_font(value);
4511 gap_x = atoi(value);
4517 gap_y = atoi(value);
4522 CONF("mail_spool") {
4525 variable_substitute(value, buf, 256);
4529 if (current_mail_spool)
4530 free(current_mail_spool);
4531 current_mail_spool = strdup(buf);
4537 CONF("minimum_size") {
4540 (value, "%d %d", &minimum_width,
4541 &minimum_height) != 2)
4544 &minimum_width) != 1)
4549 CONF("maximum_width") {
4551 if (sscanf(value, "%d", &maximum_width) != 1)
4557 CONF("no_buffers") {
4558 no_buffers = string_to_bool(value);
4561 CONF("mldonkey_hostname") {
4563 if (mlconfig.mldonkey_hostname != NULL) {
4564 free(mlconfig.mldonkey_hostname);
4566 mlconfig.mldonkey_hostname = strdup(value);
4571 CONF("mldonkey_port") {
4573 mlconfig.mldonkey_port = atoi(value);
4577 CONF("mldonkey_login") {
4579 if (mlconfig.mldonkey_login != NULL) {
4580 free(mlconfig.mldonkey_login);
4582 mlconfig.mldonkey_login = strdup(value);
4587 CONF("mldonkey_password") {
4589 if (mlconfig.mldonkey_password != NULL) {
4590 free(mlconfig.mldonkey_password);
4592 mlconfig.mldonkey_password = strdup(value);
4598 CONF("pad_percents") {
4599 pad_percents = atoi(value);
4603 CONF("own_window") {
4604 own_window = string_to_bool(value);
4606 CONF("own_window_transparent") {
4607 set_transparent = string_to_bool(value);
4609 CONF("own_window_colour") {
4610 background_colour = get_x11_color(value);
4613 CONF("stippled_borders") {
4615 stippled_borders = strtol(value, 0, 0);
4617 stippled_borders = 4;
4621 ERR("temp1 configuration is obsolete, use ${i2c <i2c device here> temp 1}");
4624 ERR("temp2 configuration is obsolete, use ${i2c <i2c device here> temp 2}");
4626 CONF("update_interval") {
4628 update_interval = strtod(value, 0);
4632 CONF("total_run_times") {
4634 total_run_times = strtod(value, 0);
4639 stuff_in_upper_case = string_to_bool(value);
4644 malloc(strlen(value)
4646 strcpy(seti_dir, value);
4650 if (text != original_text)
4660 int l = strlen(text);
4661 if (fgets(buf, 256, fp) == NULL)
4664 realloc(text, l + strlen(buf)
4668 if (strlen(text) > 1024 * 8)
4675 ERR("%s: %d: no such configuration: '%s'", f, line, name);
4685 /* : means that character before that takes an argument */
4686 static const char *getopt_string = "vVdt:f:u:i:hc:w:x:y:a:"
4699 int main(int argc, char **argv)
4701 /* handle command line parameters that don't change configs */
4707 if (((s = getenv("LC_ALL")) && *s) || ((s = getenv("LC_CTYPE")) &&
4708 *s) || ((s = getenv("LANG")) && *s)) {
4710 for(x = 0; x < strlen(s) ; x++) {
4711 temp[x] = tolower(s[x]);
4713 if (strstr(temp, "utf-8") || strstr(temp, "utf8")) {
4717 if (!setlocale(LC_CTYPE, "")) {
4718 ERR("Can't set the specified locale!\nCheck LANG, LC_CTYPE, LC_ALL.");
4723 int c = getopt(argc,
4733 ("Conky " VERSION " compiled " __DATE__ "\n");
4737 /* if current_config is set to a strdup of CONFIG_FILE, free it (even
4738 * though free() does the NULL check itself;), then load optarg value */
4740 free(current_config);
4741 current_config = strdup(optarg);
4746 ("Usage: %s [OPTION]...\n"
4747 "Conky is a system monitor that renders text on desktop or to own transparent\n"
4748 "window. Command line options will override configurations defined in config\n"
4751 " -c FILE config file to load instead of "
4754 " -d daemonize, fork to background\n"
4757 " -a ALIGNMENT text alignment on screen, {top,bottom}_{left,right}\n"
4758 " -f FONT font to use\n"
4760 " -o create own window to draw\n"
4763 " -b double buffer (prevents flickering)\n"
4765 " -w WIN_ID window id to draw\n"
4766 " -x X x position\n"
4767 " -y Y y position\n"
4769 " -t TEXT text to render, remember single quotes, like -t '$uptime'\n"
4770 " -u SECS update interval\n"
4771 " -i NUM number of times to update Conky\n", argv[0]);
4775 window.window = strtol(optarg, 0, 0);
4784 /* initalize X BEFORE we load config. (we need to so that 'screen' is set) */
4788 tmpstring1 = (char *)
4789 malloc(TEXT_BUFFER_SIZE);
4790 tmpstring2 = (char *)
4791 malloc(TEXT_BUFFER_SIZE);
4793 /* load current_config or CONFIG_FILE */
4796 if (current_config == NULL) {
4797 /* load default config file */
4800 variable_substitute(CONFIG_FILE, buf, 256);
4803 current_config = strdup(buf);
4807 if (current_config != NULL && fopen((const char *)current_config, (const char *)"r"))
4808 load_config_file(current_config);
4810 set_default_configurations();
4814 if (current_mail_spool == NULL) {
4816 variable_substitute(MAIL_FILE, buf, 256);
4819 current_mail_spool = strdup(buf);
4823 /* handle other command line arguments */
4825 #if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__NetBSD__)
4826 optind = optreset = 1;
4832 int c = getopt(argc,
4840 fork_to_background = 1;
4845 set_first_font(optarg);
4848 text_alignment = string_to_alignment(optarg);
4863 if (text != original_text)
4865 text = strdup(optarg);
4866 convert_escapes(text);
4870 update_interval = strtod(optarg, 0);
4874 total_run_times = strtod(optarg, 0);
4878 gap_x = atoi(optarg);
4882 gap_y = atoi(optarg);
4896 /* generate text and get initial size */
4897 extract_variable_text(text);
4898 if (text != original_text) {
4907 update_text_area(); /* to get initial size of the window */
4909 #if defined OWN_WINDOW
4912 text_width + border_margin * 2 + 1,
4913 text_height + border_margin * 2 + 1,
4914 on_bottom, fixed_pos, set_transparent, background_colour);
4918 text_width + border_margin * 2 + 1,
4919 text_height + border_margin * 2 + 1,
4920 on_bottom, set_transparent, background_colour);
4924 update_text_area(); /* to position text/window on screen */
4928 // why the fuck not?
4934 if (own_window && !fixed_pos) {
4935 XMoveWindow(display, window.window, window.x, window.y);
4938 set_transparent_background(window.window);
4949 if (fork_to_background) {
4953 ERR("can't fork() to background: %s",
4963 "Conky: forked to background, pid is %d\n",
4969 /* set SIGUSR1, SIGINT and SIGTERM handlers */
4974 sa.sa_handler = reload_handler;
4975 sigemptyset(&sa.sa_mask);
4976 sa.sa_flags = SA_RESTART;
4977 if (sigaction(SIGUSR1, &sa, NULL) != 0)
4978 ERR("can't set signal handler for SIGUSR1: %s",
4981 sa.sa_handler = term_handler;
4982 sigemptyset(&sa.sa_mask);
4983 sa.sa_flags = SA_RESTART;
4984 if (sigaction(SIGINT, &sa, NULL) != 0)
4985 ERR("can't set signal handler for SIGINT: %s",
4988 sa.sa_handler = term_handler;
4989 sigemptyset(&sa.sa_mask);
4990 sa.sa_flags = SA_RESTART;
4991 if (sigaction(SIGTERM, &sa, NULL) != 0)
4992 ERR("can't set signal handler for SIGTERM: %s",