A whole bunch of changes, mostly Lua related.
[monky] / src / conky.c
index a82c08a..3ffb55d 100644 (file)
 #include "openbsd.h"
 #endif
 
+#if defined(__FreeBSD_kernel__)
+#include <bsd/bsd.h>
+#endif
+
 /* FIXME: apm_getinfo is unused here. maybe it's meant for common.c */
 #if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
                || defined(__OpenBSD__)) && (defined(i386) || defined(__i386__))
@@ -104,10 +108,8 @@ char *get_apm_battery_time(void);
 
 #ifdef CONFIG_OUTPUT
 #include "defconfig.h"
-#ifdef HAVE_FOPENCOOKIE
 #include "conf_cookie.h"
 #endif
-#endif
 
 #ifndef S_ISSOCK
 #define S_ISSOCK(x)   ((x & S_IFMT) == S_IFSOCK)
@@ -127,6 +129,7 @@ static char *tmpstring1, *tmpstring2;
 
 /* variables holding various config settings */
 int short_units;
+int format_human_readable;
 int cpu_separate;
 enum {
        NO_SPACER = 0,
@@ -134,19 +137,22 @@ enum {
        RIGHT_SPACER
 } use_spacer;
 int top_cpu, top_mem, top_time;
+#ifdef IOSTATS
+int top_io;
+#endif
 static unsigned int top_name_width = 15;
 int output_methods;
 enum x_initialiser_state x_initialised = NO;
 static volatile int g_signal_pending;
 /* Update interval */
 double update_interval;
+void *global_cpu = NULL;
 
 
 /* prototypes for internally used functions */
 static void signal_handler(int);
 static void print_version(void) __attribute__((noreturn));
 static void reload_config(void);
-static void clean_up(void);
 static void generate_text_internal(char *, int, struct text_object,
                                    struct information *);
 static int extract_variable_text_internal(struct text_object *,
@@ -157,7 +163,8 @@ static void print_version(void)
        printf(PACKAGE_NAME" "VERSION" compiled "BUILD_DATE" for "BUILD_ARCH"\n");
 
        printf("\nCompiled in features:\n\n"
-                  "System config file: "SYSTEM_CONFIG_FILE"\n\n"
+                  "System config file: "SYSTEM_CONFIG_FILE"\n"
+                  "Package library path: "PACKAGE_LIBDIR"\n\n"
 #ifdef X11
                   " X11:\n"
 # ifdef HAVE_XDAMAGE
@@ -202,9 +209,9 @@ static void print_version(void)
 #ifdef RSS
                   "  * RSS\n"
 #endif /* RSS */
-#ifdef HAVE_LUA
-                  "  * Lua\n"
-#endif /* HAVE_LUA */
+#ifdef WEATHER
+                  "  * Weather (METAR)\n"
+#endif /* WEATHER */
 #ifdef HAVE_IWLIB
                   "  * wireless\n"
 #endif /* HAVE_IWLIB */
@@ -221,14 +228,27 @@ static void print_version(void)
                   "  * config-output\n"
 #endif /* CONFIG_OUTPUT */
 #ifdef IMLIB2
-                  "  * IMLIB2\n"
+                  "  * Imlib2\n"
 #endif /* IMLIB2 */
 #ifdef MIXER_IS_ALSA
                   "  * ALSA mixer support\n"
 #endif /* MIXER_IS_ALSA */
 #ifdef APCUPSD
-                       "  * apcupsd\n"
+                  "  * apcupsd\n"
 #endif /* APCUPSD */
+#ifdef IOSTATS
+                  "  * iostats\n"
+#endif /* IOSTATS */
+#ifdef HAVE_LUA
+                  "  * Lua\n"
+                  "\n  Lua bindings:\n"
+#ifdef HAVE_LUA_CAIRO
+                  "   * Cairo\n"
+#endif /* HAVE_LUA_CAIRO */
+#ifdef HAVE_LUA_IMLIB2
+                  "   * Imlib2\n"
+#endif /* IMLIB2 */
+#endif /* HAVE_LUA */
        );
 
        exit(0);
@@ -241,6 +261,7 @@ static const char *suffixes[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "" };
 
 static void X11_destroy_window(void);
 static void X11_create_window(void);
+static void X11_initialisation(void);
 
 struct _x11_stuff_s {
        Region region;
@@ -278,8 +299,8 @@ static char *disp = NULL;
  * instances of the same text object */
 struct information info;
 
-/* default config file */
-static char *current_config;
+/* path to config file */
+char *current_config;
 
 /* set to 1 if you want all text to be in uppercase */
 static unsigned int stuff_in_upper_case;
@@ -312,8 +333,6 @@ static int stippled_borders;
 
 static int draw_shades, draw_outline;
 
-static int border_margin, border_width;
-
 static long default_fg_color, default_bg_color, default_out_color;
 
 /* create own window or draw stuff to root? */
@@ -339,10 +358,11 @@ static int sensor_device;
 static long color0, color1, color2, color3, color4, color5, color6, color7,
        color8, color9;
 
-static char *template[10];
+#define MAX_TEMPLATES 10
+static char *template[MAX_TEMPLATES];
 
 /* maximum size of config TEXT buffer, i.e. below TEXT line. */
-static unsigned int max_user_text = MAX_USER_TEXT_DEFAULT;
+unsigned int max_user_text;
 
 /* maximum size of individual text buffers, ie $exec buffer size */
 unsigned int text_buffer_size = DEFAULT_TEXT_BUFFER_SIZE;
@@ -408,11 +428,10 @@ int check_contains(char *f, char *s)
        FILE *where = open_file(f, 0);
 
        if (where) {
-               char buf1[256], buf2[256];
+               char buf1[256];
 
                while (fgets(buf1, 256, where)) {
-                       sscanf(buf1, "%255s", buf2);
-                       if (strstr(buf2, s)) {
+                       if (strstr(buf1, s)) {
                                ret = 1;
                                break;
                        }
@@ -554,6 +573,11 @@ static void human_readable(long long num, char *buf, int size)
        int width;
        const char *format;
 
+       /* Possibly just output as usual, for example for stdout usage */
+       if (!format_human_readable) {
+               spaced_print(buf, size, "%d", 6, round_to_int(num));
+               return;
+       }
        if (short_units) {
                width = 5;
                format = "%.*f%.1s";
@@ -680,6 +704,9 @@ static void free_text_objects(struct text_object *root, int internal)
                                close(data.sysfs.fd);
                                break;
 #endif /* __linux__ */
+                       case OBJ_read_tcp:
+                               free(data.read_tcp.host);
+                               break;
                        case OBJ_time:
                        case OBJ_utime:
                                free(data.s);
@@ -786,6 +813,7 @@ static void free_text_objects(struct text_object *root, int internal)
                        case OBJ_if_up:
                                free(data.ifblock.s);
                                free(data.ifblock.str);
+                               break;
 #endif
 #ifdef XMMS2
                        case OBJ_xmms2_artist:
@@ -876,12 +904,16 @@ static void free_text_objects(struct text_object *root, int internal)
                                free(data.rss.action);
                                break;
 #endif
+#ifdef WEATHER
+                       case OBJ_weather:
+                               free(data.weather.uri);
+                               free(data.weather.data_type);
+                               break;
+#endif
 #ifdef HAVE_LUA
                        case OBJ_lua:
-                       case OBJ_lua_parse:
-                       case OBJ_lua_read_parse:
-#ifdef X11
                        case OBJ_lua_bar:
+#ifdef X11
                        case OBJ_lua_graph:
                        case OBJ_lua_gauge:
 #endif /* X11 */
@@ -903,11 +935,11 @@ static void free_text_objects(struct text_object *root, int internal)
 #endif /* !__OpenBSD__ */
                        case OBJ_execpi:
                        case OBJ_execi:
-#ifdef X11
                        case OBJ_execibar:
+#ifdef X11
                        case OBJ_execigraph:
                        case OBJ_execigauge:
-#endif
+#endif /* X11 */
                                free(data.execi.cmd);
                                free(data.execi.buffer);
                                break;
@@ -921,6 +953,9 @@ static void free_text_objects(struct text_object *root, int internal)
                        case OBJ_top:
                        case OBJ_top_mem:
                        case OBJ_top_time:
+#ifdef IOSTATS
+                       case OBJ_top_io:
+#endif
                                if (info.first_process && !internal) {
                                        free_all_processes();
                                        info.first_process = NULL;
@@ -934,12 +969,11 @@ static void free_text_objects(struct text_object *root, int internal)
                                if (data.hddtemp.temp)
                                        free(data.hddtemp.temp);
                                break;
-#endif
+#endif /* HDDTEMP */
                        case OBJ_entropy_avail:
+                       case OBJ_entropy_perc:
                        case OBJ_entropy_poolsize:
-#ifdef X11
                        case OBJ_entropy_bar:
-#endif
                                break;
                        case OBJ_user_names:
                                if (info.users.names) {
@@ -970,11 +1004,11 @@ static void free_text_objects(struct text_object *root, int internal)
                                free(data.ifblock.s);
                                free(data.ifblock.str);
                                break;
-#endif
+#endif /* IBM */
 #ifdef NVIDIA
                        case OBJ_nvidia:
                                break;
-#endif
+#endif /* NVIDIA */
 #ifdef MPD
                        case OBJ_mpd_title:
                        case OBJ_mpd_artist:
@@ -984,9 +1018,7 @@ static void free_text_objects(struct text_object *root, int internal)
                        case OBJ_mpd_vol:
                        case OBJ_mpd_bitrate:
                        case OBJ_mpd_status:
-#ifdef X11
                        case OBJ_mpd_bar:
-#endif
                        case OBJ_mpd_elapsed:
                        case OBJ_mpd_length:
                        case OBJ_mpd_track:
@@ -997,7 +1029,7 @@ static void free_text_objects(struct text_object *root, int internal)
                        case OBJ_if_mpd_playing:
                                free_mpd();
                                break;
-#endif
+#endif /* MPD */
 #ifdef MOC
                        case OBJ_moc_state:
                        case OBJ_moc_file:
@@ -1012,7 +1044,12 @@ static void free_text_objects(struct text_object *root, int internal)
                        case OBJ_moc_rate:
                                free_moc();
                                break;
-#endif
+#endif /* MOC */
+                       case OBJ_blink:
+                       case OBJ_to_bytes:
+                               free_text_objects(obj->sub, 1);
+                               free(obj->sub);
+                               break;
                        case OBJ_scroll:
                                free(data.scroll.text);
                                free_text_objects(obj->sub, 1);
@@ -1034,11 +1071,11 @@ static void free_text_objects(struct text_object *root, int internal)
                        case OBJ_apcupsd_status:
                        case OBJ_apcupsd_linev:
                        case OBJ_apcupsd_load:
-#ifdef X11
                        case OBJ_apcupsd_loadbar:
+#ifdef X11
                        case OBJ_apcupsd_loadgraph:
                        case OBJ_apcupsd_loadgauge:
-#endif
+#endif /* X11 */
                        case OBJ_apcupsd_charge:
                        case OBJ_apcupsd_timeleft:
                        case OBJ_apcupsd_temp:
@@ -1065,7 +1102,7 @@ void scan_mixer_bar(const char *arg, int *a, int *w, int *h)
                scan_bar(arg, w, h);
        }
 }
-#endif
+#endif /* X11 */
 
 /* strip a leading /dev/ if any, following symlinks first
  *
@@ -1115,8 +1152,17 @@ static int parse_top_args(const char *s, const char *arg, struct text_object *ob
        } else if (strcmp(&s[3], "_time") == EQUAL) {
                obj->type = OBJ_top_time;
                top_time = 1;
+#ifdef IOSTATS
+       } else if (strcmp(&s[3], "_io") == EQUAL) {
+               obj->type = OBJ_top_io;
+               top_io = 1;
+#endif
        } else {
+#ifdef IOSTATS
+               ERR("Must be top, top_mem, top_time or top_io");
+#else
                ERR("Must be top, top_mem or top_time");
+#endif
                return 0;
        }
 
@@ -1140,9 +1186,22 @@ static int parse_top_args(const char *s, const char *arg, struct text_object *ob
                        obj->data.top.type = TOP_MEM_RES;
                } else if (strcmp(buf, "mem_vsize") == EQUAL) {
                        obj->data.top.type = TOP_MEM_VSIZE;
+#ifdef IOSTATS
+               } else if (strcmp(buf, "io_read") == EQUAL) {
+                       obj->data.top.type = TOP_READ_BYTES;
+               } else if (strcmp(buf, "io_write") == EQUAL) {
+                       obj->data.top.type = TOP_WRITE_BYTES;
+               } else if (strcmp(buf, "io_perc") == EQUAL) {
+                       obj->data.top.type = TOP_IO_PERC;
+#endif
                } else {
                        ERR("invalid type arg for top");
+#ifdef IOSTATS
+                       ERR("must be one of: name, cpu, pid, mem, time, mem_res, mem_vsize, "
+                                       "io_read, io_write, io_perc");
+#else
                        ERR("must be one of: name, cpu, pid, mem, time, mem_res, mem_vsize");
+#endif
                        return 0;
                }
                if (n < 1 || n > 10) {
@@ -1176,6 +1235,11 @@ static struct text_object *construct_text_object(const char *s,
        obj->type = OBJ_##a; need_mask |= (1ULL << n); {
 #define END } } else
 
+#define SIZE_DEFAULTS(arg) { \
+       obj->a = default_##arg##_width; \
+       obj->b = default_##arg##_height; \
+}
+
 #ifdef X11
        if (s[0] == '#') {
                obj->type = OBJ_color;
@@ -1211,6 +1275,22 @@ static struct text_object *construct_text_object(const char *s,
                        obj->data.cpu_index = atoi(&arg[0]);
                }
                obj->a = 1;
+       END OBJ(read_tcp, 0)
+               if (arg) {
+                       obj->data.read_tcp.host = malloc(text_buffer_size);
+                       sscanf(arg, "%s", obj->data.read_tcp.host);
+                       sscanf(arg+strlen(obj->data.read_tcp.host), "%u", &(obj->data.read_tcp.port));
+                       if(obj->data.read_tcp.port == 0) {
+                               obj->data.read_tcp.port = atoi(obj->data.read_tcp.host);
+                               strcpy(obj->data.read_tcp.host,"localhost");
+                       }
+                       obj->data.read_tcp.port = htons(obj->data.read_tcp.port);
+                       if(obj->data.read_tcp.port < 1 || obj->data.read_tcp.port > 65535) {
+                               CRIT_ERR("read_tcp: Needs \"(host) port\" as argument(s)");
+                       }
+               }else{
+                       CRIT_ERR("read_tcp: Needs \"(host) port\" as argument(s)");
+               }
 #if defined(__linux__)
        END OBJ(voltage_mv, 0)
                get_cpu_count();
@@ -1240,50 +1320,75 @@ static struct text_object *construct_text_object(const char *s,
                if (arg) {
                        obj->data.net = get_net_stat(arg);
                } else {
-                       CRIT_ERR("wireless_essid: needs an argument");
+                       // default to DEFAULTNETDEV
+                       char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
+                       obj->data.net = get_net_stat(buf);
+                       free(buf);
                }
        END OBJ(wireless_mode, INFO_NET)
                if (arg) {
                        obj->data.net = get_net_stat(arg);
                } else {
-                       CRIT_ERR("wireless_mode: needs an argument");
+                       // default to DEFAULTNETDEV
+                       char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
+                       obj->data.net = get_net_stat(buf);
+                       free(buf);
                }
        END OBJ(wireless_bitrate, INFO_NET)
                if (arg) {
                        obj->data.net = get_net_stat(arg);
                } else {
-                       CRIT_ERR("wireless_bitrate: needs an argument");
+                       // default to DEFAULTNETDEV
+                       char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
+                       obj->data.net = get_net_stat(buf);
+                       free(buf);
                }
        END OBJ(wireless_ap, INFO_NET)
                if (arg) {
                        obj->data.net = get_net_stat(arg);
                } else {
-                       CRIT_ERR("wireless_ap: needs an argument");
+                       // default to DEFAULTNETDEV
+                       char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
+                       obj->data.net = get_net_stat(buf);
+                       free(buf);
                }
        END OBJ(wireless_link_qual, INFO_NET)
                if (arg) {
                        obj->data.net = get_net_stat(arg);
                } else {
-                       CRIT_ERR("wireless_link_qual: needs an argument");
+                       // default to DEFAULTNETDEV
+                       char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
+                       obj->data.net = get_net_stat(buf);
+                       free(buf);
                }
        END OBJ(wireless_link_qual_max, INFO_NET)
                if (arg) {
                        obj->data.net = get_net_stat(arg);
                } else {
-                       CRIT_ERR("wireless_link_qual_max: needs an argument");
+                       // default to DEFAULTNETDEV
+                       char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
+                       obj->data.net = get_net_stat(buf);
+                       free(buf);
                }
        END OBJ(wireless_link_qual_perc, INFO_NET)
                if (arg) {
                        obj->data.net = get_net_stat(arg);
                } else {
-                       CRIT_ERR("wireless_link_qual_perc: needs an argument");
+                       // default to DEFAULTNETDEV
+                       char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
+                       obj->data.net = get_net_stat(buf);
+                       free(buf);
                }
        END OBJ(wireless_link_bar, INFO_NET)
+               SIZE_DEFAULTS(bar);
                if (arg) {
                        arg = scan_bar(arg, &obj->a, &obj->b);
                        obj->data.net = get_net_stat(arg);
                } else {
-                       CRIT_ERR("wireless_link_bar: needs an argument");
+                       // default to DEFAULTNETDEV
+                       char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
+                       obj->data.net = get_net_stat(buf);
+                       free(buf);
                }
 #endif /* HAVE_IWLIB */
 
@@ -1327,9 +1432,9 @@ static struct text_object *construct_text_object(const char *s,
                        strcpy(bat, "BAT0");
                }
                obj->data.s = strndup(bat, text_buffer_size);
-#ifdef X11
        END OBJ(battery_bar, 0)
                char bat[64];
+               SIZE_DEFAULTS(bar);
                obj->b = 6;
                if (arg) {
                        arg = scan_bar(arg, &obj->a, &obj->b);
@@ -1338,7 +1443,6 @@ static struct text_object *construct_text_object(const char *s,
                        strcpy(bat, "BAT0");
                }
                obj->data.s = strndup(bat, text_buffer_size);
-#endif
 #endif /* !__OpenBSD__ */
 
 #if defined(__linux__)
@@ -1402,8 +1506,9 @@ static struct text_object *construct_text_object(const char *s,
                if (!arg) {
                        ERR("if_up needs an argument");
                        obj->data.ifblock.s = 0;
-               } else
+               } else {
                        obj->data.ifblock.s = strndup(arg, text_buffer_size);
+               }
 #endif
 #if defined(__OpenBSD__)
        END OBJ(obsd_sensors_temp, 0)
@@ -1455,20 +1560,29 @@ static struct text_object *construct_text_object(const char *s,
                DBGP2("Adding $cpu for CPU %d", obj->data.cpu_index);
 #ifdef X11
        END OBJ(cpugauge, INFO_CPU)
+               SIZE_DEFAULTS(gauge);
                SCAN_CPU(arg, obj->data.cpu_index);
                scan_gauge(arg, &obj->a, &obj->b);
                DBGP2("Adding $cpugauge for CPU %d", obj->data.cpu_index);
+#endif /* X11 */
        END OBJ(cpubar, INFO_CPU)
+               SIZE_DEFAULTS(bar);
                SCAN_CPU(arg, obj->data.cpu_index);
                scan_bar(arg, &obj->a, &obj->b);
                DBGP2("Adding $cpubar for CPU %d", obj->data.cpu_index);
+#ifdef X11
        END OBJ(cpugraph, INFO_CPU)
+               char *buf = 0;
+               SIZE_DEFAULTS(graph);
                SCAN_CPU(arg, obj->data.cpu_index);
-               scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
+               buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
                        &obj->e, &obj->char_a, &obj->char_b);
                DBGP2("Adding $cpugraph for CPU %d", obj->data.cpu_index);
+               if (buf) free(buf);
        END OBJ(loadgraph, INFO_LOADAVG)
-               char *buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
+               char *buf = 0;
+               SIZE_DEFAULTS(graph);
+               buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
                                &obj->e, &obj->char_a, &obj->char_b);
                if (buf) {
                        int a = 1, r = 3;
@@ -1478,7 +1592,7 @@ static struct text_object *construct_text_object(const char *s,
                        obj->data.loadavg[0] = (r >= 1) ? (unsigned char) a : 0;
                        free(buf);
                }
-#endif
+#endif /* X11 */
        END OBJ(diskio, INFO_DISKIO)
                obj->data.diskio = prepare_diskio_stat(dev_name(arg));
        END OBJ(diskio_read, INFO_DISKIO)
@@ -1487,27 +1601,30 @@ static struct text_object *construct_text_object(const char *s,
                obj->data.diskio = prepare_diskio_stat(dev_name(arg));
 #ifdef X11
        END OBJ(diskiograph, INFO_DISKIO)
-               char *buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
+               char *buf = 0;
+               SIZE_DEFAULTS(graph);
+               buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
                                &obj->e, &obj->char_a, &obj->char_b);
 
                obj->data.diskio = prepare_diskio_stat(dev_name(buf));
-               if (buf)
-                       free(buf);
+               if (buf) free(buf);
        END OBJ(diskiograph_read, INFO_DISKIO)
-               char *buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
+               char *buf = 0;
+               SIZE_DEFAULTS(graph);
+               buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
                                &obj->e, &obj->char_a, &obj->char_b);
 
                obj->data.diskio = prepare_diskio_stat(dev_name(buf));
-               if (buf)
-                       free(buf);
+               if (buf) free(buf);
        END OBJ(diskiograph_write, INFO_DISKIO)
-               char *buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
+               char *buf = 0;
+               SIZE_DEFAULTS(graph);
+               buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
                                &obj->e, &obj->char_a, &obj->char_b);
 
                obj->data.diskio = prepare_diskio_stat(dev_name(buf));
-               if (buf)
-                       free(buf);
-#endif
+               if (buf) free(buf);
+#endif /* X11 */
        END OBJ(color, 0)
 #ifdef X11
                if (output_methods & TO_X) {
@@ -1537,7 +1654,7 @@ static struct text_object *construct_text_object(const char *s,
 #ifdef X11
        END OBJ(font, 0)
                obj->data.s = scan_font(arg);
-#endif
+#endif /* X11 */
        END OBJ(conky_version, 0)
        END OBJ(conky_build_date, 0)
        END OBJ(conky_build_arch, 0)
@@ -1545,24 +1662,32 @@ static struct text_object *construct_text_object(const char *s,
                if (arg) {
                        obj->data.net = get_net_stat(arg);
                } else {
-                       CRIT_ERR("downspeed needs argument");
+                       // default to DEFAULTNETDEV
+                       char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
+                       obj->data.net = get_net_stat(buf);
+                       free(buf);
                }
        END OBJ(downspeedf, INFO_NET)
                if (arg) {
                        obj->data.net = get_net_stat(arg);
                } else {
-                       CRIT_ERR("downspeedf needs argument");
+                       // default to DEFAULTNETDEV
+                       char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
+                       obj->data.net = get_net_stat(buf);
+                       free(buf);
                }
 #ifdef X11
        END OBJ(downspeedgraph, INFO_NET)
-               char *buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
+               char *buf = 0;
+               SIZE_DEFAULTS(graph);
+               buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
                                &obj->e, &obj->char_a, &obj->char_b);
 
                // default to DEFAULTNETDEV
-               buf = strndup(buf ? buf : "DEFAULTNETDEV", text_buffer_size);
+               buf = strndup(buf ? buf : DEFAULTNETDEV, text_buffer_size);
                obj->data.net = get_net_stat(buf);
                free(buf);
-#endif
+#endif /* X11 */
        END OBJ(else, 0)
                obj_be_ifblock_else(ifblock_opaque, obj);
        END OBJ(endif, 0)
@@ -1576,10 +1701,6 @@ static struct text_object *construct_text_object(const char *s,
                obj->data.s = strndup(arg ? arg : "", text_buffer_size);
        END OBJ(execp, 0)
                obj->data.s = strndup(arg ? arg : "", text_buffer_size);
-#define SIZE_DEFAULTS(arg) { \
-       obj->a = default_##arg##_width; \
-       obj->b = default_##arg##_height; \
-}
        END OBJ(execbar, 0)
                SIZE_DEFAULTS(bar);
                obj->data.s = strndup(arg ? arg : "", text_buffer_size);
@@ -1590,6 +1711,7 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ(execgraph, 0)
                SIZE_DEFAULTS(graph);
                obj->data.s = strndup(arg ? arg : "", text_buffer_size);
+#endif /* X11 */
        END OBJ(execibar, 0)
                int n;
                SIZE_DEFAULTS(bar);
@@ -1604,6 +1726,7 @@ static struct text_object *construct_text_object(const char *s,
                } else {
                        obj->data.execi.cmd = strndup(arg + n, text_buffer_size);
                }
+#ifdef X11
        END OBJ(execigraph, 0)
                int n;
                SIZE_DEFAULTS(graph);
@@ -1632,7 +1755,7 @@ static struct text_object *construct_text_object(const char *s,
                } else {
                        obj->data.execi.cmd = strndup(arg + n, text_buffer_size);
                }
-#endif
+#endif /* X11 */
        END OBJ(execi, 0)
                int n;
 
@@ -1687,10 +1810,10 @@ static struct text_object *construct_text_object(const char *s,
                obj->data.s = strndup("", text_buffer_size);
        }
 #endif
-#ifdef X11
        END OBJ(fs_bar, INFO_FS)
+               SIZE_DEFAULTS(bar);
                arg = scan_bar(arg, &obj->data.fsbar.w, &obj->data.fsbar.h);
-       if (arg) {
+               if (arg) {
                        while (isspace(*arg)) {
                                arg++;
                        }
@@ -1702,6 +1825,7 @@ static struct text_object *construct_text_object(const char *s,
                }
                obj->data.fsbar.fs = prepare_fs_stat(arg);
        END OBJ(fs_bar_free, INFO_FS)
+               SIZE_DEFAULTS(bar);
                arg = scan_bar(arg, &obj->data.fsbar.w, &obj->data.fsbar.h);
                if (arg) {
                        while (isspace(*arg)) {
@@ -1715,7 +1839,6 @@ static struct text_object *construct_text_object(const char *s,
                }
 
                obj->data.fsbar.fs = prepare_fs_stat(arg);
-#endif
        END OBJ(fs_free, INFO_FS)
                if (!arg) {
                        arg = "/";
@@ -1875,8 +1998,8 @@ static struct text_object *construct_text_object(const char *s,
 #endif /* !__OpenBSD__ */
 
        END
-       /* we have three different types of top (top, top_mem and top_time). To
-        * avoid having almost-same code three times, we have this special
+       /* we have four different types of top (top, top_mem, top_time and top_io). To
+        * avoid having almost-same code four times, we have this special
         * handler. */
        if (strncmp(s, "top", 3) == EQUAL) {
                if (!parse_top_args(s, arg, obj)) {
@@ -1886,14 +2009,20 @@ static struct text_object *construct_text_object(const char *s,
                if (arg) {
                        obj->data.net = get_net_stat(arg);
                } else {
-                       CRIT_ERR("addr needs argument");
+                       // default to DEFAULTNETDEV
+                       char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
+                       obj->data.net = get_net_stat(buf);
+                       free(buf);
                }
 #if defined(__linux__)
        END OBJ(addrs, INFO_NET)
                if (arg) {
                        obj->data.net = get_net_stat(arg);
                } else {
-                       CRIT_ERR("addrs needs argument");
+                       // default to DEFAULTNETDEV
+                       char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
+                       obj->data.net = get_net_stat(buf);
+                       free(buf);
                }
 #endif /* __linux__ */
        END OBJ(tail, 0)
@@ -1981,12 +2110,18 @@ static struct text_object *construct_text_object(const char *s,
                } else {
                        obj->data.ifblock.s = strndup(arg, text_buffer_size);
                }
+#ifdef __linux__
+       END OBJ_IF(if_running, INFO_TOP)
+               if (arg) {
+                       obj->data.ifblock.s = strndup(arg, text_buffer_size);
+#else
        END OBJ_IF(if_running, 0)
                if (arg) {
                        char buf[256];
 
                        snprintf(buf, 256, "pidof %s >/dev/null", arg);
                        obj->data.ifblock.s = strndup(buf, text_buffer_size);
+#endif
                } else {
                        ERR("if_running needs an argument");
                        obj->data.ifblock.s = 0;
@@ -2215,17 +2350,21 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ(memperc, INFO_MEM)
 #ifdef X11
        END OBJ(memgauge, INFO_MEM)
+               SIZE_DEFAULTS(gauge);
                scan_gauge(arg, &obj->data.pair.a, &obj->data.pair.b);
+#endif /* X11*/
        END OBJ(membar, INFO_MEM)
+               SIZE_DEFAULTS(bar);
                scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
+#ifdef X11
        END OBJ(memgraph, INFO_MEM)
-               char *buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
+               char *buf = 0;
+               SIZE_DEFAULTS(graph);
+               buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
                                &obj->e, &obj->char_a, &obj->char_b);
 
-               if (buf) {
-                       free(buf);
-               }
-#endif
+               if (buf) free(buf);
+#endif /* X11*/
        END OBJ(mixer, INFO_MIXER)
                obj->data.l = mixer_init(arg);
        END OBJ(mixerl, INFO_MIXER)
@@ -2234,12 +2373,15 @@ static struct text_object *construct_text_object(const char *s,
                obj->data.l = mixer_init(arg);
 #ifdef X11
        END OBJ(mixerbar, INFO_MIXER)
+               SIZE_DEFAULTS(bar);
                scan_mixer_bar(arg, &obj->data.mixerbar.l, &obj->data.mixerbar.w,
                        &obj->data.mixerbar.h);
        END OBJ(mixerlbar, INFO_MIXER)
+               SIZE_DEFAULTS(bar);
                scan_mixer_bar(arg, &obj->data.mixerbar.l, &obj->data.mixerbar.w,
                        &obj->data.mixerbar.h);
        END OBJ(mixerrbar, INFO_MIXER)
+               SIZE_DEFAULTS(bar);
                scan_mixer_bar(arg, &obj->data.mixerbar.l, &obj->data.mixerbar.w,
                        &obj->data.mixerbar.h);
 #endif
@@ -2276,12 +2418,12 @@ static struct text_object *construct_text_object(const char *s,
                obj->data.pair.b = b;
 #endif /* X11 */
        END OBJ(swap, INFO_MEM)
+       END OBJ(swapfree, INFO_MEM)
        END OBJ(swapmax, INFO_MEM)
        END OBJ(swapperc, INFO_MEM)
-#ifdef X11
        END OBJ(swapbar, INFO_MEM)
+               SIZE_DEFAULTS(bar);
                scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
-#endif
        END OBJ(sysname, 0)
        END OBJ(time, 0)
                obj->data.s = strndup(arg ? arg : "%F %T", text_buffer_size);
@@ -2338,14 +2480,20 @@ static struct text_object *construct_text_object(const char *s,
                if (arg) {
                        obj->data.net = get_net_stat(arg);
                } else {
-                       CRIT_ERR("totaldown needs argument");
+                       // default to DEFAULTNETDEV
+                       char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
+                       obj->data.net = get_net_stat(buf);
+                       free(buf);
                }
        END OBJ(totalup, INFO_NET)
                obj->data.net = get_net_stat(arg);
                if (arg) {
                        obj->data.net = get_net_stat(arg);
                } else {
-                       CRIT_ERR("totalup needs argument");
+                       // default to DEFAULTNETDEV
+                       char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
+                       obj->data.net = get_net_stat(buf);
+                       free(buf);
                }
        END OBJ(updates, 0)
        END OBJ_IF(if_updatenr, 0)
@@ -2360,22 +2508,30 @@ static struct text_object *construct_text_object(const char *s,
                if (arg) {
                        obj->data.net = get_net_stat(arg);
                } else {
-                       CRIT_ERR("upspeed needs argument");
+                       // default to DEFAULTNETDEV
+                       char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
+                       obj->data.net = get_net_stat(buf);
+                       free(buf);
                }
        END OBJ(upspeedf, INFO_NET)
                if (arg) {
                        obj->data.net = get_net_stat(arg);
                } else {
-                       CRIT_ERR("upspeedf needs argument");
+                       // default to DEFAULTNETDEV
+                       char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
+                       obj->data.net = get_net_stat(buf);
+                       free(buf);
                }
 
 #ifdef X11
        END OBJ(upspeedgraph, INFO_NET)
-               char *buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
+               char *buf = 0;
+               SIZE_DEFAULTS(graph);
+               buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
                                &obj->e, &obj->char_a, &obj->char_b);
 
                // default to DEFAULTNETDEV
-               buf = strndup(buf ? buf : "DEFAULTNETDEV", text_buffer_size);
+               buf = strndup(buf ? buf : DEFAULTNETDEV, text_buffer_size);
                obj->data.net = get_net_stat(buf);
                free(buf);
 #endif
@@ -2458,7 +2614,9 @@ static struct text_object *construct_text_object(const char *s,
                        obj->data.s = strndup(arg, text_buffer_size);
                else
                        ERR("smapi_bat_power needs an argument");
+#ifdef X11
        END OBJ(smapi_bat_bar, 0)
+               SIZE_DEFAULTS(bar);
                if(arg) {
                        int cnt;
                        if(sscanf(arg, "%i %n", &obj->data.i, &cnt) <= 0) {
@@ -2470,6 +2628,7 @@ static struct text_object *construct_text_object(const char *s,
                        }
                } else
                        ERR("smapi_bat_bar needs an argument");
+#endif /* X11 */
 #endif /* IBM */
 #ifdef MPD
 #define mpd_set_maxlen(name) \
@@ -2507,11 +2666,10 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ(mpd_vol, INFO_MPD) init_mpd();
        END OBJ(mpd_bitrate, INFO_MPD) init_mpd();
        END OBJ(mpd_status, INFO_MPD) init_mpd();
-#ifdef X11
        END OBJ(mpd_bar, INFO_MPD)
+               SIZE_DEFAULTS(bar);
                scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
                init_mpd();
-#endif
        END OBJ(mpd_smart, INFO_MPD)
                mpd_set_maxlen(mpd_smart);
                init_mpd();
@@ -2548,8 +2706,11 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ(xmms2_size, INFO_XMMS2)
        END OBJ(xmms2_status, INFO_XMMS2)
        END OBJ(xmms2_percent, INFO_XMMS2)
+#ifdef X11
        END OBJ(xmms2_bar, INFO_XMMS2)
+               SIZE_DEFAULTS(bar);
                scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
+#endif /* X11 */
        END OBJ(xmms2_smart, INFO_XMMS2)
        END OBJ(xmms2_playlist, INFO_XMMS2)
        END OBJ(xmms2_timesplayed, INFO_XMMS2)
@@ -2577,8 +2738,11 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ(audacious_playlist_length, INFO_AUDACIOUS)
        END OBJ(audacious_playlist_position, INFO_AUDACIOUS)
        END OBJ(audacious_main_volume, INFO_AUDACIOUS)
+#ifdef X11
        END OBJ(audacious_bar, INFO_AUDACIOUS)
+               SIZE_DEFAULTS(bar);
                scan_bar(arg, &obj->a, &obj->b);
+#endif /* X11 */
 #endif
 #ifdef BMPX
        END OBJ(bmpx_title, INFO_BMPX)
@@ -2634,6 +2798,42 @@ static struct text_object *construct_text_object(const char *s,
                                        "[act_par] [spaces in front]");
                }
 #endif
+#ifdef WEATHER
+       END OBJ(weather, 0)
+               if (arg) {
+                       int argc, delay;
+                       char *icao = (char *) malloc(5 * sizeof(char));
+                       char *uri = (char *) malloc(128 * sizeof(char));
+                       char *data_type = (char *) malloc(32 * sizeof(char));
+                       char *tmp_p;
+
+                       argc = sscanf(arg, "%4s %31s %d", icao, data_type, &delay);
+
+                       //icao MUST BE upper-case
+                       tmp_p = icao;
+                       while (*tmp_p) {
+                         *tmp_p = toupper(*tmp_p);
+                         tmp_p++;
+                       }
+
+                       strcpy(uri, "http://weather.noaa.gov/pub/data/observations/metar/stations/");
+                       strcat(uri, icao);
+                       strcat(uri, ".TXT");
+                       obj->data.weather.uri = uri;
+
+                       obj->data.weather.data_type = data_type;
+
+                       //The data retrieval interval is limited to half an hour
+                       if(delay < 30) {
+                         delay = 30;
+                       }
+                       obj->data.weather.delay = delay*60;
+
+                       init_weather_info();
+               } else {
+                       CRIT_ERR("weather needs arguments: <icao> <data_type> [delay in minutes]");
+               }
+#endif
 #ifdef HAVE_LUA
        END OBJ(lua, 0)
                if (arg) {
@@ -2647,14 +2847,8 @@ static struct text_object *construct_text_object(const char *s,
                } else {
                        CRIT_ERR("lua_parse needs arguments: <function name> [function parameters]");
                }
-       END OBJ(lua_read_parse, 0)
-               if (arg) {
-                       obj->data.s = strndup(arg, text_buffer_size);
-               } else {
-                       CRIT_ERR("lua_read_parse needs arguments: <function name> <string to pass>");
-               }
-#ifdef X11
        END OBJ(lua_bar, 0)
+               SIZE_DEFAULTS(bar);
                if (arg) {
                        arg = scan_bar(arg, &obj->a, &obj->b);
                        if(arg) {
@@ -2665,19 +2859,23 @@ static struct text_object *construct_text_object(const char *s,
                } else {
                        CRIT_ERR("lua_bar needs arguments: <height>,<width> <function name> [function parameters]");
                }
+#ifdef X11
        END OBJ(lua_graph, 0)
+               SIZE_DEFAULTS(graph);
                if (arg) {
-                       arg = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
+                       char *buf = 0;
+                       buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
                                        &obj->e, &obj->char_a, &obj->char_b);
-                       if (arg) {
-                               obj->data.s = strndup(arg, text_buffer_size);
+                       if (buf) {
+                               obj->data.s = buf;
                        } else {
-                               CRIT_ERR("lua_graph needs arguments: <\"normal\"|\"log\"> <height>,<width> <gradient colour 1> <gradient colour 2> <scale> <function name> [function parameters]");
+                               CRIT_ERR("lua_graph needs arguments: <function name> [height],[width] [gradient colour 1] [gradient colour 2] [scale] [-t] [-l]");
                        }
                } else {
-                       CRIT_ERR("lua_graph needs arguments: <\"normal\"|\"log\"> <height>,<width> <gradient colour 1> <gradient colour 2> <scale> <function name> [function parameters]");
+                       CRIT_ERR("lua_graph needs arguments: <function name> [height],[width] [gradient colour 1] [gradient colour 2] [scale] [-t] [-l]");
        }
        END OBJ(lua_gauge, 0)
+               SIZE_DEFAULTS(gauge);
                if (arg) {
                        arg = scan_gauge(arg, &obj->a, &obj->b);
                        if (arg) {
@@ -2700,17 +2898,31 @@ static struct text_object *construct_text_object(const char *s,
                        obj->data.hddtemp.update_time = 0;
                } else
                        obj->data.hddtemp.temp = NULL;
-#endif
+#endif /* HDDTEMP */
 #ifdef TCP_PORT_MONITOR
        END OBJ(tcp_portmon, INFO_TCP_PORT_MONITOR)
                tcp_portmon_init(arg, &obj->data.tcp_port_monitor);
-#endif
+#endif /* TCP_PORT_MONITOR */
        END OBJ(entropy_avail, INFO_ENTROPY)
+       END OBJ(entropy_perc, INFO_ENTROPY)
        END OBJ(entropy_poolsize, INFO_ENTROPY)
-#ifdef X11
        END OBJ(entropy_bar, INFO_ENTROPY)
+               SIZE_DEFAULTS(bar);
                scan_bar(arg, &obj->a, &obj->b);
-#endif
+       END OBJ(blink, 0)
+               if(arg) {
+                       obj->sub = malloc(sizeof(struct text_object));
+                       extract_variable_text_internal(obj->sub, arg, 0);
+               }else{
+                       CRIT_ERR("blink needs a argument");
+               }
+       END OBJ(to_bytes, 0)
+               if(arg) {
+                       obj->sub = malloc(sizeof(struct text_object));
+                       extract_variable_text_internal(obj->sub, arg, 0);
+               }else{
+                       CRIT_ERR("to_bytes needs a argument");
+               }
        END OBJ(scroll, 0)
                int n1, n2;
 
@@ -2734,7 +2946,7 @@ static struct text_object *construct_text_object(const char *s,
                        int endvar[2];
                        startvar[0] = endvar[0] = startvar[1] = endvar[1] = -1;
                        j=0;
-                       for(i=0; arg[i] != 0 && j < 2; i++) {
+                       for (i=0; arg[i] != 0 && j < 2; i++) {
                                if(startvar[j] == -1) {
                                        if(arg[i] == '$') {
                                                startvar[j] = i;
@@ -2752,12 +2964,19 @@ static struct text_object *construct_text_object(const char *s,
                                }
                        }
                        if(startvar[0] >= 0 && endvar[0] >= 0 && startvar[1] >= 0 && endvar[1] >= 0) {
-                               obj->data.combine.left=malloc(endvar[0]-startvar[0]+1);
-                               obj->data.combine.seperation=malloc(startvar[1]-endvar[0]+1);
-                               obj->data.combine.right=malloc(endvar[1]-startvar[1]+1);
-                               strncpy(obj->data.combine.left, arg+startvar[0], endvar[0]-startvar[0]); obj->data.combine.left[endvar[0]-startvar[0]]=0;
-                               strncpy(obj->data.combine.seperation, arg+endvar[0], startvar[1]-endvar[0]); obj->data.combine.seperation[startvar[1]-endvar[0]]=0;
-                               strncpy(obj->data.combine.right, arg+startvar[1], endvar[1]-startvar[1]); obj->data.combine.right[endvar[1]-startvar[1]]=0;
+                               obj->data.combine.left = malloc(endvar[0]-startvar[0] + 1);
+                               obj->data.combine.seperation = malloc(startvar[1] - endvar[0] + 1);
+                               obj->data.combine.right= malloc(endvar[1]-startvar[1] + 1);
+                               
+                               strncpy(obj->data.combine.left, arg + startvar[0], endvar[0] - startvar[0]);
+                               obj->data.combine.left[endvar[0] - startvar[0]] = 0;
+                               
+                               strncpy(obj->data.combine.seperation, arg + endvar[0], startvar[1] - endvar[0]);
+                               obj->data.combine.seperation[startvar[1] - endvar[0]] = 0;
+                               
+                               strncpy(obj->data.combine.right, arg + startvar[1], endvar[1] - startvar[1]);
+                               obj->data.combine.right[endvar[1] - startvar[1]] = 0;
+
                                obj->sub = malloc(sizeof(struct text_object));
                                extract_variable_text_internal(obj->sub, obj->data.combine.left, 0);
                                obj->sub->sub = malloc(sizeof(struct text_object));
@@ -2799,16 +3018,20 @@ static struct text_object *construct_text_object(const char *s,
                        END OBJ(apcupsd_status, INFO_APCUPSD)
                        END OBJ(apcupsd_linev, INFO_APCUPSD)
                        END OBJ(apcupsd_load, INFO_APCUPSD)
-#ifdef X11
                        END OBJ(apcupsd_loadbar, INFO_APCUPSD)
+                               SIZE_DEFAULTS(bar);
                                scan_bar(arg, &obj->a, &obj->b);
+#ifdef X11
                        END OBJ(apcupsd_loadgraph, INFO_APCUPSD)
-                               char* buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
+                               char* buf = 0;
+                               SIZE_DEFAULTS(graph);
+                               buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
                                                &obj->e, &obj->char_a, &obj->char_b);
                                if (buf) free(buf);
                        END OBJ(apcupsd_loadgauge, INFO_APCUPSD)
+                               SIZE_DEFAULTS(gauge);
                                scan_gauge(arg, &obj->a, &obj->b);
-#endif
+#endif /* X11 */
                        END OBJ(apcupsd_charge, INFO_APCUPSD)
                        END OBJ(apcupsd_timeleft, INFO_APCUPSD)
                        END OBJ(apcupsd_temp, INFO_APCUPSD)
@@ -2908,37 +3131,40 @@ static char *backslash_escape(const char *src, char **templates, unsigned int te
  */
 static char *handle_template(const char *tmpl, const char *args)
 {
-       char *args_dup, *p, *p_old;
+       char *args_dup = NULL;
+       char *p, *p_old;
        char **argsp = NULL;
        unsigned int argcnt = 0, template_idx, i;
        char *eval_text;
 
        if ((sscanf(tmpl, "template%u", &template_idx) != 1) ||
-           (template_idx > 9))
+           (template_idx >= MAX_TEMPLATES))
                return NULL;
 
-       args_dup = strdup(args);
-       p = args_dup;
-       while (*p) {
-               while (*p && (*p == ' ' && *(p - 1) != '\\'))
-                       p++;
-               if (*(p - 1) == '\\')
-                       p--;
-               p_old = p;
-               while (*p && (*p != ' ' || *(p - 1) == '\\'))
-                       p++;
-               if (*p) {
-                       (*p) = '\0';
-                       p++;
+       if(args) {
+               args_dup = strdup(args);
+               p = args_dup;
+               while (*p) {
+                       while (*p && (*p == ' ' && (p == args_dup || *(p - 1) != '\\')))
+                               p++;
+                       if (p > args_dup && *(p - 1) == '\\')
+                               p--;
+                       p_old = p;
+                       while (*p && (*p != ' ' || (p > args_dup && *(p - 1) == '\\')))
+                               p++;
+                       if (*p) {
+                               (*p) = '\0';
+                               p++;
+                       }
+                       argsp = realloc(argsp, ++argcnt * sizeof(char *));
+                       argsp[argcnt - 1] = p_old;
+               }
+               for (i = 0; i < argcnt; i++) {
+                       char *tmp;
+                       tmp = backslash_escape(argsp[i], NULL, 0);
+                       DBGP2("%s: substituted arg '%s' to '%s'", tmpl, argsp[i], tmp);
+                       argsp[i] = tmp;
                }
-               argsp = realloc(argsp, ++argcnt * sizeof(char *));
-               argsp[argcnt - 1] = p_old;
-       }
-       for (i = 0; i < argcnt; i++) {
-               char *tmp;
-               tmp = backslash_escape(argsp[i], NULL, 0);
-               DBGP2("%s: substituted arg '%s' to '%s'", tmpl, argsp[i], tmp);
-               argsp[i] = tmp;
        }
 
        eval_text = backslash_escape(template[template_idx], argsp, argcnt);
@@ -2973,30 +3199,40 @@ static char *find_and_replace_templates(const char *inbuf)
                }
 
                if (*(p + 1) == '{') {
-                       templ = p + 2;
-                       while (*p != ' ')
+                       p += 2;
+                       templ = p;
+                       while (*p && !isspace(*p) && *p != '{' && *p != '}')
                                p++;
-                       *(p++) = '\0';
-                       args = p;
+                       if (*p == '}')
+                               args = NULL;
+                       else
+                               args = p;
+
                        stack = 1;
-                       while (stack > 0) {
-                               p++;
+                       while (*p && stack > 0) {
                                if (*p == '{')
                                        stack++;
                                else if (*p == '}')
                                        stack--;
+                               p++;
+                       }
+                       if (stack == 0) {
+                               // stack is empty. that means the previous char was }, so we zero it
+                               *(p - 1) = '\0';
+                       } else {
+                               // we ran into the end of string without finding a closing }, bark
+                               CRIT_ERR("cannot find a closing '}' in template expansion");
                        }
-                       *(p++) = '\0';
                } else {
                        templ = p + 1;
-                       while (*p != ' ')
+                       while (*p && !isspace(*p))
                                p++;
-                       *(p++) = '\0';
                        args = NULL;
                }
                tmpl_out = handle_template(templ, args);
                if (tmpl_out) {
                        outlen += strlen(tmpl_out);
+                       *o = '\0';
                        outbuf = realloc(outbuf, outlen * sizeof(char));
                        strcat (outbuf, tmpl_out);
                        free(tmpl_out);
@@ -3020,18 +3256,41 @@ static int text_contains_templates(const char *text)
        return 0;
 }
 
+/* folds a string over top of itself, like so:
+ *
+ * if start is "blah", and you call it with count = 1, the result will be "lah"
+ */
 static void strfold(char *start, int count)
 {
        char *curplace;
        for (curplace = start + count; *curplace != 0; curplace++) {
                *(curplace - count) = *curplace;
        }
-       *(curplace - count - 1) = 0;
+       *(curplace - count) = 0;
+}
+
+/*
+ * - assumes that *string is '#'
+ * - removes the part from '#' to the end of line ('\n' or '\0')
+ * - it removes the '\n'
+ * - copies the last char into 'char *last' argument, which should be a pointer
+ *   to a char rather than a string.
+ */
+static size_t remove_comment(char *string, char *last)
+{
+       char *end = string;
+       while (*end != '\0' && *end != '\n') {
+               ++end;
+       }
+       if (last) *last = *end;
+       if (*end == '\n') end++;
+       strfold(string, end - string);
+       return end - string;
 }
 
 static size_t remove_comments(char *string)
 {
-       char *curplace, *curplace2;
+       char *curplace;
        size_t folded = 0;
        for (curplace = string; *curplace != 0; curplace++) {
                if (*curplace == '\\' && *(curplace + 1) == '#') {
@@ -3039,19 +3298,7 @@ static size_t remove_comments(char *string)
                        strfold(curplace, 1);
                        folded += 1;
                } else if (*curplace == '#') {
-                       // remove everything until we hit a '\n'
-                       curplace2 = curplace;
-                       while (*curplace2) {
-                               curplace2++;
-                               if (*curplace2 == '\n' &&
-                                               *(curplace2 + 1) != '#') break;
-                       }
-                       if (*curplace2) {
-                               strfold(curplace, curplace2 - curplace);
-                               folded += curplace2 - curplace;
-                       } else {
-                               *curplace = 0;
-                       }
+                       folded += remove_comment(curplace, 0);
                }
        }
        return folded;
@@ -3189,12 +3436,17 @@ static int extract_variable_text_internal(struct text_object *retval, const char
                                        append_object(retval, obj);
                                }
                        }
+               } else if (*p == '\\' && *(p+1) == '#') {
+                       strfold(p, 1);
                } else if (*p == '#') {
-                       remove_comments(p);
+                       char c;
+                       if (remove_comment(p, &c) && p > orig_p && c == '\n') {
+                               /* if remove_comment removed a newline, we need to 'back up' with p */
+                               p--;
+                       }
                }
                p++;
        }
-       remove_comments(s);
        obj = create_plain_text(s);
        if (obj != NULL) {
                append_object(retval, obj);
@@ -3387,6 +3639,9 @@ static void generate_text_internal(char *p, int p_max_size,
                struct text_object root, struct information *cur)
 {
        struct text_object *obj;
+#ifdef X11
+       int need_to_load_fonts = 0;
+#endif /* X11 */
 
        /* for the OBJ_top* handler */
        struct process **needed = 0;
@@ -3395,7 +3650,7 @@ static void generate_text_internal(char *p, int p_max_size,
        char buff_in[p_max_size];
        buff_in[0] = 0;
        iconv_converting = 0;
-#endif
+#endif /* HAVE_ICONV */
 
        p[0] = 0;
        obj = root.next;
@@ -3431,6 +3686,39 @@ static void generate_text_internal(char *p, int p_max_size,
                switch (obj->type) {
                        default:
                                ERR("not implemented obj type %d", obj->type);
+                       OBJ(read_tcp) {
+                               int sock, received;
+                               struct sockaddr_in addr;
+                               struct hostent* he = gethostbyname(obj->data.read_tcp.host);
+                               if(he != NULL) {
+                                       sock = socket(he->h_addrtype, SOCK_STREAM, 0);
+                                       if(sock != -1) {
+                                               memset(&addr, 0, sizeof(addr));
+                                               addr.sin_family = AF_INET;
+                                               addr.sin_port = obj->data.read_tcp.port;
+                                               memcpy(&addr.sin_addr, he->h_addr, he->h_length);
+                                               if (connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr)) == 0) {
+                                                       fd_set readfds;
+                                                       struct timeval tv;
+                                                       FD_ZERO(&readfds);
+                                                       FD_SET(sock, &readfds);
+                                                       tv.tv_sec = 1;
+                                                       tv.tv_usec = 0;
+                                                       if(select(sock + 1, &readfds, NULL, NULL, &tv) > 0){
+                                                               received = recv(sock, p, p_max_size, 0);
+                                                               p[received] = 0;
+                                                       }
+                                                       close(sock);
+                                               } else {
+                                                       ERR("read_tcp: Couldn't create a connection");
+                                               }
+                                       }else{
+                                               ERR("read_tcp: Couldn't create a socket");
+                                       }
+                               }else{
+                                       ERR("read_tcp: Problem with resolving the hostname");
+                               }
+                       }
 #ifndef __OpenBSD__
                        OBJ(acpitemp) {
                                temp_print(p, p_max_size, get_acpi_temperature(obj->data.i), TEMP_CELSIUS);
@@ -3451,7 +3739,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                        /* OpenBSD has no such flag (SUSv2) */
                                        obj->a = get_freq(p, p_max_size, "%.2f", 1000,
                                                        obj->data.cpu_index);
-#endif
+#endif /* __OpenBSD */
                                }
                        }
 #if defined(__linux__)
@@ -3499,8 +3787,18 @@ static void generate_text_internal(char *p, int p_max_size,
                                }
                        }
                        OBJ(wireless_link_bar) {
-                               new_bar(p, obj->a, obj->b, ((double) obj->data.net->link_qual /
-                                                       obj->data.net->link_qual_max) * 255.0);
+#ifdef X11
+                               if(output_methods & TO_X) {
+                                       new_bar(p, obj->a, obj->b, ((double) obj->data.net->link_qual /
+                                               obj->data.net->link_qual_max) * 255.0);
+                               }else{
+#endif /* X11 */
+                                       if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
+                                       new_bar_in_shell(p, p_max_size, ((double) obj->data.net->link_qual /
+                                               obj->data.net->link_qual_max) * 100.0, obj->a);
+#ifdef X11
+                               }
+#endif /* X11 */
                        }
 #endif /* HAVE_IWLIB */
 
@@ -3528,11 +3826,18 @@ static void generate_text_internal(char *p, int p_max_size,
                        OBJ(battery_percent) {
                                percent_print(p, p_max_size, get_battery_perct(obj->data.s));
                        }
-#ifdef X11
                        OBJ(battery_bar) {
-                               new_bar(p, obj->a, obj->b, get_battery_perct_bar(obj->data.s));
+#ifdef X11
+                               if(output_methods & TO_X) {
+                                       new_bar(p, obj->a, obj->b, get_battery_perct_bar(obj->data.s));
+                               }else{
+#endif /* X11 */
+                                       if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
+                                       new_bar_in_shell(p, p_max_size, get_battery_perct_bar(obj->data.s) / 2.55, obj->a);
+#ifdef X11
+                               }
+#endif /* X11 */
                        }
-#endif
                        OBJ(battery_short) {
                                get_battery_short_status(p, p_max_size, obj->data.s);
                        }
@@ -3557,10 +3862,21 @@ static void generate_text_internal(char *p, int p_max_size,
                        OBJ(cpugauge)
                                new_gauge(p, obj->a, obj->b,
                                                round_to_int(cur->cpu_usage[obj->data.cpu_index] * 255.0));
+#endif /* X11 */
                        OBJ(cpubar) {
-                               new_bar(p, obj->a, obj->b,
+#ifdef X11
+                               if(output_methods & TO_X) {
+                                       new_bar(p, obj->a, obj->b,
                                                round_to_int(cur->cpu_usage[obj->data.cpu_index] * 255.0));
+                               }else{
+#endif /* X11 */
+                                       if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
+                                       new_bar_in_shell(p, p_max_size, round_to_int(cur->cpu_usage[obj->data.cpu_index] * 100), obj->a);
+#ifdef X11
+                               }
+#endif /* X11 */
                        }
+#ifdef X11
                        OBJ(cpugraph) {
                                new_graph(p, obj->a, obj->b, obj->c, obj->d,
                                                round_to_int(cur->cpu_usage[obj->data.cpu_index] * 100),
@@ -3603,7 +3919,7 @@ static void generate_text_internal(char *p, int p_max_size,
                        OBJ(color9) {
                                new_fg(p, color9);
                        }
-#endif
+#endif /* X11 */
                        OBJ(conky_version) {
                                snprintf(p, p_max_size, "%s", VERSION);
                        }
@@ -3761,8 +4077,9 @@ static void generate_text_internal(char *p, int p_max_size,
 #ifdef X11
                        OBJ(font) {
                                new_font(p, obj->data.s);
+                               need_to_load_fonts = 1;
                        }
-#endif
+#endif /* X11 */
                        /* TODO: move this correction from kB to kB/s elsewhere
                         * (or get rid of it??) */
                        OBJ(diskio) {
@@ -3790,7 +4107,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                new_graph(p, obj->a, obj->b, obj->c, obj->d,
                                          obj->data.diskio->current_write, obj->e, 1, obj->char_a, obj->char_b);
                        }
-#endif
+#endif /* X11 */
                        OBJ(downspeed) {
                                human_readable(obj->data.net->recv_speed, p, 255);
                        }
@@ -3803,7 +4120,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                new_graph(p, obj->a, obj->b, obj->c, obj->d,
                                        obj->data.net->recv_speed / 1024.0, obj->e, 1, obj->char_a, obj->char_b);
                        }
-#endif
+#endif /* X11 */
                        OBJ(else) {
                                /* Since we see you, you're if has not jumped.
                                 * Do Ninja jump here: without leaving traces.
@@ -3849,18 +4166,7 @@ static void generate_text_internal(char *p, int p_max_size,
                        }
 #endif /* IMLIB2 */
                        OBJ(eval) {
-                               struct information *tmp_info;
-                               struct text_object subroot, subroot2;
-
-                               tmp_info = malloc(sizeof(struct information));
-                               memcpy(tmp_info, cur, sizeof(struct information));
-                               parse_conky_vars(&subroot, obj->data.s, p, tmp_info);
-                               DBGP("evaluated '%s' to '%s'", obj->data.s, p);
-                               parse_conky_vars(&subroot2, p, p, tmp_info);
-
-                               free_text_objects(&subroot, 1);
-                               free_text_objects(&subroot2, 1);
-                               free(tmp_info);
+                               evaluate(obj->data.s, p);
                        }
                        OBJ(exec) {
                                read_exec(obj->data.s, p, text_buffer_size);
@@ -3891,10 +4197,9 @@ static void generate_text_internal(char *p, int p_max_size,
                                        new_gauge(p, obj->a, obj->b, round_to_int(barnum * 255.0));
                                }
                        }
-#endif
+#endif /* X11 */
                        OBJ(execbar) {
                                double barnum;
-                               int i = 0, j = 0;
 
                                read_exec(obj->data.s, p, text_buffer_size);
                                barnum = get_barnum(p);
@@ -3905,27 +4210,12 @@ static void generate_text_internal(char *p, int p_max_size,
                                                barnum /= 100;
                                                new_bar(p, obj->a, obj->b, round_to_int(barnum * 255.0));
                                        }else{
-#endif
+#endif /* X11 */
                                                if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
-                                               barnum = round_to_int( ( barnum * obj->a ) / 100);
-                                               #ifdef HAVE_OPENMP
-                                               #pragma omp parallel for
-                                               #endif /* HAVE_OPENMP */
-                                               for(i=0; i<(int)barnum; i++) {
-                                                       *(p+i)='#';
-                                               }
-                                               /* gcc seems to think i is not initialized properly :/ */
-                                               j = i;
-                                               #ifdef HAVE_OPENMP
-                                               #pragma omp parallel for
-                                               #endif /* HAVE_OPENMP */
-                                               for(i = j/* cheats */; i < obj->a; i++) {
-                                                       *(p+i)='_';
-                                               }
-                                               *(p+i)=0;
+                                               new_bar_in_shell(p, p_max_size, barnum, obj->a);
 #ifdef X11
                                        }
-#endif
+#endif /* X11 */
                                }
                        }
 #ifdef X11
@@ -3935,24 +4225,23 @@ static void generate_text_internal(char *p, int p_max_size,
                                double barnum;
                                char *cmd = obj->data.s;
 
-                               if (strncasecmp(obj->data.execi.cmd, LOGGRAPH" ", strlen(LOGGRAPH" ")) == EQUAL) {
-                                       showaslog = TRUE;
-                                       cmd = cmd + strlen(LOGGRAPH" ") * sizeof(char);
-                               } else if(strncasecmp(obj->data.s, NORMGRAPH" ", strlen(NORMGRAPH" ")) == EQUAL) {
-                                       cmd = cmd + strlen(NORMGRAPH" ") * sizeof(char);
-                               }
                                if (strstr(cmd, " "TEMPGRAD) && strlen(cmd) > strlen(" "TEMPGRAD)) {
                                        tempgrad = TRUE;
                                        cmd += strlen(" "TEMPGRAD);
                                }
+                               if (strstr(cmd, " "LOGGRAPH) && strlen(cmd) > strlen(" "LOGGRAPH)) {
+                                       showaslog = TRUE;
+                                       cmd += strlen(" "LOGGRAPH);
+                               }
                                read_exec(cmd, p, text_buffer_size);
                                barnum = get_barnum(p);
 
-                               if (barnum >= 0.0) {
+                               if (barnum > 0) {
                                        new_graph(p, obj->a, obj->b, obj->c, obj->d, round_to_int(barnum),
                                                        100, 1, showaslog, tempgrad);
                                }
                        }
+#endif /* X11 */
                        OBJ(execibar) {
                                if (current_update_time - obj->data.execi.last_update
                                                >= obj->data.execi.interval) {
@@ -3962,12 +4251,22 @@ static void generate_text_internal(char *p, int p_max_size,
                                        barnum = get_barnum(p);
 
                                        if (barnum >= 0.0) {
-                                               obj->f = 255 * barnum / 100.0;
+                                               obj->f = barnum;
                                        }
                                        obj->data.execi.last_update = current_update_time;
                                }
-                               new_bar(p, obj->a, obj->b, round_to_int(obj->f));
+#ifdef X11
+                               if(output_methods & TO_X) {
+                                       new_bar(p, obj->a, obj->b, round_to_int(obj->f * 2.55));
+                               } else {
+#endif /* X11 */
+                                       if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
+                                       new_bar_in_shell(p, p_max_size, round_to_int(obj->f), obj->a);
+#ifdef X11
+                               }
+#endif /* X11 */
                        }
+#ifdef X11
                        OBJ(execigraph) {
                                if (current_update_time - obj->data.execi.last_update
                                                >= obj->data.execi.interval) {
@@ -3976,16 +4275,14 @@ static void generate_text_internal(char *p, int p_max_size,
                                        char tempgrad = FALSE;
                                        char *cmd = obj->data.execi.cmd;
 
-                                       if (strncasecmp(obj->data.execi.cmd, LOGGRAPH" ", strlen(LOGGRAPH" ")) == EQUAL) {
-                                               showaslog = TRUE;
-                                               cmd = cmd + strlen(LOGGRAPH" ") * sizeof(char);
-                                       } else if(strncasecmp(obj->data.s, NORMGRAPH" ", strlen(NORMGRAPH" ")) == EQUAL) {
-                                               cmd = cmd + strlen(NORMGRAPH" ") * sizeof(char);
-                                       }
                                        if (strstr(cmd, " "TEMPGRAD) && strlen(cmd) > strlen(" "TEMPGRAD)) {
                                                tempgrad = TRUE;
                                                cmd += strlen(" "TEMPGRAD);
                                        }
+                                       if (strstr(cmd, " "LOGGRAPH) && strlen(cmd) > strlen(" "LOGGRAPH)) {
+                                               showaslog = TRUE;
+                                               cmd += strlen(" "LOGGRAPH);
+                                       }
                                        obj->char_a = showaslog;
                                        obj->char_b = tempgrad;
                                        read_exec(cmd, p, text_buffer_size);
@@ -4013,7 +4310,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                }
                                new_gauge(p, obj->a, obj->b, round_to_int(obj->f));
                        }
-#endif
+#endif /* X11 */
                        OBJ(execi) {
                                if (current_update_time - obj->data.execi.last_update
                                                >= obj->data.execi.interval
@@ -4109,23 +4406,39 @@ static void generate_text_internal(char *p, int p_max_size,
                                        timed_thread_unlock(mail->p_timed_thread);
                                }
                        }
-#ifdef X11
                        OBJ(fs_bar) {
                                if (obj->data.fs != NULL) {
                                        if (obj->data.fs->size == 0) {
-                                               new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h, 255);
+#ifdef X11
+                                               if(output_methods & TO_X) {
+                                                       new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h, 255);
+                                               }else{
+#endif /* X11 */
+                                                       if(!obj->data.fsbar.w) obj->data.fsbar.w = DEFAULT_BAR_WIDTH_NO_X;
+                                                       new_bar_in_shell(p, p_max_size, 100, obj->data.fsbar.w);
+#ifdef X11
+                                               }
+#endif /* X11 */
                                        } else {
-                                               new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h,
-                                                       (int) (255 - obj->data.fsbar.fs->avail * 255 /
-                                                       obj->data.fs->size));
+#ifdef X11
+                                               if(output_methods & TO_X) {
+                                                       new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h,
+                                                               (int) (255 - obj->data.fsbar.fs->avail * 255 /
+                                                               obj->data.fs->size));
+                                               }else{
+#endif /* X11 */
+                                                       if(!obj->data.fsbar.w) obj->data.fsbar.w = DEFAULT_BAR_WIDTH_NO_X;
+                                                       new_bar_in_shell(p, p_max_size,
+                                                               (int) (100 - obj->data.fsbar.fs->avail * 100 / obj->data.fs->size), obj->data.fsbar.w);
+#ifdef X11
+                                               }
+#endif /* X11 */
                                        }
                                }
                        }
-#endif
                        OBJ(fs_free) {
                                if (obj->data.fs != NULL) {
-                                       human_readable( (obj->data.fs->free ? obj->data.fs->free :
-                                                               obj->data.fs->avail), p, 255);
+                                       human_readable(obj->data.fs->avail, p, 255);
                                }
                        }
                        OBJ(fs_free_perc) {
@@ -4133,9 +4446,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                        int val = 0;
 
                                        if (obj->data.fs->size) {
-                                               val = (obj->data.fs->free ? obj->data.fs->free :
-                                                               obj->data.fs->avail) * 100 /
-                                                       obj->data.fs->size;
+                                               val = obj->data.fs->avail * 100 / obj->data.fs->size;
                                        }
 
                                        percent_print(p, p_max_size, val);
@@ -4152,30 +4463,47 @@ static void generate_text_internal(char *p, int p_max_size,
                        }
                        OBJ(fs_used) {
                                if (obj->data.fs != NULL) {
-                                       human_readable(obj->data.fs->size - (obj->data.fs->free
-                                               ? obj->data.fs->free : obj->data.fs->avail), p, 255);
+                                       human_readable(obj->data.fs->size - obj->data.fs->free, p,
+                                                       255);
                                }
                        }
-#ifdef X11
                        OBJ(fs_bar_free) {
                                if (obj->data.fs != NULL) {
                                        if (obj->data.fs->size == 0) {
-                                               new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h, 255);
+#ifdef X11
+                                               if(output_methods & TO_X) {
+                                                       new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h, 255);
+                                               }else{
+#endif /* X11 */
+                                                       if(!obj->data.fsbar.w) obj->data.fsbar.w = DEFAULT_BAR_WIDTH_NO_X;
+                                                       new_bar_in_shell(p, p_max_size, 100, obj->data.fsbar.w);
+#ifdef X11
+                                               }
+#endif /* X11 */
                                        } else {
-                                               new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h,
-                                                       (int) (obj->data.fsbar.fs->avail * 255 /
-                                                       obj->data.fs->size));
+#ifdef X11
+                                               if(output_methods & TO_X) {
+                                                       new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h,
+                                                               (int) (obj->data.fsbar.fs->avail * 255 /
+                                                               obj->data.fs->size));
+                                               }else{
+#endif /* X11 */
+                                                       if(!obj->data.fsbar.w) obj->data.fsbar.w = DEFAULT_BAR_WIDTH_NO_X;
+                                                       new_bar_in_shell(p, p_max_size,
+                                                               (int) (obj->data.fsbar.fs->avail * 100 / obj->data.fs->size), obj->data.fsbar.w);
+#ifdef X11
+                                               }
+#endif /* X11 */
                                        }
                                }
                        }
-#endif
                        OBJ(fs_used_perc) {
                                if (obj->data.fs != NULL) {
                                        int val = 0;
 
                                        if (obj->data.fs->size) {
-                                               val = (obj->data.fs->free ? obj->data.fs->free :
-                                                               obj->data.fs->avail) * 100 /
+                                               val = obj->data.fs->free
+                                                               * 100 /
                                                        obj->data.fs->size;
                                        }
 
@@ -4296,6 +4624,91 @@ static void generate_text_internal(char *p, int p_max_size,
                                }
                        }
 #endif
+#ifdef WEATHER
+                       OBJ(weather) {
+                               PWEATHER *data = get_weather_info(obj->data.weather.uri, obj->data.weather.delay);
+
+                               static const char *wc[18] =
+                               {"", "drizzle", "rain", "hail", "soft hail",
+                                       "snow", "snow grains", "fog", "haze", "smoke",
+                                       "mist", "dust", "sand", "funnel cloud tornado",
+                                       "dust/sand", "squall", "sand storm", "dust storm"};
+
+
+                               if (data == NULL) {
+                                       strncpy(p, "Error reading weather data", p_max_size);
+                               } else {
+                                       if (strcmp(obj->data.weather.data_type, "last_update") == EQUAL) {
+                                               strncpy(p, data->lastupd, p_max_size);
+                                       } else if (strcmp(obj->data.weather.data_type, "temperature_C") == EQUAL) {
+                                               snprintf(p, p_max_size, "%d", data->tmpC);
+                                       } else if (strcmp(obj->data.weather.data_type, "temperature_F") == EQUAL) {
+                                               snprintf(p, p_max_size, "%d", data->tmpF);
+                                       } else if (strcmp(obj->data.weather.data_type, "cloud_cover") == EQUAL) {
+                                               if (data->cc == 0) {
+                                                       strncpy(p, "", p_max_size);
+                                               } else if (data->cc < 3) {
+                                                       strncpy(p, "clear", p_max_size);
+                                               } else if (data->cc < 5) {
+                                                       strncpy(p, "partly cloudy", p_max_size);
+                                               } else if (data->cc == 5) {
+                                                       strncpy(p, "cloudy", p_max_size);
+                                               } else if (data->cc == 6) {
+                                                       strncpy(p, "overcast", p_max_size);
+                                               } else if (data->cc == 7) {
+                                                       strncpy(p, "towering cumulus", p_max_size);
+                                               } else  {
+                                                       strncpy(p, "cumulonimbus", p_max_size);
+                                               }
+                                       } else if (strcmp(obj->data.weather.data_type, "pressure") == EQUAL) {
+                                               snprintf(p, p_max_size, "%d", data->bar);
+                                       } else if (strcmp(obj->data.weather.data_type, "wind_speed") == EQUAL) {
+                                               snprintf(p, p_max_size, "%d", data->wind_s);
+                                       } else if (strcmp(obj->data.weather.data_type, "wind_dir") == EQUAL) {
+                                               if ((data->wind_d >= 349) || (data->wind_d < 12)) {
+                                                       strncpy(p, "N", p_max_size);
+                                               } else if (data->wind_d < 33) {
+                                                       strncpy(p, "NNE", p_max_size);
+                                               } else if (data->wind_d < 57) {
+                                                       strncpy(p, "NE", p_max_size);
+                                               } else if (data->wind_d < 79) {
+                                                       strncpy(p, "ENE", p_max_size);
+                                               } else if (data->wind_d < 102) {
+                                                       strncpy(p, "E", p_max_size);
+                                               } else if (data->wind_d < 124) {
+                                                       strncpy(p, "ESE", p_max_size);
+                                               } else if (data->wind_d < 147) {
+                                                       strncpy(p, "SE", p_max_size);
+                                               } else if (data->wind_d < 169) {
+                                                       strncpy(p, "SSE", p_max_size);
+                                               } else if (data->wind_d < 192) {
+                                                       strncpy(p, "S", p_max_size);
+                                               } else if (data->wind_d < 214) {
+                                                       strncpy(p, "SSW", p_max_size);
+                                               } else if (data->wind_d < 237) {
+                                                       strncpy(p, "SW", p_max_size);
+                                               } else if (data->wind_d < 259) {
+                                                       strncpy(p, "WSW", p_max_size);
+                                               } else if (data->wind_d < 282) {
+                                                       strncpy(p, "W", p_max_size);
+                                               } else if (data->wind_d < 304) {
+                                                       strncpy(p, "WNW", p_max_size);
+                                               } else if (data->wind_d < 327) {
+                                                       strncpy(p, "NW", p_max_size);
+                                               } else if (data->wind_d < 349) {
+                                                       strncpy(p, "NNW", p_max_size);
+                                               };
+                                       } else if (strcmp(obj->data.weather.data_type, "wind_dir_DEG") == EQUAL) {
+                                               snprintf(p, p_max_size, "%d", data->wind_d);
+
+                                       } else if (strcmp(obj->data.weather.data_type, "humidity") == EQUAL) {
+                                               snprintf(p, p_max_size, "%d", data->hmid);
+                                       } else if (strcmp(obj->data.weather.data_type, "weather") == EQUAL) {
+                                               strncpy(p, wc[data->wc], p_max_size);
+                                       }
+                               }
+                       }
+#endif
 #ifdef HAVE_LUA
                        OBJ(lua) {
                                char *str = llua_getstring(obj->data.s);
@@ -4307,59 +4720,35 @@ static void generate_text_internal(char *p, int p_max_size,
                        OBJ(lua_parse) {
                                char *str = llua_getstring(obj->data.s);
                                if (str) {
-                                       struct information *tmp_info;
-                                       struct text_object subroot;
-
-                                       tmp_info = malloc(sizeof(struct information));
-                                       memcpy(tmp_info, cur, sizeof(struct information));
-                                       parse_conky_vars(&subroot, str, p, tmp_info);
-
-                                       free_text_objects(&subroot, 1);
-                                       free(tmp_info);
-                                       free(str);
-                               }
-                       }
-                       OBJ(lua_read_parse) {
-                               struct information *tmp_info;
-                               struct text_object subroot, subroot2;
-                               char func[64];
-                               char *text, *str;
-                               sscanf(obj->data.s, "%64s", func);
-                               text = obj->data.s + strlen(func) + 1;
-
-                               tmp_info = malloc(sizeof(struct information));
-                               memcpy(tmp_info, cur, sizeof(struct information));
-                               parse_conky_vars(&subroot, text, p, tmp_info);
-                               DBGP("evaluated '%s' to '%s'", text, p);
-
-                               str = llua_getstring_read(func, p);
-                               if (str) {
-                                       parse_conky_vars(&subroot2, str, p, tmp_info);
-                                       DBGP("evaluated '%s' to '%s'", str, p);
-
-                                       free(str);
-                                       free_text_objects(&subroot2, 1);
+                                       evaluate(str, p);
                                }
-                               free_text_objects(&subroot, 1);
-                               free(tmp_info);
                        }
-#ifdef X11
                        OBJ(lua_bar) {
-                               int per;
-                               if (llua_getinteger(obj->data.s, &per)) {
-                                       new_bar(p, obj->a, obj->b, (per/100.0 * 255));
+                               double per;
+                               if (llua_getnumber(obj->data.s, &per)) {
+#ifdef X11
+                                       if(output_methods & TO_X) {
+                                               new_bar(p, obj->a, obj->b, (per/100.0 * 255));
+                                       } else {
+#endif /* X11 */
+                                               if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
+                                               new_bar_in_shell(p, p_max_size, per, obj->a);
+#ifdef X11
+                                       }
+#endif /* X11 */
                                }
                        }
+#ifdef X11
                        OBJ(lua_graph) {
-                               int per;
-                               if (llua_getinteger(obj->data.s, &per)) {
+                               double per;
+                               if (llua_getnumber(obj->data.s, &per)) {
                                        new_graph(p, obj->a, obj->b, obj->c, obj->d,
-                                                       (per/100.0 * 255), 100, 1, obj->char_a, obj->char_b);
+                                                       per, obj->e, 1, obj->char_a, obj->char_b);
                                }
                        }
                        OBJ(lua_gauge) {
-                               int per;
-                               if (llua_getinteger(obj->data.s, &per)) {
+                               double per;
+                               if (llua_getnumber(obj->data.s, &per)) {
                                        new_gauge(p, obj->a, obj->b, (per/100.0 * 255));
                                }
                        }
@@ -4505,7 +4894,11 @@ static void generate_text_internal(char *p, int p_max_size,
                                }
                        }
                        OBJ(if_running) {
+#ifdef __linux__
+                               if (!get_process_by_name(obj->data.ifblock.s)) {
+#else
                                if ((obj->data.ifblock.s) && system(obj->data.ifblock.s)) {
+#endif
                                        DO_JUMP;
                                }
                        }
@@ -4543,16 +4936,27 @@ static void generate_text_internal(char *p, int p_max_size,
                                new_gauge(p, obj->data.pair.a, obj->data.pair.b,
                                        cur->memmax ? (cur->mem * 255) / (cur->memmax) : 0);
                        }
+#endif /* X11 */
                        OBJ(membar) {
-                               new_bar(p, obj->data.pair.a, obj->data.pair.b,
-                                       cur->memmax ? (cur->mem * 255) / (cur->memmax) : 0);
+#ifdef X11
+                               if(output_methods & TO_X) {
+                                       new_bar(p, obj->data.pair.a, obj->data.pair.b,
+                                               cur->memmax ? (cur->mem * 255) / (cur->memmax) : 0);
+                               }else{
+#endif /* X11 */
+                                       if(!obj->data.pair.a) obj->data.pair.a = DEFAULT_BAR_WIDTH_NO_X;
+                                       new_bar_in_shell(p, p_max_size, cur->memmax ? (cur->mem * 100) / (cur->memmax) : 0, obj->data.pair.a);
+#ifdef X11
+                               }
+#endif /* X11 */
                        }
+#ifdef X11
                        OBJ(memgraph) {
                                new_graph(p, obj->a, obj->b, obj->c, obj->d,
                                        cur->memmax ? (cur->mem * 100.0) / (cur->memmax) : 0.0,
                                        100, 1, obj->char_a, obj->char_b);
                        }
-#endif
+#endif /* X11 */
                        /* mixer stuff */
                        OBJ(mixer) {
                                percent_print(p, p_max_size, mixer_get_avg(obj->data.l));
@@ -4576,7 +4980,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                new_bar(p, obj->data.mixerbar.w, obj->data.mixerbar.h,
                                        mixer_to_255(obj->data.mixerbar.l,mixer_get_right(obj->data.mixerbar.l)));
                        }
-#endif
+#endif /* X11 */
                        OBJ(if_mixer_mute) {
                                if (!mixer_is_mute(obj->data.ifblock.i)) {
                                        DO_JUMP;
@@ -4589,7 +4993,7 @@ static void generate_text_internal(char *p, int p_max_size,
                        OBJ(monitor_number) {
                                snprintf(p, p_max_size, "%d", cur->x11.monitor.number);
                        }
-#endif
+#endif /* X11 */
 
                        /* mail stuff */
                        OBJ(mails) {
@@ -4678,10 +5082,13 @@ static void generate_text_internal(char *p, int p_max_size,
                        OBJ(stippled_hr) {
                                new_stippled_hr(p, obj->data.pair.a, obj->data.pair.b);
                        }
-#endif
+#endif /* X11 */
                        OBJ(swap) {
                                human_readable(cur->swap * 1024, p, 255);
                        }
+                       OBJ(swapfree) {
+                               human_readable(cur->swapfree * 1024, p, 255);
+                       }
                        OBJ(swapmax) {
                                human_readable(cur->swapmax * 1024, p, 255);
                        }
@@ -4692,12 +5099,19 @@ static void generate_text_internal(char *p, int p_max_size,
                                        percent_print(p, p_max_size, cur->swap * 100 / cur->swapmax);
                                }
                        }
-#ifdef X11
                        OBJ(swapbar) {
-                               new_bar(p, obj->data.pair.a, obj->data.pair.b,
-                                       cur->swapmax ? (cur->swap * 255) / (cur->swapmax) : 0);
+#ifdef X11
+                               if(output_methods & TO_X) {
+                                       new_bar(p, obj->data.pair.a, obj->data.pair.b,
+                                               cur->swapmax ? (cur->swap * 255) / (cur->swapmax) : 0);
+                               }else{
+#endif /* X11 */
+                                       if(!obj->data.pair.a) obj->data.pair.a = DEFAULT_BAR_WIDTH_NO_X;
+                                       new_bar_in_shell(p, p_max_size, cur->swapmax ? (cur->swap * 100) / (cur->swapmax) : 0, obj->data.pair.a);
+#ifdef X11
+                               }
+#endif /* X11 */
                        }
-#endif
                        OBJ(sysname) {
                                snprintf(p, p_max_size, "%s", cur->uname_s.sysname);
                        }
@@ -4763,7 +5177,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                new_graph(p, obj->a, obj->b, obj->c, obj->d,
                                        obj->data.net->trans_speed / 1024.0, obj->e, 1, obj->char_a, obj->char_b);
                        }
-#endif
+#endif /* X11 */
                        OBJ(uptime_short) {
                                format_seconds_short(p, p_max_size, (int) cur->uptime);
                        }
@@ -4847,12 +5261,19 @@ static void generate_text_internal(char *p, int p_max_size,
                        OBJ(mpd_percent) {
                                percent_print(p, p_max_size, (int)(mpd_get_info()->progress * 100));
                        }
-#ifdef X11
                        OBJ(mpd_bar) {
-                               new_bar(p, obj->data.pair.a, obj->data.pair.b,
-                                       (int) (mpd_get_info()->progress * 255.0f));
+#ifdef X11
+                               if(output_methods & TO_X) {
+                                       new_bar(p, obj->data.pair.a, obj->data.pair.b,
+                                               (int) (mpd_get_info()->progress * 255.0f));
+                               } else {
+#endif /* X11 */
+                                       if(!obj->data.pair.a) obj->data.pair.a = DEFAULT_BAR_WIDTH_NO_X;
+                                       new_bar_in_shell(p, p_max_size, (int) (mpd_get_info()->progress * 100.0f), obj->data.pair.a);
+#ifdef X11
+                               }
+#endif /* X11 */
                        }
-#endif
                        OBJ(mpd_smart) {
                                struct mpd_s *mpd = mpd_get_info();
                                int len = obj->data.i;
@@ -4883,10 +5304,6 @@ static void generate_text_internal(char *p, int p_max_size,
 #undef mpd_printf
 #endif
 
-#ifdef XMMS2
-    free_xmms2();
-#endif
-
 #ifdef MOC
 #define MOC_PRINT(t, a) \
        snprintf(p, p_max_size, "%s", (moc.t ? moc.t : a))
@@ -4976,10 +5393,12 @@ static void generate_text_internal(char *p, int p_max_size,
                        OBJ(xmms2_percent) {
                                snprintf(p, p_max_size, "%2.0f", cur->xmms2.progress * 100);
                        }
+#ifdef X11
                        OBJ(xmms2_bar) {
                                new_bar(p, obj->data.pair.a, obj->data.pair.b,
                                        (int) (cur->xmms2.progress * 255.0f));
                        }
+#endif /* X11 */
                        OBJ(xmms2_playlist) {
                                snprintf(p, p_max_size, "%s", cur->xmms2.playlist);
                        }
@@ -5000,7 +5419,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                        DO_JUMP;
                                }
                        }
-#endif
+#endif /* XMMS */
 #ifdef AUDACIOUS
                        OBJ(audacious_status) {
                                snprintf(p, p_max_size, "%s",
@@ -5055,6 +5474,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                snprintf(p, p_max_size, "%s",
                                        cur->audacious.items[AUDACIOUS_MAIN_VOLUME]);
                        }
+#ifdef X11
                        OBJ(audacious_bar) {
                                double progress;
 
@@ -5063,7 +5483,8 @@ static void generate_text_internal(char *p, int p_max_size,
                                        atof(cur->audacious.items[AUDACIOUS_LENGTH_SECONDS]);
                                new_bar(p, obj->a, obj->b, (int) (progress * 255.0f));
                        }
-#endif
+#endif /* X11 */
+#endif /* AUDACIOUS */
 
 #ifdef BMPX
                        OBJ(bmpx_title) {
@@ -5084,9 +5505,9 @@ static void generate_text_internal(char *p, int p_max_size,
                        OBJ(bmpx_bitrate) {
                                snprintf(p, p_max_size, "%i", cur->bmpx.bitrate);
                        }
-#endif
-                       /* we have three different types of top (top, top_mem
-                        * and top_time). To avoid having almost-same code three
+#endif /* BMPX */
+                       /* we have four different types of top (top, top_mem,
+                        * top_time and top_io). To avoid having almost-same code four
                         * times, we have this special handler. */
                        break;
                        case OBJ_top:
@@ -5098,6 +5519,11 @@ static void generate_text_internal(char *p, int p_max_size,
                        case OBJ_top_time:
                                parse_top_args("top_time", obj->data.top.s, obj);
                                if (!needed) needed = cur->time;
+#ifdef IOSTATS
+                       case OBJ_top_io:
+                               parse_top_args("top_io", obj->data.top.s, obj);
+                               if (!needed) needed = cur->io;
+#endif
 
                                if (needed[obj->data.top.num]) {
                                        char *timeval;
@@ -5133,6 +5559,20 @@ static void generate_text_internal(char *p, int p_max_size,
                                                        human_readable(needed[obj->data.top.num]->vsize,
                                                                        p, 255);
                                                        break;
+#ifdef IOSTATS
+                                               case TOP_READ_BYTES:
+                                                       human_readable(needed[obj->data.top.num]->read_bytes / update_interval,
+                                                                       p, 255);
+                                                       break;
+                                               case TOP_WRITE_BYTES:
+                                                       human_readable(needed[obj->data.top.num]->write_bytes / update_interval,
+                                                                       p, 255);
+                                                       break;
+                                               case TOP_IO_PERC:
+                                                       snprintf(p, 7, "%6.2f",
+                                                                       needed[obj->data.top.num]->io_perc);
+                                                       break;
+#endif
                                        }
                                }
                        OBJ(tail)
@@ -5195,7 +5635,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                tcp_portmon_action(p, p_max_size,
                                                   &obj->data.tcp_port_monitor);
                        }
-#endif
+#endif /* TCP_PORT_MONITOR */
 
 #ifdef HAVE_ICONV
                        OBJ(iconv_start) {
@@ -5206,23 +5646,35 @@ static void generate_text_internal(char *p, int p_max_size,
                                iconv_converting = 0;
                                iconv_selected = 0;
                        }
-#endif
+#endif /* HAVE_ICONV */
 
                        OBJ(entropy_avail) {
                                snprintf(p, p_max_size, "%d", cur->entropy.entropy_avail);
                        }
+                       OBJ(entropy_perc) {
+                               percent_print(p, p_max_size,
+                                             cur->entropy.entropy_avail *
+                                             100 / cur->entropy.poolsize);
+                       }
                        OBJ(entropy_poolsize) {
                                snprintf(p, p_max_size, "%d", cur->entropy.poolsize);
                        }
-#ifdef X11
                        OBJ(entropy_bar) {
                                double entropy_perc;
 
                                entropy_perc = (double) cur->entropy.entropy_avail /
                                        (double) cur->entropy.poolsize;
-                               new_bar(p, obj->a, obj->b, (int) (entropy_perc * 255.0f));
+#ifdef X11
+                               if(output_methods & TO_X) {
+                                       new_bar(p, obj->a, obj->b, (int) (entropy_perc * 255.0f));
+                               } else {
+#endif /* X11 */
+                                       if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
+                                       new_bar_in_shell(p, p_max_size, (int) (entropy_perc * 100.0f), obj->a);
+#ifdef X11
+                               }
+#endif /* X11 */
                        }
-#endif
 #ifdef IBM
                        OBJ(smapi) {
                                char *s;
@@ -5270,6 +5722,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                } else
                                        ERR("argument to smapi_bat_power must be an integer");
                        }
+#ifdef X11
                        OBJ(smapi_bat_bar) {
                                if(obj->data.i >= 0 && smapi_bat_installed(obj->data.i))
                                        new_bar(p, obj->a, obj->b, (int)
@@ -5277,7 +5730,36 @@ static void generate_text_internal(char *p, int p_max_size,
                                else
                                        new_bar(p, obj->a, obj->b, 0);
                        }
+#endif /* X11 */
 #endif /* IBM */
+                       OBJ(blink) {
+                               //blinking like this can look a bit ugly if the chars in the font don't have the same width
+                               char buf[max_user_text];
+                               unsigned int j;
+
+                               generate_text_internal(buf, max_user_text, *obj->sub, cur);
+                               snprintf(p, p_max_size, "%s", buf);
+                               if(total_updates % 2) {
+                                       for(j=0; p[j] != 0; j++) {
+                                               p[j] = ' ';
+                                       }
+                               }
+                       }
+                       OBJ(to_bytes) {
+                               char buf[max_user_text];
+                               long long bytes;
+                               char unit[16];  //16 because we can also have long names (like mega-bytes)
+
+                               generate_text_internal(buf, max_user_text, *obj->sub, cur);
+                               if(sscanf(buf, "%lli%s", &bytes, unit) == 2 && strlen(unit) < 16){
+                                       if(strncasecmp("b", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes);
+                                       else if(strncasecmp("k", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes * 1024);
+                                       else if(strncasecmp("m", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes * 1024 * 1024);
+                                       else if(strncasecmp("g", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes * 1024 * 1024 * 1024);
+                                       else if(strncasecmp("t", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes * 1024 * 1024 * 1024 * 1024);
+                               }
+                               snprintf(p, p_max_size, "%s", buf);
+                       }
                        OBJ(scroll) {
                                unsigned int j;
                                char *tmp, buf[max_user_text];
@@ -5330,23 +5812,13 @@ static void generate_text_internal(char *p, int p_max_size,
                                struct text_object * objsub = obj->sub;
 
                                p[0]=0;
-                               #ifdef HAVE_OPENMP
-                               #pragma omp parallel for
-                               #endif /* HAVE_OPENMP */
                                for(i=0; i<2; i++) {
                                        nr_rows[i] = 1;
                                        nextstart = 0;
                                        ll_rows[i] = malloc(sizeof(struct llrows));
                                        current[i] = ll_rows[i];
-                                       #ifdef HAVE_OPENMP
-                                       #pragma omp parallel for
-                                       #endif /* HAVE_OPENMP */
                                        for(j=0; j<i; j++) objsub = objsub->sub;
                                        generate_text_internal(buf[i], max_user_text, *objsub, cur);
-                                       /* doesnut work
-                                        * #ifdef HAVE_OPENMP
-                                        * #pragma omp parallel for reduction (+:nr_rows[i])
-                                        * #endif  HAVE_OPENMP */
                                        for(j=0; buf[i][j] != 0; j++) {
                                                if(buf[i][j] == '\t') buf[i][j] = ' ';
                                                if(buf[i][j] == '\n') {
@@ -5441,12 +5913,22 @@ static void generate_text_internal(char *p, int p_max_size,
                                snprintf(p, p_max_size, "%s",
                                                 cur->apcupsd.items[APCUPSD_LOAD]);
                        }
-#ifdef X11
                        OBJ(apcupsd_loadbar) {
                                double progress;
-                               progress =      atof(cur->apcupsd.items[APCUPSD_LOAD]) / 100.0 * 255.0;
-                               new_bar(p, obj->a, obj->b, (int)progress);
+#ifdef X11
+                               if(output_methods & TO_X) {
+                                       progress = atof(cur->apcupsd.items[APCUPSD_LOAD]) / 100.0 * 255.0;
+                                       new_bar(p, obj->a, obj->b, (int) progress);
+                               } else {
+#endif /* X11 */
+                                       progress = atof(cur->apcupsd.items[APCUPSD_LOAD]);
+                                       if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
+                                       new_bar_in_shell(p, p_max_size, (int) progress, obj->a);
+#ifdef X11
+                               }
+#endif /* X11 */
                        }
+#ifdef X11
                        OBJ(apcupsd_loadgraph) {
                                double progress;
                                progress =      atof(cur->apcupsd.items[APCUPSD_LOAD]);
@@ -5459,7 +5941,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                new_gauge(p, obj->a, obj->b,
                                                  (int)progress);
                        }
-#endif
+#endif /* X11 */
                        OBJ(apcupsd_charge) {
                                snprintf(p, p_max_size, "%s",
                                                 cur->apcupsd.items[APCUPSD_CHARGE]);
@@ -5490,7 +5972,11 @@ static void generate_text_internal(char *p, int p_max_size,
                                        && (iconv_cd[iconv_selected - 1] != (iconv_t) (-1))) {
                                int bytes;
                                size_t dummy1, dummy2;
+#ifdef __FreeBSD__
+                               const char *ptr = buff_in;
+#else
                                char *ptr = buff_in;
+#endif
                                char *outptr = p;
 
                                dummy1 = dummy2 = a;
@@ -5517,6 +6003,26 @@ static void generate_text_internal(char *p, int p_max_size,
                }
                obj = obj->next;
        }
+#ifdef X11
+       /* load any new fonts we may have had */
+       if (need_to_load_fonts) {
+               load_fonts();
+       }
+#endif /* X11 */
+}
+
+void evaluate(char *text, char *buffer)
+{
+       struct information *tmp_info;
+       struct text_object subroot;
+
+       tmp_info = malloc(sizeof(struct information));
+       memcpy(tmp_info, &info, sizeof(struct information));
+       parse_conky_vars(&subroot, text, buffer, tmp_info);
+       DBGP("evaluated '%s' to '%s'", text, buffer);
+
+       free_text_objects(&subroot, 1);
+       free(tmp_info);
 }
 
 double current_update_time, next_update_time, last_update_time;
@@ -5706,10 +6212,10 @@ static void update_text_area(void)
        if (own_window && !fixed_pos) {
                x += workarea[0];
                y += workarea[1];
-               text_start_x = border_margin + 1;
-               text_start_y = border_margin + 1;
-               window.x = x - border_margin - 1;
-               window.y = y - border_margin - 1;
+               text_start_x = window.border_inner_margin + window.border_outer_margin + window.border_width;
+               text_start_y = window.border_inner_margin + window.border_outer_margin + window.border_width;
+               window.x = x - window.border_inner_margin - window.border_outer_margin - window.border_width;
+               window.y = y - window.border_inner_margin - window.border_outer_margin - window.border_width;
        } else
 #endif
        {
@@ -5724,6 +6230,10 @@ static void update_text_area(void)
                text_start_x = x;
                text_start_y = y;
        }
+#ifdef HAVE_LUA
+       /* update lua window globals */
+       llua_update_window_table(text_start_x, text_start_y, text_width, text_height);
+#endif /* HAVE_LUA */
 }
 
 /* drawing stuff */
@@ -5917,13 +6427,13 @@ static void draw_line(char *s)
        int cur_y_add = 0;
        int font_h;
        char *tmp_str;
-#endif /* X11 */
 
        if ((output_methods & TO_X) == 0) {
+#endif /* X11 */
                draw_string(s);
                return;
-       }
 #ifdef X11
+       }
        cur_x = text_start_x;
        cur_y += font_ascent();
        font_h = font_height();
@@ -6223,12 +6733,12 @@ static void draw_line(char *s)
 
                                        cur_y -= font_ascent();
                                        selected_font = specials[special_index].font_added;
+                                       set_font();
                                        if (cur_y + font_ascent() < cur_y + old) {
                                                cur_y += old;
                                        } else {
                                                cur_y += font_ascent();
                                        }
-                                       set_font();
                                        font_h = font_height();
                                        break;
                                }
@@ -6278,18 +6788,18 @@ static void draw_line(char *s)
 
                                case ALIGNR:
                                {
-                                       /* TODO: add back in "+ border_margin" to the end of
+                                       /* TODO: add back in "+ window.border_inner_margin" to the end of
                                         * this line? */
                                        int pos_x = text_start_x + text_width -
                                                get_string_width_special(s);
 
                                        /* printf("pos_x %i text_start_x %i text_width %i cur_x %i "
                                                "get_string_width(p) %i gap_x %i "
-                                               "specials[special_index].arg %i border_margin %i "
-                                               "border_width %i\n", pos_x, text_start_x, text_width,
+                                               "specials[special_index].arg %i window.border_inner_margin %i "
+                                               "window.border_width %i\n", pos_x, text_start_x, text_width,
                                                cur_x, get_string_width_special(s), gap_x,
-                                               specials[special_index].arg, border_margin,
-                                               border_width); */
+                                               specials[special_index].arg, window.border_inner_margin,
+                                               window.border_width); */
                                        if (pos_x > specials[special_index].arg && pos_x > cur_x) {
                                                cur_x = pos_x - specials[special_index].arg;
                                        }
@@ -6335,34 +6845,40 @@ static void draw_line(char *s)
 static void draw_text(void)
 {
 #ifdef X11
+#ifdef HAVE_LUA
+       llua_draw_pre_hook();
+#endif /* HAVE_LUA */
        if (output_methods & TO_X) {
                cur_y = text_start_y;
 
                /* draw borders */
-               if (draw_borders && border_width > 0) {
-                       unsigned int b = (border_width + 1) / 2;
-
+               if (draw_borders && window.border_width > 0) {
                        if (stippled_borders) {
                                char ss[2] = { stippled_borders, stippled_borders };
-                               XSetLineAttributes(display, window.gc, border_width, LineOnOffDash,
+                               XSetLineAttributes(display, window.gc, window.border_width, LineOnOffDash,
                                        CapButt, JoinMiter);
                                XSetDashes(display, window.gc, 0, ss, 2);
                        } else {
-                               XSetLineAttributes(display, window.gc, border_width, LineSolid,
+                               XSetLineAttributes(display, window.gc, window.border_width, LineSolid,
                                        CapButt, JoinMiter);
                        }
 
                        XDrawRectangle(display, window.drawable, window.gc,
-                               text_start_x - border_margin + b, text_start_y - border_margin + b,
-                               text_width + border_margin * 2 - 1 - b * 2,
-                               text_height + border_margin * 2 - 1 - b * 2);
+                               text_start_x - window.border_inner_margin - window.border_width,
+                               text_start_y - window.border_inner_margin - window.border_width,
+                               text_width + window.border_inner_margin * 2 + window.border_width * 2,
+                               text_height + window.border_inner_margin * 2 + window.border_width * 2);
                }
 
                /* draw text */
                special_index = 0;
        }
+       setup_fonts();
 #endif /* X11 */
        for_each_line(text_buffer, draw_line);
+#if defined(HAVE_LUA) && defined(X11)
+       llua_draw_post_hook();
+#endif /* HAVE_LUA */
 }
 
 static void draw_stuff(void)
@@ -6447,12 +6963,12 @@ static void clear_text(int exposures)
                return;
        } else
 #endif
-       {
+       if (display && window.window) { // make sure these are !null
                /* there is some extra space for borders and outlines */
-               XClearArea(display, window.window, text_start_x - border_margin - 1,
-                       text_start_y - border_margin - 1,
-                       text_width + border_margin * 2 + 2,
-                       text_height + border_margin * 2 + 2, exposures ? True : 0);
+               XClearArea(display, window.window, text_start_x - window.border_inner_margin - window.border_outer_margin - window.border_width,
+                       text_start_y - window.border_inner_margin - window.border_outer_margin - window.border_width,
+                       text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2,
+                       text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2, exposures ? True : 0);
        }
 }
 #endif /* X11 */
@@ -6479,12 +6995,13 @@ int inotify_fd;
 
 static void main_loop(void)
 {
+       int terminate = 0;
 #ifdef SIGNAL_BLOCKING
        sigset_t newmask, oldmask;
 #endif
        double t;
 #ifdef HAVE_SYS_INOTIFY_H
-       int inotify_config_wd = 0;
+       int inotify_config_wd = -1;
 #define INOTIFY_EVENT_SIZE  (sizeof(struct inotify_event))
 #define INOTIFY_BUF_LEN     (20 * (INOTIFY_EVENT_SIZE + 16))
        char inotify_buff[INOTIFY_BUF_LEN];
@@ -6498,9 +7015,10 @@ static void main_loop(void)
        sigaddset(&newmask, SIGUSR1);
 #endif
 
-       next_update_time = last_update_time = get_time();
+       last_update_time = 0.0;
+       next_update_time = get_time();
        info.looped = 0;
-       while (total_run_times == 0 || info.looped < total_run_times) {
+       while (terminate == 0 && (total_run_times == 0 || info.looped < total_run_times)) {
                info.looped++;
 
 #ifdef SIGNAL_BLOCKING
@@ -6556,23 +7074,63 @@ static void main_loop(void)
                                update_text_area();
 #ifdef OWN_WINDOW
                                if (own_window) {
+                                       int changed = 0;
+
                                        /* resize window if it isn't right size */
                                        if (!fixed_size
-                                               && (text_width + border_margin * 2 + 1 != window.width
-                                               || text_height + border_margin * 2 + 1 != window.height)) {
-                                                       window.width = text_width + border_margin * 2 + 1;
-                                                       window.height = text_height + border_margin * 2 + 1;
+                                               && (text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2 != window.width
+                                               || text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2 != window.height)) {
+                                                       window.width = text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2;
+                                                       window.height = text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2;
                                                        XResizeWindow(display, window.window, window.width,
                                                                window.height);
-                                                       if (own_window) {
-                                                               set_transparent_background(window.window);
-                                                       }
+                                                       set_transparent_background(window.window);
+
+                                                       changed++;
                                        }
 
                                        /* move window if it isn't in right position */
                                        if (!fixed_pos && (window.x != wx || window.y != wy)) {
                                                XMoveWindow(display, window.window, window.x, window.y);
+                                               changed++;
                                        }
+
+                                        /* update struts */
+                                        if (changed && window.type == TYPE_PANEL) {
+                                               int sidenum = -1;
+
+                                                fprintf(stderr, PACKAGE_NAME": defining struts\n");
+                                                fflush(stderr);
+
+                                               switch (text_alignment) {
+                                                       case TOP_LEFT:
+                                                       case TOP_RIGHT:
+                                                       case TOP_MIDDLE:
+                                                       {
+                                                               sidenum = 2;
+                                                               break;
+                                                       }
+                                                       case BOTTOM_LEFT:
+                                                       case BOTTOM_RIGHT:
+                                                       case BOTTOM_MIDDLE:
+                                                       {
+                                                               sidenum = 3;
+                                                               break;
+                                                       }
+                                                       case MIDDLE_LEFT:
+                                                       {
+                                                               sidenum = 0;
+                                                               break;
+                                                       }
+                                                       case MIDDLE_RIGHT:
+                                                       {
+                                                               sidenum = 1;
+                                                               break;
+                                                       }
+                                               }
+
+                                               set_struts(sidenum);
+                                        }
                                }
 #endif
 
@@ -6582,10 +7140,10 @@ static void main_loop(void)
                                if (use_xdbe) {
                                        XRectangle r;
 
-                                       r.x = text_start_x - border_margin;
-                                       r.y = text_start_y - border_margin;
-                                       r.width = text_width + border_margin * 2;
-                                       r.height = text_height + border_margin * 2;
+                                       r.x = text_start_x - window.border_inner_margin - window.border_outer_margin - window.border_width;
+                                       r.y = text_start_y - window.border_inner_margin - window.border_outer_margin - window.border_width;
+                                       r.width = text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2;
+                                       r.height = text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2;
                                        XUnionRectWithRegion(&r, x11_stuff.region, x11_stuff.region);
                                }
 #endif
@@ -6638,8 +7196,8 @@ static void main_loop(void)
                                                                        }
                                                                }
 
-                                                               text_width = window.width - border_margin * 2 - 1;
-                                                               text_height = window.height - border_margin * 2 - 1;
+                                                               text_width = window.width - window.border_inner_margin * 2 - window.border_outer_margin * 2 - window.border_width * 2;
+                                                               text_height = window.height - window.border_inner_margin * 2 - window.border_outer_margin * 2 - window.border_width * 2;
                                                                if (text_width > maximum_width
                                                                                && maximum_width > 0) {
                                                                        text_width = maximum_width;
@@ -6657,7 +7215,6 @@ static void main_loop(void)
                                                                        || ev.xconfigure.y != 0)) {
                                                                fixed_pos = 1;
                                                        } */
-                                                       set_font();
                                                }
                                                break;
 
@@ -6673,6 +7230,8 @@ static void main_loop(void)
                                                                /* forward the click to the desktop window */
                                                                XUngrabPointer(display, ev.xbutton.time);
                                                                ev.xbutton.window = window.desktop;
+                                                               ev.xbutton.x = ev.xbutton.x_root;
+                                                               ev.xbutton.y = ev.xbutton.y_root;
                                                                XSendEvent(display, ev.xbutton.window, False,
                                                                        ButtonPressMask, &ev);
                                                                XSetInputFocus(display, ev.xbutton.window,
@@ -6692,6 +7251,8 @@ static void main_loop(void)
                                                        } else {
                                                                /* forward the release to the desktop window */
                                                                ev.xbutton.window = window.desktop;
+                                                               ev.xbutton.x = ev.xbutton.x_root;
+                                                               ev.xbutton.y = ev.xbutton.y_root;
                                                                XSendEvent(display, ev.xbutton.window, False,
                                                                        ButtonReleaseMask, &ev);
                                                        }
@@ -6730,10 +7291,10 @@ static void main_loop(void)
                                if (use_xdbe) {
                                        XRectangle r;
 
-                                       r.x = text_start_x - border_margin;
-                                       r.y = text_start_y - border_margin;
-                                       r.width = text_width + border_margin * 2;
-                                       r.height = text_height + border_margin * 2;
+                                       r.x = text_start_x - window.border_inner_margin - window.border_outer_margin - window.border_width;
+                                       r.y = text_start_y - window.border_inner_margin - window.border_outer_margin - window.border_width;
+                                       r.width = text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2;
+                                       r.height = text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2;
                                        XUnionRectWithRegion(&r, x11_stuff.region, x11_stuff.region);
                                }
 #endif
@@ -6776,6 +7337,7 @@ static void main_loop(void)
                        case SIGINT:
                        case SIGTERM:
                                ERR("received SIGINT or SIGTERM to terminate. bye!");
+                               terminate = 1;
                                clean_up();
 #ifdef X11
                                if (output_methods & TO_X) {
@@ -6786,6 +7348,9 @@ static void main_loop(void)
                                        XFixesDestroyRegion(display, x11_stuff.region2);
                                        XFixesDestroyRegion(display, x11_stuff.part);
 #endif /* HAVE_XDAMAGE */
+                                       if (disp) {
+                                               free(disp);
+                                       }
                                }
 #endif /* X11 */
                                if(overwrite_file) {
@@ -6796,8 +7361,7 @@ static void main_loop(void)
                                        free(append_file);
                                        append_file = 0;
                                }
-                               return; /* return from main_loop */
-                               /* break; */
+                               break;
                        default:
                                /* Reaching here means someone set a signal
                                 * (SIGXXXX, signal_handler), but didn't write any code
@@ -6810,17 +7374,17 @@ static void main_loop(void)
                                break;
                }
 #ifdef HAVE_SYS_INOTIFY_H
-               if (inotify_fd && !inotify_config_wd) {
+               if (inotify_fd != -1 && inotify_config_wd == -1) {
                        inotify_config_wd = inotify_add_watch(inotify_fd,
                                        current_config,
                                        IN_MODIFY);
                }
-               if (inotify_fd && inotify_config_wd) {
+               if (inotify_fd != -1 && inotify_config_wd != -1) {
                        int len = 0, idx = 0;
                        fd_set descriptors;
                        struct timeval time_to_wait;
 
-                       FD_ZERO (&descriptors);
+                       FD_ZERO(&descriptors);
                        FD_SET(inotify_fd, &descriptors);
 
                        time_to_wait.tv_sec = time_to_wait.tv_usec = 0;
@@ -6858,22 +7422,22 @@ static void main_loop(void)
        }
 
 #ifdef HAVE_SYS_INOTIFY_H
-       if (inotify_fd) {
+       if (inotify_fd != -1) {
                inotify_rm_watch(inotify_fd, inotify_config_wd);
                close(inotify_fd);
                inotify_fd = inotify_config_wd = 0;
        }
 #endif /* HAVE_SYS_INOTIFY_H */
 
-#if defined(X11) && defined(HAVE_XDAMAGE)
+#ifdef X11
        X11_destroy_window();
-#endif /* X11 && HAVE_XDAMAGE */
+#endif /* X11 */
 }
 
 static void load_config_file(const char *);
 static void load_config_file_x11(const char *);
 
-/* reload the config file */
+       /* reload the config file */
 static void reload_config(void)
 {
        timed_thread_destroy_registered_threads();
@@ -6915,7 +7479,9 @@ static void reload_config(void)
                }
 
 #ifdef X11
-               x_initialised = NO;
+               if (output_methods & TO_X) {
+                       X11_initialisation();
+               }
 #endif /* X11 */
                extract_variable_text(global_text);
                free(global_text);
@@ -6935,15 +7501,16 @@ static void reload_config(void)
                }
                text_buffer = malloc(max_user_text);
                memset(text_buffer, 0, max_user_text);
-               update_text();
 #ifdef X11
                X11_create_window();
 #endif /* X11 */
+               update_text();
        }
 }
 
-static void clean_up(void)
+void clean_up(void)
 {
+       int i;
        timed_thread_destroy_registered_threads();
 
        if (info.cpu_usage) {
@@ -6970,12 +7537,18 @@ static void clean_up(void)
                        XFlush(display);
                }
 
-               XFreeGC(display, window.gc);
                free_fonts();
        }
 
 #endif /* X11 */
 
+       for (i = 0; i < MAX_TEMPLATES; i++) {
+               if (template[i]) {
+                       free(template[i]);
+                       template[i] = NULL;
+               }
+       }
+
        free_text_objects(&global_root_object, 0);
        if (tmpstring1) {
                free(tmpstring1);
@@ -7003,13 +7576,14 @@ static void clean_up(void)
 #ifdef RSS
        free_rss_info();
 #endif
+#ifdef WEATHER
+       free_weather_info();
+#endif
 #ifdef HAVE_LUA
        llua_close();
 #endif /* HAVE_LUA */
 
        if (specials) {
-               unsigned int i;
-
                for (i = 0; i < special_count; i++) {
                        if (specials[i].type == GRAPH) {
                                free(specials[i].graph);
@@ -7019,7 +7593,9 @@ static void clean_up(void)
                specials = NULL;
        }
 
+       clear_net_stats();
        clear_diskio_stats();
+       if(global_cpu != NULL) free(global_cpu);
 }
 
 static int string_to_bool(const char *s)
@@ -7100,6 +7676,11 @@ static void set_default_configurations_for_x(void)
 
 static void set_default_configurations(void)
 {
+       int i;
+#ifdef MPD
+       char *mpd_env_host;
+       char *mpd_env_port;
+#endif
        update_uname();
        fork_to_background = 0;
        total_run_times = 0;
@@ -7110,11 +7691,43 @@ static void set_default_configurations(void)
        top_cpu = 0;
        cpu_separate = 0;
        short_units = 0;
+       format_human_readable = 1;
        top_mem = 0;
        top_time = 0;
+#ifdef IOSTATS
+       top_io = 0;
+#endif
 #ifdef MPD
-       mpd_set_host("localhost");
-       mpd_set_port("6600");
+       mpd_env_host = getenv("MPD_HOST");
+       mpd_env_port = getenv("MPD_PORT");
+
+       if (!mpd_env_host || !strlen(mpd_env_host)) {
+               mpd_set_host("localhost");
+       } else {
+               /* MPD_HOST environment variable is set */
+               char *mpd_hostpart = strchr(mpd_env_host, '@');
+               if (!mpd_hostpart) {
+                       mpd_set_host(mpd_env_host);
+               } else {
+                       /* MPD_HOST contains a password */
+                       char mpd_password[mpd_hostpart - mpd_env_host + 1];
+                       snprintf(mpd_password, mpd_hostpart - mpd_env_host + 1, "%s", mpd_env_host);
+
+                       if (!strlen(mpd_hostpart + 1)) {
+                               mpd_set_host("localhost");
+                       } else {
+                               mpd_set_host(mpd_hostpart + 1);
+                       }
+
+                       mpd_set_password(mpd_password, 1);
+               }
+       }
+
+
+       if (!mpd_env_port || mpd_set_port(mpd_env_port)) {
+               /* failed to set port from environment variable */
+               mpd_set_port("6600");
+       }
 #endif
 #ifdef XMMS2
        info.xmms2.artist = NULL;
@@ -7135,16 +7748,6 @@ static void set_default_configurations(void)
 #ifdef X11
        show_graph_scale = 0;
        show_graph_range = 0;
-       template[0] = strdup("");
-       template[1] = strdup("");
-       template[2] = strdup("");
-       template[3] = strdup("");
-       template[4] = strdup("");
-       template[5] = strdup("");
-       template[6] = strdup("");
-       template[7] = strdup("");
-       template[8] = strdup("");
-       template[9] = strdup("");
        draw_shades = 1;
        draw_borders = 0;
        draw_graph_borders = 1;
@@ -7163,13 +7766,20 @@ static void set_default_configurations(void)
        sprintf(window.title, PACKAGE_NAME" (%s)", info.uname_s.nodename);
 #endif
        stippled_borders = 0;
-       border_margin = 3;
-       border_width = 1;
+       window.border_inner_margin = 3;
+       window.border_outer_margin = 1;
+       window.border_width = 1;
        text_alignment = BOTTOM_LEFT;
        info.x11.monitor.number = 1;
        info.x11.monitor.current = 0;
 #endif /* X11 */
 
+       for (i = 0; i < MAX_TEMPLATES; i++) {
+               if (template[i])
+                       free(template[i]);
+               template[i] = strdup("");
+       }
+
        free(current_mail_spool);
        {
                char buf[256];
@@ -7215,6 +7825,36 @@ static _Bool append_works(const char *path)
 }
 
 #ifdef X11
+#ifdef DEBUG
+/* WARNING, this type not in Xlib spec */
+int x11_error_handler(Display *d, XErrorEvent *err)
+       __attribute__((noreturn));
+int x11_error_handler(Display *d, XErrorEvent *err)
+{
+       ERR("X Error: type %i Display %lx XID %li serial %lu error_code %i request_code %i minor_code %i other Display: %lx\n",
+                       err->type,
+                       (long unsigned)err->display,
+                       (long)err->resourceid,
+                       err->serial,
+                       err->error_code,
+                       err->request_code,
+                       err->minor_code,
+                       (long unsigned)d
+                       );
+       abort();
+}
+
+int x11_ioerror_handler(Display *d)
+       __attribute__((noreturn));
+int x11_ioerror_handler(Display *d)
+{
+       ERR("X Error: Display %lx\n",
+                       (long unsigned)d
+                       );
+       abort();
+}
+#endif /* DEBUG */
+
 static void X11_initialisation(void)
 {
        if (x_initialised == YES) return;
@@ -7222,6 +7862,12 @@ static void X11_initialisation(void)
        init_X11(disp);
        set_default_configurations_for_x();
        x_initialised = YES;
+#ifdef DEBUG
+       _Xdebug = 1;
+       /* WARNING, this type not in Xlib spec */
+       XSetErrorHandler(&x11_error_handler);
+       XSetIOErrorHandler(&x11_ioerror_handler);
+#endif /* DEBUG */
 }
 
 static void X11_destroy_window(void)
@@ -7232,11 +7878,14 @@ static void X11_destroy_window(void)
                XDamageDestroy(display, x11_stuff.damage);
                XFixesDestroyRegion(display, x11_stuff.region2);
                XFixesDestroyRegion(display, x11_stuff.part);
-               XDestroyRegion(x11_stuff.region);
+               if (x11_stuff.region) {
+                       XDestroyRegion(x11_stuff.region);
+               }
                x11_stuff.region = NULL;
 #endif /* HAVE_XDAMAGE */
                destroy_window();
        }
+       x_initialised = NO;
 }
 
 static char **xargv = 0;
@@ -7246,16 +7895,16 @@ static void X11_create_window(void)
 {
        if (output_methods & TO_X) {
 #ifdef OWN_WINDOW
-               init_window(own_window, text_width + border_margin * 2 + 1,
-                               text_height + border_margin * 2 + 1, set_transparent, background_colour,
+               init_window(own_window, text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2,
+                               text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2, set_transparent, background_colour,
                                xargv, xargc);
 #else /* OWN_WINDOW */
-               init_window(0, text_width + border_margin * 2 + 1,
-                               text_height + border_margin * 2 + 1, set_transparent, 0,
+               init_window(0, text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2,
+                               text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2, set_transparent, 0,
                                xargv, xargc);
 #endif /* OWN_WINDOW */
 
-               selected_font = 0;
+               setup_fonts();
                load_fonts();
                update_text_area();     /* to position text/window on screen */
 
@@ -7270,7 +7919,6 @@ static void X11_create_window(void)
 
                create_gc();
 
-               set_font();
                draw_stuff();
 
                x11_stuff.region = XCreateRegion();
@@ -7286,6 +7934,10 @@ static void X11_create_window(void)
                selected_font = 0;
                update_text_area();     /* to get initial size of the window */
        }
+#ifdef HAVE_LUA
+       /* setup lua window globals */
+       llua_setup_window_table(text_start_x, text_start_y, text_width, text_height);
+#endif /* HAVE_LUA */
 }
 #endif /* X11 */
 
@@ -7303,9 +7955,7 @@ static FILE *open_config_file(const char *f)
 {
 #ifdef CONFIG_OUTPUT
        if (!strcmp(f, "==builtin==")) {
-#ifdef HAVE_FOPENCOOKIE
-               return fopencookie(NULL, "r", conf_cookie);
-#endif /* HAVE_FOPENCOOKIE */
+               return conf_cookie_open();
        } else
 #endif /* CONFIG_OUTPUT */
                return fopen(f, "r");
@@ -7435,19 +8085,39 @@ static void load_config_file(const char *f)
                        show_graph_range = string_to_bool(value);
                }
                CONF("border_margin") {
+                       ERR("border_margin is deprecated, please use window.border_inner_margin instead");
+                       if (value) {
+                               window.border_inner_margin = strtol(value, 0, 0);
+                               if (window.border_inner_margin < 0) window.border_inner_margin = 0;
+                       } else {
+                               CONF_ERR;
+                       }
+               }
+               CONF("border_inner_margin") {
+                       if (value) {
+                               window.border_inner_margin = strtol(value, 0, 0);
+                               if (window.border_inner_margin < 0) window.border_inner_margin = 0;
+                       } else {
+                               CONF_ERR;
+                       }
+               }
+               CONF("border_outer_margin") {
                        if (value) {
-                               border_margin = strtol(value, 0, 0);
+                               window.border_outer_margin = strtol(value, 0, 0);
+                               if (window.border_outer_margin < 0) window.border_outer_margin = 0;
                        } else {
                                CONF_ERR;
                        }
                }
                CONF("border_width") {
                        if (value) {
-                               border_width = strtol(value, 0, 0);
+                               window.border_width = strtol(value, 0, 0);
+                               if (window.border_width < 0) window.border_width = 0;
                        } else {
                                CONF_ERR;
                        }
                }
+#endif /* X11 */
 #define TEMPLATE_CONF(n) \
                CONF("template"#n) { \
                        if (value) { \
@@ -7467,7 +8137,6 @@ static void load_config_file(const char *f)
                TEMPLATE_CONF(7)
                TEMPLATE_CONF(8)
                TEMPLATE_CONF(9)
-#endif /* X11 */
                CONF("imap") {
                        if (value) {
                                info.mail = parse_mail_args(IMAP_TYPE, value);
@@ -7538,7 +8207,7 @@ static void load_config_file(const char *f)
                }
                CONF("mpd_password") {
                        if (value) {
-                               mpd_set_password(value);
+                               mpd_set_password(value, 0);
                        } else {
                                CONF_ERR;
                        }
@@ -7695,7 +8364,7 @@ static void load_config_file(const char *f)
 #else
                CONF("use_xft") {
                        if (string_to_bool(value)) {
-                               ERR("Xft not enabled");
+                               ERR("Xft not enabled at compile time");
                        }
                }
                CONF("xftfont") {
@@ -7788,6 +8457,9 @@ static void load_config_file(const char *f)
                CONF("short_units") {
                        short_units = string_to_bool(value);
                }
+               CONF("format_human_readable") {
+                       format_human_readable = string_to_bool(value);
+               }
                CONF("pad_percents") {
                        pad_percents = atoi(value);
                }
@@ -7854,9 +8526,11 @@ static void load_config_file(const char *f)
                                        window.type = TYPE_NORMAL;
                                } else if (strncmp(value, "desktop", 7) == EQUAL) {
                                        window.type = TYPE_DESKTOP;
-                               } else if (strncmp(value, "dock", 7) == EQUAL) {
+                               } else if (strncmp(value, "dock", 4) == EQUAL) {
                                        window.type = TYPE_DOCK;
                                        text_alignment = TOP_LEFT;
+                               } else if (strncmp(value, "panel", 5) == EQUAL) {
+                                       window.type = TYPE_PANEL;
                                } else if (strncmp(value, "override", 8) == EQUAL) {
                                        window.type = TYPE_OVERRIDE;
                                } else {
@@ -7880,6 +8554,11 @@ static void load_config_file(const char *f)
                                cimlib_set_cache_size(atoi(value));
                        }
                }
+               CONF("imlib_cache_flush_interval") {
+                       if (value) {
+                               cimlib_set_cache_flush_interval(atoi(value));
+                       }
+               }
 #endif /* IMLIB2 */
 #endif /* X11 */
                CONF("update_interval") {
@@ -7930,7 +8609,7 @@ static void load_config_file(const char *f)
                }
                CONF("text") {
 #ifdef X11
-                       if(output_methods & TO_X) {
+                       if (output_methods & TO_X) {
                                X11_initialisation();
                        }
 #endif
@@ -8042,10 +8721,9 @@ static void load_config_file(const char *f)
                }
 #ifdef HAVE_LUA
                CONF("lua_load") {
-                       llua_init();
-                       if(value) {
+                       if (value) {
                                char *ptr = strtok(value, " ");
-                               while(ptr) {
+                               while (ptr) {
                                        llua_load(ptr);
                                        ptr = strtok(NULL, " ");
                                }
@@ -8053,6 +8731,22 @@ static void load_config_file(const char *f)
                                CONF_ERR;
                        }
                }
+#ifdef X11
+               CONF("lua_draw_hook_pre") {
+                       if (value) {
+                               llua_set_draw_pre_hook(value);
+                       } else {
+                               CONF_ERR;
+                       }
+               }
+               CONF("lua_draw_hook_post") {
+                       if (value) {
+                               llua_set_draw_post_hook(value);
+                       } else {
+                               CONF_ERR;
+                       }
+               }
+#endif /* X11 */
 #endif /* HAVE_LUA */
 
                CONF("color0"){}
@@ -8278,7 +8972,7 @@ static void print_help(const char *prog_name) {
                        "file.\n"
                        "   -v, --version             version\n"
                        "   -q, --quiet               quiet mode\n"
-                       "   -D, --debug               increase debugging output\n"
+                       "   -D, --debug               increase debugging output, ie. -DD for more debugging\n"
                        "   -c, --config=FILE         config file to load\n"
 #ifdef CONFIG_OUTPUT
                        "   -C, --print-config        print the builtin default config to stdout\n"
@@ -8358,7 +9052,10 @@ int main(int argc, char **argv)
        struct sigaction act, oact;
 
        g_signal_pending = 0;
+       max_user_text = MAX_USER_TEXT_DEFAULT;
+       current_config = 0;
        memset(&info, 0, sizeof(info));
+       memset(template, 0, sizeof(template));
        clear_net_stats();
 
 #ifdef TCP_PORT_MONITOR
@@ -8585,7 +9282,6 @@ int main(int argc, char **argv)
        /* load font */
        if (output_methods & TO_X) {
                load_config_file_x11(current_config);
-               load_fonts();
        }
 #endif /* X11 */