Make a description of ${cpu} variable not so confusing.
[monky] / src / conky.c
index 9e272df..f9188c3 100644 (file)
 #include <sys/time.h>
 #ifdef X11
 #include <X11/Xutil.h>
+#include <X11/extensions/Xdamage.h>
+#ifdef IMLIB2
+#include <Imlib2.h>
+#endif /* IMLIB2 */
 #endif /* X11 */
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -37,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
 
 #ifdef X11
 
+/*
+ * text size
+ */
+
+static int text_start_x, text_start_y; /* text start position in window */
+static int text_width, text_height;
+
 /* alignments */
 enum alignment {
        TOP_LEFT = 1,
@@ -75,10 +88,10 @@ struct font_list *fonts = NULL;
 
 #ifdef XFT
 
-#define font_height() use_xft ? (fonts[selected_font].xftfont->ascent + fonts[selected_font].xftfont->descent) : \
-(fonts[selected_font].font->max_bounds.ascent + fonts[selected_font].font->max_bounds.descent)
-#define font_ascent() use_xft ? fonts[selected_font].xftfont->ascent : fonts[selected_font].font->max_bounds.ascent
-#define font_descent() use_xft ? fonts[selected_font].xftfont->descent : fonts[selected_font].font->max_bounds.descent
+#define font_height() (use_xft ? (fonts[selected_font].xftfont->ascent + fonts[selected_font].xftfont->descent) : \
+(fonts[selected_font].font->max_bounds.ascent + fonts[selected_font].font->max_bounds.descent))
+#define font_ascent() (use_xft ? fonts[selected_font].xftfont->ascent : fonts[selected_font].font->max_bounds.ascent)
+#define font_descent() (use_xft ? fonts[selected_font].xftfont->descent : fonts[selected_font].font->max_bounds.descent)
 
 #else
 
@@ -93,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) {
@@ -439,6 +511,8 @@ enum {
        OFFSET,
        VOFFSET,
        FONT,
+       GOTO,
+       TAB,
 };
 
 static struct special_t {
@@ -550,10 +624,6 @@ static char *scan_font(const char *args)
        if (args && sizeof(args) < 127) {
                return strdup(args);
        }
-/*     else {
-               ERR("font scan failed, lets hope it doesn't mess stuff up");
-               we'll assume this means to use the default font now, like $color
-       }*/
        return NULL;
 }
 
@@ -565,7 +635,6 @@ static void new_font(char *buf, char * args) {
                        int tmp = selected_font;
                        selected_font = s->font_added = addfont(args);
                        load_fonts();
-                       //set_font();
                        selected_font = tmp;
                }
        } else {
@@ -573,7 +642,6 @@ static void new_font(char *buf, char * args) {
                int tmp = selected_font;
                selected_font = s->font_added = 0;
                load_fonts();
-               //set_font();
                selected_font = tmp;
        }
 }
