Better argument handling for rss/curl/weather.
[monky] / src / conky.c
index 1f61616..136773c 100644 (file)
@@ -108,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)
@@ -139,30 +137,36 @@ 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;
 
+int argc_copy;
+char** argv_copy;
 
 /* 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 *,
-                                          const char *, char);
+                                          const char *);
 
 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
@@ -204,12 +208,18 @@ static void print_version(void)
 #ifdef TCP_PORT_MONITOR
                   "  * portmon\n"
 #endif /* TCP_PORT_MONITOR */
+#ifdef HAVE_CURL
+                  "  * Curl\n"
+#endif /* HAVE_CURL */
 #ifdef RSS
                   "  * RSS\n"
 #endif /* RSS */
-#ifdef HAVE_LUA
-                  "  * Lua\n"
-#endif /* HAVE_LUA */
+#ifdef WEATHER
+                  "  * Weather (NOAA)\n"
+#ifdef XOAP
+                  "  * Weather (XOAP)\n"
+#endif /* XOAP */
+#endif /* WEATHER */
 #ifdef HAVE_IWLIB
                   "  * wireless\n"
 #endif /* HAVE_IWLIB */
@@ -232,8 +242,21 @@ static void print_version(void)
                   "  * 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);
@@ -244,7 +267,6 @@ static const char *suffixes[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "" };
 
 #ifdef X11
 
-static void X11_destroy_window(void);
 static void X11_create_window(void);
 static void X11_initialisation(void);
 
@@ -284,11 +306,11 @@ 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;
+static unsigned int stuff_in_uppercase;
 
 /* Run how many times? */
 static unsigned long total_run_times;
@@ -302,6 +324,11 @@ static int cpu_avg_samples, net_avg_samples, diskio_avg_samples;
 char *overwrite_file = NULL; FILE *overwrite_fpointer = NULL;
 char *append_file = NULL; FILE *append_fpointer = NULL;
 
+/* xoap suffix for weather from weather.com */
+#ifdef WEATHER
+static char *xoap = NULL;
+#endif /* WEATHER */
+
 #ifdef X11
 
 static int show_graph_scale;
@@ -318,8 +345,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? */
@@ -349,7 +374,7 @@ static long color0, color1, color2, color3, color4, color5, color6, color7,
 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;
@@ -365,11 +390,11 @@ int register_iconv(iconv_t *new_iconv)
 {
        iconv_cd = realloc(iconv_cd, sizeof(iconv_t *) * (iconv_count + 1));
        if (!iconv_cd) {
-               CRIT_ERR("Out of memory");
+               CRIT_ERR(NULL, NULL, "Out of memory");
        }
        iconv_cd[iconv_count] = malloc(sizeof(iconv_t));
        if (!iconv_cd[iconv_count]) {
-               CRIT_ERR("Out of memory");
+               CRIT_ERR(NULL, NULL, "Out of memory");
        }
        memcpy(iconv_cd[iconv_count], new_iconv, sizeof(iconv_t));
        iconv_count++;
@@ -430,11 +455,15 @@ int check_contains(char *f, char *s)
        return ret;
 }
 
+#define SECRIT_MULTILINE_CHAR '\x02'
+
 #ifdef X11
+
 static inline int calc_text_width(const char *s, int l)
 {
-       if ((output_methods & TO_X) == 0)
+       if ((output_methods & TO_X) == 0) {
                return 0;
+       }
 #ifdef XFT
        if (use_xft) {
                XGlyphInfo gi;
@@ -460,27 +489,24 @@ static inline int calc_text_width(const char *s, int l)
 
 static char *text_buffer;
 
-#ifdef X11
-static unsigned int special_index;     /* used when drawing */
-#endif /* X11 */
-
 /* quite boring functions */
 
-static inline void for_each_line(char *b, void f(char *))
+static inline void for_each_line(char *b, int f(char *, int))
 {
        char *ps, *pe;
+       int special_index = 0; /* specials index */
 
        for (ps = b, pe = b; *pe; pe++) {
                if (*pe == '\n') {
                        *pe = '\0';
-                       f(ps);
+                       special_index = f(ps, special_index);
                        *pe = '\n';
                        ps = pe + 1;
                }
        }
 
        if (ps < pe) {
-               f(ps);
+               f(ps, special_index);
        }
 }
 
@@ -885,16 +911,26 @@ static void free_text_objects(struct text_object *root, int internal)
                        case OBJ_eve:
                                break;
 #endif
+#ifdef HAVE_CURL
+                       case OBJ_curl:
+                               free(data.curl.uri);
+                               break;
+#endif
 #ifdef RSS
                        case OBJ_rss:
                                free(data.rss.uri);
                                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:
                        case OBJ_lua_bar:
 #ifdef X11
                        case OBJ_lua_graph:
@@ -927,6 +963,7 @@ static void free_text_objects(struct text_object *root, int internal)
                                free(data.execi.buffer);
                                break;
                        case OBJ_texeci:
+                               if (data.texeci.p_timed_thread) timed_thread_destroy(data.texeci.p_timed_thread, &data.texeci.p_timed_thread);
                                free(data.texeci.cmd);
                                free(data.texeci.buffer);
                                break;
@@ -936,6 +973,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;
@@ -1025,6 +1065,11 @@ static void free_text_objects(struct text_object *root, int internal)
                                free_moc();
                                break;
 #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);
@@ -1057,6 +1102,20 @@ static void free_text_objects(struct text_object *root, int internal)
                        case OBJ_apcupsd_lastxfer:
                                break;
 #endif /* APCUPSD */
+#ifdef X11
+                       case OBJ_desktop:
+                       case OBJ_desktop_number:
+                       case OBJ_desktop_name:
+                               if(info.x11.desktop.name) {
+                                 free(info.x11.desktop.name);
+                                 info.x11.desktop.name = NULL;
+                               }
+                               if(info.x11.desktop.all_names) {
+                                 free(info.x11.desktop.all_names);
+                                 info.x11.desktop.all_names = NULL;
+                               }
+                               break;
+#endif /* X11 */
                }
                free(obj);
        }
@@ -1127,8 +1186,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;
        }
 
@@ -1152,9 +1220,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) {
@@ -1170,9 +1251,11 @@ static int parse_top_args(const char *s, const char *arg, struct text_object *ob
        return 1;
 }
 
+long current_text_color;
+
 /* construct_text_object() creates a new text_object */
 static struct text_object *construct_text_object(const char *s,
-               const char *arg, long line, char allow_threaded, void **ifblock_opaque)
+               const char *arg, long line, void **ifblock_opaque, void *free_at_crash)
 {
        // struct text_object *obj = new_text_object();
        struct text_object *obj = new_text_object_internal();
@@ -1184,8 +1267,6 @@ static struct text_object *construct_text_object(const char *s,
 #define OBJ_IF(a, n) if (strcmp(s, #a) == 0) { \
        obj->type = OBJ_##a; need_mask |= (1ULL << n); \
        obj_be_ifblock_if(ifblock_opaque, obj); {
-#define OBJ_THREAD(a, n) if (strcmp(s, #a) == 0 && allow_threaded) { \
-       obj->type = OBJ_##a; need_mask |= (1ULL << n); {
 #define END } } else
 
 #define SIZE_DEFAULTS(arg) { \
@@ -1239,10 +1320,10 @@ static struct text_object *construct_text_object(const char *s,
                        }
                        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)");
+                               CRIT_ERR(obj, free_at_crash, "read_tcp: Needs \"(host) port\" as argument(s)");
                        }
                }else{
-                       CRIT_ERR("read_tcp: Needs \"(host) port\" as argument(s)");
+                       CRIT_ERR(obj, free_at_crash, "read_tcp: Needs \"(host) port\" as argument(s)");
                }
 #if defined(__linux__)
        END OBJ(voltage_mv, 0)
