2 * Conky, a system monitor, based on torsmo
4 * This program is licensed under BSD license, read COPYING
27 #include <X11/Xutil.h>
29 #include <sys/types.h>
32 #define CONFIG_FILE "$HOME/.conkyrc"
33 #define MAIL_FILE "$MAIL"
34 #define MAX_IF_BLOCK_DEPTH 5
36 /* #define SIGNAL_BLOCKING */
37 #undef SIGNAL_BLOCKING
54 char name[TEXT_BUFFER_SIZE];
64 static int selected_font = 0;
65 static int font_count = -1;
66 struct font_list *fonts = NULL;
70 #define font_height() use_xft ? (fonts[selected_font].xftfont->ascent + fonts[selected_font].xftfont->descent) : \
71 (fonts[selected_font].font->max_bounds.ascent + fonts[selected_font].font->max_bounds.descent)
72 #define font_ascent() use_xft ? fonts[selected_font].xftfont->ascent : fonts[selected_font].font->max_bounds.ascent
73 #define font_descent() use_xft ? fonts[selected_font].xftfont->descent : fonts[selected_font].font->max_bounds.descent
77 #define font_height() (fonts[selected_font].font->max_bounds.ascent + fonts[selected_font].font->max_bounds.descent)
78 #define font_ascent() fonts[selected_font].font->max_bounds.ascent
79 #define font_descent() fonts[selected_font].font->max_bounds.descent
83 #define MAX_FONTS 64 // hmm, no particular reason, just makes sense.
86 static void set_font();
88 int addfont(const char *data_in)
90 if (font_count > MAX_FONTS) {
91 CRIT_ERR("you don't need that many fonts, sorry.");
94 if (font_count == 0) {
98 if ((fonts = (struct font_list*)malloc(sizeof(struct font_list))) == NULL) {
102 fonts = realloc(fonts, (sizeof(struct font_list) * (font_count+1)));
104 CRIT_ERR("realloc in addfont");
106 if (strlen(data_in) < TEXT_BUFFER_SIZE) { // must account for null terminator
107 strncpy(fonts[font_count].name, data_in, TEXT_BUFFER_SIZE);
109 fonts[font_count].font_alpha = 0xffff;
112 CRIT_ERR("Oops...looks like something overflowed in addfont().");
117 void set_first_font(const char *data_in)
119 if (font_count < 0) {
120 if ((fonts = (struct font_list*)malloc(sizeof(struct font_list))) == NULL) {
125 if (strlen(data_in) > 1) {
126 strncpy(fonts[0].name, data_in, TEXT_BUFFER_SIZE-1);
128 fonts[0].font_alpha = 0xffff;
136 for (i=0;i<=font_count;i++) {
139 XftFontClose(display, fonts[i].xftfont);
143 XFreeFont(display, fonts[i].font);
150 set_first_font("6x10");
154 static void load_fonts()
157 for (i=0;i<=font_count;i++) {
161 /*if (fonts[i].xftfont != NULL && selected_font == 0) {
162 XftFontClose(display, fonts[i].xftfont);
164 if ((fonts[i].xftfont =
165 XftFontOpenName(display, screen, fonts[i].name)) != NULL)
168 ERR("can't load Xft font '%s'", fonts[i].name);
169 if ((fonts[i].xftfont =
170 XftFontOpenName(display, screen,
171 "courier-12")) != NULL)
174 ERR("can't load Xft font '%s'", "courier-12");
176 if ((fonts[i].font = XLoadQueryFont(display, "fixed")) == NULL) {
177 CRIT_ERR("can't load font '%s'", "fixed");
184 /* load normal font */
185 /* if (fonts[i].font != NULL)
186 XFreeFont(display, fonts[i].font);*/
188 if ((fonts[i].font = XLoadQueryFont(display, fonts[i].name)) == NULL) {
189 ERR("can't load font '%s'", fonts[i].name);
190 if ((fonts[i].font = XLoadQueryFont(display, "fixed")) == NULL) {
191 CRIT_ERR("can't load font '%s'", "fixed");
192 printf("loaded fixed?\n");
200 /* default config file */
201 static char *current_config;
203 /* set to 1 if you want all text to be in uppercase */
204 static unsigned int stuff_in_upper_case;
206 /* Update interval */
207 static double update_interval;
209 /* Run how many times? */
210 static unsigned long total_run_times;
213 static int fork_to_background;
215 static int cpu_avg_samples, net_avg_samples;
219 /* Always on bottom */
220 static int on_bottom;
222 /* Position on the screen */
223 static int text_alignment;
224 static int gap_x, gap_y;
227 static int draw_borders;
228 static int draw_graph_borders;
229 static int stippled_borders;
231 static int draw_shades, draw_outline;
233 static int border_margin, border_width;
235 static long default_fg_color, default_bg_color, default_out_color;
237 /* create own window or draw stuff to root? */
238 static int set_transparent = 0;
242 static int own_window = 0;
243 static int background_colour = 0;
244 /* fixed size/pos is set if wm/user changes them */
245 static int fixed_size = 0, fixed_pos = 0;
248 static int minimum_width, minimum_height;
249 static int maximum_width;
256 /* no buffers in used memory? */
259 /* pad percentages to decimals? */
260 static int pad_percents = 0;
262 #ifdef TCP_PORT_MONITOR
263 tcp_port_monitor_collection_args_t tcp_port_monitor_collection_args;
264 tcp_port_monitor_args_t tcp_port_monitor_args;
267 /* Text that is shown */
268 static char original_text[] =
269 "$nodename - $sysname $kernel on $machine\n"
271 "${color grey}Uptime:$color $uptime\n"
272 "${color grey}Frequency (in MHz):$color $freq\n"
273 "${color grey}Frequency (in GHz):$color $freq_g\n"
274 "${color grey}RAM Usage:$color $mem/$memmax - $memperc% ${membar 4}\n"
275 "${color grey}Swap Usage:$color $swap/$swapmax - $swapperc% ${swapbar 4}\n"
276 "${color grey}CPU Usage:$color $cpu% ${cpubar 4}\n"
277 "${color grey}Processes:$color $processes ${color grey}Running:$color $running_processes\n"
279 "${color grey}File systems:\n"
280 " / $color${fs_free /}/${fs_size /} ${fs_bar 6 /}\n"
281 "${color grey}Networking:\n"
282 " Up:$color ${upspeed eth0} k/s${color grey} - Down:$color ${downspeed eth0} k/s\n"
285 "${color grey}SETI@Home Statistics:\n"
286 "${color grey}Seti Unit Number:$color $seti_credit\n"
287 "${color grey}Seti Progress:$color $seti_prog% $seti_progbar\n"
290 "${color grey}MPD: $mpd_status $mpd_artist - $mpd_title from $mpd_album at $mpd_vol\n"
291 "Bitrate: $mpd_bitrate\n" "Progress: $mpd_bar\n"
294 "${color grey}XMMS2: $xmms2_status $xmms2_artist - $xmms2_title from $xmms2_album\n"
295 "Progress: $xmms2_bar\n"
297 "${color grey}Name PID CPU% MEM%\n"
298 " ${color lightgrey} ${top name 1} ${top pid 1} ${top cpu 1} ${top mem 1}\n"
299 " ${color lightgrey} ${top name 2} ${top pid 2} ${top cpu 2} ${top mem 2}\n"
300 " ${color lightgrey} ${top name 3} ${top pid 3} ${top cpu 3} ${top mem 3}\n"
301 " ${color lightgrey} ${top name 4} ${top pid 4} ${top cpu 4} ${top mem 4}\n"
302 "${tail /var/log/Xorg.0.log 3}";
304 static char *text = original_text;
306 static int total_updates;
309 static int blockdepth = 0;
310 static int if_jumped = 0;
311 static int blockstart[MAX_IF_BLOCK_DEPTH];
313 int check_mount(char *s)
315 #if defined(__linux__)
317 FILE *mtab = fopen("/etc/mtab", "r");
319 char buf1[256], buf2[128];
320 while (fgets(buf1, 256, mtab)) {
321 sscanf(buf1, "%*s %128s", buf2);
322 if (!strcmp(s, buf2)) {
329 ERR("Could not open mtab");
332 #elif defined(__FreeBSD__)
333 struct statfs *mntbuf;
336 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
337 for (i = mntsize - 1; i >= 0; i--)
338 if (strcmp(mntbuf[i].f_mntonname, s) == 0)
347 static inline int calc_text_width(const char *s, int l)
353 XftTextExtentsUtf8(display, fonts[selected_font].xftfont, s, l, &gi);
355 XftTextExtents8(display, fonts[selected_font].xftfont, s, l, &gi);
361 return XTextWidth(fonts[selected_font].font, s, l);
366 /* formatted text to render on screen, generated in generate_text(),
367 * drawn in draw_stuff() */
369 static char text_buffer[TEXT_BUFFER_SIZE * 4];
371 /* special stuff in text_buffer */
373 #define SPECIAL_CHAR '\x01'
390 static struct special_t {
400 unsigned long first_colour; // for graph gradient
401 unsigned long last_colour;
404 static int special_count;
406 static int special_index; /* used when drawing */
409 #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? */
411 static struct special_t *new_special(char *buf, int t)
413 if (special_count >= 512)
414 CRIT_ERR("too many special things in text");
416 buf[0] = SPECIAL_CHAR;
418 specials[special_count].type = t;
419 return &specials[special_count++];
422 typedef struct tailstring_list {
423 char data[TEXT_BUFFER_SIZE];
424 struct tailstring_list *next;
425 struct tailstring_list *first;
428 void addtail(tailstring ** head, char *data_in)
431 if ((tmp = malloc(sizeof(*tmp))) == NULL) {
437 tmp->first = (*head)->first;
439 strncpy(tmp->data, data_in, TEXT_BUFFER_SIZE);
444 void freetail(tailstring * head)
447 while (head != NULL) {
454 void freelasttail(tailstring * head)
456 tailstring * tmp = head;
458 if (tmp->next == head->first) {
465 while(head != NULL && tmp != NULL) {
471 static void new_bar(char *buf, int w, int h, int usage)
473 struct special_t *s = new_special(buf, BAR);
474 s->arg = (usage > 255) ? 255 : ((usage < 0) ? 0 : usage);
479 static const char *scan_bar(const char *args, int *w, int *h)
481 *w = 0; /* zero width means all space that is available */
483 /* bar's argument is either height or height,width */
486 if (sscanf(args, "%d,%d %n", h, w, &n) <= 1)
487 sscanf(args, "%d %n", h, &n);
494 static char *scan_font(const char *args)
496 if (args && sizeof(args) < 127) {
500 ERR("font scan failed, lets hope it doesn't mess stuff up");
506 static void new_font(char *buf, char * args) {
507 struct special_t *s = new_special(buf, FONT);
508 if (!s->font_added || strcmp(args, fonts[s->font_added].name)) {
509 int tmp = selected_font;
510 selected_font = s->font_added = addfont(args);
518 inline void graph_append(struct special_t *graph, double f)
520 if (!graph->scaled && f > graph->graph_scale) {
521 f = graph->graph_scale;
525 graph->graph_scale = 1;
527 graph->graph[0] = f; /* add new data */
528 for (i = graph->graph_width - 1; i > 0; i--) { /* shift all the data by 1 */
529 graph->graph[i] = graph->graph[i - 1];
530 if (graph->scaled && graph->graph[i] > graph->graph_scale) {
531 graph->graph_scale = graph->graph[i]; /* check if we need to update the scale */
536 short colour_depth = 0;
537 void set_up_gradient();
539 /* precalculated: 31/255, and 63/255 */
540 #define CONST_8_TO_5_BITS 0.12156862745098
541 #define CONST_8_TO_6_BITS 0.247058823529412
543 /* adjust color values depending on color depth*/
544 static unsigned int adjust_colors(unsigned int color)
547 if (colour_depth == 0) {
550 if (colour_depth == 16) {
551 r = (color & 0xff0000) >> 16;
552 g = (color & 0xff00) >> 8;
554 color = (int)(r * CONST_8_TO_5_BITS) << 11;
555 color |= (int)(g * CONST_8_TO_6_BITS) << 5;
556 color |= (int)(b * CONST_8_TO_5_BITS);
561 static void new_graph(char *buf, int w, int h, unsigned int first_colour, unsigned int second_colour, double i, int scale, int append)
563 struct special_t *s = new_special(buf, GRAPH);
565 if (s->graph == NULL) {
566 if (s->width > 0 && s->width < MAX_GRAPH_DEPTH) {
567 s->graph_width = s->width - 3; // subtract 3 for the box
569 s->graph_width = MAX_GRAPH_DEPTH - 3;
571 s->graph = malloc(s->graph_width * sizeof(double));
572 memset(s->graph, 0, s->graph_width * sizeof(double));
573 s->graph_scale = 100;
576 s->first_colour = adjust_colors(first_colour);
577 s->last_colour = adjust_colors(second_colour);
584 s->graph_width = s->width - 3; // subtract 3 for rectangle around
589 s->graph_scale = scale;
596 static const char *scan_graph(const char *args, int *w, int *h, unsigned int *first_colour, unsigned int *last_colour, unsigned int *scale)
598 *w = 0; /* zero width means all space that is available */
602 /* graph's argument is either height or height,width */
604 if (sscanf(args, "%*s %d,%d %x %x %i", h, w, first_colour, last_colour, scale) < 5) {
605 if (sscanf(args, "%*s %d,%d %x %x", h, w, first_colour, last_colour) < 4) {
607 if (sscanf(args, "%d,%d %x %x %i", h, w, first_colour, last_colour, scale) < 5) {
609 if (sscanf(args, "%d,%d %x %x", h, w, first_colour, last_colour) < 4) {
612 if (sscanf(args, "%*s %x %x %i", first_colour, last_colour, scale) < 3) {
616 if (sscanf(args, "%*s %x %x", first_colour, last_colour) < 2) {
619 if (sscanf(args, "%x %x %i", first_colour, last_colour, scale) < 3) {
623 if (sscanf(args, "%x %x", first_colour, last_colour) < 2) {
626 if (sscanf(args, "%d,%d %i", h, w, scale) < 3) {
630 if (sscanf(args, "%d,%d", h, w) < 2) {
633 sscanf(args, "%*s %d,%d", h, w);
639 static inline void new_hr(char *buf, int a)
641 new_special(buf, HORIZONTAL_LINE)->height = a;
644 static inline void new_stippled_hr(char *buf, int a, int b)
646 struct special_t *s = new_special(buf, STIPPLED_HR);
651 static inline void new_fg(char *buf, long c)
653 new_special(buf, FG)->arg = c;
656 static inline void new_bg(char *buf, long c)
658 new_special(buf, BG)->arg = c;
661 static inline void new_outline(char *buf, long c)
663 new_special(buf, OUTLINE)->arg = c;
666 static inline void new_offset(char *buf, long c)
668 new_special(buf, OFFSET)->arg = c;
671 static inline void new_voffset(char *buf, long c)
673 new_special(buf, VOFFSET)->arg = c;
676 static inline void new_alignr(char *buf, long c)
678 new_special(buf, ALIGNR)->arg = c;
681 static inline void new_alignc(char *buf, long c)
683 new_special(buf, ALIGNC)->arg = c;
686 /* quite boring functions */
688 static inline void for_each_line(char *b, void (*f) (char *))
692 for (ps = b, pe = b; *pe; pe++) {
705 static void convert_escapes(char *buf)
707 char *p = buf, *s = buf;
723 /* converts from bytes to human readable format (k, M, G, T) */
724 static void human_readable(long long a, char *buf, int size)
726 // Strange conditional due to possible overflows
727 if(a / 1024 / 1024 / 1024.0 > 1024.0){
728 snprintf(buf, size, "%.2fT", (a / 1024 / 1024 / 1024) / 1024.0);
730 else if (a >= 1024 * 1024 * 1024) {
731 snprintf(buf, size, "%.2fG", (a / 1024 / 1024) / 1024.0);
733 else if (a >= 1024 * 1024) {
734 double m = (a / 1024) / 1024.0;
736 snprintf(buf, size, "%.0fM", m);
738 snprintf(buf, size, "%.1fM", m);
739 } else if (a >= 1024)
740 snprintf(buf, size, "%Ldk", a / (long long) 1024);
742 snprintf(buf, size, "%Ld", a);
747 enum text_object_type {
795 #if defined(__linux__)
801 OBJ_i8k_left_fan_status,
802 OBJ_i8k_right_fan_status,
803 OBJ_i8k_left_fan_rpm,
804 OBJ_i8k_right_fan_rpm,
806 OBJ_i8k_buttons_status,
807 #endif /* __linux__ */
834 OBJ_ml_upload_counter,
835 OBJ_ml_download_counter,
836 OBJ_ml_nshared_files,
837 OBJ_ml_shared_counter,
838 OBJ_ml_tcp_upload_rate,
839 OBJ_ml_tcp_download_rate,
840 OBJ_ml_udp_upload_rate,
841 OBJ_ml_udp_download_rate,
842 OBJ_ml_ndownloaded_files,
843 OBJ_ml_ndownloading_files,
846 OBJ_running_processes,
855 OBJ_temp1, /* i2c is used instead in these */
868 #if defined(__FreeBSD__) && (defined(i386) || defined(__i386__))
870 OBJ_apm_battery_time,
871 OBJ_apm_battery_life,
872 #endif /* __FreeBSD__ */
906 // OBJ_xmms2_bitrate,
917 #if defined(XMMS) || defined(BMP) || defined(AUDACIOUS) || defined(INFOPIPE)
921 OBJ_xmms_length_seconds,
923 OBJ_xmms_position_seconds,
928 OBJ_xmms_playlist_length,
929 OBJ_xmms_playlist_position,
940 #ifdef TCP_PORT_MONITOR
945 struct thread_info_s {
952 unsigned int c, d, e;
955 char *s; /* some string */
956 int i; /* some integer */
957 long l; /* some other integer */
958 struct net_stat *net;
960 unsigned char loadavg[3];
961 unsigned int cpu_index;
1003 struct thread_info_s thread_info;
1009 #ifdef TCP_PORT_MONITOR
1011 in_port_t port_range_begin; /* starting port to monitor */
1012 in_port_t port_range_end; /* ending port to monitor */
1013 int item; /* enum value from libtcp-portmon.h, e.g. COUNT, REMOTEIP, etc. */
1014 int connection_index; /* 0 to n-1 connections. */
1020 struct text_object_list {
1021 unsigned int text_object_count;
1022 struct text_object *text_objects;
1025 static unsigned int text_object_count;
1026 static struct text_object *text_objects;
1027 static void generate_text_internal(char *p, int p_max_size, struct text_object *objs, unsigned int object_count, struct information *cur);
1029 #define MAX_THREADS 512 // sure whatever
1030 typedef struct thread_info_s *thread_info;
1031 static thread_info thread_list[MAX_THREADS];
1032 static int thread_count = 0;
1033 static int threads_runnable = 1;
1035 int register_thread(struct thread_info_s *new_thread)
1037 if (thread_count >= MAX_THREADS) {
1038 CRIT_ERR("Uh oh, tried to register too many threads");
1040 thread_list[thread_count] = new_thread;
1043 return thread_count - 1;
1046 void replace_thread(struct thread_info_s *new_thread, int pos) // this isn't even used anymore; oh wells
1048 if (pos >= 0 && pos < MAX_THREADS) {
1049 thread_list[pos] = new_thread;
1051 ERR("thread position out of bounds");
1055 void *threaded_exec(struct text_object *obj) { // pthreads are really beginning to piss me off
1057 int run_code = threads_runnable;
1058 while (threads_runnable == run_code) {
1059 update_time = get_time();
1060 char *p2 = obj->data.execi.buffer;
1061 FILE *fp = popen(obj->data.execi.cmd,"r");
1062 int n2 = fread(p2, 1, TEXT_BUFFER_SIZE, fp);
1065 if (n2 && p2[n2 - 1] == '\n') {
1069 if (*p2 == '\001') {
1074 obj->data.execi.last_update = update_time;
1075 usleep(100); // prevent race condition
1076 if (get_time() - obj->data.execi.last_update > obj->data.execi.interval) {
1079 unsigned int delay = 1000000.0 * (obj->data.execi.interval -(get_time() - obj->data.execi.last_update));
1080 if (delay < update_interval * 500000) {
1081 delay = update_interval * 1000000;
1086 ERR("exiting thread");
1091 static struct text_object *new_text_object_internal()
1093 struct text_object *obj = malloc(sizeof(struct text_object));
1094 memset(obj, 0, sizeof(struct text_object));
1101 if (mlconfig.mldonkey_hostname) {
1102 free(mlconfig.mldonkey_hostname);
1103 mlconfig.mldonkey_hostname = NULL;
1108 static void free_text_objects(unsigned int count, struct text_object *objs)
1111 for (i = 0; i < count; i++) {
1112 switch (objs[i].type) {
1114 close(objs[i].data.i);
1117 close(objs[i].data.i);
1120 close(objs[i].data.i2c.fd);
1123 free(objs[i].data.s);
1126 case OBJ_if_existing:
1127 case OBJ_if_mounted:
1128 case OBJ_if_running:
1129 free(objs[i].data.ifblock.s);
1132 free(objs[i].data.tail.logfile);
1133 free(objs[i].data.tail.buffer);
1135 case OBJ_text: case OBJ_font:
1136 free(objs[i].data.s);
1139 free(objs[i].data.s);
1142 free(objs[i].data.s);
1145 free(objs[i].data.s);
1147 /* case OBJ_execibar:
1148 free(objs[i].data.s);
1150 case OBJ_execigraph:
1151 free(objs[i].data.s);
1155 if (info.mpd.title) {
1156 free(info.mpd.title);
1160 case OBJ_mpd_artist:
1161 if (info.mpd.artist) {
1162 free(info.mpd.artist);
1163 info.mpd.artist = 0;
1167 if (info.mpd.album) {
1168 free(info.mpd.album);
1172 case OBJ_mpd_random:
1173 if (info.mpd.random) {
1174 free(info.mpd.random);
1175 info.mpd.random = 0;
1178 case OBJ_mpd_repeat:
1179 if (info.mpd.repeat) {
1180 free(info.mpd.repeat);
1181 info.mpd.repeat = 0;
1185 if (info.mpd.track) {
1186 free(info.mpd.track);
1191 if (info.mpd.name) {
1192 free(info.mpd.name);
1197 if (info.mpd.file) {
1198 free(info.mpd.file);
1202 case OBJ_mpd_status:
1203 if (info.mpd.status) {
1204 free(info.mpd.status);
1205 info.mpd.status = 0;
1209 if (info.mpd.artist) {
1210 free(info.mpd.artist);
1211 info.mpd.artist = 0;
1213 if (info.mpd.title) {
1214 free(info.mpd.title);
1217 if (info.mpd.file) {
1218 free(info.mpd.file);
1225 case OBJ_xmms2_title:
1226 if (info.xmms2.title) {
1227 free(info.xmms2.title);
1228 info.xmms2.title = 0;
1231 case OBJ_xmms2_artist:
1232 if (info.xmms2.artist) {
1233 free(info.xmms2.artist);
1234 info.xmms2.artist = 0;
1237 case OBJ_xmms2_album:
1238 if (info.xmms2.album) {
1239 free(info.xmms2.album);
1240 info.xmms2.album = 0;
1243 case OBJ_xmms2_track:
1244 if (info.xmms2.track) {
1245 free(info.xmms2.track);
1246 info.xmms2.track = 0;
1249 case OBJ_xmms2_file:
1250 if (info.xmms2.file) {
1251 free(info.xmms2.file);
1252 info.xmms2.file = 0;
1255 case OBJ_xmms2_status:
1256 if (info.xmms2.status) {
1257 free(info.xmms2.status);
1258 info.xmms2.status = 0;
1261 /* case OBJ_xmms2_smart:
1262 if (info.xmms2.artist) {
1263 free(info.xmms2.artist);
1264 info.xmms2.artist = 0;
1266 if (info.xmms2.title) {
1267 free(info.xmms2.title);
1268 info.xmms2.title = 0;
1270 if (info.xmms2.file) {
1271 free(info.xmms2.file);
1272 info.xmms2.file = 0;
1277 case OBJ_bmpx_title:
1278 case OBJ_bmpx_artist:
1279 case OBJ_bmpx_album:
1280 case OBJ_bmpx_track:
1282 case OBJ_bmpx_bitrate:
1286 free(objs[i].data.s);
1290 free(objs[i].data.execi.cmd);
1291 free(objs[i].data.execi.buffer);
1294 free(objs[i].data.execi.cmd);
1295 free(objs[i].data.execi.buffer);
1298 if (info.first_process) {
1299 free_all_processes();
1300 info.first_process = NULL;
1304 if (info.first_process) {
1305 free_all_processes();
1306 info.first_process = NULL;
1312 //text_objects = NULL;
1313 //text_object_count = 0;
1316 void scan_mixer_bar(const char *arg, int *a, int *w, int *h)
1321 if (arg && sscanf(arg, "%63s %n", buf1, &n) >= 1) {
1322 *a = mixer_init(buf1);
1323 (void) scan_bar(arg + n, w, h);
1326 (void) scan_bar(arg, w, h);
1331 /* construct_text_object() creates a new text_object */
1332 static struct text_object *construct_text_object(const char *s, const char *arg, unsigned int object_count, struct text_object *text_objects)
1334 //struct text_object *obj = new_text_object();
1335 struct text_object *obj = new_text_object_internal();
1337 #define OBJ(a, n) if (strcmp(s, #a) == 0) { obj->type = OBJ_##a; need_mask |= (1 << n); {
1338 #define END ; } } else
1342 obj->type = OBJ_color;
1343 obj->data.l = get_x11_color(s);
1346 OBJ(acpitemp, 0) obj->data.i = open_acpi_temperature(arg);
1347 END OBJ(acpitempf, 0) obj->data.i = open_acpi_temperature(arg);
1348 END OBJ(acpiacadapter, 0)
1351 END OBJ(freq_dyn, 0);
1352 END OBJ(freq_dyn_g, 0);
1353 END OBJ(acpifan, 0);
1354 END OBJ(battery, 0);
1357 sscanf(arg, "%63s", bat);
1359 strcpy(bat, "BAT0");
1360 obj->data.s = strdup(bat);
1361 #if defined(__linux__)
1362 END OBJ(i8k_version, INFO_I8K)
1363 END OBJ(i8k_bios, INFO_I8K)
1364 END OBJ(i8k_serial, INFO_I8K)
1365 END OBJ(i8k_cpu_temp, INFO_I8K)
1366 END OBJ(i8k_cpu_tempf, INFO_I8K)
1367 END OBJ(i8k_left_fan_status, INFO_I8K)
1368 END OBJ(i8k_right_fan_status, INFO_I8K)
1369 END OBJ(i8k_left_fan_rpm, INFO_I8K)
1370 END OBJ(i8k_right_fan_rpm, INFO_I8K)
1371 END OBJ(i8k_ac_status, INFO_I8K)
1372 END OBJ(i8k_buttons_status, INFO_I8K)
1373 #endif /* __linux__ */
1374 END OBJ(buffers, INFO_BUFFERS)
1375 END OBJ(cached, INFO_BUFFERS)
1376 END OBJ(cpu, INFO_CPU)
1378 if (strncmp(arg, "cpu", 3) == 0 && isdigit(arg[3])) {
1379 obj->data.cpu_index = atoi(&arg[3]);
1381 } else {obj->data.cpu_index = 0; }
1383 obj->data.cpu_index = 0;
1385 END OBJ(cpubar, INFO_CPU)
1387 if (strncmp(arg, "cpu", 3) == 0 && isdigit(arg[3])) {
1388 obj->data.cpu_index = atoi(&arg[3]);
1391 else {obj->data.cpu_index = 0;}
1392 (void) scan_bar(arg, &obj->a, &obj->b);
1394 (void) scan_bar(arg, &obj->a, &obj->b);
1395 obj->data.cpu_index = 0;
1397 END OBJ(cpugraph, INFO_CPU)
1399 if (strncmp(arg, "cpu", 3) == 0 && isdigit(arg[3])) {
1400 obj->data.cpu_index = atoi(&arg[3]);
1403 (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
1405 (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
1406 obj->data.cpu_index = 0;
1408 END OBJ(diskio, INFO_DISKIO)
1409 END OBJ(diskiograph, INFO_DISKIO) (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
1412 obj->data.l = arg ? get_x11_color(arg) : default_fg_color;
1416 obj->data.s = scan_font(arg);
1418 OBJ(downspeed, INFO_NET)
1420 obj->data.net = get_net_stat(arg);
1423 CRIT_ERR("downspeed needs argument");
1425 END OBJ(downspeedf, INFO_NET)
1427 obj->data.net = get_net_stat(arg);
1430 CRIT_ERR("downspeedf needs argument");
1432 END OBJ(downspeedgraph, INFO_NET)
1433 (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
1435 sscanf(arg, "%63s %*i,%*i %*i", buf);
1436 obj->data.net = get_net_stat(buf);
1437 if (sscanf(arg, "%*s %d,%d %*d", &obj->b, &obj->a) <= 1) {
1438 if (sscanf(arg, "%*s %d,%d", &obj->b, &obj->a) <= 1) {
1445 (text_objects[blockstart[blockdepth - 1]]).data.ifblock.pos = object_count;
1446 blockstart[blockdepth - 1] = object_count;
1447 obj->data.ifblock.pos = object_count + 2;
1449 ERR("$else: no matching $if_*");
1454 text_objects[blockstart[blockdepth]].data.ifblock.pos = object_count;
1456 ERR("$endif: no matching $if_*");
1460 OBJ(exec, 0) obj->data.s = strdup(arg ? arg : "");
1461 END OBJ(execbar, 0) obj->data.s = strdup(arg ? arg : "");
1462 END OBJ(execgraph, 0) obj->data.s = strdup(arg ? arg : "");
1463 END OBJ(execibar, 0) unsigned int n;
1464 if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
1466 ERR("${execibar <interval> command}");
1467 obj->type = OBJ_text;
1468 snprintf(buf, 256, "${%s}", s);
1469 obj->data.s = strdup(buf);
1471 obj->data.execi.cmd = strdup(arg + n);
1473 END OBJ(execigraph, 0) unsigned int n;
1474 if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
1476 ERR("${execigraph <interval> command}");
1477 obj->type = OBJ_text;
1478 snprintf(buf, 256, "${%s}", s);
1479 obj->data.s = strdup(buf);
1481 obj->data.execi.cmd = strdup(arg + n);
1483 END OBJ(execi, 0) unsigned int n;
1486 || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
1488 ERR("${execi <interval> command}");
1489 obj->type = OBJ_text;
1490 snprintf(buf, 256, "${%s}", s);
1491 obj->data.s = strdup(buf);
1493 obj->data.execi.cmd = strdup(arg + n);
1494 obj->data.execi.buffer =
1495 (char *) calloc(1, TEXT_BUFFER_SIZE);
1497 END OBJ(texeci, 0) unsigned int n;
1499 if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
1501 ERR("${texeci <interval> command}");
1502 obj->type = OBJ_text;
1503 snprintf(buf, 256, "${%s}", s);
1504 obj->data.s = strdup(buf);
1506 obj->data.execi.cmd = strdup(arg + n);
1507 obj->data.execi.buffer =
1508 (char *) calloc(1, TEXT_BUFFER_SIZE);
1510 obj->data.execi.pos = -1;
1511 END OBJ(pre_exec, 0) obj->type = OBJ_text;
1513 FILE *fp = popen(arg, "r");
1517 n = fread(buf, 1, 2048, fp);
1520 if (n && buf[n - 1] == '\n')
1525 obj->data.s = strdup(buf);
1527 obj->data.s = strdup("");
1530 OBJ(fs_bar, INFO_FS) obj->data.fsbar.h = 4;
1531 arg = scan_bar(arg, &obj->data.fsbar.w, &obj->data.fsbar.h);
1533 while (isspace(*arg))
1539 obj->data.fsbar.fs = prepare_fs_stat(arg);
1540 END OBJ(fs_bar_free, INFO_FS) obj->data.fsbar.h = 4;
1543 if (sscanf(arg, "%d %n", &obj->data.fsbar.h, &n) >= 1)
1547 obj->data.fsbar.fs = prepare_fs_stat(arg);
1548 END OBJ(fs_free, INFO_FS) if (!arg)
1550 obj->data.fs = prepare_fs_stat(arg);
1551 END OBJ(fs_used_perc, INFO_FS) if (!arg)
1553 obj->data.fs = prepare_fs_stat(arg);
1554 END OBJ(fs_free_perc, INFO_FS) if (!arg)
1556 obj->data.fs = prepare_fs_stat(arg);
1557 END OBJ(fs_size, INFO_FS) if (!arg)
1559 obj->data.fs = prepare_fs_stat(arg);
1560 END OBJ(fs_used, INFO_FS) if (!arg)
1562 obj->data.fs = prepare_fs_stat(arg);
1563 END OBJ(hr, 0) obj->data.i = arg ? atoi(arg) : 1;
1564 END OBJ(offset, 0) obj->data.i = arg ? atoi(arg) : 1;
1565 END OBJ(voffset, 0) obj->data.i = arg ? atoi(arg) : 1;
1566 END OBJ(i2c, INFO_I2C) char buf1[64], buf2[64];
1570 ERR("i2c needs arguments");
1571 obj->type = OBJ_text;
1572 //obj->data.s = strdup("${i2c}");
1576 if (sscanf(arg, "%63s %63s %d", buf1, buf2, &n) != 3) {
1577 /* if scanf couldn't read three values, read type and num and use
1579 sscanf(arg, "%63s %d", buf2, &n);
1581 open_i2c_sensor(0, buf2, n, &obj->data.i2c.arg,
1582 obj->data.i2c.devtype);
1583 strncpy(obj->data.i2c.type, buf2, 63);
1586 open_i2c_sensor(buf1, buf2, n, &obj->data.i2c.arg,
1587 obj->data.i2c.devtype);
1588 strncpy(obj->data.i2c.type, buf2, 63);
1591 END OBJ(top, INFO_TOP)
1595 ERR("top needs arguments");
1596 obj->type = OBJ_text;
1597 //obj->data.s = strdup("${top}");
1600 if (sscanf(arg, "%63s %i", buf, &n) == 2) {
1601 if (strcmp(buf, "name") == 0) {
1602 obj->data.top.type = TOP_NAME;
1603 } else if (strcmp(buf, "cpu") == 0) {
1604 obj->data.top.type = TOP_CPU;
1605 } else if (strcmp(buf, "pid") == 0) {
1606 obj->data.top.type = TOP_PID;
1607 } else if (strcmp(buf, "mem") == 0) {
1608 obj->data.top.type = TOP_MEM;
1610 ERR("invalid arg for top");
1613 if (n < 1 || n > 10) {
1614 CRIT_ERR("invalid arg for top");
1617 obj->data.top.num = n - 1;
1621 ERR("invalid args given for top");
1624 END OBJ(top_mem, INFO_TOP)
1628 ERR("top_mem needs arguments");
1629 obj->type = OBJ_text;
1630 obj->data.s = strdup("${top_mem}");
1633 if (sscanf(arg, "%63s %i", buf, &n) == 2) {
1634 if (strcmp(buf, "name") == 0) {
1635 obj->data.top.type = TOP_NAME;
1636 } else if (strcmp(buf, "cpu") == 0) {
1637 obj->data.top.type = TOP_CPU;
1638 } else if (strcmp(buf, "pid") == 0) {
1639 obj->data.top.type = TOP_PID;
1640 } else if (strcmp(buf, "mem") == 0) {
1641 obj->data.top.type = TOP_MEM;
1643 ERR("invalid arg for top");
1646 if (n < 1 || n > 10) {
1647 CRIT_ERR("invalid arg for top");
1650 obj->data.top.num = n - 1;
1654 ERR("invalid args given for top");
1657 END OBJ(addr, INFO_NET)
1659 obj->data.net = get_net_stat(arg);
1662 CRIT_ERR("addr needs argument");
1664 END OBJ(linkstatus, INFO_WIFI)
1666 obj->data.net = get_net_stat(arg);
1669 CRIT_ERR("linkstatus needs argument");
1675 ERR("tail needs arguments");
1676 obj->type = OBJ_text;
1677 obj->data.s = strdup("${tail}");
1680 if (sscanf(arg, "%63s %i %i", buf, &n1, &n2) == 2) {
1681 if (n1 < 1 || n1 > 30) {
1682 CRIT_ERR("invalid arg for tail, number of lines must be between 1 and 30");
1686 fp = fopen(buf, "r");
1688 obj->data.tail.logfile =
1689 malloc(TEXT_BUFFER_SIZE);
1690 strcpy(obj->data.tail.logfile, buf);
1691 obj->data.tail.wantedlines = n1 - 1;
1692 obj->data.tail.interval =
1693 update_interval * 2;
1697 CRIT_ERR("tail logfile does not exist, or you do not have correct permissions");
1700 } else if (sscanf(arg, "%63s %i %i", buf, &n1, &n2) == 3) {
1701 if (n1 < 1 || n1 > 30) {
1703 ("invalid arg for tail, number of lines must be between 1 and 30");
1705 } else if (n2 < 1 || n2 < update_interval) {
1707 ("invalid arg for tail, interval must be greater than 0 and Conky's interval");
1711 fp = fopen(buf, "r");
1713 obj->data.tail.logfile =
1714 malloc(TEXT_BUFFER_SIZE);
1715 strcpy(obj->data.tail.logfile, buf);
1716 obj->data.tail.wantedlines = n1 - 1;
1717 obj->data.tail.interval = n2;
1721 CRIT_ERR("tail logfile does not exist, or you do not have correct permissions");
1727 ERR("invalid args given for tail");
1730 obj->data.tail.buffer = malloc(TEXT_BUFFER_SIZE * 20); /* asumming all else worked */
1735 ERR("head needs arguments");
1736 obj->type = OBJ_text;
1737 obj->data.s = strdup("${head}");
1740 if (sscanf(arg, "%63s %i %i", buf, &n1, &n2) == 2) {
1741 if (n1 < 1 || n1 > 30) {
1742 CRIT_ERR("invalid arg for head, number of lines must be between 1 and 30");
1746 fp = fopen(buf, "r");
1748 obj->data.tail.logfile =
1749 malloc(TEXT_BUFFER_SIZE);
1750 strcpy(obj->data.tail.logfile, buf);
1751 obj->data.tail.wantedlines = n1 - 1;
1752 obj->data.tail.interval =
1753 update_interval * 2;
1757 CRIT_ERR("head logfile does not exist, or you do not have correct permissions");
1760 } else if (sscanf(arg, "%63s %i %i", buf, &n1, &n2) == 3) {
1761 if (n1 < 1 || n1 > 30) {
1763 ("invalid arg for head, number of lines must be between 1 and 30");
1765 } else if (n2 < 1 || n2 < update_interval) {
1767 ("invalid arg for head, interval must be greater than 0 and Conky's interval");
1771 fp = fopen(buf, "r");
1773 obj->data.tail.logfile =
1774 malloc(TEXT_BUFFER_SIZE);
1775 strcpy(obj->data.tail.logfile, buf);
1776 obj->data.tail.wantedlines = n1 - 1;
1777 obj->data.tail.interval = n2;
1781 CRIT_ERR("head logfile does not exist, or you do not have correct permissions");
1787 ERR("invalid args given for head");
1790 obj->data.tail.buffer = malloc(TEXT_BUFFER_SIZE * 20); /* asumming all else worked */
1791 END OBJ(loadavg, INFO_LOADAVG) int a = 1, b = 2, c = 3, r = 3;
1793 r = sscanf(arg, "%d %d %d", &a, &b, &c);
1794 if (r >= 3 && (c < 1 || c > 3))
1796 if (r >= 2 && (b < 1 || b > 3))
1798 if (r >= 1 && (a < 1 || a > 3))
1801 obj->data.loadavg[0] = (r >= 1) ? (unsigned char) a : 0;
1802 obj->data.loadavg[1] = (r >= 2) ? (unsigned char) b : 0;
1803 obj->data.loadavg[2] = (r >= 3) ? (unsigned char) c : 0;
1804 END OBJ(if_existing, 0)
1805 if (blockdepth >= MAX_IF_BLOCK_DEPTH) {
1806 CRIT_ERR("MAX_IF_BLOCK_DEPTH exceeded");
1809 ERR("if_existing needs an argument");
1810 obj->data.ifblock.s = 0;
1812 obj->data.ifblock.s = strdup(arg);
1813 blockstart[blockdepth] = object_count;
1814 obj->data.ifblock.pos = object_count + 2;
1816 END OBJ(if_mounted, 0)
1817 if (blockdepth >= MAX_IF_BLOCK_DEPTH) {
1818 CRIT_ERR("MAX_IF_BLOCK_DEPTH exceeded");
1821 ERR("if_mounted needs an argument");
1822 obj->data.ifblock.s = 0;
1824 obj->data.ifblock.s = strdup(arg);
1825 blockstart[blockdepth] = object_count;
1826 obj->data.ifblock.pos = object_count + 2;
1828 END OBJ(if_running, 0)
1829 if (blockdepth >= MAX_IF_BLOCK_DEPTH) {
1830 CRIT_ERR("MAX_IF_BLOCK_DEPTH exceeded");
1834 snprintf(buf, 256, "pidof %s >/dev/null", arg);
1835 obj->data.ifblock.s = strdup(buf);
1837 ERR("if_running needs an argument");
1838 obj->data.ifblock.s = 0;
1840 blockstart[blockdepth] = object_count;
1841 obj->data.ifblock.pos = object_count + 2;
1845 END OBJ(mails, INFO_MAIL)
1846 END OBJ(mem, INFO_MEM)
1847 END OBJ(memmax, INFO_MEM)
1848 END OBJ(memperc, INFO_MEM)
1849 END OBJ(membar, INFO_MEM)
1850 (void) scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
1851 END OBJ(memgraph, INFO_MEM)
1852 (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
1853 END OBJ(mixer, INFO_MIXER) obj->data.l = mixer_init(arg);
1854 END OBJ(mixerl, INFO_MIXER) obj->data.l = mixer_init(arg);
1855 END OBJ(mixerr, INFO_MIXER) obj->data.l = mixer_init(arg);
1856 END OBJ(mixerbar, INFO_MIXER)
1857 scan_mixer_bar(arg, &obj->data.mixerbar.l,
1858 &obj->data.mixerbar.w, &obj->data.mixerbar.h);
1859 END OBJ(mixerlbar, INFO_MIXER)
1860 scan_mixer_bar(arg, &obj->data.mixerbar.l,
1861 &obj->data.mixerbar.w, &obj->data.mixerbar.h);
1862 END OBJ(mixerrbar, INFO_MIXER)
1863 scan_mixer_bar(arg, &obj->data.mixerbar.l,
1864 &obj->data.mixerbar.w, &obj->data.mixerbar.h);
1867 OBJ(ml_upload_counter, INFO_MLDONKEY)
1868 END OBJ(ml_download_counter, INFO_MLDONKEY)
1869 END OBJ(ml_nshared_files, INFO_MLDONKEY)
1870 END OBJ(ml_shared_counter, INFO_MLDONKEY)
1871 END OBJ(ml_tcp_upload_rate, INFO_MLDONKEY)
1872 END OBJ(ml_tcp_download_rate, INFO_MLDONKEY)
1873 END OBJ(ml_udp_upload_rate, INFO_MLDONKEY)
1874 END OBJ(ml_udp_download_rate, INFO_MLDONKEY)
1875 END OBJ(ml_ndownloaded_files, INFO_MLDONKEY)
1876 END OBJ(ml_ndownloading_files, INFO_MLDONKEY) END
1878 OBJ(new_mails, INFO_MAIL)
1879 END OBJ(nodename, 0)
1880 END OBJ(processes, INFO_PROCS)
1881 END OBJ(running_processes, INFO_RUN_PROCS)
1882 END OBJ(shadecolor, 0)
1884 obj->data.l = arg ? get_x11_color(arg) : default_bg_color;
1886 END OBJ(outlinecolor, 0)
1888 obj->data.l = arg ? get_x11_color(arg) : default_out_color;
1890 END OBJ(stippled_hr, 0)
1892 int a = stippled_borders, b = 1;
1894 if (sscanf(arg, "%d %d", &a, &b) != 2)
1895 sscanf(arg, "%d", &b);
1899 obj->data.pair.a = a;
1900 obj->data.pair.b = b;
1902 END OBJ(swap, INFO_MEM)
1903 END OBJ(swapmax, INFO_MEM)
1904 END OBJ(swapperc, INFO_MEM)
1905 END OBJ(swapbar, INFO_MEM)
1906 (void) scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
1907 END OBJ(sysname, 0) END OBJ(temp1, INFO_I2C) obj->type = OBJ_i2c;
1909 open_i2c_sensor(0, "temp", 1, &obj->data.i2c.arg,
1910 obj->data.i2c.devtype);
1911 END OBJ(temp2, INFO_I2C) obj->type = OBJ_i2c;
1913 open_i2c_sensor(0, "temp", 2, &obj->data.i2c.arg,
1914 obj->data.i2c.devtype);
1915 END OBJ(time, 0) obj->data.s = strdup(arg ? arg : "%F %T");
1916 END OBJ(utime, 0) obj->data.s = strdup(arg ? arg : "%F %T");
1917 END OBJ(totaldown, INFO_NET)
1919 obj->data.net = get_net_stat(arg);
1922 CRIT_ERR("totaldown needs argument");
1924 END OBJ(totalup, INFO_NET) obj->data.net = get_net_stat(arg);
1926 obj->data.net = get_net_stat(arg);
1929 CRIT_ERR("totalup needs argument");
1932 END OBJ(alignr, 0) obj->data.i = arg ? atoi(arg) : 0;
1933 END OBJ(alignc, 0) obj->data.i = arg ? atoi(arg) : 0;
1934 END OBJ(upspeed, INFO_NET)
1936 obj->data.net = get_net_stat(arg);
1939 CRIT_ERR("upspeed needs argument");
1941 END OBJ(upspeedf, INFO_NET)
1943 obj->data.net = get_net_stat(arg);
1946 CRIT_ERR("upspeedf needs argument");
1949 END OBJ(upspeedgraph, INFO_NET)
1950 (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
1952 sscanf(arg, "%63s %*i,%*i %*i", buf);
1953 obj->data.net = get_net_stat(buf);
1954 if (sscanf(arg, "%*s %d,%d %*d", &obj->b, &obj->a) <= 1) {
1955 if (sscanf(arg, "%*s %d,%d", &obj->a, &obj->a) <= 1) {
1960 END OBJ(uptime_short, INFO_UPTIME) END OBJ(uptime, INFO_UPTIME) END
1961 OBJ(adt746xcpu, 0) END OBJ(adt746xfan, 0) END
1962 #if defined(__FreeBSD__) && (defined(i386) || defined(__i386__))
1963 OBJ(apm_adapter, 0) END
1964 OBJ(apm_battery_life, 0) END
1965 OBJ(apm_battery_time, 0) END
1966 #endif /* __FreeBSD__ */
1968 OBJ(seti_prog, INFO_SETI) END OBJ(seti_progbar, INFO_SETI)
1969 (void) scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
1970 END OBJ(seti_credit, INFO_SETI) END
1973 OBJ(mpd_artist, INFO_MPD)
1974 END OBJ(mpd_title, INFO_MPD)
1975 END OBJ(mpd_random, INFO_MPD)
1976 END OBJ(mpd_repeat, INFO_MPD)
1977 END OBJ(mpd_elapsed, INFO_MPD)
1978 END OBJ(mpd_length, INFO_MPD)
1979 END OBJ(mpd_track, INFO_MPD)
1980 END OBJ(mpd_name, INFO_MPD)
1981 END OBJ(mpd_file, INFO_MPD)
1982 END OBJ(mpd_percent, INFO_MPD)
1983 END OBJ(mpd_album, INFO_MPD)
1984 END OBJ(mpd_vol, INFO_MPD)
1985 END OBJ(mpd_bitrate, INFO_MPD)
1986 END OBJ(mpd_status, INFO_MPD)
1987 END OBJ(mpd_bar, INFO_MPD)
1988 (void) scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
1989 END OBJ(mpd_smart, INFO_MPD) END
1992 OBJ(xmms2_artist, INFO_XMMS2)
1993 END OBJ(xmms2_title, INFO_XMMS2)
1994 END OBJ(xmms2_length, INFO_XMMS2)
1995 END OBJ(xmms2_track, INFO_XMMS2)
1996 END OBJ(xmms2_file, INFO_XMMS2)
1997 END OBJ(xmms2_album, INFO_XMMS2)
1998 END OBJ(xmms2_status, INFO_XMMS2)
1999 END OBJ(xmms2_elapsed, INFO_XMMS2)
2000 END OBJ(xmms2_length, INFO_XMMS2)
2001 END OBJ(xmms2_percent, INFO_XMMS2)
2002 END OBJ(xmms2_bar, INFO_XMMS2)
2003 (void) scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
2006 #if defined(XMMS) || defined(BMP) || defined(AUDACIOUS) || defined(INFOPIPE)
2007 OBJ(xmms_status, INFO_XMMS) END
2008 OBJ(xmms_title, INFO_XMMS) END
2009 OBJ(xmms_length, INFO_XMMS) END
2010 OBJ(xmms_length_seconds, INFO_XMMS) END
2011 OBJ(xmms_position, INFO_XMMS) END
2012 OBJ(xmms_position_seconds, INFO_XMMS) END
2013 OBJ(xmms_bitrate, INFO_XMMS) END
2014 OBJ(xmms_frequency, INFO_XMMS) END
2015 OBJ(xmms_channels, INFO_XMMS) END
2016 OBJ(xmms_filename, INFO_XMMS) END
2017 OBJ(xmms_playlist_length, INFO_XMMS) END
2018 OBJ(xmms_playlist_position, INFO_XMMS) END
2019 OBJ(xmms_bar, INFO_XMMS)
2020 (void) scan_bar(arg, &obj->a, &obj->b);
2024 OBJ(bmpx_title, INFO_BMPX)
2025 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
2027 OBJ(bmpx_artist, INFO_BMPX)
2028 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
2030 OBJ(bmpx_album, INFO_BMPX)
2031 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
2033 OBJ(bmpx_track, INFO_BMPX)
2034 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
2036 OBJ(bmpx_uri, INFO_BMPX)
2037 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
2039 OBJ(bmpx_bitrate, INFO_BMPX)
2040 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
2043 #ifdef TCP_PORT_MONITOR
2044 OBJ(tcp_portmon, INFO_TCP_PORT_MONITOR)
2045 int argc, port_begin, port_end, item, connection_index;
2047 memset(itembuf,0,sizeof(itembuf));
2049 /* massive argument checking */
2051 CRIT_ERR("tcp_portmon: needs arguments");
2053 argc=sscanf(arg, "%d %d %31s %d", &port_begin, &port_end, itembuf, &connection_index);
2054 if ( (argc != 3) && (argc != 4) )
2056 CRIT_ERR("tcp_portmon: requires 3 or 4 arguments");
2058 if ( (port_begin<1) || (port_begin>65535) || (port_end<1) || (port_end>65535) )
2060 CRIT_ERR("tcp_portmon: port values must be from 1 to 65535");
2062 if ( port_begin > port_end )
2064 CRIT_ERR("tcp_portmon: starting port must be <= ending port");
2066 if ( strncmp(itembuf,"count",31) == 0 )
2068 else if ( strncmp(itembuf,"rip",31) == 0 )
2070 else if ( strncmp(itembuf,"rhost",31) == 0 )
2072 else if ( strncmp(itembuf,"rport",31) == 0 )
2074 else if ( strncmp(itembuf,"rservice",31) == 0 )
2076 else if ( strncmp(itembuf,"lip",31) == 0 )
2078 else if ( strncmp(itembuf,"lhost",31) == 0 )
2080 else if ( strncmp(itembuf,"lport",31) == 0 )
2082 else if ( strncmp(itembuf,"lservice",31) == 0 )
2086 CRIT_ERR("tcp_portmon: invalid item specified");
2088 if ( (argc==3) && (item!=COUNT) )
2090 CRIT_ERR("tcp_portmon: 3 argument form valid only for \"count\" item");
2092 if ( (argc==4) && (connection_index<0) )
2094 CRIT_ERR("tcp_portmon: connection index must be non-negative");
2096 /* ok, args looks good. save the text object data */
2097 obj->data.tcp_port_monitor.port_range_begin = (in_addr_t)port_begin;
2098 obj->data.tcp_port_monitor.port_range_end = (in_addr_t)port_end;
2099 obj->data.tcp_port_monitor.item = item;
2100 obj->data.tcp_port_monitor.connection_index = connection_index;
2102 /* if the port monitor collection hasn't been created, we must create it */
2103 if ( !info.p_tcp_port_monitor_collection )
2105 info.p_tcp_port_monitor_collection =
2106 create_tcp_port_monitor_collection( &tcp_port_monitor_collection_args );
2107 if ( !info.p_tcp_port_monitor_collection )
2109 CRIT_ERR("tcp_portmon: unable to create port monitor collection");
2113 /* if a port monitor for this port does not exist, create one and add it to the collection */
2114 if ( find_tcp_port_monitor( info.p_tcp_port_monitor_collection, port_begin, port_end ) == NULL )
2116 tcp_port_monitor_t * p_monitor =
2117 create_tcp_port_monitor( port_begin, port_end, &tcp_port_monitor_args );
2120 CRIT_ERR("tcp_portmon: unable to create port monitor");
2122 /* add the newly created monitor to the collection */
2123 if ( insert_tcp_port_monitor_into_collection( info.p_tcp_port_monitor_collection,
2126 CRIT_ERR("tcp_portmon: unable to add port monitor to collection");
2133 ERR("unknown variable %s", s);
2134 obj->type = OBJ_text;
2135 snprintf(buf, 256, "${%s}", s);
2136 obj->data.s = strdup(buf);
2143 static struct text_object *create_plain_text(const char *s)
2145 struct text_object *obj;
2147 if (s == NULL || *s == '\0') {
2151 obj = new_text_object_internal();
2153 obj->type = OBJ_text;
2154 obj->data.s = strdup(s);
2158 static struct text_object_list *extract_variable_text_internal(const char *p)
2160 struct text_object_list *retval;
2161 struct text_object *obj;
2164 retval = malloc(sizeof(struct text_object_list));
2165 memset(retval, 0, sizeof(struct text_object_list));
2166 retval->text_object_count = 0;
2171 obj = create_plain_text(s);
2173 // allocate memory for the object
2174 retval->text_objects = realloc(retval->text_objects,
2175 sizeof(struct text_object) * (retval->text_object_count+1));
2176 // assign the new object to the end of the list.
2177 memcpy(&retval->text_objects[retval->text_object_count++],
2178 obj, sizeof(struct text_object));
2190 /* variable is either $foo or ${foo} */
2194 while (*p && *p != '}')
2200 while (*p && (isalnum((int) *p)
2205 /* copy variable to buffer */
2206 len = (p - s > 255) ? 255 : (p - s);
2207 strncpy(buf, s, len);
2216 /* if variable wasn't found from environment, use some special */
2222 if (strchr(buf, ' ')) {
2223 arg = strchr(buf, ' ');
2226 while (isspace((int) *arg))
2232 /* lowercase variable name */
2239 // create new object
2240 obj = construct_text_object(buf, arg, retval->text_object_count, retval->text_objects);
2242 // allocate memory for the object
2243 retval->text_objects = realloc(retval->text_objects,
2244 sizeof(struct text_object) * (retval->text_object_count+1));
2245 // assign the new object to the end of the list.
2246 memcpy(&retval->text_objects[retval->text_object_count++],
2247 obj, sizeof(struct text_object));
2253 obj = create_plain_text("$");
2255 // allocate memory for the object
2256 retval->text_objects = realloc(retval->text_objects,
2257 sizeof(struct text_object) * (retval->text_object_count+1));
2258 // assign the new object to the end of the list.
2259 memcpy(&retval->text_objects[retval->text_object_count++],
2260 obj, sizeof(struct text_object));
2267 obj = create_plain_text(s);
2269 // allocate memory for the object
2270 retval->text_objects = realloc(retval->text_objects,
2271 sizeof(struct text_object) * (retval->text_object_count+1));
2272 // assign the new object to the end of the list.
2273 memcpy(&retval->text_objects[retval->text_object_count++],
2274 obj, sizeof(struct text_object));
2279 ERR("one or more $endif's are missing");
2285 static void extract_variable_text(const char *p)
2287 struct text_object_list *list;
2289 free_text_objects(text_object_count, text_objects);
2290 text_object_count = 0;
2291 text_objects = NULL;
2295 #endif /* MLDONKEY */
2297 list = extract_variable_text_internal(p);
2298 text_objects = list->text_objects;
2299 text_object_count = list->text_object_count;
2306 void parse_conky_vars(char * text, char * p, struct information *cur) {
2307 struct text_object_list *object_list = extract_variable_text_internal(text);
2308 generate_text_internal(p, P_MAX_SIZE, object_list->text_objects, object_list->text_object_count, cur);
2312 static void generate_text_internal(char *p, int p_max_size, struct text_object *objs, unsigned int object_count, struct information *cur)
2315 for (i = 0; i < object_count; i++) {
2316 struct text_object *obj = &objs[i];
2318 #define OBJ(a) break; case OBJ_##a:
2320 switch (obj->type) {
2323 ERR("not implemented obj type %d",
2327 /* does anyone have decimals in acpi temperature? */
2329 snprintf(p, p_max_size, "%d", (int)
2330 get_acpi_temperature(obj->
2334 snprintf(p, 5, "%d ", (int)
2335 get_acpi_temperature(obj->
2340 /* does anyone have decimals in acpi temperature? */
2342 snprintf(p, p_max_size, "%d", (int)
2343 ((get_acpi_temperature(obj->
2345 i)+ 40) * 9.0 / 5 - 40));
2347 snprintf(p, 5, "%d ", (int)
2348 ((get_acpi_temperature(obj->
2350 i)+ 40) * 9.0 / 5 - 40));
2353 get_freq(p, p_max_size, "%.0f", 1); /* pk */
2356 get_freq(p, p_max_size, "%'.2f", 1000); /* pk */
2360 get_freq_dynamic(p, 6, "%.0f ", 1 ); /* pk */
2362 get_freq_dynamic(p, p_max_size, "%.0f", 1 ); /* pk */
2367 get_freq_dynamic(p, 6, "%'.2f ", 1000); /* pk */
2369 get_freq_dynamic(p, p_max_size, "%'.2f", 1000); /* pk */
2373 get_adt746x_cpu(p, p_max_size); /* pk */
2376 get_adt746x_fan(p, p_max_size); /* pk */
2379 get_acpi_fan(p, p_max_size); /* pk */
2381 OBJ(acpiacadapter) {
2382 get_acpi_ac_adapter(p, p_max_size); /* pk */
2385 get_battery_stuff(p, p_max_size, obj->data.s);
2388 human_readable(cur->buffers * 1024, p, 255);
2391 human_readable(cur->cached * 1024, p, 255);
2394 if (obj->data.cpu_index > info.cpu_count) {
2395 printf("obj->data.cpu_index %i info.cpu_count %i", obj->data.cpu_index, info.cpu_count);
2396 CRIT_ERR("attempting to use more CPUs then you have!");
2399 snprintf(p, p_max_size, "%*d", pad_percents,
2400 (int) round_to_int(cur->cpu_usage[obj->data.cpu_index] *
2403 snprintf(p, 4, "%*d ",
2405 (int) round_to_int(cur->cpu_usage[obj->data.cpu_index] *
2411 (int) round_to_int(cur->cpu_usage[obj->data.cpu_index] * 255.0));
2414 new_graph(p, obj->a,
2415 obj->b, obj->c, obj->d,
2416 (unsigned int) round_to_int(cur->cpu_usage[obj->data.cpu_index] *
2420 new_fg(p, obj->data.l);
2422 #if defined(__linux__)
2424 snprintf(p, p_max_size, "%s", i8k.version);
2427 snprintf(p, p_max_size, "%s", i8k.bios);
2430 snprintf(p, p_max_size, "%s", i8k.serial);
2433 snprintf(p, p_max_size, "%s", i8k.cpu_temp);
2435 OBJ(i8k_cpu_tempf) {
2437 sscanf(i8k.cpu_temp, "%d", &cpu_temp);
2438 snprintf(p, p_max_size, "%.1f", cpu_temp*(9.0/5.0)+32.0);
2440 OBJ(i8k_left_fan_status) {
2441 int left_fan_status;
2442 sscanf(i8k.left_fan_status, "%d", &left_fan_status);
2443 if(left_fan_status == 0) {
2444 snprintf(p, p_max_size,"off");
2445 } if(left_fan_status == 1) {
2446 snprintf(p, p_max_size, "low");
2447 } if(left_fan_status == 2) {
2448 snprintf(p, p_max_size, "high");
2452 OBJ(i8k_right_fan_status) {
2453 int right_fan_status;
2454 sscanf(i8k.right_fan_status, "%d", &right_fan_status);
2455 if(right_fan_status == 0) {
2456 snprintf(p, p_max_size,"off");
2457 } if(right_fan_status == 1) {
2458 snprintf(p, p_max_size, "low");
2459 } if(right_fan_status == 2) {
2460 snprintf(p, p_max_size, "high");
2463 OBJ(i8k_left_fan_rpm) {
2464 snprintf(p, p_max_size, "%s", i8k.left_fan_rpm);
2466 OBJ(i8k_right_fan_rpm) {
2467 snprintf(p, p_max_size, "%s", i8k.right_fan_rpm);
2469 OBJ(i8k_ac_status) {
2471 sscanf(i8k.ac_status, "%d", &ac_status);
2472 if(ac_status == -1) {
2473 snprintf(p, p_max_size,"disabled (read i8k docs)");
2474 } if(ac_status == 0) {
2475 snprintf(p, p_max_size, "off");
2476 } if(ac_status == 1) {
2477 snprintf(p, p_max_size, "on");
2480 OBJ(i8k_buttons_status) {
2481 snprintf(p, p_max_size, "%s", i8k.buttons_status);
2484 #endif /* __linux__ */
2488 new_font(p, obj->data.s);
2493 if (diskio_value > 1024*1024) {
2494 snprintf(p, p_max_size, "%.1fG",
2495 (double)diskio_value/1024/1024);
2496 } else if (diskio_value > 1024) {
2497 snprintf(p, p_max_size, "%.1fM",
2498 (double)diskio_value/1024);
2499 } else if (diskio_value > 0) {
2500 snprintf(p, p_max_size, "%dK", diskio_value);
2502 snprintf(p, p_max_size, "%d", diskio_value);
2505 if (diskio_value > 1024*1024) {
2506 snprintf(p, 6, "%.1fG ",
2507 (double)diskio_value/1024/1024);
2508 } else if (diskio_value > 1024) {
2509 snprintf(p, 6, "%.1fM ",
2510 (double)diskio_value/1024);
2511 } else if (diskio_value > 0) {
2512 snprintf(p, 6, "%dK ", diskio_value);
2514 snprintf(p, 6, "%d ", diskio_value);
2519 new_graph(p, obj->a,
2520 obj->b, obj->c, obj->d,
2521 diskio_value, obj->e, 1);
2526 snprintf(p, p_max_size, "%d",
2527 (int) (obj->data.net->
2531 snprintf(p, 6, "%d ",
2532 (int) (obj->data.net->
2538 snprintf(p, p_max_size, "%.1f",
2540 recv_speed / 1024.0);
2542 snprintf(p, 8, "%.1f ",
2544 recv_speed / 1024.0);
2546 OBJ(downspeedgraph) {
2547 if (obj->data.net->recv_speed == 0) // this is just to make the ugliness at start go away
2548 obj->data.net->recv_speed = 0.01;
2549 new_graph(p, obj->a, obj->b, obj->c, obj->d,
2550 (obj->data.net->recv_speed /
2551 1024.0), obj->e, 1);
2557 i = obj->data.ifblock.pos - 2;
2567 snprintf(p, p_max_size, "%u.%u.%u.%u",
2568 obj->data.net->addr.
2570 obj->data.net->addr.
2572 obj->data.net->addr.
2574 obj->data.net->addr.
2579 snprintf(p, p_max_size, "%d",
2580 obj->data.net->linkstatus);
2584 FILE *fp = popen(obj->data.s, "r");
2585 int length = fread(p, 1, p_max_size, fp);
2588 /*output[length] = '\0';
2589 if (length > 0 && output[length - 1] == '\n') {
2590 output[length - 1] = '\0';
2593 if (length > 0 && p[length - 1] == '\n') {
2594 p[length - 1] = '\0';
2597 //parse_conky_vars(output, p, cur);
2601 FILE *fp = popen(obj->data.s, "r");
2602 int n2 = fread(p, 1, p_max_size, fp);
2606 if (n2 && p[n2 - 1] == '\n')
2615 if (sscanf(p, "%lf", &barnum) == 0) {
2616 ERR("reading execbar value failed (perhaps it's not the correct format?)");
2618 if (barnum > 100 || barnum < 0) {
2619 ERR("your execbar value is not between 0 and 100, therefore it will be ignored");
2621 barnum = barnum / 100.0;
2622 new_bar(p, 0, 4, (int) (barnum * 255.0));
2628 FILE *fp = popen(obj->data.s, "r");
2629 int n2 = fread(p, 1, p_max_size, fp);
2633 if (n2 && p[n2 - 1] == '\n')
2642 if (sscanf(p, "%lf", &barnum) == 0) {
2643 ERR("reading execgraph value failed (perhaps it's not the correct format?)");
2645 if (barnum > 100 || barnum < 0) {
2646 ERR("your execgraph value is not between 0 and 100, therefore it will be ignored");
2648 new_graph(p, 0, 25, obj->c, obj->d, (int) (barnum), obj->e, 1);
2653 if (current_update_time - obj->data.execi.last_update < obj->data.execi.interval) {
2654 new_bar(p, 0, 4, (int) obj->f);
2657 FILE *fp = popen(obj->data.execi.cmd, "r");
2658 int n2 = fread(p, 1, p_max_size, fp);
2661 if (n2 && p[n2 - 1] == '\n')
2670 if (sscanf(p, "%f", &barnum) == 0) {
2671 ERR("reading execibar value failed (perhaps it's not the correct format?)");
2673 if (barnum > 100 || barnum < 0) {
2674 ERR("your execibar value is not between 0 and 100, therefore it will be ignored");
2676 obj->f = 255 * barnum / 100.0;
2677 new_bar(p, 0, 4, (int) obj->f);
2679 obj->data.execi.last_update =
2680 current_update_time;
2684 if (current_update_time - obj->data.execi.last_update < obj->data.execi.interval) {
2685 new_graph(p, 0, 25, obj->c, obj->d, (int) (obj->f), 100, 0);
2688 FILE *fp = popen(obj->data.execi.cmd, "r");
2689 int n2 = fread(p, 1, p_max_size, fp);
2692 if (n2 && p[n2 - 1] == '\n')
2701 if (sscanf(p, "%f", &barnum) == 0) {
2702 ERR("reading execigraph value failed (perhaps it's not the correct format?)");
2704 if (barnum > 100 || barnum < 0) {
2705 ERR("your execigraph value is not between 0 and 100, therefore it will be ignored");
2708 new_graph(p, 0, 25, obj->c, obj->d, (int) (obj->f), 100, 1);
2710 obj->data.execi.last_update = current_update_time;
2716 if (current_update_time - obj->data.execi.last_update < obj->data.execi.interval || obj->data.execi.interval == 0) {
2717 snprintf(p, p_max_size, "%s", obj->data.execi.buffer);
2719 char *output = obj->data.execi.buffer;
2720 FILE *fp = popen(obj->data.execi.cmd, "r");
2721 //int length = fread(output, 1, TEXT_BUFFER_SIZE, fp);
2722 int length = fread(output, 1, TEXT_BUFFER_SIZE, fp);
2725 output[length] = '\0';
2726 if (length > 0 && output[length - 1] == '\n') {
2727 output[length - 1] = '\0';
2729 obj->data.execi.last_update = current_update_time;
2730 snprintf(p, p_max_size, "%s", output);
2732 //parse_conky_vars(output, p, cur);
2735 if (obj->data.execi.pos < 0) {
2736 obj->data.execi.last_update = current_update_time;
2737 if (pthread_create(&(obj->data.execi.thread_info.thread), NULL, (void*)threaded_exec, (void*) obj)) {
2738 ERR("Error starting thread");
2740 obj->data.execi.pos = register_thread(&(obj->data.execi.thread_info));
2742 snprintf(p, p_max_size, "%s", obj->data.execi.buffer);
2746 if (obj->data.fs != NULL) {
2747 if (obj->data.fs->size == 0)
2766 if (obj->data.fs != NULL)
2767 human_readable(obj->data.fs->avail,
2771 if (obj->data.fs != NULL) {
2772 if (obj->data.fs->size)
2773 snprintf(p, p_max_size, "%*d",
2782 snprintf(p, p_max_size, "0");
2786 if (obj->data.fs != NULL)
2787 human_readable(obj->data.fs->size,
2791 if (obj->data.fs != NULL)
2792 human_readable(obj->data.fs->size -
2793 (obj->data.fs->free ? obj->data.fs->free :obj->data.fs->avail),
2797 if (obj->data.fs != NULL) {
2798 if (obj->data.fs->size == 0)
2816 if (obj->data.fs != NULL) {
2817 if (obj->data.fs->size)
2818 snprintf(p, 4, "%d",
2828 snprintf(p, p_max_size, "0");
2832 float *v = info.loadavg;
2834 if (obj->data.loadavg[2])
2835 snprintf(p, p_max_size, "%.2f %.2f %.2f",
2836 v[obj->data.loadavg[0] -
2838 v[obj->data.loadavg[1] -
2840 v[obj->data.loadavg[2] -
2842 else if (obj->data.loadavg[1])
2843 snprintf(p, p_max_size, "%.2f %.2f",
2844 v[obj->data.loadavg[0] -
2846 v[obj->data.loadavg[1] -
2848 else if (obj->data.loadavg[0])
2849 snprintf(p, p_max_size, "%.2f",
2850 v[obj->data.loadavg[0] -
2854 new_hr(p, obj->data.i);
2857 new_offset(p, obj->data.i);
2860 new_voffset(p, obj->data.i);
2865 r = get_i2c_info(&obj->data.i2c.fd,
2867 obj->data.i2c.devtype,
2868 obj->data.i2c.type);
2870 if (r >= 100.0 || r == 0)
2871 snprintf(p, p_max_size, "%d", (int) r);
2873 snprintf(p, p_max_size, "%.1f", r);
2876 new_alignr(p, obj->data.i);
2879 new_alignc(p, obj->data.i);
2883 if ((obj->data.ifblock.s)
2884 && (stat(obj->data.ifblock.s, &tmp) ==
2886 i = obj->data.ifblock.pos;
2893 if ((obj->data.ifblock.s)
2894 && (!check_mount(obj->data.ifblock.s))) {
2895 i = obj->data.ifblock.pos;
2902 if ((obj->data.ifblock.s)
2903 && system(obj->data.ifblock.s)) {
2904 i = obj->data.ifblock.pos;
2911 snprintf(p, p_max_size, "%s", cur->uname_s.release);
2914 snprintf(p, p_max_size, "%s", cur->uname_s.machine);
2919 human_readable(cur->mem * 1024, p, 6);
2922 human_readable(cur->memmax * 1024, p, 255);
2927 snprintf(p, p_max_size, "%*lu",
2932 snprintf(p, 4, "%*lu ",
2939 new_bar(p, obj->data.pair.a,
2941 cur->memmax ? (cur->mem * 255) /
2946 new_graph(p, obj->a,
2947 obj->b, obj->c, obj->d,
2948 cur->memmax ? (cur->mem * 100.0) /
2949 (cur->memmax) : 0.0, 100, 1);
2953 snprintf(p, p_max_size, "%d",
2954 mixer_get_avg(obj->data.l));
2957 snprintf(p, p_max_size, "%d",
2958 mixer_get_left(obj->data.l));
2961 snprintf(p, p_max_size, "%d",
2962 mixer_get_right(obj->data.l));
2965 new_bar(p, obj->data.mixerbar.w,
2966 obj->data.mixerbar.h,
2967 mixer_get_avg(obj->data.mixerbar.
2971 new_bar(p, obj->data.mixerbar.w,
2972 obj->data.mixerbar.h,
2973 mixer_get_left(obj->data.mixerbar.
2977 new_bar(p, obj->data.mixerbar.w,
2978 obj->data.mixerbar.h,
2979 mixer_get_right(obj->data.mixerbar.
2985 snprintf(p, p_max_size, "%d", cur->mail_count);
2988 snprintf(p, p_max_size, "%d", cur->new_mail_count);
2991 OBJ(ml_upload_counter) {
2992 snprintf(p, p_max_size, "%lld",
2993 mlinfo.upload_counter / 1048576);
2995 OBJ(ml_download_counter) {
2996 snprintf(p, p_max_size, "%lld",
2997 mlinfo.download_counter /
3000 OBJ(ml_nshared_files) {
3001 snprintf(p, p_max_size, "%i", mlinfo.nshared_files);
3003 OBJ(ml_shared_counter) {
3004 snprintf(p, p_max_size, "%lld",
3005 mlinfo.shared_counter / 1048576);
3007 OBJ(ml_tcp_upload_rate) {
3008 snprintf(p, p_max_size, "%.2f",
3009 (float) mlinfo.tcp_upload_rate /
3012 OBJ(ml_tcp_download_rate) {
3013 snprintf(p, p_max_size, "%.2f",
3014 (float) mlinfo.tcp_download_rate /
3017 OBJ(ml_udp_upload_rate) {
3018 snprintf(p, p_max_size, "%.2f",
3019 (float) mlinfo.udp_upload_rate /
3022 OBJ(ml_udp_download_rate) {
3023 snprintf(p, p_max_size, "%.2f",
3024 (float) mlinfo.udp_download_rate /
3027 OBJ(ml_ndownloaded_files) {
3028 snprintf(p, p_max_size, "%i",
3029 mlinfo.ndownloaded_files);
3031 OBJ(ml_ndownloading_files) {
3032 snprintf(p, p_max_size, "%i",
3033 mlinfo.ndownloading_files);
3038 snprintf(p, p_max_size, "%s",
3039 cur->uname_s.nodename);
3042 new_outline(p, obj->data.l);
3046 snprintf(p, p_max_size, "%hu", cur->procs);
3048 snprintf(p, 5, "%hu ",
3051 OBJ(running_processes) {
3053 snprintf(p, p_max_size, "%hu",
3056 snprintf(p, 3, "%hu ",
3060 snprintf(p, p_max_size, "%s", obj->data.s);
3063 new_bg(p, obj->data.l);
3066 new_stippled_hr(p, obj->data.pair.a,
3070 human_readable(cur->swap * 1024, p, 255);
3073 human_readable(cur->swapmax * 1024, p,
3077 if (cur->swapmax == 0) {
3078 strncpy(p, "No swap", 255);
3081 snprintf(p, 255, "%*lu",
3087 snprintf(p, 4, "%*lu ",
3095 new_bar(p, obj->data.pair.a,
3097 cur->swapmax ? (cur->swap * 255) /
3098 (cur->swapmax) : 0);
3101 snprintf(p, p_max_size, "%s", cur->uname_s.sysname);
3104 time_t t = time(NULL);
3105 struct tm *tm = localtime(&t);
3106 setlocale(LC_TIME, "");
3107 strftime(p, p_max_size, obj->data.s, tm);
3110 time_t t = time(NULL);
3111 struct tm *tm = gmtime(&t);
3112 strftime(p, p_max_size, obj->data.s, tm);
3115 human_readable(obj->data.net->recv, p,
3119 human_readable(obj->data.net->trans, p,
3123 snprintf(p, p_max_size, "%d", total_updates);
3127 snprintf(p, p_max_size, "%d",
3128 (int) (obj->data.net->
3132 snprintf(p, 5, "%d ",
3133 (int) (obj->data.net->
3139 snprintf(p, p_max_size, "%.1f",
3141 trans_speed / 1024.0);
3143 snprintf(p, 8, "%.1f ",
3145 trans_speed / 1024.0);
3148 if (obj->data.net->trans_speed == 0) // this is just to make the ugliness at start go away
3149 obj->data.net->trans_speed = 0.01;
3150 new_graph(p, obj->a, obj->b, obj->c, obj->d,
3151 (obj->data.net->trans_speed /
3152 1024.0), obj->e, 1);
3155 format_seconds_short(p, p_max_size,
3159 format_seconds(p, p_max_size, (int) cur->uptime);
3162 #if defined(__FreeBSD__) && (defined(i386) || defined(__i386__))
3164 snprintf(p, p_max_size, "%s", get_apm_adapter());
3166 OBJ(apm_battery_life) {
3168 msg = get_apm_battery_life();
3169 snprintf(p, p_max_size, "%s", msg);
3172 OBJ(apm_battery_time) {
3174 msg = get_apm_battery_time();
3175 snprintf(p, p_max_size, "%s", msg);
3178 #endif /* __FreeBSD__ */
3181 snprintf(p, p_max_size, "%.2f",
3182 cur->seti_prog * 100.0f);
3185 new_bar(p, obj->data.pair.a,
3187 (int) (cur->seti_prog * 255.0f));
3190 snprintf(p, p_max_size, "%.0f", cur->seti_credit);
3196 snprintf(p, p_max_size, "%s", cur->mpd.title);
3199 snprintf(p, p_max_size, "%s", cur->mpd.artist);
3202 snprintf(p, p_max_size, "%s", cur->mpd.album);
3205 snprintf(p, p_max_size, "%s", cur->mpd.random);
3208 snprintf(p, p_max_size, "%s", cur->mpd.repeat);
3211 snprintf(p, p_max_size, "%s", cur->mpd.track);
3214 snprintf(p, p_max_size, "%s", cur->mpd.name);
3217 snprintf(p, p_max_size, "%s", cur->mpd.file);
3220 snprintf(p, p_max_size, "%i", cur->mpd.volume);
3223 snprintf(p, p_max_size, "%i", cur->mpd.bitrate);
3226 snprintf(p, p_max_size, "%s", cur->mpd.status);
3229 int days = 0, hours = 0, minutes =
3231 int tmp = cur->mpd.elapsed;
3232 while (tmp >= 86400) {
3236 while (tmp >= 3600) {
3246 snprintf(p, p_max_size, "%i days %i:%02i:%02i",
3247 days, hours, minutes,
3250 snprintf(p, p_max_size, "%i:%02i:%02i", hours,
3253 snprintf(p, p_max_size, "%i:%02i", minutes,
3257 int days = 0, hours = 0, minutes =
3259 int tmp = cur->mpd.length;
3260 while (tmp >= 86400) {
3264 while (tmp >= 3600) {
3274 snprintf(p, p_max_size,
3275 "%i days %i:%02i:%02i",
3276 days, hours, minutes,
3279 snprintf(p, p_max_size, "%i:%02i:%02i", hours,
3282 snprintf(p, p_max_size, "%i:%02i", minutes,
3286 snprintf(p, p_max_size, "%2.0f",
3287 cur->mpd.progress * 100);
3290 new_bar(p, obj->data.pair.a,
3292 (int) (cur->mpd.progress *
3296 if (strlen(cur->mpd.title) < 2 && strlen(cur->mpd.title) < 2) {
3297 snprintf(p, p_max_size, "%s", cur->mpd.file);
3299 snprintf(p, p_max_size, "%s - %s", cur->mpd.artist, cur->mpd.title);
3305 snprintf(p, p_max_size, "%s", cur->xmms2.title);
3308 snprintf(p, p_max_size, "%s", cur->xmms2.artist);
3311 snprintf(p, p_max_size, "%s", cur->xmms2.album);
3314 snprintf(p, p_max_size, "%i", cur->xmms2.track);
3317 snprintf(p, p_max_size, "%s", cur->xmms2.file);
3320 snprintf(p, p_max_size, "%s", cur->xmms2.status);
3322 OBJ(xmms2_elapsed) {
3323 int tmp = cur->xmms2.elapsed;
3324 snprintf(p, p_max_size, "%02d:%02d",
3325 tmp / 60000, (tmp / 1000) % 60);
3328 int tmp = cur->xmms2.length;
3329 snprintf(p, p_max_size, "%02d:%02d",
3330 tmp / 60000, (tmp / 1000) % 60);
3332 OBJ(xmms2_percent) {
3333 snprintf(p, p_max_size, "%2.0f",
3334 cur->xmms2.progress * 100);
3337 new_bar(p, obj->data.pair.a,
3339 (int) (cur->xmms2.progress *
3344 #if defined(XMMS) || defined(BMP) || defined(AUDACIOUS) || defined(INFOPIPE)
3346 snprintf(p, p_max_size, "%s", cur->xmms.items[XMMS_STATUS]);
3349 snprintf(p, p_max_size, "%s", cur->xmms.items[XMMS_TITLE]);
3352 snprintf(p, p_max_size, "%s", cur->xmms.items[XMMS_LENGTH]);
3354 OBJ(xmms_length_seconds) {
3355 snprintf(p, p_max_size, "%s", cur->xmms.items[XMMS_LENGTH_SECONDS]);
3357 OBJ(xmms_position) {
3358 snprintf(p, p_max_size, "%s", cur->xmms.items[XMMS_POSITION]);
3360 OBJ(xmms_position_seconds) {
3361 snprintf(p, p_max_size, "%s", cur->xmms.items[XMMS_POSITION_SECONDS]);
3364 snprintf(p, p_max_size, "%s", cur->xmms.items[XMMS_BITRATE]);
3366 OBJ(xmms_frequency) {
3367 snprintf(p, p_max_size, "%s", cur->xmms.items[XMMS_FREQUENCY]);
3369 OBJ(xmms_channels) {
3370 snprintf(p, p_max_size, "%s", cur->xmms.items[XMMS_CHANNELS]);
3372 OBJ(xmms_filename) {
3373 snprintf(p, p_max_size, "%s", cur->xmms.items[XMMS_FILENAME]);
3375 OBJ(xmms_playlist_length) {
3376 snprintf(p, p_max_size, "%s", cur->xmms.items[XMMS_PLAYLIST_LENGTH]);
3378 OBJ(xmms_playlist_position) {
3379 snprintf(p, p_max_size, "%s", cur->xmms.items[XMMS_PLAYLIST_POSITION]);
3383 progress= atof(cur->xmms.items[XMMS_POSITION_SECONDS]) /
3384 atof(cur->xmms.items[XMMS_LENGTH_SECONDS]);
3385 new_bar(p,obj->a,obj->b,(int)(progress*255.0f));
3390 snprintf(p, p_max_size, "%s", cur->bmpx.title);
3393 snprintf(p, p_max_size, "%s", cur->bmpx.artist);
3396 snprintf(p, p_max_size, "%s", cur->bmpx.album);
3399 snprintf(p, p_max_size, "%s", cur->bmpx.uri);
3402 snprintf(p, p_max_size, "%i", cur->bmpx.track);
3405 snprintf(p, p_max_size, "%i", cur->bmpx.bitrate);
3409 if (obj->data.top.type == TOP_NAME
3410 && obj->data.top.num >= 0
3411 && obj->data.top.num < 10) {
3412 // if we limit the buffer and add a bunch of space after, it stops the thing from
3413 // moving other shit around, which is really fucking annoying
3414 snprintf(p, 17, "%s ", cur->cpu[obj->data.top.num]->name);
3415 } else if (obj->data.top.type == TOP_CPU
3416 && obj->data.top.num >= 0
3417 && obj->data.top.num < 10) {
3418 snprintf(p, 7, "%3.2f ",
3419 cur->cpu[obj->data.top.
3421 } else if (obj->data.top.type == TOP_PID
3422 && obj->data.top.num >= 0
3423 && obj->data.top.num < 10) {
3424 snprintf(p, 8, "%i ",
3425 cur->cpu[obj->data.top.
3427 } else if (obj->data.top.type == TOP_MEM
3428 && obj->data.top.num >= 0
3429 && obj->data.top.num < 10) {
3430 snprintf(p, 7, "%3.2f ",
3431 cur->cpu[obj->data.top.
3436 if (obj->data.top.type == TOP_NAME
3437 && obj->data.top.num >= 0
3438 && obj->data.top.num < 10) {
3439 // if we limit the buffer and add a bunch of space after, it stops the thing from
3440 // moving other shit around, which is really fucking annoying
3443 cur->memu[obj->data.top.
3445 } else if (obj->data.top.type == TOP_CPU
3446 && obj->data.top.num >= 0
3447 && obj->data.top.num < 10) {
3448 snprintf(p, 7, "%3.2f ",
3449 cur->memu[obj->data.top.
3451 } else if (obj->data.top.type == TOP_PID
3452 && obj->data.top.num >= 0
3453 && obj->data.top.num < 10) {
3454 snprintf(p, 8, "%i ",
3455 cur->memu[obj->data.top.
3457 } else if (obj->data.top.type == TOP_MEM
3458 && obj->data.top.num >= 0
3459 && obj->data.top.num < 10) {
3460 snprintf(p, 7, "%3.2f ",
3461 cur->memu[obj->data.top.
3468 if (current_update_time -obj->data.tail.last_update < obj->data.tail.interval) {
3469 snprintf(p, p_max_size, "%s", obj->data.tail.buffer);
3471 obj->data.tail.last_update = current_update_time;
3475 tailstring *head = NULL;
3476 tailstring *headtmp = NULL;
3477 tailstring *freetmp = NULL;
3478 fp = fopen(obj->data.tail.logfile, "rt");
3480 ERR("tail logfile failed to open");
3483 obj->data.tail.readlines = 0;
3485 while (fgets(obj->data.tail.buffer, TEXT_BUFFER_SIZE*20, fp) != NULL) {
3492 addtail(&head, obj->data.tail.buffer);
3493 obj->data.tail.readlines++;
3499 if (obj->data.tail.readlines > 0) {
3500 for (i = 0;i < obj->data.tail.wantedlines + 1 && i < obj->data.tail.readlines; i++) {
3501 addtail(&headtmp, head->data);
3506 strcpy(obj->data.tail.buffer, headtmp->data);
3507 headtmp = headtmp->next;
3508 for (i = 1;i < obj->data.tail.wantedlines + 1 && i < obj->data.tail.readlines; i++) {
3510 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 */
3511 headtmp = headtmp->next;
3515 /* get rid of any ugly newlines at the end */
3516 if (obj->data.tail.buffer[strlen(obj->data.tail.buffer)-1] == '\n') {
3517 obj->data.tail.buffer[strlen(obj->data.tail.buffer)-1] = '\0';
3519 snprintf(p, p_max_size, "%s", obj->data.tail.buffer);
3523 strcpy(obj->data.tail.buffer, "Logfile Empty");
3524 snprintf(p, p_max_size, "Logfile Empty");
3525 } /* if readlines */
3527 } /* if cur_upd_time >= */
3529 //parse_conky_vars(obj->data.tail.buffer, p, cur);
3533 if (current_update_time -obj->data.tail.last_update < obj->data.tail.interval) {
3534 snprintf(p, p_max_size, "%s", obj->data.tail.buffer);
3536 obj->data.tail.last_update = current_update_time;
3538 tailstring *head = NULL;
3539 tailstring *headtmp = NULL;
3540 tailstring *freetmp = NULL;
3541 fp = fopen(obj->data.tail.logfile, "rt");
3543 ERR("head logfile failed to open");
3545 obj->data.tail.readlines = 0;
3546 while (fgets(obj->data.tail.buffer, TEXT_BUFFER_SIZE*20, fp) != NULL && obj->data.tail.readlines <= obj->data.tail.wantedlines) {
3547 addtail(&head, obj->data.tail.buffer);
3548 obj->data.tail.readlines++;
3552 if (obj->data.tail.readlines > 0) {
3554 addtail(&headtmp, head->data);
3559 strcpy(obj->data.tail.buffer, headtmp->data);
3560 headtmp = headtmp->next;
3562 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 */
3563 headtmp = headtmp->next;
3566 /* get rid of any ugly newlines at the end */
3567 if (obj->data.tail.buffer[strlen(obj->data.tail.buffer)-1] == '\n') {
3568 obj->data.tail.buffer[strlen(obj->data.tail.buffer)-1] = '\0';
3570 snprintf(p, p_max_size, "%s", obj->data.tail.buffer);
3572 strcpy(obj->data.tail.buffer, "Logfile Empty");
3573 snprintf(p, p_max_size, "Logfile Empty");
3574 } /* if readlines > 0 */
3575 } /* if fp == null */
3576 } /* cur_upd_time >= */
3578 //parse_conky_vars(obj->data.tail.buffer, p, cur);
3581 #ifdef TCP_PORT_MONITOR
3584 /* grab a pointer to this port monitor */
3585 tcp_port_monitor_t * p_monitor =
3586 find_tcp_port_monitor( info.p_tcp_port_monitor_collection,
3587 obj->data.tcp_port_monitor.port_range_begin,
3588 obj->data.tcp_port_monitor.port_range_end );
3590 snprintf(p, p_max_size, "monitor not found");
3594 /* now grab the text of interest */
3595 if ( peek_tcp_port_monitor( p_monitor,
3596 obj->data.tcp_port_monitor.item,
3597 obj->data.tcp_port_monitor.connection_index,
3598 p, p_max_size ) != 0 )
3600 snprintf(p, p_max_size, "monitor peek error");
3610 unsigned int a = strlen(p);
3618 double current_update_time, last_update_time;
3620 static void generate_text()
3622 struct information *cur = &info;
3629 current_update_time = get_time();
3633 /* add things to the buffer */
3639 generate_text_internal(p, P_MAX_SIZE, text_objects, text_object_count, cur);
3641 if (stuff_in_upper_case) {
3651 last_update_time = current_update_time;
3658 static void set_font()
3662 if (window.xftdraw != NULL) {
3663 XftDrawDestroy(window.xftdraw);
3665 window.xftdraw = XftDrawCreate(display, window.drawable,
3666 DefaultVisual(display,
3668 DefaultColormap(display,
3673 XSetFont(display, window.gc, fonts[selected_font].font->fid);
3682 static int text_start_x, text_start_y; /* text start position in window */
3683 static int text_width, text_height;
3687 static inline int get_string_width(const char *s)
3690 return *s ? calc_text_width(s, strlen(s)) : 0;
3696 static inline int get_string_width_special(char *s)
3709 if (*p == SPECIAL_CHAR) {
3710 /* shift everything over by 1 so that the special char doesn't mess up the size calculation */
3711 for (i = 0; i < strlen(p); i++) {
3712 *(p + i) = *(p + i + 1);
3714 if (specials[special_index+index].type == GRAPH || specials[special_index+index].type == BAR) {
3715 width += specials[special_index+index].width;
3722 if (strlen(final) > 1) {
3723 width += calc_text_width(final, strlen(final));
3735 static void text_size_updater(char *s)
3739 int h = font_height();
3740 /* get string widths and skip specials */
3743 if (*p == SPECIAL_CHAR) {
3745 w += get_string_width(s);
3748 if (specials[special_index].type == BAR
3749 || specials[special_index].type == GRAPH) {
3750 w += specials[special_index].width;
3751 if (specials[special_index].height > h) {
3752 h = specials[special_index].height;
3757 else if (specials[special_index].type == OFFSET) {
3758 w += specials[special_index].arg + get_string_width("a"); /* filthy, but works */
3760 else if (specials[special_index].type == VOFFSET) {
3761 h += specials[special_index].arg;
3763 else if (specials[special_index].type == FONT) {
3764 fontchange = specials[special_index].font_added;
3765 selected_font = specials[special_index].font_added;
3775 w += get_string_width(s);
3778 if (text_width > maximum_width && maximum_width)
3779 text_width = maximum_width;
3790 static void update_text_area()
3794 /* update text size if it isn't fixed */
3799 text_width = minimum_width;
3802 for_each_line(text_buffer, text_size_updater);
3804 if (text_height < minimum_height)
3805 text_height = minimum_height;
3806 if (text_width > maximum_width && maximum_width > 0)
3807 text_width = maximum_width;
3810 /* get text position on workarea */
3811 switch (text_alignment) {
3818 x = workarea[2] - text_width - gap_x;
3825 y = workarea[3] - text_height - gap_y;
3829 x = workarea[2] - text_width - gap_x;
3830 y = workarea[3] - text_height - gap_y;
3834 case NONE: // Let the WM manage the window
3845 if (own_window && !fixed_pos) {
3848 text_start_x = border_margin + 1;
3849 text_start_y = border_margin + 1;
3850 window.x = x - border_margin - 1;
3851 window.y = y - border_margin - 1;
3855 /* If window size doesn't match to workarea's size, then window
3856 * probably includes panels (gnome).
3857 * Blah, doesn't work on KDE. */
3858 if (workarea[2] != window.width
3859 || workarea[3] != window.height) {
3873 static int cur_x, cur_y; /* current x and y for drawing */
3874 static int draw_mode; /* FG, BG or OUTLINE */
3875 static long current_color;
3877 static inline void set_foreground_color(long c)
3880 XSetForeground(display, window.gc, c);
3884 static void draw_string(const char *s)
3888 int i, i2, pos, width_of_s;
3891 width_of_s = get_string_width(s);
3892 if (out_to_console) {
3894 fflush(stdout); /* output immediately, don't buffer */
3896 /* 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 */
3897 memset(tmpstring1,0,TEXT_BUFFER_SIZE);
3898 memset(tmpstring2,0,TEXT_BUFFER_SIZE);
3899 strncpy(tmpstring1, s, TEXT_BUFFER_SIZE-1);
3903 snprintf(space, 2, " ");
3905 max = ((text_width - width_of_s) / get_string_width(space));
3908 * This code looks for tabs in the text and coverts them to spaces.
3909 * The trick is getting the correct number of spaces,
3910 * and not going over the window's size without forcing
3911 * the window larger.
3913 for (i = 0; i < TEXT_BUFFER_SIZE; i++) {
3914 if (tmpstring1[i] == '\t') // 9 is ascii tab
3918 i2 < (8 - (1 + pos) % 8) && added <= max;
3921 if ( pos + i2 > TEXT_BUFFER_SIZE-1 )
3922 fprintf(stderr,"buffer overrun detected\n");
3924 tmpstring2[ MIN(pos + i2, TEXT_BUFFER_SIZE-1) ] = ' '; /* guard against overrun */
3929 if (tmpstring1[i] != 9) {
3931 if ( pos > TEXT_BUFFER_SIZE-1 )
3932 fprintf(stderr,"buffer overrun detected\n");
3934 tmpstring2[ MIN(pos, TEXT_BUFFER_SIZE-1) ] = tmpstring1[i]; /* guard against overrun */
3940 if (text_width == maximum_width) {
3941 /* this means the text is probably pushing the limit, so we'll chop it */
3942 while (cur_x + get_string_width(tmpstring2) - text_start_x > maximum_width && strlen(tmpstring2) > 0) {
3943 tmpstring2[strlen(tmpstring2)-1] = '\0';
3953 c.pixel = current_color;
3954 XQueryColor(display, DefaultColormap(display, screen), &c);
3957 c2.color.red = c.red;
3958 c2.color.green = c.green;
3959 c2.color.blue = c.blue;
3960 c2.color.alpha = fonts[selected_font].font_alpha;
3962 XftDrawStringUtf8(window.xftdraw, &c2, fonts[selected_font].xftfont,
3963 cur_x, cur_y, (XftChar8 *) s,
3966 XftDrawString8(window.xftdraw, &c2, fonts[selected_font].xftfont,
3967 cur_x, cur_y, (XftChar8 *) s,
3973 XDrawString(display, window.drawable, window.gc,
3974 cur_x, cur_y, s, strlen(s));
3976 cur_x += width_of_s;
3978 memcpy(tmpstring1, s, TEXT_BUFFER_SIZE);
3981 long redmask, greenmask, bluemask;
3983 void set_up_gradient()
3986 colour_depth = DisplayPlanes(display, screen);
3990 if (colour_depth != 24 && colour_depth != 16) {
3991 ERR("using non-standard colour depth, gradients may look like a lolly-pop");
3997 for(i = (colour_depth / 3)-1; i>=0; i--) {
3999 greenmask |= 1 << i;
4002 if (colour_depth%3 == 1) {
4003 greenmask |= 1 << (colour_depth / 3);
4005 redmask = redmask << (2*colour_depth / 3 + colour_depth%3);
4006 greenmask = greenmask << (colour_depth / 3);
4009 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 */
4011 int red1, green1, blue1; // first colour
4012 int red2, green2, blue2; // second colour
4013 int red3 = 0, green3 = 0, blue3 = 0; // difference
4014 short redshift = (2*colour_depth / 3 + colour_depth%3);
4015 short greenshift = (colour_depth / 3);
4016 red1 = (first_colour & redmask) >> redshift;
4017 green1 = (first_colour & greenmask) >> greenshift;
4018 blue1 = first_colour & bluemask;
4019 red2 = (last_colour & redmask) >> redshift;
4020 green2 = (last_colour & greenmask) >> greenshift;
4021 blue2 = last_colour & bluemask;
4028 if (green1 > green2) {
4031 if (green1 < green2) {
4034 if (blue1 > blue2) {
4037 if (blue1 < blue2) {
4052 if (red1 > bluemask) {
4055 if (green1 > bluemask) {
4058 if (blue1 > bluemask) {
4061 tmp_color = (red1 << redshift) | (green1 << greenshift) | blue1;
4065 inline unsigned long gradient_max(unsigned long first_colour, unsigned long last_colour) { /* this function returns the max diff for a gradient */
4066 if (colour_depth == 0) {
4069 int red1, green1, blue1; // first colour
4070 int red2, green2, blue2; // second colour
4071 long redshift = (2*colour_depth / 3 + colour_depth%3);
4072 long greenshift = (colour_depth / 3);
4073 int red3 = 0, green3 = 0, blue3 = 0; // difference
4074 red1 = (first_colour & redmask) >> redshift;
4075 green1 = (first_colour & greenmask) >> greenshift;
4076 blue1 = first_colour & bluemask;
4077 red2 = (last_colour & redmask) >> redshift;
4078 green2 = (last_colour & greenmask) >> greenshift;
4079 blue2 = last_colour & bluemask;
4080 red3 = abs(red1 - red2);
4081 green3 = abs(green1 - green2);
4082 blue3 = abs(blue1 - blue2);
4091 static void draw_line(char *s)
4095 cur_x = text_start_x;
4096 cur_y += font_ascent();
4098 short font_h = font_height();
4100 /* find specials and draw stuff */
4103 if (*p == SPECIAL_CHAR) {
4106 /* draw string before special */
4113 switch (specials[special_index].type) {
4114 case HORIZONTAL_LINE:
4117 specials[special_index].height;
4118 int mid = font_ascent() / 2;
4119 w = text_start_x + text_width -
4122 XSetLineAttributes(display,
4127 XDrawLine(display, window.drawable,
4138 specials[special_index].height;
4140 specials[special_index].arg;
4141 int mid = font_ascent() / 2;
4142 char ss[2] = { s, s };
4143 w = text_start_x + text_width -
4146 XSetLineAttributes(display,
4151 XSetDashes(display, window.gc, 0,
4153 XDrawLine(display, window.drawable,
4163 if (cur_x - text_start_x > maximum_width && maximum_width > 0) {
4167 specials[special_index].height;
4169 specials[special_index].arg;
4174 by = cur_y - (font_ascent() + h) / 2 - 1;
4178 by = cur_y - (font_ascent()/2) - 1;
4180 if (h < (font_height())) {
4183 w = specials[special_index].width;
4186 text_width - cur_x - 1;
4190 XSetLineAttributes(display,
4196 XDrawRectangle(display,
4200 XFillRectangle(display,
4204 w * bar_usage / 255,
4206 if (specials[special_index].
4208 && specials[special_index].
4212 [special_index].height;
4219 if (cur_x - text_start_x > maximum_width && maximum_width > 0) {
4223 specials[special_index].height;
4225 unsigned long last_colour = current_color;
4228 by = cur_y - (font_ascent() + h) / 2 - 1;
4232 by = cur_y - (font_ascent()/2) - 1;
4234 if (h < (font_height())) {
4237 w = specials[special_index].width;
4239 w = text_start_x + text_width - cur_x - 1;
4242 if (draw_graph_borders) {
4243 XSetLineAttributes(display, window.gc, 1, LineSolid, CapButt, JoinMiter);
4244 XDrawRectangle(display,window.drawable, window.gc, cur_x, by, w, h);
4246 XSetLineAttributes(display,
4253 int gradient_size = 0;
4254 float gradient_factor = 0;
4255 float gradient_update = 0;
4256 unsigned long tmpcolour = current_color;
4257 if (specials[special_index].last_colour != specials[special_index].first_colour) {
4258 tmpcolour = specials[special_index].last_colour;
4259 gradient_size = gradient_max(specials[special_index].last_colour, specials[special_index].first_colour);
4260 gradient_factor = (float)gradient_size / (w - 3);
4262 for (i = w - 3; i > 0; i--) {
4263 if (specials[special_index].last_colour != specials[special_index].first_colour) {
4264 XSetForeground(display, window.gc, tmpcolour);
4265 gradient_update += gradient_factor;
4266 while (gradient_update > 0) {
4267 tmpcolour = do_gradient(tmpcolour, specials[special_index].first_colour);
4271 if ((w - 3 - i) / ((float) (w - 3) / (specials[special_index].graph_width)) > j) {
4274 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 */
4276 if (specials[special_index].
4278 && specials[special_index].
4282 [special_index].height;
4284 /* if (draw_mode == BG) {
4285 set_foreground_color(default_bg_color);
4287 else if (draw_mode == OUTLINE) {
4288 set_foreground_color(default_out_color);
4290 set_foreground_color(default_fg_color);
4292 set_foreground_color(last_colour);
4298 cur_y -= font_ascent();
4299 selected_font = specials[special_index].font_added;
4300 cur_y += font_ascent();
4302 if (!use_xft || use_xdbe)
4310 if (draw_mode == FG)
4311 set_foreground_color(specials
4317 if (draw_mode == BG)
4318 set_foreground_color(specials
4324 if (draw_mode == OUTLINE)
4325 set_foreground_color(specials
4332 w += specials[special_index].arg;
4337 cur_y += specials[special_index].arg;
4343 int pos_x = text_start_x + text_width - get_string_width_special(s) /*+ border_margin*/;
4344 /*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);*/
4345 if (pos_x > specials[special_index].arg && pos_x > cur_x) {
4346 cur_x = pos_x - specials[special_index].arg;
4353 int pos_x = (text_width)/2 - get_string_width_special(s)/2 - (cur_x - text_start_x);
4354 /*int pos_x = text_start_x + text_width/2 - get_string_width_special(s)/2;*/
4355 /*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);*/
4357 specials[special_index].arg)
4360 [special_index].arg;
4377 if (cur_y_add > 0) {
4379 cur_y -= font_descent();
4384 cur_y += font_descent();
4391 static void draw_text()
4394 cur_y = text_start_y;
4397 if (draw_borders && border_width > 0) {
4398 unsigned int b = (border_width + 1) / 2;
4400 if (stippled_borders) {
4402 { stippled_borders, stippled_borders };
4403 XSetLineAttributes(display, window.gc,
4404 border_width, LineOnOffDash,
4405 CapButt, JoinMiter);
4406 XSetDashes(display, window.gc, 0, ss, 2);
4408 XSetLineAttributes(display, window.gc,
4409 border_width, LineSolid,
4410 CapButt, JoinMiter);
4413 XDrawRectangle(display, window.drawable, window.gc,
4414 text_start_x - border_margin + b,
4415 text_start_y - border_margin + b,
4416 text_width + border_margin * 2 - 1 - b * 2,
4417 text_height + border_margin * 2 - 1 -
4424 for_each_line(text_buffer, draw_line);
4427 static void draw_stuff()
4430 if (draw_shades && !draw_outline) {
4433 set_foreground_color(default_bg_color);
4442 for (i = -1; i < 2; i++)
4443 for (j = -1; j < 2; j++) {
4444 if (i == 0 && j == 0)
4448 set_foreground_color(default_out_color);
4449 draw_mode = OUTLINE;
4456 set_foreground_color(default_fg_color);
4464 swap.swap_window = window.window;
4465 swap.swap_action = XdbeBackground;
4466 XdbeSwapBuffers(display, &swap, 1);
4472 static void clear_text(int exposures)
4476 return; /* The swap action is XdbeBackground, which clears */
4480 /* there is some extra space for borders and outlines */
4481 XClearArea(display, window.drawable,
4482 text_start_x - border_margin - 1,
4483 text_start_y - border_margin - 1,
4484 text_width + border_margin * 2 + 2,
4485 text_height + border_margin * 2 + 2,
4486 exposures ? True : 0);
4491 static int need_to_update;
4493 /* update_text() generates new text and clears old text area */
4494 static void update_text()
4503 static void main_loop()
4505 #ifdef SIGNAL_BLOCKING
4506 sigset_t newmask, oldmask;
4508 sigemptyset(&newmask);
4509 sigaddset(&newmask,SIGINT);
4510 sigaddset(&newmask,SIGTERM);
4511 sigaddset(&newmask,SIGUSR1);
4515 Region region = XCreateRegion();
4519 while (total_run_times == 0 || info.looped < total_run_times - 1) {
4522 #ifdef SIGNAL_BLOCKING
4523 /* block signals. we will inspect for pending signals later */
4524 if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
4525 CRIT_ERR("unable to sigprocmask()");
4531 /* wait for X event or timeout */
4533 if (!XPending(display)) {
4538 update_interval - (get_time() -
4544 tv.tv_sec = (long) t;
4545 tv.tv_usec = (long) (t * 1000000) % 1000000;
4547 FD_SET(ConnectionNumber(display), &fdsr);
4550 s = select(ConnectionNumber(display) + 1, &fdsr, 0,
4553 usleep(update_interval*1000000); /* FIXME just sleep for the interval time if no X11 */
4558 ERR("can't select(): %s",
4569 if (need_to_update) {
4571 int wx = window.x, wy = window.y;
4579 /* resize window if it isn't right size */
4581 (text_width + border_margin * 2 + 1 !=
4583 || text_height + border_margin * 2 + 1 !=
4587 border_margin * 2 + 1;
4590 border_margin * 2 + 1;
4591 XResizeWindow(display,
4596 set_transparent_background(window.window);
4600 /* move window if it isn't in right position */
4603 || window.y != wy)) {
4604 XMoveWindow(display, window.window,
4605 window.x, window.y);
4615 r.x = text_start_x - border_margin;
4616 r.y = text_start_y - border_margin;
4617 r.width = text_width + border_margin * 2;
4618 r.height = text_height + border_margin * 2;
4619 XUnionRectWithRegion(&r, region, region);
4624 /* handle X events */
4626 while (XPending(display)) {
4628 XNextEvent(display, &ev);
4635 r.width = ev.xexpose.width;
4636 r.height = ev.xexpose.height;
4637 XUnionRectWithRegion(&r, region,
4643 case ReparentNotify:
4644 /* set background to ParentRelative for all parents */
4646 set_transparent_background(window.
4651 case ConfigureNotify:
4653 /* if window size isn't what expected, set fixed size */
4654 if (ev.xconfigure.width !=
4656 || ev.xconfigure.height !=
4658 if (window.width != 0
4659 && window.height != 0)
4662 /* clear old stuff before screwing up size and pos */
4668 if (XGetWindowAttributes(display, window.window, &attrs)) {
4683 border_margin * 2 - 1;
4686 border_margin * 2 - 1;
4687 if (text_width > maximum_width && maximum_width > 0)
4688 text_width = maximum_width;
4691 /* if position isn't what expected, set fixed pos, total_updates
4692 * avoids setting fixed_pos when window is set to weird locations
4694 /*if (total_updates >= 2 this is broken
4696 && (window.x != ev.xconfigure.x
4699 && (ev.xconfigure.x != 0
4700 || ev.xconfigure.y != 0)) {
4710 /* forward the click to the desktop window */
4711 XUngrabPointer(display, ev.xbutton.time);
4712 ev.xbutton.window = window.desktop;
4713 XSendEvent(display, ev.xbutton.window, False, ButtonPressMask, &ev);
4720 /* forward the release to the desktop window */
4721 ev.xbutton.window = window.desktop;
4722 XSendEvent(display, ev.xbutton.window, False, ButtonReleaseMask, &ev);
4733 /* XDBE doesn't seem to provide a way to clear the back buffer without
4734 * interfering with the front buffer, other than passing XdbeBackground
4735 * to XdbeSwapBuffers. That means that if we're using XDBE, we need to
4736 * redraw the text even if it wasn't part of the exposed area. OTOH,
4737 * if we're not going to call draw_stuff at all, then no swap happens
4738 * and we can safely do nothing.
4741 if (!XEmptyRegion(region)) {
4745 r.x = text_start_x - border_margin;
4746 r.y = text_start_y - border_margin;
4747 r.width = text_width + border_margin * 2;
4748 r.height = text_height + border_margin * 2;
4749 XUnionRectWithRegion(&r, region, region);
4752 XSetRegion(display, window.gc, region);
4755 XftDrawSetClip(window.xftdraw, region);
4761 XDestroyRegion(region);
4762 region = XCreateRegion();
4766 #ifdef SIGNAL_BLOCKING
4767 /* unblock signals of interest and let handler fly */
4768 if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
4769 CRIT_ERR("unable to sigprocmask()");
4772 switch(g_signal_pending) {
4775 ERR("received SIGUSR1. reloading the config file.");
4782 ERR("received SIGINT or SIGTERM to terminate. bye!");
4785 XDestroyRegion(region);
4788 return; /* return from main_loop */
4793 /* Reaching here means someone set a signal( SIGXXXX, signal_handler )
4794 * but didn't write any code to deal with it. if you don't want to
4795 * handle a signal, don't set a handler on it in the first place. */
4796 if (g_signal_pending)
4797 ERR("ignoring signal (%d)", g_signal_pending);
4805 XDestroyRegion(region);
4810 static void load_config_file(const char *);
4812 /* reload the config file */
4813 void reload_config(void)
4815 //lock_all_threads();
4817 #if defined(XMMS) || defined(BMP) || defined(AUDACIOUS) || defined(INFOPIPE)
4818 if (info.xmms.thread) {
4819 if (destroy_xmms_thread()!=0)
4821 ERR("error destroying xmms_player thread");
4825 #ifdef TCP_PORT_MONITOR
4826 destroy_tcp_port_monitor_collection( info.p_tcp_port_monitor_collection );
4829 if (current_config) {
4831 load_config_file(current_config);
4835 XClearWindow(display, RootWindow(display, screen)); // clear the window first
4838 #ifdef TCP_PORT_MONITOR
4839 info.p_tcp_port_monitor_collection = NULL;
4841 #if defined(XMMS) || defined(BMP) || defined(AUDACIOUS) || defined(INFOPIPE)
4842 if ( (!info.xmms.thread) && (info.xmms.current_project > PROJECT_NONE) &&
4843 (create_xmms_thread() !=0) )
4845 CRIT_ERR("unable to create xmms_player thread!");
4848 extract_variable_text(text);
4858 //lock_all_threads();
4863 XdbeDeallocateBackBufferName(display, window.back_buffer);
4869 XDestroyWindow(display, window.window);
4870 XClearWindow(display, RootWindow(display, screen));
4876 XClearWindow(display, RootWindow(display, screen));
4881 XFreeGC(display, window.gc);
4885 /* it is really pointless to free() memory at the end of program but ak|ra
4886 * wants me to do this */
4888 free_text_objects(text_object_count, text_objects);
4889 text_object_count = 0;
4890 text_objects = NULL;
4894 #endif /* MLDONKEY */
4896 if (text != original_text)
4899 free(current_config);
4900 free(current_mail_spool);
4904 #ifdef TCP_PORT_MONITOR
4905 destroy_tcp_port_monitor_collection( info.p_tcp_port_monitor_collection );
4906 info.p_tcp_port_monitor_collection = NULL;
4908 #if defined(XMMS) || defined(BMP) || defined(AUDACIOUS) || defined(INFOPIPE)
4909 if ( info.xmms.thread && (destroy_xmms_thread()!=0) )
4911 ERR("error destroying xmms_player thread");
4916 static int string_to_bool(const char *s)
4920 if (strcasecmp(s, "yes") == 0)
4922 if (strcasecmp(s, "true") == 0)
4924 if (strcasecmp(s, "1") == 0)
4929 static enum alignment string_to_alignment(const char *s)
4931 if (strcasecmp(s, "top_left") == 0)
4933 else if (strcasecmp(s, "top_right") == 0)
4935 else if (strcasecmp(s, "bottom_left") == 0)
4937 else if (strcasecmp(s, "bottom_right") == 0)
4938 return BOTTOM_RIGHT;
4939 else if (strcasecmp(s, "tl") == 0)
4941 else if (strcasecmp(s, "tr") == 0)
4943 else if (strcasecmp(s, "bl") == 0)
4945 else if (strcasecmp(s, "br") == 0)
4946 return BOTTOM_RIGHT;
4947 else if (strcasecmp(s, "none") == 0)
4954 static void set_default_configurations(void)
4956 fork_to_background = 0;
4957 total_run_times = 0;
4958 info.cpu_avg_samples = 2;
4959 info.net_avg_samples = 2;
4964 strcpy(info.mpd.host, "localhost");
4965 info.mpd.port = 6600;
4966 info.mpd.status = NULL;
4967 info.mpd.artist = NULL;
4968 info.mpd.album = NULL;
4969 info.mpd.title = NULL;
4970 info.mpd.random = NULL;
4971 info.mpd.track = NULL;
4972 info.mpd.name = NULL;
4973 info.mpd.file = NULL;
4976 info.xmms2.status = NULL;
4977 info.xmms2.artist = NULL;
4978 info.xmms2.album = NULL;
4979 info.xmms2.title = NULL;
4980 // info.xmms2.random = NULL;
4981 // info.xmms2.track = NULL;
4982 // info.xmms2.name = NULL;
4983 info.xmms2.file = NULL;
4984 // info.xmms2.connection = NULL;
4993 default_fg_color = WhitePixel(display, screen);
4994 default_bg_color = BlackPixel(display, screen);
4995 default_out_color = BlackPixel(display, screen);
4998 draw_graph_borders = 1;
5000 set_first_font("6x10");
5008 window.type=TYPE_NORMAL;
5010 strcpy(window.wm_class_name, "conky");
5012 stippled_borders = 0;
5015 text_alignment = BOTTOM_LEFT;
5019 free(current_mail_spool);
5022 variable_substitute(MAIL_FILE, buf, 256);
5024 current_mail_spool = strdup(buf);
5028 update_interval = 10.0;
5029 stuff_in_upper_case = 0;
5031 mlconfig.mldonkey_hostname = strdup("127.0.0.1");
5032 mlconfig.mldonkey_port = 4001;
5033 mlconfig.mldonkey_login = NULL;
5034 mlconfig.mldonkey_password = NULL;
5037 #ifdef TCP_PORT_MONITOR
5038 tcp_port_monitor_collection_args.min_port_monitors = MIN_PORT_MONITORS_DEFAULT;
5039 tcp_port_monitor_args.min_port_monitor_connections = MIN_PORT_MONITOR_CONNECTIONS_DEFAULT;
5042 #if defined(XMMS) || defined(BMP) || defined(AUDACIOUS) || defined(INFOPIPE)
5043 info.xmms.current_project=PROJECT_NONE;
5047 static void load_config_file(const char *f)
5049 #define CONF_ERR ERR("%s: %d: config file error", f, line)
5053 set_default_configurations();
5059 char buf[256], *p, *p2, *name, *value;
5061 if (fgets(buf, 256, fp) == NULL)
5066 /* break at comment */
5067 p2 = strchr(p, '#');
5072 while (*p && isspace((int) *p))
5075 continue; /* empty line */
5081 while (*p2 && !isspace((int) *p2))
5084 *p2 = '\0'; /* break at name's end */
5091 while (*p && isspace((int) *p))
5096 p2 = value + strlen(value);
5097 while (isspace((int) *(p2 - 1)))
5103 #define CONF2(a) if (strcasecmp(name, a) == 0)
5104 #define CONF(a) else CONF2(a)
5105 #define CONF3(a,b) \
5106 else if (strcasecmp(name, a) == 0 || strcasecmp(name, b) == 0)
5110 CONF2("alignment") {
5112 int a = string_to_alignment(value);
5122 ERR("on_bottom is deprecated. use own_window_hints below");
5123 on_bottom = string_to_bool(value);
5125 SET_HINT(window.hints,HINT_BELOW);
5130 CONF("background") {
5131 fork_to_background = string_to_bool(value);
5135 CONF2("background") {
5136 fork_to_background = string_to_bool(value);
5140 CONF("border_margin") {
5142 border_margin = strtol(value, 0, 0);
5146 CONF("border_width") {
5148 border_width = strtol(value, 0, 0);
5152 CONF("default_color") {
5154 default_fg_color = get_x11_color(value);
5158 CONF3("default_shade_color", "default_shadecolor") {
5160 default_bg_color = get_x11_color(value);
5164 CONF3("default_outline_color", "default_outlinecolor") {
5166 default_out_color = get_x11_color(value);
5171 #if defined(XMMS) || defined(BMP) || defined(AUDACIOUS) || defined(INFOPIPE)
5172 CONF("xmms_player") {
5174 if (strncmp(value,"none",4)==0)
5175 info.xmms.current_project=PROJECT_NONE;
5176 else if (strncmp(value,"xmms",4)==0)
5177 info.xmms.current_project=PROJECT_XMMS;
5178 else if (strncmp(value,"bmp",3)==0)
5179 info.xmms.current_project=PROJECT_BMP;
5180 else if (strncmp(value,"audacious",9)==0)
5181 info.xmms.current_project=PROJECT_AUDACIOUS;
5182 else if (strncmp(value,"infopipe",8)==0)
5183 info.xmms.current_project=PROJECT_INFOPIPE;
5194 strncpy(info.mpd.host, value, 127);
5200 info.mpd.port = strtol(value, 0, 0);
5201 if (info.mpd.port < 1
5202 || info.mpd.port > 0xffff)
5206 CONF("mpd_password") {
5208 strncpy(info.mpd.password, value, 127);
5213 CONF("cpu_avg_samples") {
5215 cpu_avg_samples = strtol(value, 0, 0);
5216 if (cpu_avg_samples < 1
5217 || cpu_avg_samples > 14)
5226 CONF("net_avg_samples") {
5228 net_avg_samples = strtol(value, 0, 0);
5229 if (net_avg_samples < 1
5230 || net_avg_samples > 14)
5246 CONF("double_buffer") {
5247 use_xdbe = string_to_bool(value);
5251 CONF("override_utf8_locale") {
5252 utf8_mode = string_to_bool(value);
5255 CONF("draw_borders") {
5256 draw_borders = string_to_bool(value);
5258 CONF("draw_graph_borders") {
5259 draw_graph_borders = string_to_bool(value);
5261 CONF("draw_shades") {
5262 draw_shades = string_to_bool(value);
5264 CONF("draw_outline") {
5265 draw_outline = string_to_bool(value);
5268 CONF("out_to_console") {
5269 out_to_console = string_to_bool(value);
5271 CONF("use_spacer") {
5272 use_spacer = string_to_bool(value);
5277 use_xft = string_to_bool(value);
5281 set_first_font(value);
5286 if (value && font_count >= 0)
5287 fonts[0].font_alpha = atof(value)
5296 if (string_to_bool(value))
5297 ERR("Xft not enabled");
5300 /* xftfont silently ignored when no Xft */
5303 /* xftalpha is silently ignored when no Xft */
5308 set_first_font(value);
5317 gap_x = atoi(value);
5323 gap_y = atoi(value);
5328 CONF("mail_spool") {
5331 variable_substitute(value, buf, 256);
5335 if (current_mail_spool)
5336 free(current_mail_spool);
5337 current_mail_spool = strdup(buf);
5343 CONF("minimum_size") {
5346 (value, "%d %d", &minimum_width,
5347 &minimum_height) != 2)
5350 &minimum_width) != 1)
5355 CONF("maximum_width") {
5357 if (sscanf(value, "%d", &maximum_width) != 1)
5363 CONF("no_buffers") {
5364 no_buffers = string_to_bool(value);
5367 CONF("mldonkey_hostname") {
5369 if (mlconfig.mldonkey_hostname != NULL) {
5370 free(mlconfig.mldonkey_hostname);
5372 mlconfig.mldonkey_hostname = strdup(value);
5377 CONF("mldonkey_port") {
5379 mlconfig.mldonkey_port = atoi(value);
5383 CONF("mldonkey_login") {
5385 if (mlconfig.mldonkey_login != NULL) {
5386 free(mlconfig.mldonkey_login);
5388 mlconfig.mldonkey_login = strdup(value);
5393 CONF("mldonkey_password") {
5395 if (mlconfig.mldonkey_password != NULL) {
5396 free(mlconfig.mldonkey_password);
5398 mlconfig.mldonkey_password = strdup(value);
5404 CONF("pad_percents") {
5405 pad_percents = atoi(value);
5409 CONF("own_window") {
5410 own_window = string_to_bool(value);
5412 CONF("wm_class_name") {
5413 memset(window.wm_class_name,0,sizeof(window.wm_class_name));
5414 strncpy(window.wm_class_name, value, sizeof(window.wm_class_name)-1);
5416 CONF("own_window_transparent") {
5417 set_transparent = string_to_bool(value);
5419 CONF("own_window_colour") {
5421 background_colour = get_x11_color(value);
5423 ERR("Invalid colour for own_winder_colour (try omitting the '#' for hex colours");
5426 CONF("own_window_hints") {
5428 char *p_hint, *p_save;
5429 char delim[] = ", ";
5431 /* tokenize the value into individual hints */
5432 if ((p_hint=strtok_r(value, delim, &p_save)) != NULL)
5434 /*fprintf(stderr, "hint [%s] parsed\n", p_hint);*/
5435 if (strncmp(p_hint,"undecorate",10) == 0)
5436 SET_HINT(window.hints,HINT_UNDECORATED);
5437 else if (strncmp(p_hint,"below",5) == 0)
5438 SET_HINT(window.hints,HINT_BELOW);
5439 else if (strncmp(p_hint,"above",5) == 0)
5440 SET_HINT(window.hints,HINT_ABOVE);
5441 else if (strncmp(p_hint,"sticky",6) == 0)
5442 SET_HINT(window.hints,HINT_STICKY);
5443 else if (strncmp(p_hint,"skip_taskbar",12) == 0)
5444 SET_HINT(window.hints,HINT_SKIP_TASKBAR);
5445 else if (strncmp(p_hint,"skip_pager",10) == 0)
5446 SET_HINT(window.hints,HINT_SKIP_PAGER);
5450 p_hint=strtok_r(NULL, delim, &p_save);
5452 while (p_hint!=NULL);
5455 CONF("own_window_type") {
5457 if (strncmp(value,"normal",6)==0)
5458 window.type = TYPE_NORMAL;
5459 else if (strncmp(value,"desktop",7)==0)
5460 window.type = TYPE_DESKTOP;
5461 else if (strncmp(value,"override",8)==0)
5462 window.type = TYPE_OVERRIDE;
5468 CONF("stippled_borders") {
5470 stippled_borders = strtol(value, 0, 0);
5472 stippled_borders = 4;
5476 ERR("temp1 configuration is obsolete, use ${i2c <i2c device here> temp 1}");
5479 ERR("temp2 configuration is obsolete, use ${i2c <i2c device here> temp 2}");
5481 CONF("update_interval") {
5483 update_interval = strtod(value, 0);
5487 CONF("total_run_times") {
5489 total_run_times = strtod(value, 0);
5494 stuff_in_upper_case = string_to_bool(value);
5499 malloc(strlen(value)
5501 strcpy(seti_dir, value);
5505 if (text != original_text)
5515 int l = strlen(text);
5516 if (fgets(buf, 256, fp) == NULL)
5519 realloc(text, l + strlen(buf)
5523 if (strlen(text) > 1024 * 8)
5529 #ifdef TCP_PORT_MONITOR
5530 CONF("min_port_monitors")
5533 (sscanf(value, "%d", &tcp_port_monitor_collection_args.min_port_monitors) != 1) ||
5534 tcp_port_monitor_collection_args.min_port_monitors < 0 )
5536 /* an error. use default, warn and continue. */
5537 tcp_port_monitor_collection_args.min_port_monitors = MIN_PORT_MONITORS_DEFAULT;
5540 else if ( tcp_port_monitor_collection_args.min_port_monitors == 0 )
5542 /* no error, just use default */
5543 tcp_port_monitor_collection_args.min_port_monitors = MIN_PORT_MONITORS_DEFAULT;
5545 /* else tcp_port_monitor_collection_args.min_port_monitors > 0 as per config */
5547 CONF("min_port_monitor_connections")
5550 (sscanf(value, "%d", &tcp_port_monitor_args.min_port_monitor_connections) != 1)
5551 || tcp_port_monitor_args.min_port_monitor_connections < 0 )
5553 /* an error. use default, warni and continue. */
5554 tcp_port_monitor_args.min_port_monitor_connections = MIN_PORT_MONITOR_CONNECTIONS_DEFAULT;
5557 else if ( tcp_port_monitor_args.min_port_monitor_connections == 0 )
5559 /* no error, just use default */
5560 tcp_port_monitor_args.min_port_monitor_connections = MIN_PORT_MONITOR_CONNECTIONS_DEFAULT;
5562 /* else tcp_port_monitor_args.min_port_monitor_connections > 0 as per config */
5566 ERR("%s: %d: no such configuration: '%s'", f, line, name);
5576 /* : means that character before that takes an argument */
5577 static const char *getopt_string = "vVdt:f:u:i:hc:w:x:y:a:"
5590 int main(int argc, char **argv)
5592 struct sigaction act, oact;
5595 memset(&info, 0, sizeof(info) );
5597 #ifdef TCP_PORT_MONITOR
5598 tcp_port_monitor_collection_args.min_port_monitors = MIN_PORT_MONITORS_DEFAULT;
5599 tcp_port_monitor_args.min_port_monitor_connections = MIN_PORT_MONITOR_CONNECTIONS_DEFAULT;
5603 SET_XMMS_PROJECT_AVAILABLE(info.xmms.project_mask, PROJECT_XMMS);
5606 SET_XMMS_PROJECT_AVAILABLE(info.xmms.project_mask, PROJECT_BMP);
5608 #if defined(AUDACIOUS)
5609 SET_XMMS_PROJECT_AVAILABLE(info.xmms.project_mask, PROJECT_AUDACIOUS);
5611 #if defined(INFOPIPE)
5612 SET_XMMS_PROJECT_AVAILABLE(info.xmms.project_mask, PROJECT_INFOPIPE);
5615 /* handle command line parameters that don't change configs */
5621 if (((s = getenv("LC_ALL")) && *s) || ((s = getenv("LC_CTYPE")) &&
5622 *s) || ((s = getenv("LANG")) && *s)) {
5624 for(x = 0; x < strlen(s) ; x++) {
5625 temp[x] = tolower(s[x]);
5627 if (strstr(temp, "utf-8") || strstr(temp, "utf8")) {
5631 if (!setlocale(LC_CTYPE, "")) {
5632 ERR("Can't set the specified locale!\nCheck LANG, LC_CTYPE, LC_ALL.");
5636 int c = getopt(argc,
5646 ("Conky " VERSION " compiled " __DATE__ "\n");
5650 /* if current_config is set to a strdup of CONFIG_FILE, free it (even
5651 * though free() does the NULL check itself;), then load optarg value */
5653 free(current_config);
5654 current_config = strdup(optarg);
5659 ("Usage: %s [OPTION]...\n"
5660 "Conky is a system monitor that renders text on desktop or to own transparent\n"
5661 "window. Command line options will override configurations defined in config\n"
5664 " -c FILE config file to load instead of "
5667 " -d daemonize, fork to background\n"
5670 " -a ALIGNMENT text alignment on screen, {top,bottom}_{left,right}\n"
5671 " -f FONT font to use\n"
5673 " -o create own window to draw\n"
5676 " -b double buffer (prevents flickering)\n"
5678 " -w WIN_ID window id to draw\n"
5679 " -x X x position\n"
5680 " -y Y y position\n"
5682 " -t TEXT text to render, remember single quotes, like -t '$uptime'\n"
5683 " -u SECS update interval\n"
5684 " -i NUM number of times to update Conky\n", argv[0]);
5688 window.window = strtol(optarg, 0, 0);
5697 /* initalize X BEFORE we load config. (we need to so that 'screen' is set) */
5701 /* load current_config or CONFIG_FILE */
5704 if (current_config == NULL) {
5705 /* load default config file */
5708 variable_substitute(CONFIG_FILE, buf, 256);
5711 current_config = strdup(buf);
5715 if (current_config != NULL && fopen((const char *)current_config, (const char *)"r"))
5716 load_config_file(current_config);
5718 set_default_configurations();
5722 if (current_mail_spool == NULL) {
5724 variable_substitute(MAIL_FILE, buf, 256);
5727 current_mail_spool = strdup(buf);
5731 /* handle other command line arguments */
5733 #if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__NetBSD__)
5734 optind = optreset = 1;
5739 #if defined(__FreeBSD__)
5740 if ((kd = kvm_open("/dev/null", "/dev/null", "/dev/null",
5741 O_RDONLY, "kvm_open")) == NULL)
5742 CRIT_ERR( "cannot read kvm");
5746 int c = getopt(argc,
5754 fork_to_background = 1;
5759 set_first_font(optarg);
5762 text_alignment = string_to_alignment(optarg);
5777 if (text != original_text)
5779 text = strdup(optarg);
5780 convert_escapes(text);
5784 update_interval = strtod(optarg, 0);
5788 total_run_times = strtod(optarg, 0);
5792 gap_x = atoi(optarg);
5796 gap_y = atoi(optarg);
5810 /* generate text and get initial size */
5811 extract_variable_text(text);
5812 if (text != original_text) {
5817 if (fork_to_background) {
5821 ERR("can't fork() to background: %s",
5828 fprintf(stderr,"\n");fflush(stderr);
5832 /* parent process */
5833 fprintf(stderr,"Conky: forked to background, pid is %d\n",pid);
5843 update_text_area(); /* to get initial size of the window */
5847 text_width + border_margin * 2 + 1,
5848 text_height + border_margin * 2 + 1,
5849 set_transparent, background_colour, info.uname_s.nodename, argv, argc);
5851 update_text_area(); /* to position text/window on screen */
5855 // why the fuck not?
5861 if (own_window && !fixed_pos) {
5862 XMoveWindow(display, window.window, window.x, window.y);
5865 set_transparent_background(window.window);
5876 /* Set signal handlers */
5877 act.sa_handler = signal_handler;
5878 sigemptyset(&act.sa_mask);
5881 act.sa_flags |= SA_RESTART;
5884 if ( sigaction(SIGINT,&act,&oact) < 0 ||
5885 sigaction(SIGUSR1,&act,&oact) < 0 ||
5886 sigaction(SIGTERM,&act,&oact) < 0 )
5888 ERR("error setting signal handler: %s", strerror(errno) );
5891 #if defined(XMMS) || defined(BMP) || defined(AUDACIOUS) || defined(INFOPIPE)
5892 if ( (info.xmms.current_project > PROJECT_NONE) && (create_xmms_thread() !=0) )
5894 CRIT_ERR("unable to create xmms_player thread!");
5900 #if defined(XMMS) || defined(BMP) || defined(AUDACIOUS) || defined(INFOPIPE)
5901 if ( info.xmms.thread && (destroy_xmms_thread()!=0) )
5903 ERR("error destroying xmms_player thread");
5907 #if defined(__FreeBSD__)
5914 void signal_handler(int sig)
5916 /* signal handler is light as a feather, as it should be.
5917 * we will poll g_signal_pending with each loop of conky
5918 * and do any signal processing there, NOT here. pkovacs. */
5919 g_signal_pending=sig;