@@ -747,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 *))
@@ -832,6 +911,7 @@ enum text_object_type {
        OBJ_downspeedgraph,
        OBJ_else,
        OBJ_endif,
+       OBJ_image,
        OBJ_exec,
        OBJ_execi,
        OBJ_texeci,
@@ -850,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,
@@ -928,6 +1010,7 @@ enum text_object_type {
        OBJ_text,
        OBJ_time,
        OBJ_utime,
+       OBJ_tztime,
        OBJ_totaldown,
        OBJ_totalup,
        OBJ_updates,
@@ -1025,6 +1108,9 @@ enum text_object_type {
        OBJ_iconv_start,
        OBJ_iconv_stop,
 #endif
+#ifdef HDDTEMP
+       OBJ_hddtemp,
+#endif
 };
 
 struct text_object {
@@ -1044,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;
@@ -1099,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;
 };
 
@@ -1701,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;
@@ -1739,6 +1842,9 @@ static void free_text_objects(unsigned int count, struct text_object *objs)
                        case OBJ_text: case OBJ_font:
                                free(objs[i].data.s);
                                break;
+                       case OBJ_image:
+                               free(objs[i].data.s);
+                               break;
                        case OBJ_exec:
                                free(objs[i].data.s);
                                break;
@@ -1939,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);
@@ -2182,8 +2294,10 @@ static struct text_object *construct_text_object(const char *s, const char *arg,
                        ERR("$endif: no matching $if_*");
                }
        END
+       OBJ(image, 0) obj->data.s = strdup(arg ? arg : "");
+       END
 #ifdef HAVE_POPEN
-               OBJ(exec, 0) obj->data.s = strdup(arg ? arg : "");
+       OBJ(exec, 0) obj->data.s = strdup(arg ? arg : "");
        END OBJ(execbar, 0) obj->data.s = strdup(arg ? arg : "");
        END OBJ(execgraph, 0) obj->data.s = strdup(arg ? arg : "");
        END OBJ(execibar, 0) unsigned int n;
@@ -2289,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;
 
@@ -2640,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) {
@@ -2837,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;
@@ -2891,8 +3053,8 @@ static struct text_object *construct_text_object(const char *s, const char *arg,
                CRIT_ERR("tcp_portmon: connection index must be non-negative");
        }
        /* ok, args looks good. save the text object data */
-       obj->data.tcp_port_monitor.port_range_begin = (in_addr_t)port_begin;
-       obj->data.tcp_port_monitor.port_range_end = (in_addr_t)port_end;
+       obj->data.tcp_port_monitor.port_range_begin = (in_port_t)port_begin;
+       obj->data.tcp_port_monitor.port_range_end = (in_port_t)port_end;
        obj->data.tcp_port_monitor.item = item;
        obj->data.tcp_port_monitor.connection_index = connection_index;
 
@@ -3168,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) {
@@ -3418,7 +3582,33 @@ static void generate_text_internal(char *p, int p_max_size, struct text_object *
                                        snprintf(p, p_max_size, "%d",
                                                        obj->data.net->linkstatus);
                                }
-
+#if defined(IMLIB2) && defined(X11)
+                               OBJ(image) {
+                                       if (obj->a < 1) {
+                                               obj->a++;
+                                       } else {
+                                               Imlib_Image image, buffer;
+                                               image = imlib_load_image(obj->data.s);
+                                               imlib_context_set_image(image);
+                                               if (image) {
+                                                       int w, h;
+                                                       w = imlib_image_get_width();
+                                                       h = imlib_image_get_height();
+                                                       buffer = imlib_create_image(w, h);
+                                                       imlib_context_set_display(display);
+                                                       imlib_context_set_drawable(window.drawable);
+                                                       imlib_context_set_colormap(DefaultColormap(display, screen));
+                                                       imlib_context_set_visual(DefaultVisual(display, screen));
+                                                       imlib_context_set_image(buffer);
+                                                       imlib_blend_image_onto_image(image, 0, 0, 0, w, h, text_start_x, text_start_y, w, h);
+                                                       imlib_render_image_on_drawable(text_start_x, text_start_y);
+                                                       imlib_free_image();
+                                                       imlib_context_set_image(image);
+                                                       imlib_free_image();
+                                               }
+                                       }
+                               }
+#endif /* IMLIB2 */
                                OBJ(exec) {
                                        FILE *fp = popen(obj->data.s, "r");
                                        int length = fread(p, 1, p_max_size, fp);
@@ -3804,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);
                        }
@@ -4065,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);
@@ -4700,14 +4929,6 @@ static void set_font()
 }
 }
 
-
-/*
- * text size
- */
-
-static int text_start_x, text_start_y; /* text start position in window */
-static int text_width, text_height;
-
 #endif /* X11 */
 
 static inline int get_string_width(const char *s)
@@ -4755,64 +4976,10 @@ static inline int get_string_width_special(char *s)
 #endif /* X11 */
 }
 
-int fontchange = 0;
-
 #ifdef X11
