Make a description of ${cpu} variable not so confusing.
[monky] / src / conky.c
index 90074de..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) {
@@ -355,6 +427,7 @@ static char original_text[] =
     "${tail /var/log/Xorg.0.log 3}";
 
 static char *text = original_text;
+long text_lines;
 
 static int total_updates;
 
@@ -438,6 +511,8 @@ enum {
        OFFSET,
        VOFFSET,
        FONT,
+       GOTO,
+       TAB,
 };
 
 static struct special_t {
@@ -549,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;
 }
 
@@ -564,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 {
@@ -572,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;
        }
 }
@@ -627,9 +696,9 @@ static void new_graph(char *buf, int w, int h, unsigned int first_colour, unsign
        s->width = w;
        if (s->graph == NULL) {
                if (s->width > 0 && s->width < MAX_GRAPH_DEPTH) {
-                       s->graph_width = s->width - 3;  // subtract 3 for the box
+                       s->graph_width = s->width/* - 2*/;      // subtract 2 for the box
                } else {
-                       s->graph_width = MAX_GRAPH_DEPTH - 3;
+                       s->graph_width = MAX_GRAPH_DEPTH - 2;
                }
                s->graph = malloc(s->graph_width * sizeof(double));
                memset(s->graph, 0, s->graph_width * sizeof(double));
@@ -644,7 +713,7 @@ static void new_graph(char *buf, int w, int h, unsigned int first_colour, unsign
                s->scaled = 1;
        }
        /*if (s->width) {
-               s->graph_width = s->width - 3;  // subtract 3 for rectangle around
+               s->graph_width = s->width - 2;  // subtract 2 for rectangle around
        }*/
        if (s->scaled) {
                s->graph_scale = 1;
@@ -746,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 *))
@@ -788,21 +868,21 @@ static void human_readable(long long a, char *buf, int size)
 {
        // Strange conditional due to possible overflows
        if(a / 1024 / 1024 / 1024.0 > 1024.0){
-               snprintf(buf, size, "%.2fT", (a / 1024 / 1024 / 1024) / 1024.0);
+               snprintf(buf, size, "%.2fTiB", (a / 1024 / 1024 / 1024) / 1024.0);
        }
        else if (a >= 1024 * 1024 * 1024) {
-               snprintf(buf, size, "%.2fG", (a / 1024 / 1024) / 1024.0);
+               snprintf(buf, size, "%.2fGiB", (a / 1024 / 1024) / 1024.0);
        }
        else if (a >= 1024 * 1024) {
                double m = (a / 1024) / 1024.0;
                if (m >= 100.0)
-                       snprintf(buf, size, "%.0fM", m);
+                       snprintf(buf, size, "%.0fMiB", m);
                else
-                       snprintf(buf, size, "%.1fM", m);
+                       snprintf(buf, size, "%.1fMiB", m);
        } else if (a >= 1024)
-               snprintf(buf, size, "%Ldk", a / (long long) 1024);
+               snprintf(buf, size, "%LdKiB", a / (long long) 1024);
        else
-               snprintf(buf, size, "%Ld", a);
+               snprintf(buf, size, "%LdB", a);
 }
 
 /* text handling */
@@ -831,6 +911,7 @@ enum text_object_type {
        OBJ_downspeedgraph,
        OBJ_else,
        OBJ_endif,
+       OBJ_image,
        OBJ_exec,
        OBJ_execi,
        OBJ_texeci,
@@ -849,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,
@@ -872,6 +955,8 @@ enum text_object_type {
        OBJ_ibm_volume,
        OBJ_ibm_brightness,
         OBJ_pb_battery,
+       OBJ_voltage_mv,
+       OBJ_voltage_v,
 #endif /* __linux__ */
        OBJ_if_existing,
        OBJ_if_mounted,
@@ -925,6 +1010,7 @@ enum text_object_type {
        OBJ_text,
        OBJ_time,
        OBJ_utime,
+       OBJ_tztime,
        OBJ_totaldown,
        OBJ_totalup,
        OBJ_updates,
@@ -1022,11 +1108,15 @@ enum text_object_type {
        OBJ_iconv_start,
        OBJ_iconv_stop,
 #endif
+#ifdef HDDTEMP
+       OBJ_hddtemp,
+#endif
 };
 
 struct text_object {
        int type;
        int a, b;
+       long line;
        unsigned int c, d, e;
        float f;
        char global_mode;
@@ -1040,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;
@@ -1095,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;
 };
 
@@ -1127,8 +1228,8 @@ int register_thread(struct thread_info_s *new_thread)
 }
 
 #define MAXDATASIZE 1000
-#define POP3 0
-#define IMAP 1
+#define POP3 1
+#define IMAP 2
 
 struct mail_s* parse_mail_args(char type, const char *arg) {
        struct mail_s *mail;
@@ -1212,6 +1313,7 @@ void *imap_thread(struct mail_s* mail)
        char *reply;
        int fail = 0;
        unsigned int old_unseen = UINT_MAX;
+       unsigned int old_messages = UINT_MAX;
        struct hostent *he;
        struct sockaddr_in their_addr;  // connector's address information
        if ((he = gethostbyname(mail->host)) == NULL) { // get the host info 
@@ -1221,6 +1323,7 @@ void *imap_thread(struct mail_s* mail)
        while (threads_runnable == run_code && fail < 5) {
                if (fail > 0) {
                        ERR("Trying IMAP connection again for %s@%s (try %i/5)", mail->user, mail->host, fail + 1);
+                       sleep((int)mail->interval);
                }
                update_time = get_time();
                if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
@@ -1372,13 +1475,14 @@ void *imap_thread(struct mail_s* mail)
                        continue;
                }
                close(sockfd);
-               if (strlen(mail->command) > 1 && mail->unseen > old_unseen) {   // new mail goodie
+               if (strlen(mail->command) > 1 && (mail->unseen > old_unseen || (mail->messages > old_messages && mail->unseen > 0))) {  // new mail goodie
                        if (system(mail->command) == -1) {
                                perror("system()");
                        }
                }
                fail = 0;
                old_unseen = mail->unseen;
+               old_messages = mail->messages;
                mail->last_update = update_time;
                usleep(100);    // prevent race condition
                if (get_time() - mail->last_update >
@@ -1420,6 +1524,7 @@ void *pop3_thread(struct mail_s *mail)
        while (threads_runnable == run_code && fail < 5) {
                if (fail > 0) {
                        ERR("Trying POP3 connection again for %s@%s (try %i/5)", mail->user, mail->host, fail + 1);
+                       sleep((int)mail->interval);
                }
                update_time = get_time();
                if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
@@ -1561,6 +1666,7 @@ void *pop3_thread(struct mail_s *mail)
                        pthread_mutex_lock(&(mail->thread_info.mutex));
                        sscanf(reply, "%lu %lu", &mail->unseen,
                               &mail->used);
+//                     sleep(60);
                        pthread_mutex_unlock(&(mail->thread_info.mutex));
                }
                strncpy(sendbuf, "QUIT\n", MAXDATASIZE);
@@ -1692,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;
@@ -1730,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;
@@ -1930,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);
@@ -1953,10 +2074,11 @@ void scan_mixer_bar(const char *arg, int *a, int *w, int *h)
 
 
 /* construct_text_object() creates a new text_object */
-static struct text_object *construct_text_object(const char *s, const char *arg, unsigned int object_count, struct text_object *text_objects)
+static struct text_object *construct_text_object(const char *s, const char *arg, unsigned int object_count, struct text_object *text_objects, long line)
 {
        //struct text_object *obj = new_text_object();
        struct text_object *obj = new_text_object_internal();
+       obj->line = line;
 
 #define OBJ(a, n) if (strcmp(s, #a) == 0) { obj->type = OBJ_##a; need_mask |= (1 << n); {
 #define END ; } } else
@@ -1970,8 +2092,75 @@ static struct text_object *construct_text_object(const char *s, const char *arg,
                OBJ(acpitemp, 0) obj->data.i = open_acpi_temperature(arg);
        END OBJ(acpitempf, 0) obj->data.i = open_acpi_temperature(arg);
        END OBJ(acpiacadapter, 0)
-               END OBJ(freq, 0);
+#if defined(__linux__)
+           END OBJ(freq, 0)
+           get_cpu_count();
+       if (!arg
+           || !isdigit(arg[0])
+           || strlen(arg) >=2
+           || atoi(&arg[0])==0
+           || (unsigned int)atoi(&arg[0])>info.cpu_count)
+       {
+           obj->data.cpu_index=1;
+//         ERR("freq: Invalid CPU number or you don't have that many CPUs! Displaying the clock for CPU 1.");
+       }
+       else 
+       {
+           obj->data.cpu_index=atoi(&arg[0]);
+       }
+       obj->a = 1;
+       END OBJ(freq_g, 0)
+           get_cpu_count();
+       if (!arg
+           || !isdigit(arg[0])
+           || strlen(arg) >=2
+           || atoi(&arg[0])==0
+           || (unsigned int)atoi(&arg[0])>info.cpu_count)
+       {
+           obj->data.cpu_index=1;
+//         ERR("freq_g: Invalid CPU number or you don't have that many CPUs! Displaying the clock for CPU 1.");
+       }
+       else 
+       {
+           obj->data.cpu_index=atoi(&arg[0]);
+       }
+       obj->a = 1;
+       END OBJ(voltage_mv, 0)
+           get_cpu_count();
+       if (!arg
+           || !isdigit(arg[0])
+           || strlen(arg) >=2
+           || atoi(&arg[0])==0
+           || (unsigned int)atoi(&arg[0])>info.cpu_count)
+       {
+           obj->data.cpu_index=1;
+//         ERR("voltage_mv: Invalid CPU number or you don't have that many CPUs! Displaying voltage for CPU 1.");
+       }
+       else 
+       {
+           obj->data.cpu_index=atoi(&arg[0]);
+       }
+       obj->a = 1;
+       END OBJ(voltage_v, 0)
+           get_cpu_count();
+       if (!arg
+           || !isdigit(arg[0])
+           || strlen(arg) >=2
+           || atoi(&arg[0])==0
+           || (unsigned int)atoi(&arg[0])>info.cpu_count)
+       {
+           obj->data.cpu_index=1;
+//         ERR("voltage_v: Invalid CPU number or you don't have that many CPUs! Displaying voltage for CPU 1.");
+       }
+       else 
+       {
+           obj->data.cpu_index=atoi(&arg[0]);
+       }
+       obj->a = 1;
+#else 
+       END OBJ(freq, 0);
        END OBJ(freq_g, 0);
+#endif /* __linux__ */
        END OBJ(freq_dyn, 0);
        END OBJ(freq_dyn_g, 0);
        END OBJ(acpifan, 0);
@@ -2105,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;
@@ -2212,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;
 
@@ -2563,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) {
@@ -2760,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;
@@ -2814,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;
 
@@ -2885,7 +3124,12 @@ static struct text_object_list *extract_variable_text_internal(const char *p)
        memset(retval, 0, sizeof(struct text_object_list));
        retval->text_object_count = 0;
 
+       long line = text_lines;
+
        while (*p) {
+               if (*p == '\n') {
+                       line++;
+               }
                if (*p == '$') {
                        *(char *) p = '\0';
                        obj = create_plain_text(s);
@@ -2957,7 +3201,7 @@ static struct text_object_list *extract_variable_text_internal(const char *p)
                                        }
 
                                        // create new object
-                                       obj = construct_text_object(buf, arg, retval->text_object_count, retval->text_objects);
+                                       obj = construct_text_object(buf, arg, retval->text_object_count, retval->text_objects, line);
                                        if(obj != NULL) {
                                                // allocate memory for the object
                                                retval->text_objects = realloc(retval->text_objects, 
@@ -3077,11 +3321,28 @@ static void generate_text_internal(char *p, int p_max_size, struct text_object *
                                                                                       i)+ 40) * 9.0 / 5 - 40));
                                }
                                OBJ(freq) {
-                                       get_freq(p, p_max_size, "%.0f", 1); /* pk */
+                                       if (obj->a) {
+                                               obj->a = get_freq(p, p_max_size, "%.0f", 1, obj->data.cpu_index); /* pk */
+                                       }
                                }
                                OBJ(freq_g) {
-                                       get_freq(p, p_max_size, "%'.2f", 1000); /* pk */
+                                       if (obj->a) {
+                                               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);
+                                       }
+                               }
+                               OBJ(voltage_v) {
+                                       if (obj->a) {
+                                               obj->a = get_voltage(p, p_max_size, "%'.3f", 1000, obj->data.cpu_index);
+                                       }
+                               }
+#endif /* __linux__ */
+
                                OBJ(freq_dyn) {
                                        if (use_spacer) {
                                                get_freq_dynamic(p, 6, "%.0f     ", 1 ); /* pk */
@@ -3235,27 +3496,27 @@ static void generate_text_internal(char *p, int p_max_size, struct text_object *
                                OBJ(diskio) {
                                        if (!use_spacer) {
                                                if (diskio_value > 1024*1024) {
-                                                       snprintf(p, p_max_size, "%.1fG",
+                                                       snprintf(p, p_max_size, "%.1fGiB",
                                                                        (double)diskio_value/1024/1024);
                                                } else if (diskio_value > 1024) {
-                                                       snprintf(p, p_max_size, "%.1fM",
+                                                       snprintf(p, p_max_size, "%.1fMiB",
                                                                        (double)diskio_value/1024);
                                                } else if (diskio_value > 0) {
-                                                       snprintf(p, p_max_size, "%dK", diskio_value);
+                                                       snprintf(p, p_max_size, "%dKiB", diskio_value);
                                                } else {
-                                                       snprintf(p, p_max_size, "%d", diskio_value);
+                                                       snprintf(p, p_max_size, "%dB", diskio_value);
                                                }
                                        } else {
                                                if (diskio_value > 1024*1024) {
-                                                       snprintf(p, 6, "%.1fG   ",
+                                                       snprintf(p, 6, "%.1fGiB   ",
                                                                        (double)diskio_value/1024/1024);
                                                } else if (diskio_value > 1024) {
-                                                       snprintf(p, 6, "%.1fM   ",
+                                                       snprintf(p, 6, "%.1fMiB   ",
                                                                        (double)diskio_value/1024);
                                                } else if (diskio_value > 0) {
-                                                       snprintf(p, 6, "%dK ", diskio_value);
+                                                       snprintf(p, 6, "%dKiB ", diskio_value);
                                                } else {
-                                                       snprintf(p, 6, "%d     ", diskio_value);
+                                                       snprintf(p, 6, "%dB     ", diskio_value);
                                                }
                                        }
                                }
@@ -3321,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);
@@ -3487,7 +3774,7 @@ static void generate_text_internal(char *p, int p_max_size, struct text_object *
                                }
 #endif /* HAVE_POPEN */
                                OBJ(imap_unseen) {
-                                       if (obj->global_mode) { // this means we use info
+                                       if (obj->global_mode && info.mail) { // this means we use info
                                                if (info.mail->pos < 0) {
                                                        info.mail->last_update = current_update_time;
                                                        if (pthread_create(&(info.mail->thread_info.thread), NULL, (void*)imap_thread, (void*) info.mail)) {
@@ -3499,7 +3786,7 @@ static void generate_text_internal(char *p, int p_max_size, struct text_object *
                                                pthread_mutex_lock(&(info.mail->thread_info.mutex));
                                                snprintf(p, p_max_size, "%lu", info.mail->unseen);
                                                pthread_mutex_unlock(&(info.mail->thread_info.mutex));
-                                       } else { // this means we use obj
+                                       } else if (obj->data.mail) { // this means we use obj
                                                if (obj->data.mail->pos < 0) {
                                                        obj->data.mail->last_update = current_update_time;
                                                        if (pthread_create(&(obj->data.mail->thread_info.thread), NULL, (void*)imap_thread, (void*) obj->data.mail)) {
@@ -3507,13 +3794,16 @@ static void generate_text_internal(char *p, int p_max_size, struct text_object *
                                                        }
                                                        obj->data.mail->pos = register_thread(&(obj->data.mail->thread_info));
                                                }
-                                               pthread_mutex_lock(&(info.mail->thread_info.mutex));
+                                               pthread_mutex_lock(&(obj->data.mail->thread_info.mutex));
                                                snprintf(p, p_max_size, "%lu", obj->data.mail->unseen);
-                                               pthread_mutex_unlock(&(info.mail->thread_info.mutex));
+                                               pthread_mutex_unlock(&(obj->data.mail->thread_info.mutex));
+                                       } else if (!obj->a) { // something is wrong, warn once then stop
+                                               ERR("Theres a problem with your imap_unseen settings.  Check that the global IMAP settings are defined properly (line %li).", obj->line);
+                                                       obj->a++;
                                        }
                                }
                                OBJ(imap_messages) {
-                                       if (obj->global_mode) { // this means we use info
+                                       if (obj->global_mode && info.mail) { // this means we use info
                                                if (info.mail->pos < 0) {
                                                        info.mail->last_update = current_update_time;
                                                        if (pthread_create(&(info.mail->thread_info.thread), NULL, (void*)imap_thread, (void*) info.mail)) {
@@ -3524,7 +3814,7 @@ static void generate_text_internal(char *p, int p_max_size, struct text_object *
                                                pthread_mutex_lock(&(info.mail->thread_info.mutex));
                                                snprintf(p, p_max_size, "%lu", info.mail->messages);
                                                pthread_mutex_unlock(&(info.mail->thread_info.mutex));
-                                       } else { // this means we use obj
+                                       } else if (obj->data.mail) { // this means we use obj
                                                if (obj->data.mail->pos < 0) {
                                                        obj->data.mail->last_update = current_update_time;
                                                        if (pthread_create(&(obj->data.mail->thread_info.thread), NULL, (void*)imap_thread, (void*) obj->data.mail)) {
@@ -3532,13 +3822,16 @@ static void generate_text_internal(char *p, int p_max_size, struct text_object *
                                                        }
                                                        obj->data.mail->pos = register_thread(&(obj->data.mail->thread_info));
                                                }
-                                               pthread_mutex_lock(&(info.mail->thread_info.mutex));
+                                               pthread_mutex_lock(&(obj->data.mail->thread_info.mutex));
                                                snprintf(p, p_max_size, "%lu", obj->data.mail->messages);
-                                               pthread_mutex_unlock(&(info.mail->thread_info.mutex));
+                                               pthread_mutex_unlock(&(obj->data.mail->thread_info.mutex));
+                                       } else if (!obj->a) { // something is wrong, warn once then stop
+                                               ERR("Theres a problem with your imap_messages settings.  Check that the global IMAP settings are defined properly (line %li).", obj->line);
+                                                       obj->a++;
                                        }
                                }
                                OBJ(pop3_unseen) {
-                                       if (obj->global_mode) { // this means we use info
+                                       if (obj->global_mode && info.mail) { // this means we use info
                                                if (info.mail->pos < 0) {
                                                        info.mail->last_update = current_update_time;
                                                        if (pthread_create(&(info.mail->thread_info.thread), NULL, (void*)pop3_thread, (void*) info.mail)) {
@@ -3549,7 +3842,7 @@ static void generate_text_internal(char *p, int p_max_size, struct text_object *
                                                pthread_mutex_lock(&(info.mail->thread_info.mutex));
                                                snprintf(p, p_max_size, "%lu", info.mail->unseen);
                                                pthread_mutex_unlock(&(info.mail->thread_info.mutex));
-                                       } else { // this means we use obj
+                                       } else if (obj->data.mail) { // this means we use obj
                                                if (obj->data.mail->pos < 0) {
                                                        obj->data.mail->last_update = current_update_time;
                                                        if (pthread_create(&(obj->data.mail->thread_info.thread), NULL, (void*)pop3_thread, (void*) obj->data.mail)) {
@@ -3557,13 +3850,16 @@ static void generate_text_internal(char *p, int p_max_size, struct text_object *
                                                        }
                                                        obj->data.mail->pos = register_thread(&(obj->data.mail->thread_info));
                                                }
-                                               pthread_mutex_lock(&(info.mail->thread_info.mutex));
+                                               pthread_mutex_lock(&(obj->data.mail->thread_info.mutex));
                                                snprintf(p, p_max_size, "%lu", obj->data.mail->unseen);
-                                               pthread_mutex_unlock(&(info.mail->thread_info.mutex));
+                                               pthread_mutex_unlock(&(obj->data.mail->thread_info.mutex));
+                                       } else if (!obj->a) { // something is wrong, warn once then stop
+                                               ERR("Theres a problem with your pop3_unseen settings.  Check that the global POP3 settings are defined properly (line %li).", obj->line);
+                                                       obj->a++;
                                        }
                                }
                                OBJ(pop3_used) {
-                                       if (obj->global_mode) { // this means we use info
+                                       if (obj->global_mode && info.mail) { // this means we use info
                                                if (info.mail->pos < 0) {
                                                        info.mail->last_update = current_update_time;
                                                        if (pthread_create(&(info.mail->thread_info.thread), NULL, (void*)pop3_thread, (void*) info.mail)) {
@@ -3574,7 +3870,7 @@ static void generate_text_internal(char *p, int p_max_size, struct text_object *
                                                pthread_mutex_lock(&(info.mail->thread_info.mutex));
                                                snprintf(p, p_max_size, "%.1f", info.mail->used/1024.0/1024.0);
                                                pthread_mutex_unlock(&(info.mail->thread_info.mutex));
-                                       } else { // this means we use obj
+                                       } else if (obj->data.mail) { // this means we use obj
                                                if (obj->data.mail->pos < 0) {
                                                        obj->data.mail->last_update = current_update_time;
                                                        if (pthread_create(&(obj->data.mail->thread_info.thread), NULL, (void*)pop3_thread, (void*) obj->data.mail)) {
@@ -3582,9 +3878,12 @@ static void generate_text_internal(char *p, int p_max_size, struct text_object *
                                                        }
                                                        obj->data.mail->pos = register_thread(&(obj->data.mail->thread_info));
                                                }
-                                               pthread_mutex_lock(&(info.mail->thread_info.mutex));
+                                               pthread_mutex_lock(&(obj->data.mail->thread_info.mutex));
                                                snprintf(p, p_max_size, "%.1f", obj->data.mail->used/1024.0/1024.0);
-                                               pthread_mutex_unlock(&(info.mail->thread_info.mutex));
+                                               pthread_mutex_unlock(&(obj->data.mail->thread_info.mutex));
+                                       } else if (!obj->a) { // something is wrong, warn once then stop
+                                               ERR("Theres a problem with your pop3_used settings.  Check that the global POP3 settings are defined properly (line %li).", obj->line);
+                                                       obj->a++;
                                        }
                                }
                        OBJ(fs_bar) {
@@ -3695,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);
                        }
@@ -3761,7 +4080,7 @@ static void generate_text_internal(char *p, int p_max_size, struct text_object *
 
                        /* memory stuff */
                        OBJ(mem) {
-                               human_readable(cur->mem * 1024, p, 6);
+                               human_readable(cur->mem * 1024, p, 255);
                        }
                        OBJ(memmax) {
                                human_readable(cur->memmax * 1024, p, 255);
@@ -3956,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);
@@ -4591,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)
@@ -4646,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;
-
-       text_height += h;
-/*     if (fontchange) {
-               selected_font = 0;
-       }*/
-}
-#endif /* X11 */
+static void text_size_updater(char *s);
 
-
-#ifdef X11
+int last_font_height;
 static void update_text_area()
 {
        int x, y;
@@ -4716,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;
@@ -4791,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;
@@ -5084,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;
@@ -5138,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;
@@ -5171,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 != specials[special_index].first_colour) {
+       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 - 3);
+               gradient_factor = (float)gradient_size / (w - 2);
        }
-       for (i = w - 3; i > 0; i--) {
-               if (specials[special_index].last_colour != specials[special_index].first_colour) {
+       for (i = w - 2; i > -1; i--) {
+               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) {
@@ -5185,10 +5504,10 @@ static void draw_line(char *s)
                                gradient_update--;
                        }
                }
-               if ((w - 3 - i) / ((float) (w - 3) / (specials[special_index].graph_width)) > j) {
+               if ((w - i) / ((float) (w - 2) / (specials[special_index].graph_width)) > j && j < MAX_GRAPH_DEPTH - 3) {
                        j++;
                }
-                                               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 */
+                                               XDrawLine(display,  window.drawable, window.gc, cur_x + i + 1, by + h, cur_x + i + 1, by + h - specials[special_index].graph[j] * (h - 1) / specials[special_index].graph_scale);       /* this is mugfugly, but it works */
                                        }
                                        if (specials[special_index].
                                            height > cur_y_add
@@ -5211,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:
@@ -5244,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 GOTO:
+                               if (specials[special_index].arg >= 0)
+                                       cur_x = (int)specials[special_index].arg;
                                break;
-                               case VOFFSET:
+
+                       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;
 
@@ -5299,9 +5630,6 @@ static void draw_line(char *s)
        draw_string(s);
 
        cur_y += font_descent();
-/*     if (fontchange) {
-               selected_font = 0;
-       }*/
 #endif /* X11 */
 }
 
@@ -5344,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++;
@@ -5355,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++) {
@@ -5430,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;
@@ -5489,7 +5828,7 @@ static void main_loop()
 #endif
 
                        need_to_update = 0;
-
+                       selected_font = 0;
                        update_text_area();
 #ifdef OWN_WINDOW
                        if (own_window) {
@@ -5506,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);
                        }
                                     }
 
@@ -5643,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;
                        }
                }
@@ -5718,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 *);
@@ -5731,6 +6082,10 @@ void reload_config(void)
 {
        //lock_all_threads();
        threads_runnable++;
+       if (info.cpu_usage) {
+               free(info.cpu_usage);
+               info.cpu_usage = NULL;
+       }
 #if defined(XMMS) || defined(BMP) || defined(AUDACIOUS) || defined(INFOPIPE)
         if (info.xmms.thread) {
                if (destroy_xmms_thread()!=0)
@@ -5774,6 +6129,10 @@ void clean_up(void)
 {
        //lock_all_threads();
        threads_runnable++;
+       if (info.cpu_usage) {
+               free(info.cpu_usage);
+               info.cpu_usage = NULL;
+       }
 #ifdef X11
 #ifdef XDBE
        if (use_xdbe) {
@@ -6455,6 +6814,7 @@ else if (strcasecmp(name, a) == 0 || strcasecmp(name, b) == 0)
                                        break;
                        }
                        fclose(fp);
+                       text_lines = line + 1;
                        return;
                }
 #ifdef TCP_PORT_MONITOR
@@ -6575,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 */
@@ -6773,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
@@ -6781,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 */