1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
3 * Conky, a system monitor, based on torsmo
5 * Any original torsmo code is licensed under the BSD license
7 * All code written since the fork of torsmo is licensed under the GPL
9 * Please see COPYING for details
11 * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
12 * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
14 * All rights reserved.
16 * This program is free software: you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation, either version 3 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28 * vim: ts=4 sw=4 noet ai cindent syntax=c
36 #include "text_object.h"
37 #include "obj_destroy.h"
42 #include <sys/types.h>
47 static void X11_initialisation(conky_context *ctx);
49 /* display to connect to */
50 static char *disp = NULL;
54 /* path to config file */
57 /* set to 1 if you want all text to be in uppercase */
58 static unsigned int stuff_in_uppercase;
60 /* Run how many times? */
61 static unsigned long total_run_times;
64 static int fork_to_background;
66 static int cpu_avg_samples, net_avg_samples, diskio_avg_samples;
68 /* filenames for output */
69 char *overwrite_file = NULL; FILE *overwrite_fpointer = NULL;
70 char *append_file = NULL; FILE *append_fpointer = NULL;
74 static int show_graph_scale;
75 static int show_graph_range;
77 /* Position on the screen */
78 static int text_alignment;
79 static int gap_x, gap_y;
82 static int draw_borders;
83 static int draw_graph_borders;
84 static int stippled_borders;
86 int get_stippled_borders(void)
88 return stippled_borders;
91 static int draw_shades, draw_outline;
93 long default_fg_color, default_bg_color, default_out_color;
95 /* create own window or draw stuff to root? */
96 static int set_transparent = 0;
99 static int own_window = 0;
100 static int background_colour = 0;
102 /* fixed size/pos is set if wm/user changes them */
103 static int fixed_size = 0, fixed_pos = 0;
106 static int minimum_width, minimum_height;
107 static int maximum_width;
112 static int sensor_device;
115 long color0, color1, color2, color3, color4, color5, color6, color7, color8,
118 static char *template[MAX_TEMPLATES];
120 char **get_templates(void)
125 /* maximum size of config TEXT buffer, i.e. below TEXT line. */
126 unsigned int max_user_text;
128 /* maximum size of individual text buffers, ie $exec buffer size */
129 unsigned int text_buffer_size = DEFAULT_TEXT_BUFFER_SIZE;
134 /* no buffers in used memory? */
137 /* pad percentages to decimals? */
138 static int pad_percents = 0;
140 static char *global_text = 0;
142 char *get_global_text(void)
147 long global_text_lines;
149 static int total_updates;
150 static int updatereset;
152 void set_updatereset(int i)
157 int get_updatereset(void)
162 int check_contains(char *f, char *s)
165 FILE *where = open_file(f, 0);
170 while (fgets(buf1, 256, where)) {
171 if (strstr(buf1, s)) {
178 NORM_ERR("Could not open the file");
185 static inline int calc_text_width(conky_context *ctx, const char *s, int l)
187 if ((ctx->output_methods & TO_X) == 0) {
195 XftTextExtentsUtf8(display, ctx->fonts[ctx->selected_font].xftfont,
196 (const FcChar8 *) s, l, &gi);
198 XftTextExtents8(display, ctx->fonts[ctx->selected_font].xftfont,
199 (const FcChar8 *) s, l, &gi);
205 return XTextWidth(ctx->fonts[ctx->selected_font].font, s, l);
210 /* quite boring functions */
212 static inline void for_each_line(char *b, int f(char *, int))
215 int special_index = 0; /* specials index */
217 for (ps = b, pe = b; *pe; pe++) {
220 special_index = f(ps, special_index);
227 f(ps, special_index);
231 void convert_escapes(char *buf)
233 char *p = buf, *s = buf;
240 } else if (*s == '\\') {
251 /* global object list root element */
252 static struct text_object global_root_object;
254 /* our own implementation of popen, the difference : the value of 'childpid'
255 * will be filled with the pid of the running 'command'. This is useful if want
256 * to kill it when it hangs while reading or writing to it. We have to kill it
257 * because pclose will wait until the process dies by itself */
258 FILE* pid_popen(const char *command, const char *mode, pid_t *child)
261 int parentend, childend;
263 /* by running pipe after the strcmp's we make sure that we don't have to
264 * create a pipe and close the ends if mode is something illegal */
265 if(strcmp(mode, "r") == 0) {
266 if(pipe(ends) != 0) {
271 } else if(strcmp(mode, "w") == 0) {
272 if(pipe(ends) != 0) {
285 } else if(*child > 0) {
287 waitpid(*child, NULL, 0);
289 /* don't read from both stdin and pipe or write to both stdout and pipe */
290 if(childend == ends[0]) {
295 dup(childend); /* by dupping childend, the returned fd will have close-on-exec turned off */
296 execl("/bin/sh", "sh", "-c", command, (char *) NULL);
297 _exit(EXIT_FAILURE); /* child should die here, (normally execl will take care of this but it can fail) */
299 return fdopen(parentend, mode);
302 void read_exec(const char *data, char *buf, const int size)
307 fp = pid_popen(data, "r", &childpid);
311 length = fread(buf, 1, size, fp);
314 if (length > 0 && buf[length - 1] == '\n') {
315 buf[length - 1] = '\0';
322 void *threaded_exec(void *, void *) __attribute__((noreturn));
324 void *threaded_exec(void *arg1, void *arg2)
327 struct text_object *obj = (struct text_object *)arg2;
328 conky_context *ctx = (conky_context *)arg1;
331 buff = malloc(text_buffer_size);
332 read_exec(obj->data.texeci.cmd, buff,
333 ctx->text_buffer_size);
341 timed_thread_lock(obj->data.texeci.p_timed_thread);
342 strncpy(obj->data.texeci.buffer, buff, text_buffer_size);
343 timed_thread_unlock(obj->data.texeci.p_timed_thread);
345 if (timed_thread_test(obj->data.texeci.p_timed_thread, 0)) {
346 timed_thread_exit(obj->data.texeci.p_timed_thread);
352 static long current_text_color;
354 void set_current_text_color(long colour)
356 current_text_color = colour;
359 long get_current_text_color(void)
361 return current_text_color;
364 //adds newstring to to the tree unless you can already see it when travelling back.
365 //if it's possible to attach it then it returns a pointer to the leaf, else it returns NULL
366 struct conftree* conftree_add(struct conftree* previous, const char* newstring) {
367 struct conftree* node;
368 struct conftree* node2;
370 for(node = previous; node != NULL; node = node->back) {
371 if(strcmp(node->string, newstring) == 0) {
375 node = malloc(sizeof(struct conftree));
376 if (previous != NULL) {
377 if(previous->vert_next == NULL) {
378 previous->vert_next = node;
380 for(node2 = previous->vert_next; node2->horz_next != NULL; node2 = node2->horz_next ) { }
381 node2->horz_next = node;
384 node->string = strdup(newstring);
385 node->horz_next = NULL;
386 node->vert_next = NULL;
387 node->back = previous;
391 void conftree_empty(struct conftree* tree) {
393 conftree_empty(tree->horz_next);
394 conftree_empty(tree->vert_next);
400 struct conftree *currentconffile;
402 void extract_variable_text(conky_context *ctx, const char *p)
404 free_text_objects(&global_root_object, 0);
405 if (ctx->tmpstring1) {
406 free(ctx->tmpstring1);
409 if (ctx->tmpstring2) {
410 free(ctx->tmpstring2);
413 if (ctx->text_buffer) {
414 free(ctx->text_buffer);
415 ctx->text_buffer = 0;
418 extract_variable_text_internal(ctx, &global_root_object, p);
421 void parse_conky_vars(ctx, struct text_object *root, const char *txt, char *p)
423 extract_variable_text_internal(ctx, root, txt);
424 generate_text_internal(ctx, p, max_user_text, *root);
427 static inline struct mail_s *ensure_mail_thread(struct text_object *obj,
428 void *thread(void *), const char *text)
430 if (obj->char_b && ctx->info.mail) {
431 /* this means we use ctx->info */
432 if (!ctx->info.mail->p_timed_thread) {
433 ctx->info.mail->p_timed_thread =
434 timed_thread_create(thread,
435 (void *) ctx->info.mail, ctx->info.mail->interval * 1000000);
436 if (!ctx->info.mail->p_timed_thread) {
437 NORM_ERR("Error creating %s timed thread", text);
439 timed_thread_register(ctx->info.mail->p_timed_thread,
440 &ctx->info.mail->p_timed_thread);
441 if (timed_thread_run(ctx->info.mail->p_timed_thread)) {
442 NORM_ERR("Error running %s timed thread", text);
445 return ctx->info.mail;
446 } else if (obj->data.mail) {
447 // this means we use obj
448 if (!obj->data.mail->p_timed_thread) {
449 obj->data.mail->p_timed_thread =
450 timed_thread_create(thread,
451 (void *) obj->data.mail,
452 obj->data.mail->interval * 1000000);
453 if (!obj->data.mail->p_timed_thread) {
454 NORM_ERR("Error creating %s timed thread", text);
456 timed_thread_register(obj->data.mail->p_timed_thread,
457 &obj->data.mail->p_timed_thread);
458 if (timed_thread_run(obj->data.mail->p_timed_thread)) {
459 NORM_ERR("Error running %s timed thread", text);
462 return obj->data.mail;
463 } else if (!obj->a) {
464 // something is wrong, warn once then stop
465 NORM_ERR("There's a problem with your mail settings. "
466 "Check that the global mail settings are properly defined"
467 " (line %li).", obj->line);
473 static void generate_text(void)
475 struct information *cur = &ctx->info;
480 /* update ctx->info */
482 ctx->current_update_time = get_time();
486 /* add things to the buffer */
490 p = ctx->text_buffer;
492 generate_text_internal(ctx, p, max_user_text, global_root_object);
494 if (stuff_in_uppercase) {
497 tmp_p = ctx->text_buffer;
499 *tmp_p = toupper(*tmp_p);
504 ctx->next_update_time += ctx->update_interval;
505 if (ctx->next_update_time < get_time()) {
506 ctx->next_update_time = get_time() + ctx->update_interval;
507 } else if (ctx->next_update_time > get_time() + ctx->update_interval) {
508 ctx->next_update_time = get_time() + ctx->update_interval;
510 ctx->last_update_time = ctx->current_update_time;
511 ctx->total_updates++;
514 void set_update_interval(conky_context *ctx, double interval)
516 ctx->update_interval = interval;
517 ctx->update_interval_old = interval;
520 static inline int get_string_width(const char *s)
523 if (ctx->output_methods & TO_X) {
524 return *s ? calc_text_width(s, strlen(s)) : 0;
531 static int get_string_width_special(char *s, int special_index)
538 if ((ctx->output_methods & TO_X) == 0) {
539 return (s) ? strlen(s) : 0;
546 p = strndup(s, text_buffer_size);
550 if (*p == SPECIAL_CHAR) {
551 /* shift everything over by 1 so that the special char
552 * doesn't mess up the size calculation */
553 for (i = 0; i < (long)strlen(p); i++) {
554 *(p + i) = *(p + i + 1);
556 if (specials[special_index + idx].type == GRAPH
557 || specials[special_index + idx].type == GAUGE
558 || specials[special_index + idx].type == BAR) {
559 width += specials[special_index + idx].width;
562 } else if (*p == SECRIT_MULTILINE_CHAR) {
569 if (strlen(final) > 1) {
570 width += calc_text_width(final, strlen(final));
576 static int text_size_updater(char *s, int special_index);
578 void update_text_area(conky_context *ctx)
582 if ((ctx->output_methods & TO_X) == 0)
584 /* update text size if it isn't fixed */
589 text_width = minimum_width;
591 last_font_height = font_height();
592 for_each_line(ctx->text_buffer, text_size_updater);
594 if (text_height < minimum_height) {
595 text_height = minimum_height;
597 if (text_width > maximum_width && maximum_width > 0) {
598 text_width = maximum_width;
602 /* get text position on workarea */
603 switch (text_alignment) {
610 x = workarea[2] - text_width - gap_x;
615 x = workarea[2] / 2 - text_width / 2 - gap_x;
622 y = workarea[3] - text_height - gap_y;
626 x = workarea[2] - text_width - gap_x;
627 y = workarea[3] - text_height - gap_y;
631 x = workarea[2] / 2 - text_width / 2 - gap_x;
632 y = workarea[3] - text_height - gap_y;
637 y = workarea[3] / 2 - text_height / 2 - gap_y;
641 x = workarea[2] - text_width - gap_x;
642 y = workarea[3] / 2 - text_height / 2 - gap_y;
646 case NONE: // Let the WM manage the window
657 if (own_window && !fixed_pos) {
660 text_start_x = window.border_inner_margin + window.border_outer_margin + window.border_width;
661 text_start_y = window.border_inner_margin + window.border_outer_margin + window.border_width;
662 window.x = x - window.border_inner_margin - window.border_outer_margin - window.border_width;
663 window.y = y - window.border_inner_margin - window.border_outer_margin - window.border_width;
667 /* If window size doesn't match to workarea's size,
668 * then window probably includes panels (gnome).
669 * Blah, doesn't work on KDE. */
670 if (workarea[2] != window.width || workarea[3] != window.height) {
679 /* update lua window globals */
680 llua_update_window_table(text_start_x, text_start_y, text_width, text_height);
681 #endif /* HAVE_LUA */
686 static int cur_x, cur_y; /* current x and y for drawing */
688 //draw_mode also without X11 because we only need to print to stdout with FG
689 static int draw_mode; /* FG, BG or OUTLINE */
691 static long current_color;
693 static int text_size_updater(char *s, int special_index)
698 if ((ctx->output_methods & TO_X) == 0)
700 /* get string widths and skip specials */
703 if (*p == SPECIAL_CHAR) {
705 w += get_string_width(s);
708 if (specials[special_index].type == BAR
709 || specials[special_index].type == GAUGE
710 || specials[special_index].type == GRAPH) {
711 w += specials[special_index].width;
712 if (specials[special_index].height > last_font_height) {
713 last_font_height = specials[special_index].height;
714 last_font_height += font_height();
716 } else if (specials[special_index].type == OFFSET) {
717 if (specials[special_index].arg > 0) {
718 w += specials[special_index].arg;
720 } else if (specials[special_index].type == VOFFSET) {
721 last_font_height += specials[special_index].arg;
722 } else if (specials[special_index].type == GOTO) {
723 if (specials[special_index].arg > cur_x) {
724 w = (int) specials[special_index].arg;
726 } else if (specials[special_index].type == TAB) {
727 int start = specials[special_index].arg;
728 int step = specials[special_index].width;
730 if (!step || step < 0) {
733 w += step - (cur_x - text_start_x - start) % step;
734 } else if (specials[special_index].type == FONT) {
735 ctx->selected_font = specials[special_index].font_added;
736 if (font_height() > last_font_height) {
737 last_font_height = font_height();
743 } else if (*p == SECRIT_MULTILINE_CHAR) {
746 lw = get_string_width(s);
747 *p = SECRIT_MULTILINE_CHAR;
750 text_height += last_font_height;
754 w += get_string_width(s);
755 if (w > text_width) {
758 if (text_width > maximum_width && maximum_width) {
759 text_width = maximum_width;
762 text_height += last_font_height;
763 last_font_height = font_height();
764 return special_index;
768 static inline void set_foreground_color(long c)
771 if (ctx->output_methods & TO_X) {
773 XSetForeground(display, window.gc, c);
777 if (ctx->output_methods & TO_NCURSES) {
778 attron(COLOR_PAIR(c));
785 static void draw_string(const char *s)
787 int i, i2, pos, width_of_s;
790 char *s_with_newlines;
796 width_of_s = get_string_width(s);
797 s_with_newlines = strdup(s);
798 for(i = 0; i < (int) strlen(s_with_newlines); i++) {
799 if(s_with_newlines[i] == SECRIT_MULTILINE_CHAR) {
800 s_with_newlines[i] = '\n';
803 if ((ctx->output_methods & TO_STDOUT) && draw_mode == FG) {
804 printf("%s\n", s_with_newlines);
805 if (extra_newline) fputc('\n', stdout);
806 fflush(stdout); /* output immediately, don't buffer */
808 if ((ctx->output_methods & TO_STDERR) && draw_mode == FG) {
809 fprintf(stderr, "%s\n", s_with_newlines);
810 fflush(stderr); /* output immediately, don't buffer */
812 if ((ctx->output_methods & OVERWRITE_FILE) && draw_mode == FG && overwrite_fpointer) {
813 fprintf(overwrite_fpointer, "%s\n", s_with_newlines);
815 if ((ctx->output_methods & APPEND_FILE) && draw_mode == FG && append_fpointer) {
816 fprintf(append_fpointer, "%s\n", s_with_newlines);
819 if ((ctx->output_methods & TO_NCURSES) && draw_mode == FG) {
820 printw("%s", s_with_newlines);
823 free(s_with_newlines);
824 memset(ctx->tmpstring1, 0, text_buffer_size);
825 memset(ctx->tmpstring2, 0, text_buffer_size);
826 strncpy(ctx->tmpstring1, s, text_buffer_size - 1);
831 if (ctx->output_methods & TO_X) {
832 max = ((text_width - width_of_s) / get_string_width(" "));
835 /* This code looks for tabs in the text and coverts them to spaces.
836 * The trick is getting the correct number of spaces, and not going
837 * over the window's size without forcing the window larger. */
838 for (i = 0; i < (int) text_buffer_size; i++) {
839 if (ctx->tmpstring1[i] == '\t') {
841 for (i2 = 0; i2 < (8 - (1 + pos) % 8) && added <= max; i2++) {
842 /* guard against overrun */
843 ctx->tmpstring2[MIN(pos + i2, (int)text_buffer_size - 1)] = ' ';
848 /* guard against overrun */
849 ctx->tmpstring2[MIN(pos, (int) text_buffer_size - 1)] = ctx->tmpstring1[i];
854 if (ctx->output_methods & TO_X) {
855 if (text_width == maximum_width) {
856 /* this means the text is probably pushing the limit,
857 * so we'll chop it */
858 while (cur_x + get_string_width(ctx->tmpstring2) - text_start_x
859 > maximum_width && strlen(ctx->tmpstring2) > 0) {
860 ctx->tmpstring2[strlen(ctx->tmpstring2) - 1] = '\0';
867 if (ctx->output_methods & TO_X) {
873 c.pixel = current_color;
874 XQueryColor(display, DefaultColormap(display, screen), &c);
877 c2.color.red = c.red;
878 c2.color.green = c.green;
879 c2.color.blue = c.blue;
880 c2.color.alpha = ctx->fonts[ctx->selected_font].font_alpha;
882 XftDrawStringUtf8(window.xftdraw, &c2, ctx->fonts[ctx->selected_font].xftfont,
883 cur_x, cur_y, (const XftChar8 *) s, strlen(s));
885 XftDrawString8(window.xftdraw, &c2, ctx->fonts[ctx->selected_font].xftfont,
886 cur_x, cur_y, (const XftChar8 *) s, strlen(s));
891 XDrawString(display, window.drawable, window.gc, cur_x, cur_y, s,
897 memcpy(ctx->tmpstring1, s, text_buffer_size);
900 int draw_each_line_inner(char *s, int special_index, int last_special_applied)
903 int font_h = font_height();
908 int last_special_needed = -1;
909 int orig_special_index = special_index;
912 cur_x = text_start_x;
913 cur_y += font_ascent();
917 if (*p == SECRIT_MULTILINE_CHAR) {
918 /* special newline marker for multiline objects */
923 if (*p == SPECIAL_CHAR || last_special_applied > -1) {
928 /* draw string before special, unless we're dealing multiline
930 if (last_special_applied > -1) {
931 special_index = last_special_applied;
939 switch (specials[special_index].type) {
941 case HORIZONTAL_LINE:
943 int h = specials[special_index].height;
944 int mid = font_ascent() / 2;
946 w = text_start_x + text_width - cur_x;
948 XSetLineAttributes(display, window.gc, h, LineSolid,
950 XDrawLine(display, window.drawable, window.gc, cur_x,
951 cur_y - mid / 2, cur_x + w, cur_y - mid / 2);
957 int h = specials[special_index].height;
958 int tmp_s = specials[special_index].arg;
959 int mid = font_ascent() / 2;
960 char ss[2] = { tmp_s, tmp_s };
962 w = text_start_x + text_width - cur_x - 1;
963 XSetLineAttributes(display, window.gc, h, LineOnOffDash,
965 XSetDashes(display, window.gc, 0, ss, 2);
966 XDrawLine(display, window.drawable, window.gc, cur_x,
967 cur_y - mid / 2, cur_x + w, cur_y - mid / 2);
973 int h, bar_usage, by;
974 if (cur_x - text_start_x > maximum_width
975 && maximum_width > 0) {
978 h = specials[special_index].height;
979 bar_usage = specials[special_index].arg;
980 by = cur_y - (font_ascent() / 2) - 1;
985 w = specials[special_index].width;
987 w = text_start_x + text_width - cur_x - 1;
993 XSetLineAttributes(display, window.gc, 1, LineSolid,
996 XDrawRectangle(display, window.drawable, window.gc, cur_x,
998 XFillRectangle(display, window.drawable, window.gc, cur_x,
999 by, w * bar_usage / 255, h);
1007 case GAUGE: /* new GAUGE */
1010 unsigned long last_colour = current_color;
1012 float angle, px, py;
1016 if (cur_x - text_start_x > maximum_width
1017 && maximum_width > 0) {
1021 h = specials[special_index].height;
1022 by = cur_y - (font_ascent() / 2) - 1;
1027 w = specials[special_index].width;
1029 w = text_start_x + text_width - cur_x - 1;
1035 XSetLineAttributes(display, window.gc, 1, LineSolid,
1036 CapButt, JoinMiter);
1038 XDrawArc(display, window.drawable, window.gc,
1039 cur_x, by, w, h * 2, 0, 180*64);
1042 usage = specials[special_index].arg;
1043 angle = (M_PI)*(float)(usage)/255.;
1044 px = (float)(cur_x+(w/2.))-(float)(w/2.)*cos(angle);
1045 py = (float)(by+(h))-(float)(h)*sin(angle);
1047 XDrawLine(display, window.drawable, window.gc,
1048 cur_x + (w/2.), by+(h), (int)(px), (int)(py));
1056 set_foreground_color(last_colour);
1064 int h, by, i = 0, j = 0;
1066 unsigned long last_colour = current_color;
1067 unsigned long *tmpcolour = 0;
1068 if (cur_x - text_start_x > maximum_width
1069 && maximum_width > 0) {
1072 h = specials[special_index].height;
1073 by = cur_y - (font_ascent() / 2) - 1;
1078 w = specials[special_index].width;
1080 w = text_start_x + text_width - cur_x - 1;
1085 if (draw_graph_borders) {
1086 XSetLineAttributes(display, window.gc, 1, LineSolid,
1087 CapButt, JoinMiter);
1088 XDrawRectangle(display, window.drawable, window.gc,
1091 XSetLineAttributes(display, window.gc, 1, LineSolid,
1092 CapButt, JoinMiter);
1094 if (specials[special_index].last_colour != 0
1095 || specials[special_index].first_colour != 0) {
1096 tmpcolour = do_gradient(w - 1, specials[special_index].last_colour, specials[special_index].first_colour);
1099 for (i = w - 2; i > -1; i--) {
1100 if (specials[special_index].last_colour != 0
1101 || specials[special_index].first_colour != 0) {
1102 if (specials[special_index].tempgrad) {
1105 (int)((float)(w - 2) - specials[special_index].graph[j] *
1106 (w - 2) / (float)specials[special_index].graph_scale)
1110 (int)((float)(w - 2) - specials[special_index].graph[j] *
1111 (w - 2) / (float)specials[special_index].graph_scale)
1114 if (specials[special_index].graph[j] == specials[special_index].graph_scale) {
1116 (int)((float)(w - 2) - specials[special_index].graph[j] *
1117 (w - 2) / (float)specials[special_index].graph_scale)
1121 #endif /* DEBUG_lol */
1122 XSetForeground(display, window.gc, tmpcolour[
1123 (int)((float)(w - 2) - specials[special_index].graph[j] *
1124 (w - 2) / (float)specials[special_index].graph_scale)
1127 XSetForeground(display, window.gc, tmpcolour[colour_idx++]);
1130 /* this is mugfugly, but it works */
1131 XDrawLine(display, window.drawable, window.gc,
1132 cur_x + i + 1, by + h, cur_x + i + 1,
1133 round_to_int((double)by + h - specials[special_index].graph[j] *
1134 (h - 1) / specials[special_index].graph_scale));
1135 if ((w - i) / ((float) (w - 2) /
1136 (specials[special_index].graph_width)) > j
1137 && j < MAX_GRAPH_DEPTH - 3) {
1141 if (tmpcolour) free(tmpcolour);
1146 /* if (draw_mode == BG) {
1147 set_foreground_color(default_bg_color);
1148 } else if (draw_mode == OUTLINE) {
1149 set_foreground_color(default_out_color);
1151 set_foreground_color(default_fg_color);
1153 if (show_graph_range) {
1156 unsigned short int seconds = update_interval * w;
1162 unsigned short int timeunits;
1164 timeunits = seconds / 86400; seconds %= 86400;
1165 if (timeunits > 0) {
1166 asprintf(&tmp_day_str, "%dd", timeunits);
1168 tmp_day_str = strdup("");
1170 timeunits = seconds / 3600; seconds %= 3600;
1171 if (timeunits > 0) {
1172 asprintf(&tmp_hour_str, "%dh", timeunits);
1174 tmp_hour_str = strdup("");
1176 timeunits = seconds / 60; seconds %= 60;
1177 if (timeunits > 0) {
1178 asprintf(&tmp_min_str, "%dm", timeunits);
1180 tmp_min_str = strdup("");
1183 asprintf(&tmp_sec_str, "%ds", seconds);
1185 tmp_sec_str = strdup("");
1187 asprintf(&tmp_str, "%s%s%s%s", tmp_day_str, tmp_hour_str, tmp_min_str, tmp_sec_str);
1188 free(tmp_day_str); free(tmp_hour_str); free(tmp_min_str); free(tmp_sec_str);
1190 asprintf(&tmp_str, "Range not possible"); // should never happen, but better safe then sorry
1192 cur_x += (w / 2) - (font_ascent() * (strlen(tmp_str) / 2));
1193 cur_y += font_h / 2;
1194 draw_string(tmp_str);
1200 if (show_graph_scale && (specials[special_index].show_scale == 1)) {
1204 cur_x += font_ascent() / 2;
1205 cur_y += font_h / 2;
1207 calloc(log10(floor(specials[special_index].graph_scale)) + 4,
1209 sprintf(tmp_str, "%.1f", specials[special_index].graph_scale);
1210 draw_string(tmp_str);
1216 set_foreground_color(last_colour);
1222 int old = font_ascent();
1224 cur_y -= font_ascent();
1225 ctx->selected_font = specials[special_index].font_added;
1227 if (cur_y + font_ascent() < cur_y + old) {
1230 cur_y += font_ascent();
1232 font_h = font_height();
1237 if (draw_mode == FG) {
1238 set_foreground_color(specials[special_index].arg);
1244 if (draw_mode == BG) {
1245 set_foreground_color(specials[special_index].arg);
1250 if (draw_mode == OUTLINE) {
1251 set_foreground_color(specials[special_index].arg);
1256 w += specials[special_index].arg;
1257 last_special_needed = special_index;
1261 cur_y += specials[special_index].arg;
1265 if (specials[special_index].arg >= 0) {
1266 cur_x = (int) specials[special_index].arg;
1268 last_special_needed = special_index;
1273 int start = specials[special_index].arg;
1274 int step = specials[special_index].width;
1276 if (!step || step < 0) {
1279 w = step - (cur_x - text_start_x - start) % step;
1280 last_special_needed = special_index;
1286 /* TODO: add back in "+ window.border_inner_margin" to the end of
1288 int pos_x = text_start_x + text_width -
1289 get_string_width_special(s, special_index);
1291 /* printf("pos_x %i text_start_x %i text_width %i cur_x %i "
1292 "get_string_width(p) %i gap_x %i "
1293 "specials[special_index].arg %i window.border_inner_margin %i "
1294 "window.border_width %i\n", pos_x, text_start_x, text_width,
1295 cur_x, get_string_width_special(s), gap_x,
1296 specials[special_index].arg, window.border_inner_margin,
1297 window.border_width); */
1298 if (pos_x > specials[special_index].arg && pos_x > cur_x) {
1299 cur_x = pos_x - specials[special_index].arg;
1301 last_special_needed = special_index;
1307 int pos_x = (text_width) / 2 - get_string_width_special(s,
1308 special_index) / 2 - (cur_x -
1310 /* int pos_x = text_start_x + text_width / 2 -
1311 get_string_width_special(s) / 2; */
1313 /* printf("pos_x %i text_start_x %i text_width %i cur_x %i "
1314 "get_string_width(p) %i gap_x %i "
1315 "specials[special_index].arg %i\n", pos_x, text_start_x,
1316 text_width, cur_x, get_string_width(s), gap_x,
1317 specials[special_index].arg); */
1318 if (pos_x > specials[special_index].arg) {
1319 w = pos_x - specials[special_index].arg;
1321 last_special_needed = special_index;
1331 if (special_index != last_special_applied) {
1334 special_index = orig_special_index;
1335 last_special_applied = -1;
1346 if (ctx->output_methods & TO_NCURSES) {
1349 #endif /* NCURSES */
1351 cur_y += font_descent();
1353 if (recurse && *recurse) {
1354 special_index = draw_each_line_inner(recurse, special_index, last_special_needed);
1355 *(recurse - 1) = SECRIT_MULTILINE_CHAR;
1357 return special_index;
1360 static int draw_line(char *s, int special_index)
1363 if (ctx->output_methods & TO_X) {
1364 return draw_each_line_inner(s, special_index, -1);
1368 if (ctx->output_methods & TO_NCURSES) {
1369 return draw_each_line_inner(s, special_index, -1);
1371 #endif /* NCURSES */
1373 UNUSED(special_index);
1377 static void draw_text(void)
1381 llua_draw_pre_hook();
1382 #endif /* HAVE_LUA */
1383 if (ctx->output_methods & TO_X) {
1384 cur_y = text_start_y;
1387 if (draw_borders && window.border_width > 0) {
1388 if (stippled_borders) {
1389 char ss[2] = { stippled_borders, stippled_borders };
1390 XSetLineAttributes(display, window.gc, window.border_width, LineOnOffDash,
1391 CapButt, JoinMiter);
1392 XSetDashes(display, window.gc, 0, ss, 2);
1394 XSetLineAttributes(display, window.gc, window.border_width, LineSolid,
1395 CapButt, JoinMiter);
1398 XDrawRectangle(display, window.drawable, window.gc,
1399 text_start_x - window.border_inner_margin - window.border_width,
1400 text_start_y - window.border_inner_margin - window.border_width,
1401 text_width + window.border_inner_margin * 2 + window.border_width * 2,
1402 text_height + window.border_inner_margin * 2 + window.border_width * 2);
1410 init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK);
1411 attron(COLOR_PAIR(COLOR_WHITE));
1412 #endif /* NCURSES */
1413 for_each_line(ctx->text_buffer, draw_line);
1414 #if defined(HAVE_LUA) && defined(X11)
1415 llua_draw_post_hook();
1416 #endif /* HAVE_LUA */
1419 void draw_stuff(conky_context *ctx)
1422 cimlib_render(text_start_x, text_start_y, window.width, window.height);
1424 if (overwrite_file) {
1425 overwrite_fpointer = fopen(overwrite_file, "w");
1426 if(!overwrite_fpointer)
1427 NORM_ERR("Can't overwrite '%s' anymore", overwrite_file);
1430 append_fpointer = fopen(append_file, "a");
1431 if(!append_fpointer)
1432 NORM_ERR("Can't append '%s' anymore", append_file);
1435 if (ctx->output_methods & TO_X) {
1436 ctx->selected_font = 0;
1437 if (draw_shades && !draw_outline) {
1440 set_foreground_color(default_bg_color);
1449 ctx->selected_font = 0;
1451 for (i = -1; i < 2; i++) {
1452 for (j = -1; j < 2; j++) {
1453 if (i == 0 && j == 0) {
1458 set_foreground_color(default_out_color);
1459 draw_mode = OUTLINE;
1467 set_foreground_color(default_fg_color);
1473 xdbe_swap_buffers();
1474 if (ctx->output_methods & TO_X) {
1479 if(overwrite_fpointer) {
1480 fclose(overwrite_fpointer);
1481 overwrite_fpointer = 0;
1483 if(append_fpointer) {
1484 fclose(append_fpointer);
1485 append_fpointer = 0;
1490 void clear_text(conky_context *ctx, int exposures)
1494 /* The swap action is XdbeBackground, which clears */
1498 if (display && window.window) { // make sure these are !null
1499 /* there is some extra space for borders and outlines */
1500 XClearArea(display, window.window, text_start_x - window.border_inner_margin - window.border_outer_margin - window.border_width,
1501 text_start_y - window.border_inner_margin - window.border_outer_margin - window.border_width,
1502 text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2,
1503 text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2, exposures ? True : 0);
1508 /* update_text() generates new text and clears old text area */
1509 void update_text(conky_context *ctx)
1516 if (ctx->output_methods & TO_X)
1519 ctx->need_to_update = 1;
1521 llua_update_info(&ctx->info, update_interval);
1522 #endif /* HAVE_LUA */
1525 void initialisation(conky_context *ctx, int argc, char** argv);
1527 /* reload the config file */
1528 static void reload_config(conky_context *ctx)
1530 char *current_config_copy = strdup(current_config);
1531 clean_up(NULL, NULL);
1532 current_config = current_config_copy;
1533 initialisation(ctx, argc_copy, argv_copy);
1536 void clean_up(void *memtofree1, void *memtofree2)
1541 if(ctx->output_methods & TO_NCURSES) {
1545 conftree_empty(currentconffile);
1546 currentconffile = NULL;
1553 timed_thread_destroy_registered_threads();
1555 if (ctx->info.cpu_usage) {
1556 free(ctx->info.cpu_usage);
1557 ctx->info.cpu_usage = NULL;
1560 if (x_initialised == YES) {
1561 XClearArea(display, window.window, text_start_x - window.border_inner_margin - window.border_outer_margin - window.border_width,
1562 text_start_y - window.border_inner_margin - window.border_outer_margin - window.border_width,
1563 text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2,
1564 text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2, 0);
1567 if(x11_stuff.region) {
1568 XDestroyRegion(x11_stuff.region);
1569 x11_stuff.region = NULL;
1571 XCloseDisplay(display);
1573 if(ctx->info.x11.desktop.all_names) {
1574 free(ctx->info.x11.desktop.all_names);
1575 ctx->info.x11.desktop.all_names = NULL;
1577 if (ctx->info.x11.desktop.name) {
1578 free(ctx->info.x11.desktop.name);
1579 ctx->info.x11.desktop.name = NULL;
1583 free(ctx->fonts); //in set_default_configurations a font is set but not loaded
1589 for (i = 0; i < MAX_TEMPLATES; i++) {
1596 free_text_objects(&global_root_object, 0);
1597 if (ctx->tmpstring1) {
1598 free(ctx->tmpstring1);
1599 ctx->tmpstring1 = 0;
1601 if (ctx->tmpstring2) {
1602 free(ctx->tmpstring2);
1603 ctx->tmpstring2 = 0;
1605 if (ctx->text_buffer) {
1606 free(ctx->text_buffer);
1607 ctx->text_buffer = 0;
1615 free(current_config);
1618 #ifdef TCP_PORT_MONITOR
1619 tcp_portmon_clear();
1628 weather_free_info();
1631 llua_shutdown_hook();
1633 #endif /* HAVE_LUA */
1642 for (i = 0; i < special_count; i++) {
1643 if (specials[i].type == GRAPH) {
1644 free(specials[i].graph);
1652 clear_diskio_stats();
1656 static int string_to_bool(const char *s)
1659 // Assumes an option without a true/false means true
1661 } else if (strcasecmp(s, "yes") == EQUAL) {
1663 } else if (strcasecmp(s, "true") == EQUAL) {
1665 } else if (strcasecmp(s, "1") == EQUAL) {
1672 enum alignment string_to_alignment(const char *s)
1674 if (strcasecmp(s, "top_left") == EQUAL) {
1676 } else if (strcasecmp(s, "top_right") == EQUAL) {
1678 } else if (strcasecmp(s, "top_middle") == EQUAL) {
1680 } else if (strcasecmp(s, "bottom_left") == EQUAL) {
1682 } else if (strcasecmp(s, "bottom_right") == EQUAL) {
1683 return BOTTOM_RIGHT;
1684 } else if (strcasecmp(s, "bottom_middle") == EQUAL) {
1685 return BOTTOM_MIDDLE;
1686 } else if (strcasecmp(s, "middle_left") == EQUAL) {
1688 } else if (strcasecmp(s, "middle_right") == EQUAL) {
1689 return MIDDLE_RIGHT;
1690 } else if (strcasecmp(s, "tl") == EQUAL) {
1692 } else if (strcasecmp(s, "tr") == EQUAL) {
1694 } else if (strcasecmp(s, "tm") == EQUAL) {
1696 } else if (strcasecmp(s, "bl") == EQUAL) {
1698 } else if (strcasecmp(s, "br") == EQUAL) {
1699 return BOTTOM_RIGHT;
1700 } else if (strcasecmp(s, "bm") == EQUAL) {
1701 return BOTTOM_MIDDLE;
1702 } else if (strcasecmp(s, "ml") == EQUAL) {
1704 } else if (strcasecmp(s, "mr") == EQUAL) {
1705 return MIDDLE_RIGHT;
1706 } else if (strcasecmp(s, "none") == EQUAL) {
1714 static void set_default_configurations_for_x(void)
1716 default_fg_color = WhitePixel(display, screen);
1717 default_bg_color = BlackPixel(display, screen);
1718 default_out_color = BlackPixel(display, screen);
1719 color0 = default_fg_color;
1720 color1 = default_fg_color;
1721 color2 = default_fg_color;
1722 color3 = default_fg_color;
1723 color4 = default_fg_color;
1724 color5 = default_fg_color;
1725 color6 = default_fg_color;
1726 color7 = default_fg_color;
1727 color8 = default_fg_color;
1728 color9 = default_fg_color;
1729 current_text_color = default_fg_color;
1733 void set_default_configurations(conky_context *ctx)
1740 ctx->text_buffer_size = DEFAULT_TEXT_BUFFER_SIZE;
1742 ctx->info.cpu_avg_samples = 2;
1743 ctx->info.net_avg_samples = 2;
1744 ctx->info.diskio_avg_samples = 2;
1745 format_human_readable = 1;
1747 mpd_env_host = getenv("MPD_HOST");
1748 mpd_env_port = getenv("MPD_PORT");
1750 if (!mpd_env_host || !strlen(mpd_env_host)) {
1751 mpd_set_host("localhost");
1753 /* MPD_HOST environment variable is set */
1754 char *mpd_hostpart = strchr(mpd_env_host, '@');
1755 if (!mpd_hostpart) {
1756 mpd_set_host(mpd_env_host);
1758 /* MPD_HOST contains a password */
1759 char mpd_password[mpd_hostpart - mpd_env_host + 1];
1760 snprintf(mpd_password, mpd_hostpart - mpd_env_host + 1, "%s", mpd_env_host);
1762 if (!strlen(mpd_hostpart + 1)) {
1763 mpd_set_host("localhost");
1765 mpd_set_host(mpd_hostpart + 1);
1768 mpd_set_password(mpd_password, 1);
1773 if (!mpd_env_port || mpd_set_port(mpd_env_port)) {
1774 /* failed to set port from environment variable */
1775 mpd_set_port("6600");
1779 ctx->info.xmms2.artist = NULL;
1780 ctx->info.xmms2.album = NULL;
1781 ctx->info.xmms2.title = NULL;
1782 ctx->info.xmms2.genre = NULL;
1783 ctx->info.xmms2.comment = NULL;
1784 ctx->info.xmms2.url = NULL;
1785 ctx->info.xmms2.status = NULL;
1786 ctx->info.xmms2.playlist = NULL;
1788 use_spacer = NO_SPACER;
1790 ctx->output_methods = TO_X;
1792 ctx->output_methods = TO_STDOUT;
1795 show_graph_scale = 0;
1796 show_graph_range = 0;
1799 draw_graph_borders = 1;
1801 set_first_font("6x10");
1809 window.type = TYPE_NORMAL;
1811 strcpy(window.class_name, PACKAGE_NAME);
1812 sprintf(window.title, PACKAGE_NAME" (%s)", ctx->info.uname_s.nodename);
1814 stippled_borders = 0;
1815 window.border_inner_margin = 3;
1816 window.border_outer_margin = 1;
1817 window.border_width = 1;
1818 text_alignment = BOTTOM_LEFT;
1819 ctx->info.x11.monitor.number = 1;
1820 ctx->info.x11.monitor.current = 0;
1821 ctx->info.x11.desktop.current = 1;
1822 ctx->info.x11.desktop.number = 1;
1823 ctx->info.x11.desktop.nitems = 0;
1824 ctx->info.x11.desktop.all_names = NULL;
1825 ctx->info.x11.desktop.name = NULL;
1828 for (i = 0; i < MAX_TEMPLATES; i++) {
1831 template[i] = strdup("");
1834 free(current_mail_spool);
1838 variable_substitute(MAIL_FILE, buf, 256);
1839 if (buf[0] != '\0') {
1840 current_mail_spool = strndup(buf, text_buffer_size);
1845 set_update_interval(3);
1846 update_interval_bat = NOBATTERY;
1847 ctx->info.music_player_interval = 1.0;
1848 stuff_in_uppercase = 0;
1849 ctx->info.users.number = 1;
1851 #ifdef TCP_PORT_MONITOR
1852 /* set default connection limit */
1853 tcp_portmon_set_max_connections(0);
1857 /* returns 1 if you can overwrite or create the file at 'path' */
1858 static _Bool overwrite_works(const char *path)
1862 if (!(filepointer = fopen(path, "w")))
1864 fclose(filepointer);
1868 /* returns 1 if you can append or create the file at 'path' */
1869 static _Bool append_works(const char *path)
1873 if (!(filepointer = fopen(path, "a")))
1875 fclose(filepointer);
1881 /* WARNING, this type not in Xlib spec */
1882 int x11_error_handler(Display *d, XErrorEvent *err)
1883 __attribute__((noreturn));
1884 int x11_error_handler(Display *d, XErrorEvent *err)
1886 NORM_ERR("X Error: type %i Display %lx XID %li serial %lu error_code %i request_code %i minor_code %i other Display: %lx\n",
1888 (long unsigned)err->display,
1889 (long)err->resourceid,
1899 int x11_ioerror_handler(Display *d)
1900 __attribute__((noreturn));
1901 int x11_ioerror_handler(Display *d)
1903 NORM_ERR("X Error: Display %lx\n",
1910 static void X11_initialisation(conky_context *ctx)
1912 if (x_initialised == YES) return;
1913 ctx->output_methods |= TO_X;
1915 set_default_configurations_for_x();
1916 x_initialised = YES;
1919 /* WARNING, this type not in Xlib spec */
1920 XSetErrorHandler(&x11_error_handler);
1921 XSetIOErrorHandler(&x11_ioerror_handler);
1925 void X11_create_window(conky_context *ctx)
1927 if (ctx->output_methods & TO_X) {
1929 init_window(own_window, text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2,
1930 text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2, set_transparent, background_colour,
1931 ctx->xargv, ctx->xargc);
1932 #else /* OWN_WINDOW */
1933 init_window(0, text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2,
1934 text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2, set_transparent, 0,
1935 ctx->xargv, ctx->xargc);
1936 #endif /* OWN_WINDOW */
1940 update_text_area(); /* to position text/window on screen */
1943 if (own_window && !fixed_pos) {
1944 XMoveWindow(display, window.window, window.x, window.y);
1947 set_transparent_background(window.window);
1955 x11_stuff.region = XCreateRegion();
1957 if (!XDamageQueryExtension(display, &x11_stuff.event_base, &x11_stuff.error_base)) {
1958 NORM_ERR("Xdamage extension unavailable");
1960 x11_stuff.damage = XDamageCreate(display, window.window, XDamageReportNonEmpty);
1961 x11_stuff.region2 = XFixesCreateRegionFromWindow(display, window.window, 0);
1962 x11_stuff.part = XFixesCreateRegionFromWindow(display, window.window, 0);
1963 #endif /* HAVE_XDAMAGE */
1965 ctx->selected_font = 0;
1966 update_text_area(); /* to get initial size of the window */
1969 /* setup lua window globals */
1970 llua_setup_window_table(text_start_x, text_start_y, text_width, text_height);
1971 #endif /* HAVE_LUA */
1975 #define CONF_ERR NORM_ERR("%s: %d: config file error", f, line)
1976 #define CONF_ERR2(a) NORM_ERR("%s: %d: config file error: %s", f, line, a)
1977 #define CONF2(a) if (strcasecmp(name, a) == 0)
1978 #define CONF(a) else CONF2(a)
1979 #define CONF3(a, b) else if (strcasecmp(name, a) == 0 \
1980 || strcasecmp(name, b) == 0)
1981 #define CONF_CONTINUE 1
1982 #define CONF_BREAK 2
1983 #define CONF_BUFF_SIZE 512
1985 static FILE *open_config_file(const char *f)
1987 #ifdef CONFIG_OUTPUT
1988 if (!strcmp(f, "==builtin==")) {
1989 return conf_cookie_open();
1991 #endif /* CONFIG_OUTPUT */
1992 return fopen(f, "r");
1995 static int do_config_step(int *line, FILE *fp, char *buf, char **name, char **value)
1999 if (fgets(buf, CONF_BUFF_SIZE, fp) == NULL) {
2002 remove_comments(buf);
2007 while (*p && isspace((int) *p)) {
2011 return CONF_CONTINUE; /* empty line */
2018 while (*p2 && !isspace((int) *p2)) {
2022 *p2 = '\0'; /* break at name's end */
2029 while (*p && isspace((int) *p)) {
2035 p2 = *value + strlen(*value);
2036 while (isspace((int) *(p2 - 1))) {
2045 char load_config_file(conky_context *ctx, const char *f)
2050 fp = open_config_file(f);
2054 DBGP("reading contents from config file '%s'", f);
2057 char buff[CONF_BUFF_SIZE], *name, *value;
2058 int ret = do_config_step(&line, fp, buff, &name, &value);
2059 if (ret == CONF_BREAK) {
2061 } else if (ret == CONF_CONTINUE) {
2067 /* don't listen if X is already initialised or
2068 * if we already know we don't want it */
2069 if(x_initialised != YES) {
2070 if (string_to_bool(value)) {
2071 ctx->output_methods &= TO_X;
2073 ctx->output_methods &= ~TO_X;
2074 x_initialised = NEVER;
2079 if (!value || x_initialised == YES) {
2084 disp = strdup(value);
2089 if (window.type == TYPE_DOCK)
2092 #endif /*OWN_WINDOW */
2094 int a = string_to_alignment(value);
2105 CONF("background") {
2106 fork_to_background = string_to_bool(value);
2109 CONF2("background") {
2110 fork_to_background = string_to_bool(value);
2114 CONF("show_graph_scale") {
2115 show_graph_scale = string_to_bool(value);
2117 CONF("show_graph_range") {
2118 show_graph_range = string_to_bool(value);
2120 CONF("border_inner_margin") {
2122 window.border_inner_margin = strtol(value, 0, 0);
2123 if (window.border_inner_margin < 0) window.border_inner_margin = 0;
2128 CONF("border_outer_margin") {
2130 window.border_outer_margin = strtol(value, 0, 0);
2131 if (window.border_outer_margin < 0) window.border_outer_margin = 0;
2136 CONF("border_width") {
2138 window.border_width = strtol(value, 0, 0);
2139 if (window.border_width < 0) window.border_width = 0;
2145 #define TEMPLATE_CONF(n) \
2146 CONF("template"#n) { \
2148 free(template[n]); \
2149 template[n] = strdup(value); \
2166 ctx->info.mail = parse_mail_args(IMAP_TYPE, value);
2173 ctx->info.mail = parse_mail_args(POP3_TYPE, value);
2178 CONF("default_bar_size") {
2181 if (sscanf(value, "%d %d", &default_bar_width, &default_bar_height) != 2) {
2188 CONF_ERR2("default_bar_size takes 2 integer arguments (ie. 'default_bar_size 0 6')")
2192 CONF("default_graph_size") {
2195 if (sscanf(value, "%d %d", &default_graph_width, &default_graph_height) != 2) {
2202 CONF_ERR2("default_graph_size takes 2 integer arguments (ie. 'default_graph_size 0 6')")
2205 CONF("default_gauge_size") {
2208 if (sscanf(value, "%d %d", &default_gauge_width, &default_gauge_height) != 2) {
2215 CONF_ERR2("default_gauge_size takes 2 integer arguments (ie. 'default_gauge_size 0 6')")
2222 mpd_set_host(value);
2228 if (value && mpd_set_port(value)) {
2232 CONF("mpd_password") {
2234 mpd_set_password(value, 0);
2240 CONF("music_player_interval") {
2242 ctx->info.music_player_interval = strtod(value, 0);
2248 CONF("sensor_device") {
2250 sensor_device = strtol(value, 0, 0);
2256 CONF("cpu_avg_samples") {
2258 cpu_avg_samples = strtol(value, 0, 0);
2259 if (cpu_avg_samples < 1 || cpu_avg_samples > 14) {
2262 ctx->info.cpu_avg_samples = cpu_avg_samples;
2268 CONF("net_avg_samples") {
2270 net_avg_samples = strtol(value, 0, 0);
2271 if (net_avg_samples < 1 || net_avg_samples > 14) {
2274 ctx->info.net_avg_samples = net_avg_samples;
2280 CONF("diskio_avg_samples") {
2282 diskio_avg_samples = strtol(value, 0, 0);
2283 if (diskio_avg_samples < 1 || diskio_avg_samples > 14) {
2286 ctx->info.diskio_avg_samples = diskio_avg_samples;
2294 CONF("double_buffer") {
2295 use_xdbe = string_to_bool(value);
2299 CONF("override_utf8_locale") {
2300 utf8_mode = string_to_bool(value);
2302 CONF("draw_borders") {
2303 draw_borders = string_to_bool(value);
2305 CONF("draw_graph_borders") {
2306 draw_graph_borders = string_to_bool(value);
2308 CONF("draw_shades") {
2309 draw_shades = string_to_bool(value);
2311 CONF("draw_outline") {
2312 draw_outline = string_to_bool(value);
2315 CONF("out_to_console") {
2316 if(string_to_bool(value)) {
2317 ctx->output_methods |= TO_STDOUT;
2319 ctx->output_methods &= ~TO_STDOUT;
2322 CONF("extra_newline") {
2323 extra_newline = string_to_bool(value);
2325 CONF("out_to_stderr") {
2326 if(string_to_bool(value))
2327 ctx->output_methods |= TO_STDERR;
2330 CONF("out_to_ncurses") {
2331 if(string_to_bool(value)) {
2334 ctx->output_methods |= TO_NCURSES;
2338 CONF("overwrite_file") {
2339 if(overwrite_file) {
2340 free(overwrite_file);
2343 if(overwrite_works(value)) {
2344 overwrite_file = strdup(value);
2345 ctx->output_methods |= OVERWRITE_FILE;
2347 NORM_ERR("overwrite_file won't be able to create/overwrite '%s'", value);
2349 CONF("append_file") {
2354 if(append_works(value)) {
2355 append_file = strdup(value);
2356 ctx->output_methods |= APPEND_FILE;
2358 NORM_ERR("append_file won't be able to create/append '%s'", value);
2360 CONF("use_spacer") {
2362 if (strcasecmp(value, "left") == EQUAL) {
2363 use_spacer = LEFT_SPACER;
2364 } else if (strcasecmp(value, "right") == EQUAL) {
2365 use_spacer = RIGHT_SPACER;
2366 } else if (strcasecmp(value, "none") == EQUAL) {
2367 use_spacer = NO_SPACER;
2369 use_spacer = string_to_bool(value);
2370 NORM_ERR("use_spacer should have an argument of left, right, or"
2371 " none. '%s' seems to be some form of '%s', so"
2372 " defaulting to %s.", value,
2373 use_spacer ? "true" : "false",
2374 use_spacer ? "right" : "none");
2376 use_spacer = RIGHT_SPACER;
2378 use_spacer = NO_SPACER;
2382 NORM_ERR("use_spacer should have an argument. Defaulting to right.");
2383 use_spacer = RIGHT_SPACER;
2389 use_xft = string_to_bool(value);
2393 set_first_font(value);
2397 if (value && font_count >= 0) {
2398 ctx->fonts[0].font_alpha = atof(value) * 65535.0;
2405 if (string_to_bool(value)) {
2406 NORM_ERR("Xft not enabled at compile time");
2410 /* xftfont silently ignored when no Xft */
2413 /* xftalpha is silently ignored when no Xft */
2418 set_first_font(value);
2426 gap_x = atoi(value);
2433 gap_y = atoi(value);
2439 CONF("mail_spool") {
2443 variable_substitute(value, buffer, 256);
2445 if (buffer[0] != '\0') {
2446 if (current_mail_spool) {
2447 free(current_mail_spool);
2449 current_mail_spool = strndup(buffer, text_buffer_size);
2456 CONF("minimum_size") {
2458 if (sscanf(value, "%d %d", &minimum_width, &minimum_height)
2460 if (sscanf(value, "%d", &minimum_width) != 1) {
2468 CONF("maximum_width") {
2470 if (sscanf(value, "%d", &maximum_width) != 1) {
2478 CONF("no_buffers") {
2479 no_buffers = string_to_bool(value);
2481 CONF("top_name_width") {
2483 if (sscanf(value, "%u", &top_name_width) != 1) {
2489 if (top_name_width >= max_user_text) {
2490 top_name_width = max_user_text - 1;
2493 CONF("top_cpu_separate") {
2494 cpu_separate = string_to_bool(value);
2496 CONF("short_units") {
2497 short_units = string_to_bool(value);
2499 CONF("format_human_readable") {
2500 format_human_readable = string_to_bool(value);
2502 CONF("pad_percents") {
2503 pad_percents = atoi(value);
2507 CONF("own_window") {
2509 own_window = string_to_bool(value);
2512 CONF("own_window_class") {
2514 memset(window.class_name, 0, sizeof(window.class_name));
2515 strncpy(window.class_name, value,
2516 sizeof(window.class_name) - 1);
2519 CONF("own_window_title") {
2521 memset(window.title, 0, sizeof(window.title));
2522 strncpy(window.title, value, sizeof(window.title) - 1);
2525 CONF("own_window_transparent") {
2527 set_transparent = string_to_bool(value);
2530 CONF("own_window_hints") {
2532 char *p_hint, *p_save;
2533 char delim[] = ", ";
2535 /* tokenize the value into individual hints */
2536 if ((p_hint = strtok_r(value, delim, &p_save)) != NULL) {
2538 /* fprintf(stderr, "hint [%s] parsed\n", p_hint); */
2539 if (strncmp(p_hint, "undecorate", 10) == EQUAL) {
2540 SET_HINT(window.hints, HINT_UNDECORATED);
2541 } else if (strncmp(p_hint, "below", 5) == EQUAL) {
2542 SET_HINT(window.hints, HINT_BELOW);
2543 } else if (strncmp(p_hint, "above", 5) == EQUAL) {
2544 SET_HINT(window.hints, HINT_ABOVE);
2545 } else if (strncmp(p_hint, "sticky", 6) == EQUAL) {
2546 SET_HINT(window.hints, HINT_STICKY);
2547 } else if (strncmp(p_hint, "skip_taskbar", 12) == EQUAL) {
2548 SET_HINT(window.hints, HINT_SKIP_TASKBAR);
2549 } else if (strncmp(p_hint, "skip_pager", 10) == EQUAL) {
2550 SET_HINT(window.hints, HINT_SKIP_PAGER);
2555 p_hint = strtok_r(NULL, delim, &p_save);
2556 } while (p_hint != NULL);
2562 CONF("own_window_type") {
2564 if (strncmp(value, "normal", 6) == EQUAL) {
2565 window.type = TYPE_NORMAL;
2566 } else if (strncmp(value, "desktop", 7) == EQUAL) {
2567 window.type = TYPE_DESKTOP;
2568 } else if (strncmp(value, "dock", 4) == EQUAL) {
2569 window.type = TYPE_DOCK;
2570 text_alignment = TOP_LEFT;
2571 } else if (strncmp(value, "panel", 5) == EQUAL) {
2572 window.type = TYPE_PANEL;
2573 } else if (strncmp(value, "override", 8) == EQUAL) {
2574 window.type = TYPE_OVERRIDE;
2583 CONF("stippled_borders") {
2585 stippled_borders = strtol(value, 0, 0);
2587 stippled_borders = 4;
2591 CONF("imlib_cache_size") {
2593 cimlib_set_cache_size(atoi(value));
2596 CONF("imlib_cache_flush_interval") {
2598 cimlib_set_cache_flush_interval(atoi(value));
2603 CONF("update_interval_on_battery") {
2605 update_interval_bat = strtod(value, 0);
2610 CONF("update_interval") {
2612 set_update_interval(strtod(value, 0));
2616 if (ctx->info.music_player_interval == 0) {
2617 // default to update_interval
2618 ctx->info.music_player_interval = ctx->update_interval;
2621 CONF("total_run_times") {
2623 ctx->total_run_times = strtod(value, 0);
2629 stuff_in_uppercase = string_to_bool(value);
2631 CONF("max_specials") {
2633 max_specials = atoi(value);
2638 CONF("max_user_text") {
2640 max_user_text = atoi(value);
2645 CONF("text_buffer_size") {
2647 text_buffer_size = atoi(value);
2648 if (text_buffer_size < DEFAULT_TEXT_BUFFER_SIZE) {
2649 NORM_ERR("text_buffer_size must be >=%i bytes", DEFAULT_TEXT_BUFFER_SIZE);
2650 text_buffer_size = DEFAULT_TEXT_BUFFER_SIZE;
2658 if (ctx->output_methods & TO_X) {
2659 X11_initialisation();
2668 global_text = (char *) malloc(1);
2669 global_text[0] = '\0';
2672 unsigned int l = strlen(global_text);
2674 char buf[CONF_BUFF_SIZE];
2676 if (fgets(buf, CONF_BUFF_SIZE, fp) == NULL) {
2682 if (bl >= 2 && buf[bl-2] == '\\' && buf[bl-1] == '\n') {
2690 /* Check for continuation of \\-\n. */
2691 if (l > 0 && buf[0] == '\n' && global_text[l-1] == '\\') {
2692 global_text[l-1] = '\0';
2696 global_text = (char *) realloc(global_text, l + bl + 1);
2697 strcat(global_text, buf);
2699 if (strlen(global_text) > max_user_text) {
2704 if (strlen(global_text) < 1) {
2705 CRIT_ERR(NULL, NULL, "no text supplied in configuration; exiting");
2707 global_text_lines = line + 1;
2710 #ifdef TCP_PORT_MONITOR
2711 CONF("max_port_monitor_connections") {
2713 if (!value || (sscanf(value, "%d", &max) != 1)) {
2714 /* an error. use default, warn and continue. */
2715 tcp_portmon_set_max_connections(0);
2717 } else if (tcp_portmon_set_max_connections(max)) {
2718 /* max is < 0, default has been set*/
2723 CONF("if_up_strictness") {
2725 NORM_ERR("incorrect if_up_strictness value, defaulting to 'up'");
2726 ifup_strictness = IFUP_UP;
2727 } else if (strcasecmp(value, "up") == EQUAL) {
2728 ifup_strictness = IFUP_UP;
2729 } else if (strcasecmp(value, "link") == EQUAL) {
2730 ifup_strictness = IFUP_LINK;
2731 } else if (strcasecmp(value, "address") == EQUAL) {
2732 ifup_strictness = IFUP_ADDR;
2734 NORM_ERR("incorrect if_up_strictness value, defaulting to 'up'");
2735 ifup_strictness = IFUP_UP;
2739 CONF("temperature_unit") {
2741 NORM_ERR("config option 'temperature_unit' needs an argument, either 'celsius' or 'fahrenheit'");
2742 } else if (set_temp_output_unit(value)) {
2743 NORM_ERR("temperature_unit: incorrect argument");
2750 char *ptr = strtok(value, " ");
2753 ptr = strtok(NULL, " ");
2760 CONF("lua_draw_hook_pre") {
2762 llua_set_draw_pre_hook(value);
2767 CONF("lua_draw_hook_post") {
2769 llua_set_draw_post_hook(value);
2774 CONF("lua_startup_hook") {
2776 llua_set_startup_hook(value);
2781 CONF("lua_shutdown_hook") {
2783 llua_set_shutdown_hook(value);
2789 #endif /* HAVE_LUA */
2801 CONF("default_color"){}
2802 CONF3("default_shade_color", "default_shadecolor"){}
2803 CONF3("default_outline_color", "default_outlinecolor") {}
2804 CONF("own_window_colour") {}
2807 NORM_ERR("%s: %d: no such configuration: '%s'", f, line, name);
2813 if (ctx->info.music_player_interval == 0) {
2814 // default to update_interval
2815 ctx->info.music_player_interval = ctx->update_interval;
2817 if (!global_text) { // didn't supply any text
2818 CRIT_ERR(NULL, NULL, "missing text block in configuration; exiting");
2824 void load_config_file_x11(conky_context *ctx, const char *f)
2829 fp = open_config_file(f);
2833 DBGP("reading contents from config file '%s'", f);
2836 char buff[CONF_BUFF_SIZE], *name, *value;
2837 int ret = do_config_step(&line, fp, buff, &name, &value);
2838 if (ret == CONF_BREAK) {
2840 } else if (ret == CONF_CONTINUE) {
2845 X11_initialisation();
2846 if (x_initialised == YES) {
2848 color0 = get_x11_color(value);
2855 X11_initialisation();
2856 if (x_initialised == YES) {
2858 color1 = get_x11_color(value);
2865 X11_initialisation();
2866 if (x_initialised == YES) {
2868 color2 = get_x11_color(value);
2875 X11_initialisation();
2876 if (x_initialised == YES) {
2878 color3 = get_x11_color(value);
2885 X11_initialisation();
2886 if (x_initialised == YES) {
2888 color4 = get_x11_color(value);
2895 X11_initialisation();
2896 if (x_initialised == YES) {
2898 color5 = get_x11_color(value);
2905 X11_initialisation();
2906 if (x_initialised == YES) {
2908 color6 = get_x11_color(value);
2915 X11_initialisation();
2916 if (x_initialised == YES) {
2918 color7 = get_x11_color(value);
2925 X11_initialisation();
2926 if (x_initialised == YES) {
2928 color8 = get_x11_color(value);
2935 X11_initialisation();
2936 if (x_initialised == YES) {
2938 color9 = get_x11_color(value);
2944 CONF("default_color") {
2945 X11_initialisation();
2946 if (x_initialised == YES) {
2948 default_fg_color = get_x11_color(value);
2954 CONF3("default_shade_color", "default_shadecolor") {
2955 X11_initialisation();
2956 if (x_initialised == YES) {
2958 default_bg_color = get_x11_color(value);
2964 CONF3("default_outline_color", "default_outlinecolor") {
2965 X11_initialisation();
2966 if (x_initialised == YES) {
2968 default_out_color = get_x11_color(value);
2975 CONF("own_window_colour") {
2976 X11_initialisation();
2977 if (x_initialised == YES) {
2979 background_colour = get_x11_color(value);
2981 NORM_ERR("Invalid colour for own_window_colour (try omitting the "
2982 "'#' for hex colours");
2988 /* initialize X11 if nothing X11-related is mentioned before TEXT (and if X11 is the default outputmethod) */
2989 if (ctx->output_methods & TO_X) {
2990 X11_initialisation();
2999 #undef CONF_CONTINUE
3000 #undef CONF_BUFF_SIZE