-static void text_size_updater(char *s)
-{
-       int w = 0;
-       char *p;
-       int h = font_height();
-       /* 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 > h) {
-                                       h = specials[special_index].height;
-                                       h += 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) {
-                               h += specials[special_index].arg;
-                       }
-                       else if (specials[special_index].type == FONT) {
-                               fontchange = specials[special_index].font_added;
-                               selected_font = specials[special_index].font_added;
-                               h = 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 += h;
-/*     if (fontchange) {
-               selected_font = 0;
-       }*/
-}
-#endif /* X11 */
-
-
-#ifdef X11
+int last_font_height;
 static void update_text_area()
 {
        int x, y;
@@ -4825,7 +4992,9 @@ static void update_text_area()
                text_width = minimum_width;
                text_height = 0;
                special_index = 0;
+               int first_font_height = last_font_height = font_height();
                for_each_line(text_buffer, text_size_updater);
+               text_height -= first_font_height;
                text_width += 1;
                if (text_height < minimum_height)
                        text_height = minimum_height;
@@ -4900,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;
@@ -5193,17 +5420,8 @@ static void draw_line(char *s)
                                            specials[special_index].height;
                                        int bar_usage =
                                            specials[special_index].arg;
-                                       int by;
-
-#ifdef XFT
-                                       if (use_xft) {
-                                               by = cur_y - (font_ascent() + h) / 2 - 1;
-                                       } else 
-#endif
-                                       {
-                                               by = cur_y - (font_ascent()/2) - 1;
-                                       }
-                                       if (h < (font_height())) {
+                                       int by = cur_y - (font_ascent() / 2) - 1;
+                                       if (h < font_height()) {
                                                by -= h / 2 - 1;
                                        }
                                        w = specials[special_index].width;
@@ -5247,17 +5465,9 @@ static void draw_line(char *s)
                                        }
                                        int h =
                                            specials[special_index].height;
-                                       int by;
                                        unsigned long last_colour = current_color;
-#ifdef XFT
-                                       if (use_xft) {
-                                            by = cur_y - (font_ascent() + h) / 2 - 1;
-                                       } else
-#endif
-                                       {
-                                               by = cur_y - (font_ascent()/2) - 1;
-                                       }
-                                       if (h < (font_height())) {
+                                       int by = cur_y - (font_ascent()/2) - 1;
+                                       if (h < font_height()) {
                                                by -= h / 2 - 1;
                                        }
                                        w = specials[special_index].width;
@@ -5280,13 +5490,13 @@ static void draw_line(char *s)
        float gradient_factor = 0;
        float gradient_update = 0;
        unsigned long tmpcolour = current_color;
-       if (specials[special_index].last_colour != 0 && specials[special_index].first_colour != 0) {
+       if (specials[special_index].last_colour != 0 || specials[special_index].first_colour != 0) {
                tmpcolour = specials[special_index].last_colour;
                gradient_size = gradient_max(specials[special_index].last_colour, specials[special_index].first_colour);
                gradient_factor = (float)gradient_size / (w - 2);
        }
        for (i = w - 2; i > -1; i--) {
-               if (specials[special_index].last_colour != 0 && specials[special_index].first_colour != 0) {
+               if (specials[special_index].last_colour != 0 || specials[special_index].first_colour != 0) {
                        XSetForeground(display, window.gc, tmpcolour);
                        gradient_update += gradient_factor;
                        while (gradient_update > 0) {
@@ -5320,16 +5530,16 @@ static void draw_line(char *s)
                                break;
                        
                                case FONT:
-                               if (fontchange) {
+                               {
+                                       int old = font_ascent();
                                        cur_y -= font_ascent();
                                        selected_font = specials[special_index].font_added;
-                                       cur_y += font_ascent();
-#ifdef XFT
-                                       if (!use_xft || use_xdbe)
-#endif
-                                       {
-                                               set_font();
+                                       if (cur_y + font_ascent() < cur_y + old) {
+                                               cur_y += old;
+                                       } else {
+                                               cur_y += font_ascent();
                                        }
+                                       set_font();
                                }
                                break;
                        case FG:
@@ -5353,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;
 
@@ -5408,9 +5630,6 @@ static void draw_line(char *s)
        draw_string(s);
 
        cur_y += font_descent();
-/*     if (fontchange) {
-               selected_font = 0;
-       }*/
 #endif /* X11 */
 }
 
@@ -5453,6 +5672,7 @@ static void draw_text()
 static void draw_stuff()
 {
 #ifdef X11
+       selected_font = 0;
        if (draw_shades && !draw_outline) {
                text_start_x++;
                text_start_y++;
@@ -5464,6 +5684,7 @@ static void draw_stuff()
        }
 
        if (draw_outline) {
+               selected_font = 0;
                int i, j;
                for (i = -1; i < 2; i++)
                        for (j = -1; j < 2; j++) {
@@ -5539,6 +5760,15 @@ 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;
@@ -5598,7 +5828,7 @@ static void main_loop()
 #endif
 
                        need_to_update = 0;
-
+                       selected_font = 0;
                        update_text_area();
 #ifdef OWN_WINDOW
                        if (own_window) {
@@ -5615,11 +5845,11 @@ static void main_loop()
                                            text_height +
                                            border_margin * 2 + 1;
                                        XResizeWindow(display,
-                                                     window.window,
+                                                     window.drawable,
                                                      window.width,
                                                      window.height);
                        if (own_window) {
-                               set_transparent_background(window.window);
+                               set_transparent_background(window.drawable);
                        }
                                     }
 
@@ -5752,6 +5982,15 @@ 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);
+                                       XFixesUnionRegion(display, region2, region2, part);
+                                       XDamageSubtract(display, damage, region2, None);
+                                       XFixesSetRegion(display, region2, 0, 0);
+                               }
+#endif /* HAVE_XDAMAGE */
                                break;
                        }
                }
@@ -5827,10 +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 *);
@@ -6693,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 */
@@ -6891,6 +7130,7 @@ int main(int argc, char **argv)
 
        generate_text();
 #ifdef X11
+       selected_font = 0;
        update_text_area();     /* to get initial size of the window */
 
        init_window
@@ -6899,6 +7139,7 @@ int main(int argc, char **argv)
                 text_height + border_margin * 2 + 1,
                 set_transparent, background_colour, info.uname_s.nodename, argv, argc);
        
+       selected_font = 0;
        update_text_area();     /* to position text/window on screen */
 #endif /* X11 */