Make a description of ${cpu} variable not so confusing.
[monky] / src / conky.c
index d25087e..f9188c3 100644 (file)
@@ -41,6 +41,8 @@
 #include <iconv.h>
 #endif
 
+#include "build.h"
+
 #define CONFIG_FILE "$HOME/.conkyrc"
 #define MAIL_FILE "$MAIL"
 #define MAX_IF_BLOCK_DEPTH 5
@@ -104,6 +106,65 @@ struct font_list *fonts = NULL;
 
 static void set_font();
 
+static void print_version()
+{
+       printf("Conky %s compiled %s for %s\n",
+                       VERSION, BUILD_DATE, BUILD_ARCH);
+
+       printf(
+       "\nCompiled in features:\n\n"
+#ifdef X11
+       " X11:\n"
+# ifdef XFT
+       "  * xft\n"
+# endif /* XFT */
+# ifdef HAVE_XDAMAGE
+       "  * Xdamage extension\n"
+# endif /* HAVE_XDAMAGE */
+# ifdef HAVE_XDBE
+       "  * Xdbe extension (double buffer)\n"
+# endif /* HAVE_XDBE */
+#endif /* X11 */
+       "\n Music detection:\n"
+#ifdef XMMS
+       "  * xmms\n"
+#endif /* XMMS */
+#ifdef BMP
+       "  * bmp\n"
+#endif /* BMP */
+#ifdef AUDACIOUS
+       "  * audacious\n"
+#endif /* AUDACIOUS */
+#ifdef INFOPIPE
+       "  * infopipe\n"
+#endif /* INFOPIPE */
+#ifdef BMPX
+       "  * bmpx\n"
+#endif /* BMPX */
+#ifdef XMMS2
+       "  * xmms2\n"
+#endif /* XMMS2 */
+#ifdef MPD
+       "  * mpd\n"
+#endif /* MPD */
+       "\n General features:\n"
+#ifdef TCP_PORT_MONITOR
+       "  * portmon\n"
+#endif /* TCP_PORT_MONITOR */
+#ifdef MLDONKEY
+       "  * mldonkey\n"
+#endif /* MLDONKEY */
+#ifdef HDDTEMP
+        "  * hddtemp\n"
+#endif /* HDDTEMP */
+#ifdef SETI
+       "  * seti\n"
+#endif /* SETI*/
+       "\n");  
+
+       exit(0);
+}
+
 int addfont(const char *data_in)
 {
        if (font_count > MAX_FONTS) {
@@ -450,6 +511,8 @@ enum {
        OFFSET,
        VOFFSET,
        FONT,
+       GOTO,
+       TAB,
 };
 
 static struct special_t {
@@ -752,6 +815,17 @@ static inline void new_alignc(char *buf, long c)
        new_special(buf, ALIGNC)->arg = c;
 }
 
+static inline void new_goto(char *buf, long c)
+{
+       new_special(buf, GOTO)->arg = c;
+}
+
+static inline void new_tab(char *buf, int a, int b) {
+       struct special_t *s = new_special(buf, TAB);
+       s->width = a;
+       s->arg = b;
+}
+
 /* quite boring functions */
 
 static inline void for_each_line(char *b, void (*f) (char *))
@@ -856,6 +930,8 @@ enum text_object_type {
        OBJ_fs_size,
        OBJ_fs_used,
        OBJ_fs_used_perc,
+       OBJ_goto,
+       OBJ_tab,
        OBJ_hr,
        OBJ_offset,
        OBJ_voffset,
@@ -934,6 +1010,7 @@ enum text_object_type {
        OBJ_text,
        OBJ_time,
        OBJ_utime,
+       OBJ_tztime,
        OBJ_totaldown,
        OBJ_totalup,
        OBJ_updates,
@@ -1031,6 +1108,9 @@ enum text_object_type {
        OBJ_iconv_start,
        OBJ_iconv_stop,
 #endif
+#ifdef HDDTEMP
+       OBJ_hddtemp,
+#endif
 };
 
 struct text_object {
@@ -1050,6 +1130,12 @@ struct text_object {
                unsigned char loadavg[3];
                unsigned int cpu_index;
                struct mail_s *mail;
+
+               struct {
+                       char *tz;    /* timezone variable */
+                       char *fmt;   /* time display formatting */
+               } tztime;
+
                struct {
                        struct fs_stat *fs;
                        int w, h;
@@ -1105,6 +1191,11 @@ struct text_object {
                        int        connection_index;  /* 0 to n-1 connections. */
                } tcp_port_monitor;
 #endif
+               struct {
+                       char *addr;
+                       int port;
+                       char *dev;
+               } hddtemp; /* 2 */
        } data;
 };
 
@@ -1707,6 +1798,12 @@ static void free_text_objects(unsigned int count, struct text_object *objs)
                                free(objs[i].data.s);
                                break;
                        case OBJ_utime:
+                               free(objs[i].data.s);
+                               break;
+                       case OBJ_tztime:
+                               free(objs[i].data.tztime.tz);
+                               free(objs[i].data.tztime.fmt);
+                               break;
                        case OBJ_imap:
                                free(info.mail);
                                break;
@@ -1948,6 +2045,12 @@ static void free_text_objects(unsigned int count, struct text_object *objs)
                                        info.first_process = NULL;
                                }
                                break;
+#ifdef HDDTEMP
+                       case OBJ_hddtemp:
+                               free(objs[i].data.hddtemp.dev);
+                               free(objs[i].data.hddtemp.addr);
+                               break;
+#endif
                }
        }
        free(objs);
@@ -2300,6 +2403,28 @@ static struct text_object *construct_text_object(const char *s, const char *arg,
        END OBJ(hr, 0) obj->data.i = arg ? atoi(arg) : 1;
        END OBJ(offset, 0) obj->data.i = arg ? atoi(arg) : 1;
        END OBJ(voffset, 0) obj->data.i = arg ? atoi(arg) : 1;
+       END OBJ(goto, 0)
+
+       if (!arg) {
+               ERR("goto needs arguments");
+               obj->type = OBJ_text;
+               obj->data.s = strdup("${goto}");
+               return NULL;
+       }
+       
+       obj->data.i = atoi(arg);
+       
+       END OBJ(tab, 0)
+       int a = 10, b = 0;
+       if (arg) {
+               if (sscanf(arg, "%d %d", &a, &b) != 2)
+                       sscanf(arg, "%d", &b);
+       }
+       if (a <= 0) 
+               a = 1;
+       obj->data.pair.a = a;
+       obj->data.pair.b = b;
+
        END OBJ(i2c, INFO_I2C) char buf1[64], buf2[64];
        int n;
 
@@ -2651,6 +2776,21 @@ static struct text_object *construct_text_object(const char *s, const char *arg,
                                obj->data.i2c.devtype);
        END OBJ(time, 0) obj->data.s = strdup(arg ? arg : "%F %T");
        END OBJ(utime, 0) obj->data.s = strdup(arg ? arg : "%F %T");
+       END OBJ(tztime, 0)
+               char buf1[256], buf2[256], *fmt, *tz;
+               fmt = tz = NULL;
+               if (arg) {
+                       int nArgs = sscanf(arg, "%255s %255[^\n]", buf1, buf2);
+                       switch (nArgs) {
+                               case 2:
+                                       tz = buf1;
+                               case 1:
+                                       fmt = buf2;
+                       }
+               }
+
+               obj->data.tztime.fmt = strdup(fmt ? fmt : "%F %T");
+               obj->data.tztime.tz = tz ? strdup(tz) : NULL;
 #ifdef HAVE_ICONV
        END OBJ(iconv_start, 0)
                if (iconv_converting) {
@@ -2848,6 +2988,17 @@ static struct text_object *construct_text_object(const char *s, const char *arg,
                memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
        END
 #endif
+#ifdef HDDTEMP
+       OBJ(hddtemp, 0)
+               if (!arg || scan_hddtemp(arg, &obj->data.hddtemp.dev, 
+                       &obj->data.hddtemp.addr, &obj->data.hddtemp.port)) {
+                       ERR("hddtemp needs arguments");
+                       obj->type = OBJ_text;
+                       obj->data.s = strdup("${hddtemp}");
+                       return NULL;
+               }
+       END
+#endif
 #ifdef TCP_PORT_MONITOR
                OBJ(tcp_portmon, INFO_TCP_PORT_MONITOR) 
                int argc, port_begin, port_end, item, connection_index;
@@ -3179,16 +3330,18 @@ static void generate_text_internal(char *p, int p_max_size, struct text_object *
                                                obj->a = get_freq(p, p_max_size, "%'.2f", 1000, obj->data.cpu_index); /* pk */
                                        }
                                }
+#if defined(__linux__)
                                OBJ(voltage_mv) {
                                        if (obj->a) {
-                                               obj->a = get_voltage(p, p_max_size, "%.0f", 1, obj->data.cpu_index); /* ptarjan */
+                                               obj->a = get_voltage(p, p_max_size, "%.0f", 1, obj->data.cpu_index);
                                        }
                                }
                                OBJ(voltage_v) {
                                        if (obj->a) {
-                                               obj->a = get_voltage(p, p_max_size, "%'.3f", 1000, obj->data.cpu_index); /* ptarjan */
+                                               obj->a = get_voltage(p, p_max_size, "%'.3f", 1000, obj->data.cpu_index);
                                        }
                                }
+#endif /* __linux__ */
 
                                OBJ(freq_dyn) {
                                        if (use_spacer) {
@@ -3841,9 +3994,29 @@ static void generate_text_internal(char *p, int p_max_size, struct text_object *
                                                 v[obj->data.loadavg[0] -
                                                   1]);
                        }
+                       OBJ(goto) {
+                               new_goto(p, obj->data.i);
+                       }
+                       OBJ(tab) {
+                               new_tab(p, obj->data.pair.a, obj->data.pair.b);
+                       }
                        OBJ(hr) {
                                new_hr(p, obj->data.i);
                        }
+                       OBJ(hddtemp) {
+                               char *temp;
+                               char unit;
+                               
+                               temp = get_hddtemp_info(obj->data.hddtemp.dev, 
+                                               obj->data.hddtemp.addr, obj->data.hddtemp.port, &unit);
+                               if (!temp) {
+                                       snprintf(p, p_max_size, "N/A");
+                               } else if (unit == '*') {
+                                       snprintf(p, p_max_size, "%s", temp);
+                               } else {
+                                        snprintf(p, p_max_size, "%s°%c", temp, unit);
+                               }
+                       }
                        OBJ(offset) {
                                new_offset(p, obj->data.i);
                        }
@@ -4102,6 +4275,25 @@ static void generate_text_internal(char *p, int p_max_size, struct text_object *
                                struct tm *tm = gmtime(&t);
                                strftime(p, p_max_size, obj->data.s, tm);
                        }
+                       OBJ(tztime) {
+                               char* oldTZ = NULL;
+                               if (obj->data.tztime.tz) {
+                                       oldTZ = getenv("TZ");
+                                       setenv("TZ", obj->data.tztime.tz, 1);
+                                       tzset();
+                               }
+                               time_t t = time(NULL);
+                               struct tm *tm = localtime(&t);
+                               setlocale(LC_TIME, "");
+                               strftime(p, p_max_size, obj->data.tztime.fmt, tm);
+                               if (oldTZ) {
+                                       setenv("TZ", oldTZ, 1);
+                                       tzset();
+                               } else {
+                                       unsetenv("TZ");
+                               }
+                               // Needless to free oldTZ since getenv gives ptr to static data 
+                       }
                        OBJ(totaldown) {
                                human_readable(obj->data.net->recv, p,
                                               255);
@@ -4785,57 +4977,9 @@ static inline int get_string_width_special(char *s)
 }
 
 #ifdef X11
-int last_font_height;
-static void text_size_updater(char *s)
-{
-       int w = 0;
-       char *p;
-       /* get string widths and skip specials */
-       p = s;
-       while (*p) {
-               if (*p == SPECIAL_CHAR) {
-                       *p = '\0';
-                       w += get_string_width(s);
-                       *p = SPECIAL_CHAR;
-
-                       if (specials[special_index].type == BAR
-                           || specials[special_index].type == GRAPH) {
-                               w += specials[special_index].width;
-                               if (specials[special_index].height > last_font_height) {
-                                       last_font_height = specials[special_index].height;
-                                       last_font_height += font_ascent();
-                               }
-                       } else if (specials[special_index].type == OFFSET) {
-                               w += specials[special_index].arg + get_string_width("a"); /* filthy, but works */
-                       } else if (specials[special_index].type == VOFFSET) {
-                               last_font_height += specials[special_index].arg;
-                       } else if (specials[special_index].type == FONT) {
-                               selected_font = specials[special_index].font_added;
-                               if (font_height() > last_font_height) {
-                                       last_font_height = font_height();
-                               }
-                       }
-                       
-                       special_index++;
-                       s = p + 1;
-               }
-               p++;
-       }
-       w += get_string_width(s);
-       if (w > text_width) {
-               text_width = w;
-       }
-       if (text_width > maximum_width && maximum_width) {
-               text_width = maximum_width;
-       }
+static void text_size_updater(char *s);
 
-       text_height += last_font_height;
-       last_font_height = font_height();
-}
-#endif /* X11 */
-
-
-#ifdef X11
+int last_font_height;
 static void update_text_area()
 {
        int x, y;
@@ -4925,6 +5069,64 @@ static int cur_x, cur_y; /* current x and y for drawing */
 static int draw_mode;          /* FG, BG or OUTLINE */
 static long current_color;
 
+#ifdef X11
+static void text_size_updater(char *s)
+{
+       int w = 0;
+       char *p;
+       /* get string widths and skip specials */
+       p = s;
+       while (*p) {
+               if (*p == SPECIAL_CHAR) {
+                       *p = '\0';
+                       w += get_string_width(s);
+                       *p = SPECIAL_CHAR;
+
+                       if (specials[special_index].type == BAR
+                           || specials[special_index].type == GRAPH) {
+                               w += specials[special_index].width;
+                               if (specials[special_index].height > last_font_height) {
+                                       last_font_height = specials[special_index].height;
+                                       last_font_height += font_ascent();
+                               }
+                       } else if (specials[special_index].type == OFFSET) {
+                               w += specials[special_index].arg + get_string_width("a"); /* filthy, but works */
+                       } else if (specials[special_index].type == VOFFSET) {
+                               last_font_height += specials[special_index].arg;
+                       } else if (specials[special_index].type == GOTO) {
+                               if (specials[special_index].arg >= 0)
+                                       w += (int)specials[special_index].arg - cur_x;
+                       } else if (specials[special_index].type == TAB) { 
+                               int start = specials[special_index].arg;
+                               int step = specials[special_index].width;
+                               if (!step || step < 0)
+                                       step = 10;
+                               w += step - (cur_x - text_start_x - start) % step;
+                       } else if (specials[special_index].type == FONT) {
+                               selected_font = specials[special_index].font_added;
+                               if (font_height() > last_font_height) {
+                                       last_font_height = font_height();
+                               }
+                       }
+                       
+                       special_index++;
+                       s = p + 1;
+               }
+               p++;
+       }
+       w += get_string_width(s);
+       if (w > text_width) {
+               text_width = w;
+       }
+       if (text_width > maximum_width && maximum_width) {
+               text_width = maximum_width;
+       }
+
+       text_height += last_font_height;
+       last_font_height = font_height();
+}
+#endif /* X11 */
+
 static inline void set_foreground_color(long c)
 {
        current_color = c;
@@ -5361,14 +5563,26 @@ static void draw_line(char *s)
                                                             arg);
                                break;
 
-                               case OFFSET:
-                               {
-                                       w += specials[special_index].arg;
-                               }
+                       case OFFSET:
+                               w += specials[special_index].arg;
+                               break;
+               
+                       case VOFFSET:
+                               cur_y += specials[special_index].arg;
                                break;
-                               case VOFFSET:
+
+                       case GOTO:
+                               if (specials[special_index].arg >= 0)
+                                       cur_x = (int)specials[special_index].arg;
+                               break;
+
+                       case TAB:
                                {
-                                       cur_y += specials[special_index].arg;
+                                       int start = specials[special_index].arg;
+                                       int step = specials[special_index].width;
+                                       if (!step || step < 0)
+                                               step = 10;
+                                       w = step - (cur_x - text_start_x - start) % step;
                                }
                                break;
 
@@ -5547,12 +5761,14 @@ static void main_loop()
 #ifdef X11
        Region region = XCreateRegion();
        int event_base, error_base;
+#ifdef HAVE_XDAMAGE
        if (!XDamageQueryExtension (display, &event_base, &error_base)) {
                ERR("Xdamage extension unavailable");
        }
        Damage damage = XDamageCreate(display, window.window, XDamageReportNonEmpty);
        XserverRegion region2 = XFixesCreateRegionFromWindow(display, window.window, 0);
        XserverRegion part = XFixesCreateRegionFromWindow(display, window.window, 0);
+#endif /* HAVE_XDAMAGE */
 #endif /* X11 */
 
        info.looped = 0;
@@ -5766,6 +5982,7 @@ static void main_loop()
 #endif
 
                        default:
+#ifdef HAVE_XDAMAGE
                                if (ev.type == event_base + XDamageNotify) {
                                        XDamageNotifyEvent  *dev = (XDamageNotifyEvent *) &ev;
                                        XFixesSetRegion(display, part, &dev->area, 1);
@@ -5773,6 +5990,7 @@ static void main_loop()
                                        XDamageSubtract(display, damage, region2, None);
                                        XFixesSetRegion(display, region2, 0, 0);
                                }
+#endif /* HAVE_XDAMAGE */
                                break;
                        }
                }
@@ -5848,13 +6066,13 @@ static void main_loop()
                g_signal_pending=0;
        
        }
-#ifdef X11
+#if defined(X11) && defined(HAVE_XDAMAGE)
        XDamageDestroy(display, damage);
        XFixesDestroyRegion(display, region2);
        XFixesDestroyRegion(display, part);
        XDestroyRegion(region);
        region = NULL;
-#endif /* X11 */
+#endif /* X11 && HAVE_XDAMAGE */
 }
 
 static void load_config_file(const char *);
@@ -6717,10 +6935,7 @@ int main(int argc, char **argv)
                switch (c) {
                case 'v':
                case 'V':
-                       printf
-                           ("Conky " VERSION " compiled " __DATE__ "\n");
-                       return 0;
-
+                       print_version();
                case 'c':
                        /* if current_config is set to a strdup of CONFIG_FILE, free it (even
                         * though free() does the NULL check itself;), then load optarg value */