@@ -1271,76 +1352,76 @@ static struct text_object *construct_text_object(const char *s,
 #ifdef HAVE_IWLIB
        END OBJ(wireless_essid, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(wireless_mode, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(wireless_bitrate, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(wireless_ap, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(wireless_link_qual, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(wireless_link_qual_max, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(wireless_link_qual_perc, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        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);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
 #endif /* HAVE_IWLIB */
@@ -1403,7 +1484,7 @@ static struct text_object *construct_text_object(const char *s,
                if (arg)
                        obj->data.s = strndup(dev_name(arg), text_buffer_size);
                else
-                       CRIT_ERR("disk_protect needs an argument");
+                       CRIT_ERR(obj, free_at_crash, "disk_protect needs an argument");
        END OBJ(i8k_version, INFO_I8K)
        END OBJ(i8k_bios, INFO_I8K)
        END OBJ(i8k_serial, INFO_I8K)
@@ -1418,7 +1499,7 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ(ibm_fan, 0)
        END OBJ(ibm_temps, 0)
                if (!arg) {
-                       CRIT_ERR("ibm_temps: needs an argument");
+                       CRIT_ERR(obj, free_at_crash, "ibm_temps: needs an argument");
                }
                if (!isdigit(arg[0]) || strlen(arg) >= 2 || atoi(&arg[0]) >= 8) {
                        obj->data.sensor = 0;
@@ -1435,7 +1516,7 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ_IF(if_gw, INFO_GW)
        END OBJ(ioscheduler, 0)
                if (!arg) {
-                       CRIT_ERR("get_ioscheduler needs an argument (e.g. hda)");
+                       CRIT_ERR(obj, free_at_crash, "get_ioscheduler needs an argument (e.g. hda)");
                        obj->data.s = 0;
                } else
                        obj->data.s = strndup(dev_name(arg), text_buffer_size);
@@ -1466,7 +1547,7 @@ static struct text_object *construct_text_object(const char *s,
 #if defined(__OpenBSD__)
        END OBJ(obsd_sensors_temp, 0)
                if (!arg) {
-                       CRIT_ERR("obsd_sensors_temp: needs an argument");
+                       CRIT_ERR(obj, free_at_crash, "obsd_sensors_temp: needs an argument");
                }
                if (!isdigit(arg[0]) || atoi(&arg[0]) < 0
                                || atoi(&arg[0]) > OBSD_MAX_SENSORS - 1) {
@@ -1476,7 +1557,7 @@ static struct text_object *construct_text_object(const char *s,
                obj->data.sensor = atoi(&arg[0]);
        END OBJ(obsd_sensors_fan, 0)
                if (!arg) {
-                       CRIT_ERR("obsd_sensors_fan: needs 2 arguments (device and sensor "
+                       CRIT_ERR(obj, free_at_crash, "obsd_sensors_fan: needs 2 arguments (device and sensor "
                                "number)");
                }
                if (!isdigit(arg[0]) || atoi(&arg[0]) < 0
@@ -1487,7 +1568,7 @@ static struct text_object *construct_text_object(const char *s,
                obj->data.sensor = atoi(&arg[0]);
        END OBJ(obsd_sensors_volt, 0)
                if (!arg) {
-                       CRIT_ERR("obsd_sensors_volt: needs 2 arguments (device and sensor "
+                       CRIT_ERR(obj, free_at_crash, "obsd_sensors_volt: needs 2 arguments (device and sensor "
                                "number)");
                }
                if (!isdigit(arg[0]) || atoi(&arg[0]) < 0
@@ -1525,11 +1606,13 @@ static struct text_object *construct_text_object(const char *s,
                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 = 0;
                SIZE_DEFAULTS(graph);
@@ -1558,8 +1641,7 @@ static struct text_object *construct_text_object(const char *s,
                                &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 = 0;
                SIZE_DEFAULTS(graph);
@@ -1567,8 +1649,7 @@ static struct text_object *construct_text_object(const char *s,
                                &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 = 0;
                SIZE_DEFAULTS(graph);
@@ -1576,35 +1657,45 @@ static struct text_object *construct_text_object(const char *s,
                                &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);
 #endif /* X11 */
        END OBJ(color, 0)
 #ifdef X11
                if (output_methods & TO_X) {
                        obj->data.l = arg ? get_x11_color(arg) : default_fg_color;
+                       current_text_color = obj->data.l;
                }
 #endif /* X11 */
        END OBJ(color0, 0)
                obj->data.l = color0;
+               current_text_color = obj->data.l;
        END OBJ(color1, 0)
                obj->data.l = color1;
+               current_text_color = obj->data.l;
        END OBJ(color2, 0)
                obj->data.l = color2;
+               current_text_color = obj->data.l;
        END OBJ(color3, 0)
                obj->data.l = color3;
+               current_text_color = obj->data.l;
        END OBJ(color4, 0)
                obj->data.l = color4;
+               current_text_color = obj->data.l;
        END OBJ(color5, 0)
                obj->data.l = color5;
+               current_text_color = obj->data.l;
        END OBJ(color6, 0)
                obj->data.l = color6;
+               current_text_color = obj->data.l;
        END OBJ(color7, 0)
                obj->data.l = color7;
+               current_text_color = obj->data.l;
        END OBJ(color8, 0)
                obj->data.l = color8;
+               current_text_color = obj->data.l;
        END OBJ(color9, 0)
                obj->data.l = color9;
+               current_text_color = obj->data.l;
 #ifdef X11
        END OBJ(font, 0)
                obj->data.s = scan_font(arg);
@@ -1614,20 +1705,20 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ(conky_build_arch, 0)
        END OBJ(downspeed, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(downspeedf, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
 #ifdef X11
@@ -1639,7 +1730,7 @@ static struct text_object *construct_text_object(const char *s,
 
                // default to DEFAULTNETDEV
                buf = strndup(buf ? buf : DEFAULTNETDEV, text_buffer_size);
-               obj->data.net = get_net_stat(buf);
+               obj->data.net = get_net_stat(buf, obj, free_at_crash);
                free(buf);
 #endif /* X11 */
        END OBJ(else, 0)
@@ -1738,7 +1829,7 @@ static struct text_object *construct_text_object(const char *s,
                        obj->data.execi.cmd = strndup(arg + n, text_buffer_size);
                        obj->data.execi.buffer = malloc(text_buffer_size);
                }
-       END OBJ_THREAD(texeci, 0)
+       END OBJ(texeci, 0)
                        int n;
 
                        if (!arg || sscanf(arg, "%f %n", &obj->data.texeci.interval, &n) <= 0) {
@@ -1952,8 +2043,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)) {
@@ -1961,21 +2052,21 @@ static struct text_object *construct_text_object(const char *s,
                }
        } else OBJ(addr, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
 #if defined(__linux__)
        END OBJ(addrs, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
 #endif /* __linux__ */
@@ -1993,13 +2084,13 @@ static struct text_object *construct_text_object(const char *s,
                if (arg) {
                        obj->data.s = strndup(arg, text_buffer_size);
                }else{
-                       CRIT_ERR("lines needs a argument");
+                       CRIT_ERR(obj, free_at_crash, "lines needs a argument");
                }
        END OBJ(words, 0)
                if (arg) {
                        obj->data.s = strndup(arg, text_buffer_size);
                }else{
-                       CRIT_ERR("words needs a argument");
+                       CRIT_ERR(obj, free_at_crash, "words needs a argument");
                }
        END OBJ(loadavg, INFO_LOADAVG)
                int a = 1, b = 2, c = 3, r = 3;
@@ -2027,7 +2118,7 @@ static struct text_object *construct_text_object(const char *s,
                        obj->data.ifblock.s = strndup(arg, text_buffer_size);
                        obj->sub = malloc(sizeof(struct text_object));
                        extract_variable_text_internal(obj->sub,
-                                                      obj->data.ifblock.s, 0);
+                                                      obj->data.ifblock.s);
                }
        END OBJ_IF(if_match, 0)
                if (!arg) {
@@ -2037,7 +2128,7 @@ static struct text_object *construct_text_object(const char *s,
                        obj->data.ifblock.s = strndup(arg, text_buffer_size);
                        obj->sub = malloc(sizeof(struct text_object));
                        extract_variable_text_internal(obj->sub,
-                                                      obj->data.ifblock.s, 0);
+                                                      obj->data.ifblock.s);
                }
        END OBJ_IF(if_existing, 0)
                if (!arg) {
@@ -2064,12 +2155,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;
@@ -2311,9 +2408,7 @@ static struct text_object *construct_text_object(const char *s,
                buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
                                &obj->e, &obj->char_a, &obj->char_b);
 
-               if (buf) {
-                       free(buf);
-               }
+               if (buf) free(buf);
 #endif /* X11*/
        END OBJ(mixer, INFO_MIXER)
                obj->data.l = mixer_init(arg);
@@ -2340,6 +2435,9 @@ static struct text_object *construct_text_object(const char *s,
 #ifdef X11
        END OBJ(monitor, INFO_X11)
        END OBJ(monitor_number, INFO_X11)
+       END OBJ(desktop, INFO_X11)
+       END OBJ(desktop_number, INFO_X11)
+       END OBJ(desktop_name, INFO_X11)
 #endif
        END OBJ(nodename, 0)
        END OBJ(processes, INFO_PROCS)
@@ -2368,6 +2466,7 @@ 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)
        END OBJ(swapbar, INFO_MEM)
@@ -2398,7 +2497,7 @@ static struct text_object *construct_text_object(const char *s,
 #ifdef HAVE_ICONV
        END OBJ(iconv_start, 0)
                if (iconv_converting) {
-                       CRIT_ERR("You must stop your last iconv conversion before "
+                       CRIT_ERR(obj, free_at_crash, "You must stop your last iconv conversion before "
                                "starting another");
                }
                if (arg) {
@@ -2406,7 +2505,7 @@ static struct text_object *construct_text_object(const char *s,
                        char iconv_to[CODEPAGE_LENGTH];
 
                        if (sscanf(arg, "%s %s", iconv_from, iconv_to) != 2) {
-                               CRIT_ERR("Invalid arguments for iconv_start");
+                               CRIT_ERR(obj, free_at_crash, "Invalid arguments for iconv_start");
                        } else {
                                iconv_t new_iconv;
 
@@ -2419,7 +2518,7 @@ static struct text_object *construct_text_object(const char *s,
                                }
                        }
                } else {
-                       CRIT_ERR("Iconv requires arguments");
+                       CRIT_ERR(obj, free_at_crash, "Iconv requires arguments");
                }
        END OBJ(iconv_stop, 0)
                iconv_converting = 0;
@@ -2427,27 +2526,27 @@ static struct text_object *construct_text_object(const char *s,
 #endif
        END OBJ(totaldown, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(totalup, INFO_NET)
-               obj->data.net = get_net_stat(arg);
+               obj->data.net = get_net_stat(arg, obj, free_at_crash);
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(updates, 0)
        END OBJ_IF(if_updatenr, 0)
                obj->data.ifblock.i = arg ? atoi(arg) : 0;
-               if(obj->data.ifblock.i == 0) CRIT_ERR("if_updatenr needs a number above 0 as argument");
+               if(obj->data.ifblock.i == 0) CRIT_ERR(obj, free_at_crash, "if_updatenr needs a number above 0 as argument");
                updatereset = obj->data.ifblock.i > updatereset ? obj->data.ifblock.i : updatereset;
        END OBJ(alignr, 0)
                obj->data.i = arg ? atoi(arg) : 0;
@@ -2455,20 +2554,20 @@ static struct text_object *construct_text_object(const char *s,
                obj->data.i = arg ? atoi(arg) : 0;
        END OBJ(upspeed, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(upspeedf, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
 
@@ -2481,7 +2580,7 @@ static struct text_object *construct_text_object(const char *s,
 
                // default to DEFAULTNETDEV
                buf = strndup(buf ? buf : DEFAULTNETDEV, text_buffer_size);
-               obj->data.net = get_net_stat(buf);
+               obj->data.net = get_net_stat(buf, obj, free_at_crash);
                free(buf);
 #endif
        END OBJ(uptime_short, INFO_UPTIME)
@@ -2504,7 +2603,7 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ(apm_battery_life, 0)
        END OBJ(apm_battery_time, 0)
 #endif /* __FreeBSD__ */
-       END OBJ_THREAD(imap_unseen, 0)
+       END OBJ(imap_unseen, 0)
                if (arg) {
                        // proccss
                        obj->data.mail = parse_mail_args(IMAP_TYPE, arg);
@@ -2512,7 +2611,7 @@ static struct text_object *construct_text_object(const char *s,
                } else {
                        obj->char_b = 1;
                }
-       END OBJ_THREAD(imap_messages, 0)
+       END OBJ(imap_messages, 0)
                if (arg) {
                        // proccss
                        obj->data.mail = parse_mail_args(IMAP_TYPE, arg);
@@ -2520,7 +2619,7 @@ static struct text_object *construct_text_object(const char *s,
                } else {
                        obj->char_b = 1;
                }
-       END OBJ_THREAD(pop3_unseen, 0)
+       END OBJ(pop3_unseen, 0)
                if (arg) {
                        // proccss
                        obj->data.mail = parse_mail_args(POP3_TYPE, arg);
@@ -2528,7 +2627,7 @@ static struct text_object *construct_text_object(const char *s,
                } else {
                        obj->char_b = 1;
                }
-       END OBJ_THREAD(pop3_used, 0)
+       END OBJ(pop3_used, 0)
                if (arg) {
                        // proccss
                        obj->data.mail = parse_mail_args(POP3_TYPE, arg);
@@ -2673,7 +2772,7 @@ static struct text_object *construct_text_object(const char *s,
                        if (info.audacious.max_title_len > 0) {
                                info.audacious.max_title_len++;
                        } else {
-                               CRIT_ERR("audacious_title: invalid length argument");
+                               CRIT_ERR(obj, free_at_crash, "audacious_title: invalid length argument");
                        }
                }
        END OBJ(audacious_length, INFO_AUDACIOUS)
@@ -2722,49 +2821,122 @@ static struct text_object *construct_text_object(const char *s,
 
                        init_eve();
                } else {
-                       CRIT_ERR("eve needs arguments: <userid> <apikey> <characterid>");
+                       CRIT_ERR(obj, free_at_crash, "eve needs arguments: <userid> <apikey> <characterid>");
+               }
+#endif
+#ifdef HAVE_CURL
+       END OBJ(curl, 0)
+               if (arg) {
+                       int argc;
+                       float interval;
+                       char *uri = (char *) malloc(128 * sizeof(char));
+
+                       argc = sscanf(arg, "%127s %f", uri, &interval);
+                       if (argc == 2) {
+                               obj->data.curl.uri = uri;
+                               obj->data.curl.interval = interval > 0 ? interval * 60 : 15*60;
+                       } else {
+                               ERR("wrong number of arguments for $curl");
+                       }
+               } else {
+                       CRIT_ERR(obj, free_at_crash, "curl needs arguments: <uri> <interval in minutes>");
                }
 #endif
 #ifdef RSS
        END OBJ(rss, 0)
                if (arg) {
-                       int argc, delay, act_par;
+                       float interval;
+                       int argc, act_par;
                        unsigned int nrspaces = 0;
                        char *uri = (char *) malloc(128 * sizeof(char));
                        char *action = (char *) malloc(64 * sizeof(char));
 
-                       argc = sscanf(arg, "%127s %d %63s %d %u", uri, &delay, action,
+                       argc = sscanf(arg, "%127s %f %63s %d %u", uri, &interval, action,
                                        &act_par, &nrspaces);
-                       obj->data.rss.uri = uri;
-                       obj->data.rss.delay = delay;
-                       obj->data.rss.action = action;
-                       obj->data.rss.act_par = act_par;
-                       obj->data.rss.nrspaces = nrspaces;
-
-                       init_rss_info();
+                       if (argc == 5) {
+                               obj->data.rss.uri = uri;
+                               obj->data.rss.interval = interval > 0 ? interval * 60 : 15*60;
+                               obj->data.rss.action = action;
+                               obj->data.rss.act_par = act_par;
+                               obj->data.rss.nrspaces = nrspaces;
+                       } else {
+                               ERR("wrong number of arguments for $rss");
+                       }
                } else {
-                       CRIT_ERR("rss needs arguments: <uri> <delay in minutes> <action> "
+                       CRIT_ERR(obj, free_at_crash, "rss needs arguments: <uri> <interval in minutes> <action> "
                                        "[act_par] [spaces in front]");
                }
 #endif
-#ifdef HAVE_LUA
-       END OBJ(lua, 0)
+#ifdef WEATHER
+       END OBJ(weather, 0)
                if (arg) {
-                       obj->data.s = strndup(arg, text_buffer_size);
+                       int argc;
+                       float interval;
+                       char *locID = (char *) malloc(9 * sizeof(char));
+                       char *uri = (char *) malloc(128 * sizeof(char));
+                       char *data_type = (char *) malloc(32 * sizeof(char));
+                       char *tmp_p;
+
+                       argc = sscanf(arg, "%119s %8s %31s %f", uri, locID, data_type, &interval);
+
+                       if (argc >= 3) {
+                               /* locID MUST BE upper-case */
+                               tmp_p = locID;
+                               while (*tmp_p) {
+                                       *tmp_p = toupper(*tmp_p);
+                                       tmp_p++;
+                               }
+
+                               /* Construct complete uri */
+                               if (strstr(uri, "xoap.weather.com")) {
+                                       if(xoap != NULL) {
+                                               strcat(uri, locID);
+                                               strcat(uri, xoap);
+                                       } else {
+                                               free(uri);
+                                               uri = NULL;
+                                       }
+                               } else if (strstr(uri, "weather.noaa.gov")) {
+                                       strcat(uri, locID);
+                                       strcat(uri, ".TXT");
+                               } else  if (!strstr(uri, "localhost") && !strstr(uri, "127.0.0.1")) {
+                                       CRIT_ERR(obj, free_at_crash, \
+                                                       "could not recognize the weather uri");
+                               }
+
+                               obj->data.weather.uri = uri;
+                               obj->data.weather.data_type = data_type;
+
+                               /* Limit the data retrieval interval to half hour min */
+                               if (interval < 30) {
+                                       interval = 30;
+                               }
+
+                               /* Convert to seconds */
+                               obj->data.weather.interval = interval * 60;
+                               free(locID);
+
+                               DBGP("weather: fetching %s from %s every %d seconds", \
+                                               data_type, uri, obj->data.weather.interval);
+                       } else {
+                               ERR("wrong number of arguments for $weather");
+                       }
                } else {
-                       CRIT_ERR("lua needs arguments: <function name> [function parameters]");
+                       CRIT_ERR(obj, free_at_crash, "weather needs arguments: <uri> <locID> <data_type> [interval in minutes]");
                }
-       END OBJ(lua_parse, 0)
+#endif
+#ifdef HAVE_LUA
+       END OBJ(lua, 0)
                if (arg) {
                        obj->data.s = strndup(arg, text_buffer_size);
                } else {
-                       CRIT_ERR("lua_parse needs arguments: <function name> [function parameters]");
+                       CRIT_ERR(obj, free_at_crash, "lua needs arguments: <function name> [function parameters]");
                }
-       END OBJ(lua_read_parse, 0)
+       END OBJ(lua_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>");
+                       CRIT_ERR(obj, free_at_crash, "lua_parse needs arguments: <function name> [function parameters]");
                }
        END OBJ(lua_bar, 0)
                SIZE_DEFAULTS(bar);
@@ -2773,24 +2945,25 @@ static struct text_object *construct_text_object(const char *s,
                        if(arg) {
                                obj->data.s = strndup(arg, text_buffer_size);
                        } else {
-                               CRIT_ERR("lua_bar needs arguments: <height>,<width> <function name> [function parameters]");
+                               CRIT_ERR(obj, free_at_crash, "lua_bar needs arguments: <height>,<width> <function name> [function parameters]");
                        }
                } else {
-                       CRIT_ERR("lua_bar needs arguments: <height>,<width> <function name> [function parameters]");
+                       CRIT_ERR(obj, free_at_crash, "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(obj, free_at_crash, "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(obj, free_at_crash, "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);
@@ -2799,10 +2972,10 @@ static struct text_object *construct_text_object(const char *s,
                        if (arg) {
                                obj->data.s = strndup(arg, text_buffer_size);
                        } else {
-                               CRIT_ERR("lua_gauge needs arguments: <height>,<width> <function name> [function parameters]");
+                               CRIT_ERR(obj, free_at_crash, "lua_gauge needs arguments: <height>,<width> <function name> [function parameters]");
                        }
                } else {
-                       CRIT_ERR("lua_gauge needs arguments: <height>,<width> <function name> [function parameters]");
+                       CRIT_ERR(obj, free_at_crash, "lua_gauge needs arguments: <height>,<width> <function name> [function parameters]");
                }
 #endif /* X11 */
 #endif /* HAVE_LUA */
@@ -2827,20 +3000,44 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ(entropy_bar, INFO_ENTROPY)
                SIZE_DEFAULTS(bar);
                scan_bar(arg, &obj->a, &obj->b);
+       END OBJ(blink, 0)
+               if(arg) {
+                       obj->sub = malloc(sizeof(struct text_object));
+                       extract_variable_text_internal(obj->sub, arg);
+               }else{
+                       CRIT_ERR(obj, free_at_crash, "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);
+               }else{
+                       CRIT_ERR(obj, free_at_crash, "to_bytes needs a argument");
+               }
        END OBJ(scroll, 0)
-               int n1, n2;
+               int n1 = 0, n2 = 0;
 
+               obj->data.scroll.resetcolor = current_text_color;
                obj->data.scroll.step = 1;
                if (arg && sscanf(arg, "%u %n", &obj->data.scroll.show, &n1) > 0) {
-                       if (sscanf(arg + n1, "%u %n", &obj->data.scroll.step, &n2) > 0)
+                       sscanf(arg + n1, "%u %n", &obj->data.scroll.step, &n2);
+                       if (*(arg + n1 + n2)) {
                                n1 += n2;
-                       obj->data.scroll.text = strndup(arg + n1, text_buffer_size);
+                       } else {
+                               obj->data.scroll.step = 1;
+                       }
+                       obj->data.scroll.text = malloc(strlen(arg + n1) + obj->data.scroll.show + 1);
+                       for(n2 = 0; (unsigned int) n2 < obj->data.scroll.show; n2++) {
+                               obj->data.scroll.text[n2] = ' ';
+                       }
+                       obj->data.scroll.text[n2] = 0;
+                       strcat(obj->data.scroll.text, arg + n1);
                        obj->data.scroll.start = 0;
                        obj->sub = malloc(sizeof(struct text_object));
                        extract_variable_text_internal(obj->sub,
-                                       obj->data.scroll.text, 0);
+                                       obj->data.scroll.text);
                } else {
-                       CRIT_ERR("scroll needs arguments: <length> [<step>] <text>");
+                       CRIT_ERR(obj, free_at_crash, "scroll needs arguments: <length> [<step>] <text>");
                }
        END OBJ(combine, 0)
                if(arg) {
@@ -2882,21 +3079,21 @@ static struct text_object *construct_text_object(const char *s,
                                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);
+                               extract_variable_text_internal(obj->sub, obj->data.combine.left);
                                obj->sub->sub = malloc(sizeof(struct text_object));
-                               extract_variable_text_internal(obj->sub->sub, obj->data.combine.right, 0);
+                               extract_variable_text_internal(obj->sub->sub, obj->data.combine.right);
                        } else {
-                               CRIT_ERR("combine needs arguments: <text1> <text2>");
+                               CRIT_ERR(obj, free_at_crash, "combine needs arguments: <text1> <text2>");
                        }
                } else {
-                       CRIT_ERR("combine needs arguments: <text1> <text2>");
+                       CRIT_ERR(obj, free_at_crash, "combine needs arguments: <text1> <text2>");
                }
 #ifdef NVIDIA
        END OBJ(nvidia, 0)
                if (!arg) {
-                       CRIT_ERR("nvidia needs an argument\n");
+                       CRIT_ERR(obj, free_at_crash, "nvidia needs an argument\n");
                } else if (set_nvidia_type(&obj->data.nvidia, arg)) {
-                       CRIT_ERR("nvidia: invalid argument"
+                       CRIT_ERR(obj, free_at_crash, "nvidia: invalid argument"
                                 " specified: '%s'\n", arg);
                }
 #endif /* NVIDIA */
@@ -2907,13 +3104,13 @@ static struct text_object *construct_text_object(const char *s,
                                char host[64];
                                int port;
                                if (sscanf(arg, "%63s %d", host, &port) != 2) {
-                                       CRIT_ERR("apcupsd needs arguments: <host> <port>");
+                                       CRIT_ERR(obj, free_at_crash, "apcupsd needs arguments: <host> <port>");
                                } else {
                                        info.apcupsd.port = htons(port);
                                        strncpy(info.apcupsd.host, host, sizeof(info.apcupsd.host));
                                }
                        } else {
-                               CRIT_ERR("apcupsd needs arguments: <host> <port>");
+                               CRIT_ERR(obj, free_at_crash, "apcupsd needs arguments: <host> <port>");
                        }
                        END OBJ(apcupsd_name, INFO_APCUPSD)
                        END OBJ(apcupsd_model, INFO_APCUPSD)
@@ -3125,7 +3322,7 @@ static char *find_and_replace_templates(const char *inbuf)
                                *(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");
+                               CRIT_ERR(NULL, NULL, "cannot find a closing '}' in template expansion");
                        }
                } else {
                        templ = p + 1;
@@ -3160,6 +3357,10 @@ 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;
@@ -3172,13 +3373,18 @@ static void strfold(char *start, int count)
 /*
  * - assumes that *string is '#'
  * - removes the part from '#' to the end of line ('\n' or '\0')
- * - BUT, it leaves the '\n'
+ * - 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)
+static size_t remove_comment(char *string, char *last)
 {
        char *end = string;
-       while(*end != '\0' && *end != '\n')
+       while (*end != '\0' && *end != '\n') {
                ++end;
+       }
+       if (last) *last = *end;
+       if (*end == '\n') end++;
        strfold(string, end - string);
        return end - string;
 }
@@ -3193,13 +3399,13 @@ static size_t remove_comments(char *string)
                        strfold(curplace, 1);
                        folded += 1;
                } else if (*curplace == '#') {
-                       folded += remove_comment(curplace);
+                       folded += remove_comment(curplace, 0);
                }
        }
        return folded;
 }
 
-static int extract_variable_text_internal(struct text_object *retval, const char *const_p, char allow_threaded)
+static int extract_variable_text_internal(struct text_object *retval, const char *const_p)
 {
        struct text_object *obj;
        char *p, *s, *orig_p;
@@ -3318,8 +3524,7 @@ static int extract_variable_text_internal(struct text_object *retval, const char
                                }
 
                                obj = construct_text_object(buf, arg,
-                                               line, allow_threaded,
-                                               &ifblock_opaque);
+                                               line, &ifblock_opaque, orig_p);
                                if (obj != NULL) {
                                        append_object(retval, obj);
                                }
@@ -3331,8 +3536,14 @@ 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_comment(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++;
        }
@@ -3365,14 +3576,14 @@ static void extract_variable_text(const char *p)
                text_buffer = 0;
        }
 
-       extract_variable_text_internal(&global_root_object, p, 1);
+       extract_variable_text_internal(&global_root_object, p);
 }
 
-int parse_conky_vars(struct text_object *root, char *txt, char *p, struct information *cur)
+void parse_conky_vars(struct text_object *root, char *txt, char *p, struct information *cur)
 {
-       extract_variable_text_internal(root, txt, 0);
+       extract_variable_text_internal(root, txt);
        generate_text_internal(p, max_user_text, *root, cur);
-       return 0;
+       return;
 }
 
 static inline struct mail_s *ensure_mail_thread(struct text_object *obj,
@@ -3524,6 +3735,22 @@ static inline double get_barnum(char *buf)
        return barnum;
 }
 
+/* substitutes all occurrences of '\n' with SECRIT_MULTILINE_CHAR, which allows
+ * multiline objects like $exec work with $align[rc] and friends
+ */
+void substitute_newlines(char *p, long l)
+{
+       char *s = p;
+       if (l < 0) return;
+       while (p && *p && p < s + l) {
+               if (*p == '\n') {
+                       /* only substitute if it's not the last newline */
+                       *p = SECRIT_MULTILINE_CHAR;
+               }
+               p++;
+       }
+}
+
 static void generate_text_internal(char *p, int p_max_size,
                struct text_object root, struct information *cur)
 {
@@ -3544,7 +3771,7 @@ static void generate_text_internal(char *p, int p_max_size,
        p[0] = 0;
        obj = root.next;
        while (obj && p_max_size > 0) {
-               needed = 0; // reset for top stuff
+               needed = 0; /* reset for top stuff */
 
 /* IFBLOCK jumping algorithm
  *
@@ -3742,7 +3969,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                if (obj->data.cpu_index > info.cpu_count) {
                                        ERR("obj->data.cpu_index %i info.cpu_count %i",
                                                        obj->data.cpu_index, info.cpu_count);
-                                       CRIT_ERR("attempting to use more CPUs than you have!");
+                                       CRIT_ERR(NULL, NULL, "attempting to use more CPUs than you have!");
                                }
                                percent_print(p, p_max_size,
                                              round_to_int(cur->cpu_usage[obj->data.cpu_index] * 100.0));
@@ -4038,14 +4265,13 @@ static void generate_text_internal(char *p, int p_max_size,
                        }
 #if defined(__linux__)
                        OBJ(addrs) {
-                               if(NULL != obj->data.net->addrs && strlen(obj->data.net->addrs) > 2)
-                               {
+                               if (NULL != obj->data.net->addrs && strlen(obj->data.net->addrs) > 2) {
                                        obj->data.net->addrs[strlen(obj->data.net->addrs) - 2] = 0; /* remove ", " from end of string */
                                        strcpy(p, obj->data.net->addrs);
+                               } else {
+                                       strcpy(p, "0.0.0.0");
                                }
-                               else
-                                        strcpy(p, "0.0.0.0");
-           }
+                       }
 #endif /* __linux__ */
 #if defined(IMLIB2) && defined(X11)
                        OBJ(image) {
@@ -4055,18 +4281,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);
@@ -4125,16 +4340,14 @@ 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);
 
@@ -4177,16 +4390,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);
@@ -4261,8 +4472,10 @@ static void generate_text_internal(char *p, int p_max_size,
                                        if (!obj->data.texeci.p_timed_thread) {
                                                ERR("Error creating texeci timed thread");
                                        }
-                                       timed_thread_register(obj->data.texeci.p_timed_thread,
-                                               &obj->data.texeci.p_timed_thread);
+                                       /*
+                                        * note that we don't register this thread with the
+                                        * timed_thread list, because we destroy it manually
+                                        */
                                        if (timed_thread_run(obj->data.texeci.p_timed_thread)) {
                                                ERR("Error running texeci timed thread");
                                        }
@@ -4342,8 +4555,7 @@ static void generate_text_internal(char *p, int p_max_size,
                        }
                        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) {
@@ -4351,9 +4563,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);
@@ -4370,8 +4580,8 @@ 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);
                                }
                        }
                        OBJ(fs_bar_free) {
@@ -4409,8 +4619,8 @@ 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 /
+                                               val = obj->data.fs->free
+                                                               * 100 /
                                                        obj->data.fs->size;
                                        }
 
@@ -4456,78 +4666,30 @@ static void generate_text_internal(char *p, int p_max_size,
                                snprintf(p, p_max_size, "%s", skill);
                        }
 #endif
+#ifdef HAVE_CURL
+                       OBJ(curl) {
+                               if (obj->data.curl.uri != NULL) {
+                                       ccurl_process_info(p, p_max_size, obj->data.curl.uri, obj->data.curl.interval);
+                               } else {
+                                       ERR("error processing Curl data");
+                               }
+                       }
+#endif
 #ifdef RSS
                        OBJ(rss) {
-                               PRSS *data = get_rss_info(obj->data.rss.uri,
-                                       obj->data.rss.delay);
-                               char *str;
-
-                               if (data == NULL) {
-                                       snprintf(p, p_max_size, "prss: Error reading RSS data\n");
+                               if (obj->data.rss.uri != NULL) {
+                                       rss_process_info(p, p_max_size, obj->data.rss.uri, obj->data.rss.action, obj->data.rss.act_par, obj->data.rss.interval, obj->data.rss.nrspaces);
                                } else {
-                                       if (strcmp(obj->data.rss.action, "feed_title") == EQUAL) {
-                                               str = data->title;
-                                               // remove trailing new line if one exists
-                                               if (str[strlen(str) - 1] == '\n') {
-                                                       str[strlen(str) - 1] = 0;
-                                               }
-                                               snprintf(p, p_max_size, "%s", str);
-                                       } else if (strcmp(obj->data.rss.action, "item_title") == EQUAL) {
-                                               if (obj->data.rss.act_par < data->item_count) {
-                                                       str = data->items[obj->data.rss.act_par].title;
-                                                       // remove trailing new line if one exists
-                                                       if (str[strlen(str) - 1] == '\n') {
-                                                               str[strlen(str) - 1] = 0;
-                                                       }
-                                                       snprintf(p, p_max_size, "%s", str);
-                                               }
-                                       } else if (strcmp(obj->data.rss.action, "item_desc") == EQUAL) {
-                                               if (obj->data.rss.act_par < data->item_count) {
-                                                       str =
-                                                               data->items[obj->data.rss.act_par].description;
-                                                       // remove trailing new line if one exists
-                                                       if (str[strlen(str) - 1] == '\n') {
-                                                               str[strlen(str) - 1] = 0;
-                                                       }
-                                                       snprintf(p, p_max_size, "%s", str);
-                                               }
-                                       } else if (strcmp(obj->data.rss.action, "item_titles") == EQUAL) {
-                                               if (data->item_count > 0) {
-                                                       int itmp;
-                                                       int show;
-                                                       //'tmpspaces' is a string with spaces too be placed in front of each title
-                                                       char *tmpspaces = malloc(obj->data.rss.nrspaces + 1);
-                                                       memset(tmpspaces, ' ', obj->data.rss.nrspaces);
-                                                       tmpspaces[obj->data.rss.nrspaces]=0;
-
-                                                       p[0] = 0;
-
-                                                       if (obj->data.rss.act_par > data->item_count) {
-                                                               show = data->item_count;
-                                                       } else {
-                                                               show = obj->data.rss.act_par;
-                                                       }
-                                                       for (itmp = 0; itmp < show; itmp++) {
-                                                               PRSS_Item *item = &data->items[itmp];
-
-                                                               str = item->title;
-                                                               if (str) {
-                                                                       // don't add new line before first item
-                                                                       if (itmp > 0) {
-                                                                               strncat(p, "\n", p_max_size);
-                                                                       }
-                                                                       /* remove trailing new line if one exists,
-                                                                        * we have our own */
-                                                                       if (str[strlen(str) - 1] == '\n') {
-                                                                               str[strlen(str) - 1] = 0;
-                                                                       }
-                                                                       strncat(p, tmpspaces, p_max_size);
-                                                                       strncat(p, str, p_max_size);
-                                                               }
-                                                       }
-                                                       free(tmpspaces);
-                                               }
-                                       }
+                                       ERR("error processing RSS data");
+                               }
+                       }
+#endif
+#ifdef WEATHER
+                       OBJ(weather) {
+                               if (obj->data.weather.uri != NULL) {
+                                       weather_process_info(p, p_max_size, obj->data.weather.uri, obj->data.weather.data_type, obj->data.weather.interval);
+                               } else {
+                                       ERR("error processing weather data, check that you have a valid XOAP key if using XOAP.");
                                }
                        }
 #endif
@@ -4542,41 +4704,9 @@ 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);
-
+                                       evaluate(str, p);
                                        free(str);
-                                       free_text_objects(&subroot2, 1);
                                }
-                               free_text_objects(&subroot, 1);
-                               free(tmp_info);
                        }
                        OBJ(lua_bar) {
                                double per;
@@ -4749,7 +4879,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;
                                }
                        }
@@ -4838,11 +4972,41 @@ static void generate_text_internal(char *p, int p_max_size,
                                }
                        }
 #ifdef X11
+#define NOT_IN_X "Not running in X"
                        OBJ(monitor) {
-                               snprintf(p, p_max_size, "%d", cur->x11.monitor.current);
+                               if(x_initialised != YES) {
+                                       strncpy(p, NOT_IN_X, p_max_size);
+                               }else{
+                                       snprintf(p, p_max_size, "%d", cur->x11.monitor.current);
+                               }
                        }
                        OBJ(monitor_number) {
-                               snprintf(p, p_max_size, "%d", cur->x11.monitor.number);
+                               if(x_initialised != YES) {
+                                       strncpy(p, NOT_IN_X, p_max_size);
+                               }else{
+                                       snprintf(p, p_max_size, "%d", cur->x11.monitor.number);
+                               }
+                       }
+                       OBJ(desktop) {
+                               if(x_initialised != YES) {
+                                       strncpy(p, NOT_IN_X, p_max_size);
+                               }else{
+                                       snprintf(p, p_max_size, "%d", cur->x11.desktop.current);
+                               }
+                       }
+                       OBJ(desktop_number) {
+                               if(x_initialised != YES) {
+                                       strncpy(p, NOT_IN_X, p_max_size);
+                               }else{
+                                       snprintf(p, p_max_size, "%d", cur->x11.desktop.number);
+                               }
+                       }
+                       OBJ(desktop_name) {
+                               if(x_initialised != YES) {
+                                       strncpy(p, NOT_IN_X, p_max_size);
+                               }else if(cur->x11.desktop.name != NULL) {
+                                       strncpy(p, cur->x11.desktop.name, p_max_size);
+                               }
                        }
 #endif /* X11 */
 
@@ -4937,6 +5101,9 @@ static void generate_text_internal(char *p, int p_max_size,
                        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);
                        }
@@ -5152,10 +5319,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))
@@ -5358,8 +5521,8 @@ static void generate_text_internal(char *p, int p_max_size,
                                snprintf(p, p_max_size, "%i", cur->bmpx.bitrate);
                        }
 #endif /* BMPX */
-                       /* we have three different types of top (top, top_mem
-                        * and top_time). To avoid having almost-same code three
+                       /* 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:
@@ -5371,6 +5534,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;
@@ -5406,6 +5574,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)
@@ -5565,43 +5747,100 @@ static void generate_text_internal(char *p, int p_max_size,
                        }
 #endif /* X11 */
 #endif /* IBM */
-                       OBJ(scroll) {
+                       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;
-                               char *tmp, buf[max_user_text];
-                               generate_text_internal(buf, max_user_text,
-                                                      *obj->sub, cur);
 
-                               if (strlen(buf) <= obj->data.scroll.show) {
-                                       snprintf(p, p_max_size, "%s", buf);
-                                       break;
+                               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] = ' ';
+                                       }
                                }
-#define LINESEPARATOR '|'
-                               //place all the lines behind each other with LINESEPARATOR between them
+                       }
+                       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, colorchanges = 0, frontcolorchanges = 0, visibcolorchanges = 0, strend;
+                               char *pwithcolors;
+                               char buf[max_user_text];
+                               generate_text_internal(buf, max_user_text,
+                                                      *obj->sub, cur);
                                for(j = 0; buf[j] != 0; j++) {
-                                       if(buf[j]=='\n') {
+                                       switch(buf[j]) {
+                                       case '\n':      //place all the lines behind each other with LINESEPARATOR between them
+#define LINESEPARATOR '|'
                                                buf[j]=LINESEPARATOR;
+                                               break;
+                                       case SPECIAL_CHAR:
+                                               colorchanges++;
+                                               break;
                                        }
                                }
-                               //scroll the output obj->data.scroll.start places by copying that many chars from
-                               //the front of the string to tmp, scrolling the rest to the front and placing tmp
-                               //at the back of the string
-                               tmp = calloc(obj->data.scroll.start + 1, sizeof(char));
-                               strncpy(tmp, buf, obj->data.scroll.start); tmp[obj->data.scroll.start] = 0;
-                               for(j = obj->data.scroll.start; buf[j] != 0; j++){
-                                       buf[j - obj->data.scroll.start] = buf[j];
-                               }
-                               strcpy(&buf[j - obj->data.scroll.start], tmp);
-                               free(tmp);
-                               //only show the requested number of chars
-                               if(obj->data.scroll.show < j) {
-                                       buf[obj->data.scroll.show] = 0;
-                               }
-                               //next time, scroll a place more or reset scrolling if we are at the end
+                               //no scrolling necessary if the length of the text to scroll is too short
+                               if (strlen(buf) - colorchanges <= obj->data.scroll.show) {
+                                       snprintf(p, p_max_size, "%s", buf);
+                                       break;
+                               }
+                               //make sure a colorchange at the front is not part of the string we are going to show
+                               while(*(buf + obj->data.scroll.start) == SPECIAL_CHAR) {
+                                       obj->data.scroll.start++;
+                               }
+                               //place all chars that should be visible in p, including colorchanges
+                               for(j=0; j < obj->data.scroll.show + visibcolorchanges; j++) {
+                                       p[j] = *(buf + obj->data.scroll.start + j);
+                                       if(p[j] == SPECIAL_CHAR) {
+                                               visibcolorchanges++;
+                                       }
+                                       //if there is still room fill it with spaces
+                                       if( ! p[j]) break;
+                               }
+                               for(; j < obj->data.scroll.show + visibcolorchanges; j++) {
+                                       p[j] = ' ';
+                               }
+                               p[j] = 0;
+                               //count colorchanges in front of the visible part and place that many colorchanges in front of the visible part
+                               for(j = 0; j < obj->data.scroll.start; j++) {
+                                       if(buf[j] == SPECIAL_CHAR) frontcolorchanges++;
+                               }
+                               pwithcolors=malloc(strlen(p) + 1 + colorchanges - visibcolorchanges);
+                               for(j = 0; j < frontcolorchanges; j++) {
+                                       pwithcolors[j] = SPECIAL_CHAR;
+                               }
+                               pwithcolors[j] = 0;
+                               strcat(pwithcolors,p);
+                               strend = strlen(pwithcolors);
+                               //and place the colorchanges not in front or in the visible part behind the visible part
+                               for(j = 0; j < colorchanges - frontcolorchanges - visibcolorchanges; j++) {
+                                       pwithcolors[strend + j] = SPECIAL_CHAR;
+                               }
+                               pwithcolors[strend + j] = 0;
+                               strcpy(p, pwithcolors);
+                               free(pwithcolors);
+                               //scroll
                                obj->data.scroll.start += obj->data.scroll.step;
-                               if(obj->data.scroll.start >= j){
+                               if(buf[obj->data.scroll.start] == 0){
                                         obj->data.scroll.start = 0;
                                }
-                               snprintf(p, p_max_size, "%s", buf);
+#ifdef X11
+                               //reset color when scroll is finished
+                               new_fg(p + strlen(p), obj->data.scroll.resetcolor);
+#endif
                        }
                        OBJ(combine) {
                                char buf[2][max_user_text];
@@ -5656,12 +5895,12 @@ static void generate_text_internal(char *p, int p_max_size,
                                        }
                                        strcat(p, "\n");
                                        #ifdef HAVE_OPENMP
-                                       #pragma omp parallel for
+                                       #pragma omp parallel for schedule(dynamic,10)
                                        #endif /* HAVE_OPENMP */
                                        for(i=0; i<2; i++) if(current[i]) current[i]=current[i]->next;
                                }
                                #ifdef HAVE_OPENMP
-                               #pragma omp parallel for
+                               #pragma omp parallel for schedule(dynamic,10)
                                #endif /* HAVE_OPENMP */
                                for(i=0; i<2; i++) {
                                        while(ll_rows[i] != NULL) {
@@ -5777,7 +6016,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;
@@ -5799,6 +6042,9 @@ static void generate_text_internal(char *p, int p_max_size,
                                a = outptr - p;
                        }
 #endif /* HAVE_ICONV */
+                       if (obj->type != OBJ_text) {
+                               substitute_newlines(p, a - 2);
+                       }
                        p += a;
                        p_max_size -= a;
                }
@@ -5812,6 +6058,20 @@ static void generate_text_internal(char *p, int p_max_size,
 #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;
 
 static void generate_text(void)
@@ -5835,7 +6095,7 @@ static void generate_text(void)
 
        generate_text_internal(p, max_user_text, global_root_object, cur);
 
-       if (stuff_in_upper_case) {
+       if (stuff_in_uppercase) {
                char *tmp_p;
 
                tmp_p = text_buffer;
@@ -5853,7 +6113,6 @@ static void generate_text(void)
        }
        last_update_time = current_update_time;
        total_updates++;
-       // free(p);
 }
 
 static inline int get_string_width(const char *s)
@@ -5866,18 +6125,16 @@ static inline int get_string_width(const char *s)
        return strlen(s);
 }
 
-static inline int get_string_width_special(char *s)
-{
 #ifdef X11
+static int get_string_width_special(char *s, int special_index)
+{
        char *p, *final;
        int idx = 1;
        int width = 0;
        long i;
 
        if ((output_methods & TO_X) == 0) {
-#endif
                return (s) ? strlen(s) : 0;
-#ifdef X11
        }
 
        if (!s) {
@@ -5900,6 +6157,9 @@ static inline int get_string_width_special(char *s)
                                width += specials[special_index + idx].width;
                        }
                        idx++;
+               } else if (*p == SECRIT_MULTILINE_CHAR) {
+                       *p = 0;
+                       break;
                } else {
                        p++;
                }
@@ -5909,11 +6169,9 @@ static inline int get_string_width_special(char *s)
        }
        free(final);
        return width;
-#endif /* X11 */
 }
 
-#ifdef X11
-static void text_size_updater(char *s);
+static int text_size_updater(char *s, int special_index);
 
 int last_font_height;
 static void update_text_area(void)
@@ -5929,7 +6187,6 @@ static void update_text_area(void)
        {
                text_width = minimum_width;
                text_height = 0;
-               special_index = 0;
                last_font_height = font_height();
                for_each_line(text_buffer, text_size_updater);
                text_width += 1;
@@ -5999,10 +6256,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
        {
@@ -6017,6 +6274,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 */
@@ -6028,13 +6289,13 @@ static int draw_mode;           /* FG, BG or OUTLINE */
 #ifdef X11
 static long current_color;
 
-static void text_size_updater(char *s)
+static int text_size_updater(char *s, int special_index)
 {
        int w = 0;
        char *p;
 
        if ((output_methods & TO_X) == 0)
-               return;
+               return 0;
        /* get string widths and skip specials */
        p = s;
        while (*p) {
@@ -6078,6 +6339,14 @@ static void text_size_updater(char *s)
 
                        special_index++;
                        s = p + 1;
+               } else if (*p == SECRIT_MULTILINE_CHAR) {
+                       int lw;
+                       *p = '\0';
+                       lw = get_string_width(s);
+                       *p = SECRIT_MULTILINE_CHAR;
+                       s = p + 1;
+                       w = lw > w ? lw : w;
+                       text_height += last_font_height;
                }
                p++;
        }
@@ -6091,6 +6360,7 @@ static void text_size_updater(char *s)
 
        text_height += last_font_height;
        last_font_height = font_height();
+       return special_index;
 }
 
 static inline void set_foreground_color(long c)
@@ -6203,36 +6473,39 @@ static void draw_string(const char *s)
        memcpy(tmpstring1, s, text_buffer_size);
 }
 
-static void draw_line(char *s)
-{
 #ifdef X11
-       char *p;
+int draw_each_line_inner(char *s, int special_index, int last_special_applied)
+{
+       int font_h = font_height();
        int cur_y_add = 0;
-       int font_h;
-       char *tmp_str;
+       char *recurse = 0;
+       char *p = s;
+       int last_special_needed = -1;
+       int orig_special_index = special_index;
 
-       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();
 
-       /* find specials and draw stuff */
-       p = s;
        while (*p) {
-               if (*p == SPECIAL_CHAR) {
-                       int w = 0;
-
-                       /* draw string before special */
+               if (*p == SECRIT_MULTILINE_CHAR) {
+                       /* special newline marker for multiline objects */
+                       recurse = p + 1;
                        *p = '\0';
-                       draw_string(s);
-                       *p = SPECIAL_CHAR;
-                       s = p + 1;
+                       break;
+               }
+               if (*p == SPECIAL_CHAR || last_special_applied > -1) {
+                       int w = 0;
 
+                       /* draw string before special, unless we're dealing multiline
+                        * specials */
+                       if (last_special_applied > -1) {
+                               special_index = last_special_applied;
+                       } else {
+                               *p = '\0';
+                               draw_string(s);
+                               *p = SPECIAL_CHAR;
+                               s = p + 1;
+                       }
                        /* draw special */
                        switch (specials[special_index].type) {
                                case HORIZONTAL_LINE:
@@ -6305,8 +6578,10 @@ static void draw_line(char *s)
                                {
                                        int h, by = 0;
                                        unsigned long last_colour = current_color;
+#ifdef MATH
                                        float angle, px, py;
                                        int usage;
+#endif /* MATH */
 
                                        if (cur_x - text_start_x > maximum_width
                                                        && maximum_width > 0) {
@@ -6453,6 +6728,7 @@ static void draw_line(char *s)
                                                char *tmp_hour_str;
                                                char *tmp_min_str;
                                                char *tmp_sec_str;
+                                               char *tmp_str;
                                                unsigned short int timeunits;
                                                if (seconds != 0) {
                                                        timeunits = seconds / 86400; seconds %= 86400;
@@ -6494,6 +6770,7 @@ static void draw_line(char *s)
                                        if (show_graph_scale && (specials[special_index].show_scale == 1)) {
                                                int tmp_x = cur_x;
                                                int tmp_y = cur_y;
+                                               char *tmp_str;
                                                cur_x += font_ascent() / 2;
                                                cur_y += font_h / 2;
                                                tmp_str = (char *)
@@ -6516,6 +6793,7 @@ 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 {
@@ -6544,6 +6822,7 @@ static void draw_line(char *s)
 
                                case OFFSET:
                                        w += specials[special_index].arg;
+                                       last_special_needed = special_index;
                                        break;
 
                                case VOFFSET:
@@ -6554,6 +6833,7 @@ static void draw_line(char *s)
                                        if (specials[special_index].arg >= 0) {
                                                cur_x = (int) specials[special_index].arg;
                                        }
+                                       last_special_needed = special_index;
                                        break;
 
                                case TAB:
@@ -6565,33 +6845,36 @@ static void draw_line(char *s)
                                                step = 10;
                                        }
                                        w = step - (cur_x - text_start_x - start) % step;
+                                       last_special_needed = special_index;
                                        break;
                                }
 
                                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);
+                                               get_string_width_special(s, special_index);
 
                                        /* 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;
                                        }
+                                       last_special_needed = special_index;
                                        break;
                                }
 
                                case ALIGNC:
                                {
-                                       int pos_x = (text_width) / 2 - get_string_width_special(s) /
-                                               2 - (cur_x - text_start_x);
+                                       int pos_x = (text_width) / 2 - get_string_width_special(s,
+                                                       special_index) / 2 - (cur_x -
+                                                               text_start_x);
                                        /* int pos_x = text_start_x + text_width / 2 -
                                                get_string_width_special(s) / 2; */
 
@@ -6603,58 +6886,86 @@ static void draw_line(char *s)
                                        if (pos_x > specials[special_index].arg) {
                                                w = pos_x - specials[special_index].arg;
                                        }
+                                       last_special_needed = special_index;
                                        break;
                                }
                        }
 
                        cur_x += w;
 
-                       special_index++;
+                       if (special_index != last_special_applied) {
+                               special_index++;
+                       } else {
+                               special_index = orig_special_index;
+                               last_special_applied = -1;
+                       }
                }
-
                p++;
        }
 
-       if (cur_y_add > 0) {
-               cur_y += cur_y_add;
-       }
+       cur_y += cur_y_add;
        draw_string(s);
        cur_y += font_descent();
+       if (recurse && *recurse) {
+               special_index = draw_each_line_inner(recurse, special_index, last_special_needed);
+               *(recurse - 1) = SECRIT_MULTILINE_CHAR;
+       }
+       return special_index;
+}
+#endif /* X11 */
+
+static int draw_line(char *s, int special_index)
+{
+#ifdef X11
+       if ((output_methods & TO_X) == 0) {
+#endif /* X11 */
+               draw_string(s);
+               //'special_index - special_index' instead of 0 otherwise gcc complains about not using special_index when build without X11
+               return special_index - special_index;
+#ifdef X11
+       }
 
+       /* find specials and draw stuff */
+       return draw_each_line_inner(s, special_index, -1);
 #endif /* X11 */
 }
 
 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)
@@ -6741,10 +7052,10 @@ static void clear_text(int exposures)
 #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 */
@@ -6777,7 +7088,7 @@ static void main_loop(void)
 #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];
@@ -6800,7 +7111,7 @@ static void main_loop(void)
 #ifdef SIGNAL_BLOCKING
                /* block signals.  we will inspect for pending signals later */
                if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {
-                       CRIT_ERR("unable to sigprocmask()");
+                       CRIT_ERR(NULL, NULL, "unable to sigprocmask()");
                }
 #endif
 
@@ -6850,23 +7161,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
 
@@ -6876,10 +7227,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
@@ -6902,6 +7253,14 @@ static void main_loop(void)
                                                break;
                                        }
 
+                                       case PropertyNotify:
+                                       {
+                                               if ( ev.xproperty.state == PropertyNewValue ) {
+                                                       get_x11_desktop_info( ev.xproperty.display, ev.xproperty.atom );
+                                               }
+                                               break;
+                                       }
+
 #ifdef OWN_WINDOW
                                        case ReparentNotify:
                                                /* set background to ParentRelative for all parents */
@@ -6932,8 +7291,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;
@@ -7027,10 +7386,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
@@ -7060,7 +7419,7 @@ static void main_loop(void)
 #ifdef SIGNAL_BLOCKING
                /* unblock signals of interest and let handler fly */
                if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
-                       CRIT_ERR("unable to sigprocmask()");
+                       CRIT_ERR(NULL, NULL, "unable to sigprocmask()");
                }
 #endif
 
@@ -7074,7 +7433,6 @@ static void main_loop(void)
                        case SIGTERM:
                                ERR("received SIGINT or SIGTERM to terminate. bye!");
                                terminate = 1;
-                               clean_up();
 #ifdef X11
                                if (output_methods & TO_X) {
                                        XDestroyRegion(x11_stuff.region);
@@ -7110,17 +7468,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 && current_config != 0) {
                        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 && current_config != 0) {
                        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;
@@ -7156,97 +7514,41 @@ static void main_loop(void)
 
                g_signal_pending = 0;
        }
+       clean_up(NULL, NULL);
 
 #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 */
-
-#ifdef X11
-       X11_destroy_window();
-#endif /* X11 */
 }
 
 static void load_config_file(const char *);
+#ifdef X11
 static void load_config_file_x11(const char *);
+#endif /* X11 */
+void initialisation(int argc, char** argv);
 
        /* reload the config file */
 static void reload_config(void)
 {
-       timed_thread_destroy_registered_threads();
-
-       if (info.cpu_usage) {
-               free(info.cpu_usage);
-               info.cpu_usage = NULL;
-       }
-
-       if (info.mail) {
-               free(info.mail);
-       }
-
-#ifdef X11
-       free_fonts();
-#endif /* X11 */
-
-#ifdef TCP_PORT_MONITOR
-       tcp_portmon_clear();
-#endif
-
-#ifdef HAVE_LUA
-       llua_close();
-#endif /* HAVE_LUA */
-
-#ifdef X11
-       X11_destroy_window();
-#endif /* X11 */
-
-       if (current_config) {
-               clear_fs_stats();
-               load_config_file(current_config);
-               load_config_file_x11(current_config);
-
-               /* re-init specials array */
-               if ((specials = realloc((void *) specials,
-                               sizeof(struct special_t) * max_specials)) == 0) {
-                       ERR("failed to realloc specials array");
-               }
-
-#ifdef X11
-               if (output_methods & TO_X) {
-                       X11_initialisation();
-               }
-#endif /* X11 */
-               extract_variable_text(global_text);
-               free(global_text);
-               global_text = NULL;
-               if (tmpstring1) {
-                       free(tmpstring1);
-               }
-               tmpstring1 = malloc(text_buffer_size);
-               memset(tmpstring1, 0, text_buffer_size);
-               if (tmpstring2) {
-                       free(tmpstring2);
-               }
-               tmpstring2 = malloc(text_buffer_size);
-               memset(tmpstring2, 0, text_buffer_size);
-               if (text_buffer) {
-                       free(text_buffer);
-               }
-               text_buffer = malloc(max_user_text);
-               memset(text_buffer, 0, max_user_text);
-#ifdef X11
-               X11_create_window();
-#endif /* X11 */
-               update_text();
-       }
+       char *current_config_copy = strdup(current_config);
+       clean_up(NULL, NULL);
+       current_config = current_config_copy;
+       initialisation(argc_copy, argv_copy);
 }
 
-static void clean_up(void)
+void clean_up(void *memtofree1, void* memtofree2)
 {
        int i;
+       if(memtofree1) {
+               free(memtofree1);
+       }
+       if(memtofree2) {
+               free(memtofree2);
+       }
        timed_thread_destroy_registered_threads();
 
        if (info.cpu_usage) {
@@ -7254,27 +7556,28 @@ static void clean_up(void)
                info.cpu_usage = NULL;
        }
 #ifdef X11
-       if (output_methods & TO_X) {
-#ifdef HAVE_XDBE
-               if (use_xdbe) {
-                       XdbeDeallocateBackBufferName(display, window.back_buffer);
+       if (x_initialised == YES) {
+               destroy_window();
+               free_fonts();
+               if(x11_stuff.region) {
+                       XDestroyRegion(x11_stuff.region);
+                       x11_stuff.region = NULL;
                }
-#endif
-#ifdef OWN_WINDOW
-               if (own_window) {
-                       XDestroyWindow(display, window.window);
-                       XClearWindow(display, RootWindow(display, screen));
-                       XFlush(display);
-               } else
-#endif
-               {
-                       XClearWindow(display, RootWindow(display, screen));
-                       clear_text(1);
-                       XFlush(display);
+               XClearWindow(display, RootWindow(display, screen));
+               XCloseDisplay(display);
+               display = NULL;
+               if(info.x11.desktop.all_names) {
+                       free(info.x11.desktop.all_names);
+                       info.x11.desktop.all_names = NULL;
                }
-
-               XFreeGC(display, window.gc);
-               free_fonts();
+               if (info.x11.desktop.name) {
+                       free(info.x11.desktop.name);
+                       info.x11.desktop.name = NULL;
+               }
+               x_initialised = NO;
+       }else{
+               free(fonts);    //in set_default_configurations a font is set but not loaded
+               font_count = -1;
        }
 
 #endif /* X11 */
@@ -7306,12 +7609,19 @@ static void clean_up(void)
        }
 
        free(current_config);
+       current_config = 0;
 
 #ifdef TCP_PORT_MONITOR
        tcp_portmon_clear();
 #endif
+#ifdef HAVE_CURL
+       ccurl_free_info();
+#endif
 #ifdef RSS
-       free_rss_info();
+       rss_free_info();
+#endif
+#ifdef WEATHER
+       weather_free_info();
 #endif
 #ifdef HAVE_LUA
        llua_close();
@@ -7327,7 +7637,12 @@ static void clean_up(void)
                specials = NULL;
        }
 
+       clear_net_stats();
        clear_diskio_stats();
+       if(global_cpu != NULL) {
+               free(global_cpu);
+               global_cpu = NULL;
+       }
 }
 
 static int string_to_bool(const char *s)
@@ -7403,12 +7718,17 @@ static void set_default_configurations_for_x(void)
        color7 = default_fg_color;
        color8 = default_fg_color;
        color9 = default_fg_color;
+       current_text_color = default_fg_color;
 }
 #endif /* X11 */
 
 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;
@@ -7422,9 +7742,40 @@ static void set_default_configurations(void)
        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;
@@ -7463,14 +7814,22 @@ 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;
+       info.x11.desktop.current = 1; 
+       info.x11.desktop.number = 1;
+       info.x11.desktop.nitems = 0;
+       info.x11.desktop.all_names = NULL; 
+       info.x11.desktop.name = NULL; 
 #endif /* X11 */
 
        for (i = 0; i < MAX_TEMPLATES; i++) {
+               if (template[i])
+                       free(template[i]);
                template[i] = strdup("");
        }
 
@@ -7487,7 +7846,7 @@ static void set_default_configurations(void)
        no_buffers = 1;
        update_interval = 3.0;
        info.music_player_interval = 1.0;
-       stuff_in_upper_case = 0;
+       stuff_in_uppercase = 0;
        info.users.number = 1;
 
 #ifdef TCP_PORT_MONITOR
@@ -7564,24 +7923,6 @@ static void X11_initialisation(void)
 #endif /* DEBUG */
 }
 
-static void X11_destroy_window(void)
-{
-       /* this function only exists for the sake of consistency */
-       if (output_methods & TO_X) {
-#ifdef HAVE_XDAMAGE
-               XDamageDestroy(display, x11_stuff.damage);
-               XFixesDestroyRegion(display, x11_stuff.region2);
-               XFixesDestroyRegion(display, x11_stuff.part);
-               if (x11_stuff.region) {
-                       XDestroyRegion(x11_stuff.region);
-               }
-               x11_stuff.region = NULL;
-#endif /* HAVE_XDAMAGE */
-               destroy_window();
-       }
-       x_initialised = NO;
-}
-
 static char **xargv = 0;
 static int xargc = 0;
 
@@ -7589,12 +7930,12 @@ 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 */
 
@@ -7628,6 +7969,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 */
 
@@ -7645,9 +7990,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");
@@ -7728,7 +8071,7 @@ static void load_config_file(const char *f)
                CONF2("out_to_x") {
                        /* don't listen if X is already initialised or
                         * if we already know we don't want it */
-                       if(x_initialised == NO) {
+                       if(x_initialised != YES) {
                                if (string_to_bool(value)) {
                                        output_methods &= TO_X;
                                } else {
@@ -7747,9 +8090,12 @@ static void load_config_file(const char *f)
                        }
                }
                CONF("alignment") {
+#ifdef OWN_WINDOW
                        if (window.type == TYPE_DOCK)
                                ;
-                       else if (value) {
+                       else
+#endif /*OWN_WINDOW */
+                       if (value) {
                                int a = string_to_alignment(value);
 
                                if (a <= 0) {
@@ -7777,15 +8123,34 @@ 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;
                        }
@@ -7880,7 +8245,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;
                        }
@@ -8199,9 +8564,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 {
@@ -8251,7 +8618,7 @@ static void load_config_file(const char *f)
                        }
                }
                CONF("uppercase") {
-                       stuff_in_upper_case = string_to_bool(value);
+                       stuff_in_uppercase = string_to_bool(value);
                }
                CONF("max_specials") {
                        if (value) {
@@ -8327,7 +8694,7 @@ static void load_config_file(const char *f)
                        }
                        fclose(fp);
                        if (strlen(global_text) < 1) {
-                               CRIT_ERR("no text supplied in configuration; exiting");
+                               CRIT_ERR(NULL, NULL, "no text supplied in configuration; exiting");
                        }
                        global_text_lines = line + 1;
                        return;
@@ -8392,10 +8759,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, " ");
                                }
@@ -8403,6 +8769,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"){}
@@ -8432,10 +8814,11 @@ static void load_config_file(const char *f)
                info.music_player_interval = update_interval;
        }
        if (!global_text) { // didn't supply any text
-               CRIT_ERR("missing text block in configuration; exiting");
+               CRIT_ERR(NULL, NULL, "missing text block in configuration; exiting");
        }
 }
 
+#ifdef X11
 static void load_config_file_x11(const char *f)
 {
        int line = 0;
@@ -8456,7 +8839,6 @@ static void load_config_file_x11(const char *f)
                        continue;
                }
 
-#ifdef X11
                CONF2("color0") {
                        X11_initialisation();
                        if (x_initialised == YES) {
@@ -8601,12 +8983,11 @@ static void load_config_file_x11(const char *f)
                }
 #endif
                CONF("text") {
-                       //initialize X11 if nothing X11-related is mentioned before TEXT (and if X11 is the default outputmethod)
+                       /* initialize X11 if nothing X11-related is mentioned before TEXT (and if X11 is the default outputmethod) */
                        if(output_methods & TO_X) {
                                X11_initialisation();
                        }
                }
-#endif /* X11 */
 #undef CONF
 #undef CONF2
 #undef CONF3
@@ -8620,6 +9001,43 @@ static void load_config_file_x11(const char *f)
        fclose(fp);
 
 }
+#endif /* X11 */
+
+#if defined(WEATHER) && defined(XOAP)
+/*
+ * TODO: make the xoap keys file readable from the config file
+ *       make the keys directly readable from the config file
+ *       make the xoap keys file giveable as a command line option
+ */
+static void load_xoap_keys(void)
+{
+  FILE *fp;
+  char *par = (char *) malloc(11 * sizeof(char));
+  char *key = (char *) malloc(17 * sizeof(char));
+
+  xoap = (char *) malloc(64 * sizeof(char));
+  to_real_path(xoap, XOAP_FILE);
+  fp = fopen(xoap, "r");
+  if (fp != NULL) {
+    if( fscanf(fp, "%10s %16s", par, key) == 2 ) {
+      strcpy(xoap, "?cc=*&link=xoap&prod=xoap&par=");
+      strcat(xoap, par);
+      strcat(xoap, "&key=");
+      strcat(xoap, key);
+      strcat(xoap, "&unit=m");
+    } else {
+      free(xoap);
+      xoap = NULL;
+    }
+    fclose(fp);
+  } else {
+    free(xoap);
+    xoap = NULL;
+  }
+  free(par);
+  free(key);
+}
+#endif /* WEATHER && XOAP */
 
 static void print_help(const char *prog_name) {
        printf("Usage: %s [OPTION]...\n"
@@ -8699,130 +9117,9 @@ static const struct option longopts[] = {
        { 0, 0, 0, 0 }
 };
 
-int main(int argc, char **argv)
-{
-#ifdef X11
-       char *s, *temp;
-       unsigned int x;
-#endif
+void initialisation(int argc, char **argv) {
        struct sigaction act, oact;
 
-       g_signal_pending = 0;
-       memset(&info, 0, sizeof(info));
-       clear_net_stats();
-
-#ifdef TCP_PORT_MONITOR
-       /* set default connection limit */
-       tcp_portmon_set_max_connections(0);
-#endif
-
-       /* handle command line parameters that don't change configs */
-#ifdef X11
-       if (((s = getenv("LC_ALL")) && *s) || ((s = getenv("LC_CTYPE")) && *s)
-                       || ((s = getenv("LANG")) && *s)) {
-               temp = (char *) malloc((strlen(s) + 1) * sizeof(char));
-               if (temp == NULL) {
-                       ERR("malloc failed");
-               }
-               for (x = 0; x < strlen(s); x++) {
-                       temp[x] = tolower(s[x]);
-               }
-               temp[x] = 0;
-               if (strstr(temp, "utf-8") || strstr(temp, "utf8")) {
-                       utf8_mode = 1;
-               }
-
-               free(temp);
-       }
-       if (!setlocale(LC_CTYPE, "")) {
-               ERR("Can't set the specified locale!\nCheck LANG, LC_CTYPE, LC_ALL.");
-       }
-#endif /* X11 */
-       while (1) {
-               int c = getopt_long(argc, argv, getopt_string, longopts, NULL);
-
-               if (c == -1) {
-                       break;
-               }
-
-               switch (c) {
-                       case 'v':
-                       case 'V':
-                               print_version();
-                       case 'c':
-                               if (current_config) {
-                                       free(current_config);
-                               }
-                               current_config = strndup(optarg, max_user_text);
-                               break;
-                       case 'q':
-                               freopen("/dev/null", "w", stderr);
-                               break;
-                       case 'h':
-                               print_help(argv[0]);
-                               return 0;
-#ifdef CONFIG_OUTPUT
-                       case 'C':
-                               print_defconfig();
-                               return 0;
-#endif
-#ifdef X11
-                       case 'w':
-                               window.window = strtol(optarg, 0, 0);
-                               break;
-#endif /* X11 */
-
-                       case '?':
-                               exit(EXIT_FAILURE);
-               }
-       }
-
-       /* check if specified config file is valid */
-       if (current_config) {
-               struct stat sb;
-               if (stat(current_config, &sb) ||
-                               (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode))) {
-                       ERR("invalid configuration file '%s'\n", current_config);
-                       free(current_config);
-                       current_config = 0;
-               }
-       }
-
-       /* load current_config, CONFIG_FILE or SYSTEM_CONFIG_FILE */
-
-       if (!current_config) {
-               /* load default config file */
-               char buf[DEFAULT_TEXT_BUFFER_SIZE];
-               FILE *fp;
-
-               /* Try to use personal config file first */
-               to_real_path(buf, CONFIG_FILE);
-               if (buf[0] && (fp = fopen(buf, "r"))) {
-                       current_config = strndup(buf, max_user_text);
-                       fclose(fp);
-               }
-
-               /* Try to use system config file if personal config not readable */
-               if (!current_config && (fp = fopen(SYSTEM_CONFIG_FILE, "r"))) {
-                       current_config = strndup(SYSTEM_CONFIG_FILE, max_user_text);
-                       fclose(fp);
-               }
-
-               /* No readable config found */
-               if (!current_config) {
-#ifdef CONFIG_OUTPUT
-                       current_config = strdup("==builtin==");
-                       ERR("no readable personal or system-wide config file found,"
-                                       " using builtin default");
-#else
-                       CRIT_ERR("no readable personal or system-wide config file found");
-#endif /* ! CONF_OUTPUT */
-               }
-       }
-#ifdef HAVE_SYS_INOTIFY_H
-       inotify_fd = inotify_init();
-#endif /* HAVE_SYS_INOTIFY_H */
-
        load_config_file(current_config);
 
        /* init specials array */
@@ -8854,7 +9151,7 @@ int main(int argc, char **argv)
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
        if ((kd = kvm_open("/dev/null", "/dev/null", "/dev/null", O_RDONLY,
                        "kvm_open")) == NULL) {
-               CRIT_ERR("cannot read kvm");
+               CRIT_ERR(NULL, NULL, "cannot read kvm");
        }
 #endif
 
@@ -8967,7 +9264,7 @@ int main(int argc, char **argv)
                                fprintf(stderr, PACKAGE_NAME": forked to background, pid is %d\n",
                                        pid);
                                fflush(stderr);
-                               return 0;
+                               exit(EXIT_SUCCESS);
                }
        }
 
@@ -8999,6 +9296,144 @@ int main(int argc, char **argv)
                ERR("error setting signal handler: %s", strerror(errno));
        }
 
+}
+
+int main(int argc, char **argv)
+{
+#ifdef X11
+       char *s, *temp;
+       unsigned int x;
+#endif
+
+       argc_copy = argc;
+       argv_copy = argv;
+       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
+       /* set default connection limit */
+       tcp_portmon_set_max_connections(0);
+#endif
+
+       /* handle command line parameters that don't change configs */
+#ifdef X11
+       if (((s = getenv("LC_ALL")) && *s) || ((s = getenv("LC_CTYPE")) && *s)
+                       || ((s = getenv("LANG")) && *s)) {
+               temp = (char *) malloc((strlen(s) + 1) * sizeof(char));
+               if (temp == NULL) {
+                       ERR("malloc failed");
+               }
+               for (x = 0; x < strlen(s); x++) {
+                       temp[x] = tolower(s[x]);
+               }
+               temp[x] = 0;
+               if (strstr(temp, "utf-8") || strstr(temp, "utf8")) {
+                       utf8_mode = 1;
+               }
+
+               free(temp);
+       }
+       if (!setlocale(LC_CTYPE, "")) {
+               ERR("Can't set the specified locale!\nCheck LANG, LC_CTYPE, LC_ALL.");
+       }
+#endif /* X11 */
+       while (1) {
+               int c = getopt_long(argc, argv, getopt_string, longopts, NULL);
+
+               if (c == -1) {
+                       break;
+               }
+
+               switch (c) {
+                       case 'v':
+                       case 'V':
+                               print_version();
+                       case 'c':
+                               if (current_config) {
+                                       free(current_config);
+                               }
+                               current_config = strndup(optarg, max_user_text);
+                               break;
+                       case 'q':
+                               freopen("/dev/null", "w", stderr);
+                               break;
+                       case 'h':
+                               print_help(argv[0]);
+                               return 0;
+#ifdef CONFIG_OUTPUT
+                       case 'C':
+                               print_defconfig();
+                               return 0;
+#endif
+#ifdef X11
+                       case 'w':
+                               window.window = strtol(optarg, 0, 0);
+                               break;
+#endif /* X11 */
+
+                       case '?':
+                               exit(EXIT_FAILURE);
+               }
+       }
+
+       /* check if specified config file is valid */
+       if (current_config) {
+               struct stat sb;
+               if (stat(current_config, &sb) ||
+                               (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode))) {
+                       ERR("invalid configuration file '%s'\n", current_config);
+                       free(current_config);
+                       current_config = 0;
+               }
+       }
+
+       /* load current_config, CONFIG_FILE or SYSTEM_CONFIG_FILE */
+
+       if (!current_config) {
+               /* load default config file */
+               char buf[DEFAULT_TEXT_BUFFER_SIZE];
+               FILE *fp;
+
+               /* Try to use personal config file first */
+               to_real_path(buf, CONFIG_FILE);
+               if (buf[0] && (fp = fopen(buf, "r"))) {
+                       current_config = strndup(buf, max_user_text);
+                       fclose(fp);
+               }
+
+               /* Try to use system config file if personal config not readable */
+               if (!current_config && (fp = fopen(SYSTEM_CONFIG_FILE, "r"))) {
+                       current_config = strndup(SYSTEM_CONFIG_FILE, max_user_text);
+                       fclose(fp);
+               }
+
+               /* No readable config found */
+               if (!current_config) {
+#ifdef CONFIG_OUTPUT
+                       current_config = strdup("==builtin==");
+                       ERR("no readable personal or system-wide config file found,"
+                                       " using builtin default");
+#else
+                       CRIT_ERR(NULL, NULL, "no readable personal or system-wide config file found");
+#endif /* ! CONF_OUTPUT */
+               }
+       }
+
+#if defined(WEATHER) && defined(XOAP)
+       /* Load xoap keys, if existing */
+       load_xoap_keys();
+#endif /* WEATHER && XOAP */
+
+#ifdef HAVE_SYS_INOTIFY_H
+       inotify_fd = inotify_init();
+#endif /* HAVE_SYS_INOTIFY_H */
+
+       initialisation(argc, argv);
+
        main_loop();
 
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
@@ -9015,3 +9450,4 @@ static void signal_handler(int sig)
         * and do any signal processing there, NOT here. */
        g_signal_pending = sig;
 }
+