A whole bunch of changes, mostly Lua related.
[monky] / src / conky.c
index cd21055..3ffb55d 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)
@@ -148,13 +146,13 @@ enum x_initialiser_state x_initialised = NO;
 static volatile int g_signal_pending;
 /* Update interval */
 double update_interval;
+void *global_cpu = NULL;
 
 
 /* prototypes for internally used functions */
 static void signal_handler(int);
 static void print_version(void) __attribute__((noreturn));
 static void reload_config(void);
-static void clean_up(void);
 static void generate_text_internal(char *, int, struct text_object,
                                    struct information *);
 static int extract_variable_text_internal(struct text_object *,
@@ -165,7 +163,8 @@ static void print_version(void)
        printf(PACKAGE_NAME" "VERSION" compiled "BUILD_DATE" for "BUILD_ARCH"\n");
 
        printf("\nCompiled in features:\n\n"
-                  "System config file: "SYSTEM_CONFIG_FILE"\n\n"
+                  "System config file: "SYSTEM_CONFIG_FILE"\n"
+                  "Package library path: "PACKAGE_LIBDIR"\n\n"
 #ifdef X11
                   " X11:\n"
 # ifdef HAVE_XDAMAGE
@@ -210,9 +209,9 @@ static void print_version(void)
 #ifdef RSS
                   "  * RSS\n"
 #endif /* RSS */
-#ifdef HAVE_LUA
-                  "  * Lua\n"
-#endif /* HAVE_LUA */
+#ifdef WEATHER
+                  "  * Weather (METAR)\n"
+#endif /* WEATHER */
 #ifdef HAVE_IWLIB
                   "  * wireless\n"
 #endif /* HAVE_IWLIB */
@@ -240,6 +239,16 @@ static void print_version(void)
 #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);
@@ -290,8 +299,8 @@ static char *disp = NULL;
  * instances of the same text object */
 struct information info;
 
-/* default config file */
-static char *current_config;
+/* path to config file */
+char *current_config;
 
 /* set to 1 if you want all text to be in uppercase */
 static unsigned int stuff_in_upper_case;
@@ -324,8 +333,6 @@ static int stippled_borders;
 
 static int draw_shades, draw_outline;
 
-static long border_inner_margin, border_outer_margin, border_width;
-
 static long default_fg_color, default_bg_color, default_out_color;
 
 /* create own window or draw stuff to root? */
@@ -355,7 +362,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;
@@ -897,10 +904,14 @@ static void free_text_objects(struct text_object *root, int internal)
                                free(data.rss.action);
                                break;
 #endif
+#ifdef WEATHER
+                       case OBJ_weather:
+                               free(data.weather.uri);
+                               free(data.weather.data_type);
+                               break;
+#endif
 #ifdef HAVE_LUA
                        case OBJ_lua:
-                       case OBJ_lua_parse:
-                       case OBJ_lua_read_parse:
                        case OBJ_lua_bar:
 #ifdef X11
                        case OBJ_lua_graph:
@@ -1561,11 +1572,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);
@@ -1594,8 +1607,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);
@@ -1603,8 +1615,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);
@@ -1612,8 +1623,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);
 #endif /* X11 */
        END OBJ(color, 0)
 #ifdef X11
@@ -2100,12 +2110,18 @@ static struct text_object *construct_text_object(const char *s,
                } else {
                        obj->data.ifblock.s = strndup(arg, text_buffer_size);
                }
+#ifdef __linux__
+       END OBJ_IF(if_running, INFO_TOP)
+               if (arg) {
+                       obj->data.ifblock.s = strndup(arg, text_buffer_size);
+#else
        END OBJ_IF(if_running, 0)
                if (arg) {
                        char buf[256];
 
                        snprintf(buf, 256, "pidof %s >/dev/null", arg);
                        obj->data.ifblock.s = strndup(buf, text_buffer_size);
+#endif
                } else {
                        ERR("if_running needs an argument");
                        obj->data.ifblock.s = 0;
@@ -2347,9 +2363,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);
@@ -2404,6 +2418,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)
@@ -2783,6 +2798,42 @@ static struct text_object *construct_text_object(const char *s,
                                        "[act_par] [spaces in front]");
                }
 #endif
+#ifdef WEATHER
+       END OBJ(weather, 0)
+               if (arg) {
+                       int argc, delay;
+                       char *icao = (char *) malloc(5 * sizeof(char));
+                       char *uri = (char *) malloc(128 * sizeof(char));
+                       char *data_type = (char *) malloc(32 * sizeof(char));
+                       char *tmp_p;
+
+                       argc = sscanf(arg, "%4s %31s %d", icao, data_type, &delay);
+
+                       //icao MUST BE upper-case
+                       tmp_p = icao;
+                       while (*tmp_p) {
+                         *tmp_p = toupper(*tmp_p);
+                         tmp_p++;
+                       }
+
+                       strcpy(uri, "http://weather.noaa.gov/pub/data/observations/metar/stations/");
+                       strcat(uri, icao);
+                       strcat(uri, ".TXT");
+                       obj->data.weather.uri = uri;
+
+                       obj->data.weather.data_type = data_type;
+
+                       //The data retrieval interval is limited to half an hour
+                       if(delay < 30) {
+                         delay = 30;
+                       }
+                       obj->data.weather.delay = delay*60;
+
+                       init_weather_info();
+               } else {
+                       CRIT_ERR("weather needs arguments: <icao> <data_type> [delay in minutes]");
+               }
+#endif
 #ifdef HAVE_LUA
        END OBJ(lua, 0)
                if (arg) {
@@ -2796,12 +2847,6 @@ static struct text_object *construct_text_object(const char *s,
                } else {
                        CRIT_ERR("lua_parse needs arguments: <function name> [function parameters]");
                }
-       END OBJ(lua_read_parse, 0)
-               if (arg) {
-                       obj->data.s = strndup(arg, text_buffer_size);
-               } else {
-                       CRIT_ERR("lua_read_parse needs arguments: <function name> <string to pass>");
-               }
        END OBJ(lua_bar, 0)
                SIZE_DEFAULTS(bar);
                if (arg) {
@@ -2818,15 +2863,16 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ(lua_graph, 0)
                SIZE_DEFAULTS(graph);
                if (arg) {
-                       arg = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
+                       char *buf = 0;
+                       buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
                                        &obj->e, &obj->char_a, &obj->char_b);
-                       if (arg) {
-                               obj->data.s = strndup(arg, text_buffer_size);
+                       if (buf) {
+                               obj->data.s = buf;
                        } else {
-                               CRIT_ERR("lua_graph needs arguments: <\"normal\"|\"log\"> <height>,<width> <gradient colour 1> <gradient colour 2> <scale> <function name> [function parameters]");
+                               CRIT_ERR("lua_graph needs arguments: <function name> [height],[width] [gradient colour 1] [gradient colour 2] [scale] [-t] [-l]");
                        }
                } else {
-                       CRIT_ERR("lua_graph needs arguments: <\"normal\"|\"log\"> <height>,<width> <gradient colour 1> <gradient colour 2> <scale> <function name> [function parameters]");
+                       CRIT_ERR("lua_graph needs arguments: <function name> [height],[width] [gradient colour 1] [gradient colour 2] [scale] [-t] [-l]");
        }
        END OBJ(lua_gauge, 0)
                SIZE_DEFAULTS(gauge);
@@ -3210,6 +3256,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;
@@ -3222,13 +3272,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;
 }
@@ -3243,7 +3298,7 @@ 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;
@@ -3381,8 +3436,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++;
        }
@@ -4105,18 +4166,7 @@ static void generate_text_internal(char *p, int p_max_size,
                        }
 #endif /* IMLIB2 */
                        OBJ(eval) {
-                               struct information *tmp_info;
-                               struct text_object subroot, subroot2;
-
-                               tmp_info = malloc(sizeof(struct information));
-                               memcpy(tmp_info, cur, sizeof(struct information));
-                               parse_conky_vars(&subroot, obj->data.s, p, tmp_info);
-                               DBGP("evaluated '%s' to '%s'", obj->data.s, p);
-                               parse_conky_vars(&subroot2, p, p, tmp_info);
-
-                               free_text_objects(&subroot, 1);
-                               free_text_objects(&subroot2, 1);
-                               free(tmp_info);
+                               evaluate(obj->data.s, p);
                        }
                        OBJ(exec) {
                                read_exec(obj->data.s, p, text_buffer_size);
@@ -4175,16 +4225,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);
 
@@ -4227,16 +4275,14 @@ static void generate_text_internal(char *p, int p_max_size,
                                        char tempgrad = FALSE;
                                        char *cmd = obj->data.execi.cmd;
 
-                                       if (strncasecmp(obj->data.execi.cmd, LOGGRAPH" ", strlen(LOGGRAPH" ")) == EQUAL) {
-                                               showaslog = TRUE;
-                                               cmd = cmd + strlen(LOGGRAPH" ") * sizeof(char);
-                                       } else if(strncasecmp(obj->data.s, NORMGRAPH" ", strlen(NORMGRAPH" ")) == EQUAL) {
-                                               cmd = cmd + strlen(NORMGRAPH" ") * sizeof(char);
-                                       }
                                        if (strstr(cmd, " "TEMPGRAD) && strlen(cmd) > strlen(" "TEMPGRAD)) {
                                                tempgrad = TRUE;
                                                cmd += strlen(" "TEMPGRAD);
                                        }
+                                       if (strstr(cmd, " "LOGGRAPH) && strlen(cmd) > strlen(" "LOGGRAPH)) {
+                                               showaslog = TRUE;
+                                               cmd += strlen(" "LOGGRAPH);
+                                       }
                                        obj->char_a = showaslog;
                                        obj->char_b = tempgrad;
                                        read_exec(cmd, p, text_buffer_size);
@@ -4578,6 +4624,91 @@ static void generate_text_internal(char *p, int p_max_size,
                                }
                        }
 #endif
+#ifdef WEATHER
+                       OBJ(weather) {
+                               PWEATHER *data = get_weather_info(obj->data.weather.uri, obj->data.weather.delay);
+
+                               static const char *wc[18] =
+                               {"", "drizzle", "rain", "hail", "soft hail",
+                                       "snow", "snow grains", "fog", "haze", "smoke",
+                                       "mist", "dust", "sand", "funnel cloud tornado",
+                                       "dust/sand", "squall", "sand storm", "dust storm"};
+
+
+                               if (data == NULL) {
+                                       strncpy(p, "Error reading weather data", p_max_size);
+                               } else {
+                                       if (strcmp(obj->data.weather.data_type, "last_update") == EQUAL) {
+                                               strncpy(p, data->lastupd, p_max_size);
+                                       } else if (strcmp(obj->data.weather.data_type, "temperature_C") == EQUAL) {
+                                               snprintf(p, p_max_size, "%d", data->tmpC);
+                                       } else if (strcmp(obj->data.weather.data_type, "temperature_F") == EQUAL) {
+                                               snprintf(p, p_max_size, "%d", data->tmpF);
+                                       } else if (strcmp(obj->data.weather.data_type, "cloud_cover") == EQUAL) {
+                                               if (data->cc == 0) {
+                                                       strncpy(p, "", p_max_size);
+                                               } else if (data->cc < 3) {
+                                                       strncpy(p, "clear", p_max_size);
+                                               } else if (data->cc < 5) {
+                                                       strncpy(p, "partly cloudy", p_max_size);
+                                               } else if (data->cc == 5) {
+                                                       strncpy(p, "cloudy", p_max_size);
+                                               } else if (data->cc == 6) {
+                                                       strncpy(p, "overcast", p_max_size);
+                                               } else if (data->cc == 7) {
+                                                       strncpy(p, "towering cumulus", p_max_size);
+                                               } else  {
+                                                       strncpy(p, "cumulonimbus", p_max_size);
+                                               }
+                                       } else if (strcmp(obj->data.weather.data_type, "pressure") == EQUAL) {
+                                               snprintf(p, p_max_size, "%d", data->bar);
+                                       } else if (strcmp(obj->data.weather.data_type, "wind_speed") == EQUAL) {
+                                               snprintf(p, p_max_size, "%d", data->wind_s);
+                                       } else if (strcmp(obj->data.weather.data_type, "wind_dir") == EQUAL) {
+                                               if ((data->wind_d >= 349) || (data->wind_d < 12)) {
+                                                       strncpy(p, "N", p_max_size);
+                                               } else if (data->wind_d < 33) {
+                                                       strncpy(p, "NNE", p_max_size);
+                                               } else if (data->wind_d < 57) {
+                                                       strncpy(p, "NE", p_max_size);
+                                               } else if (data->wind_d < 79) {
+                                                       strncpy(p, "ENE", p_max_size);
+                                               } else if (data->wind_d < 102) {
+                                                       strncpy(p, "E", p_max_size);
+                                               } else if (data->wind_d < 124) {
+                                                       strncpy(p, "ESE", p_max_size);
+                                               } else if (data->wind_d < 147) {
+                                                       strncpy(p, "SE", p_max_size);
+                                               } else if (data->wind_d < 169) {
+                                                       strncpy(p, "SSE", p_max_size);
+                                               } else if (data->wind_d < 192) {
+                                                       strncpy(p, "S", p_max_size);
+                                               } else if (data->wind_d < 214) {
+                                                       strncpy(p, "SSW", p_max_size);
+                                               } else if (data->wind_d < 237) {
+                                                       strncpy(p, "SW", p_max_size);
+                                               } else if (data->wind_d < 259) {
+                                                       strncpy(p, "WSW", p_max_size);
+                                               } else if (data->wind_d < 282) {
+                                                       strncpy(p, "W", p_max_size);
+                                               } else if (data->wind_d < 304) {
+                                                       strncpy(p, "WNW", p_max_size);
+                                               } else if (data->wind_d < 327) {
+                                                       strncpy(p, "NW", p_max_size);
+                                               } else if (data->wind_d < 349) {
+                                                       strncpy(p, "NNW", p_max_size);
+                                               };
+                                       } else if (strcmp(obj->data.weather.data_type, "wind_dir_DEG") == EQUAL) {
+                                               snprintf(p, p_max_size, "%d", data->wind_d);
+
+                                       } else if (strcmp(obj->data.weather.data_type, "humidity") == EQUAL) {
+                                               snprintf(p, p_max_size, "%d", data->hmid);
+                                       } else if (strcmp(obj->data.weather.data_type, "weather") == EQUAL) {
+                                               strncpy(p, wc[data->wc], p_max_size);
+                                       }
+                               }
+                       }
+#endif
 #ifdef HAVE_LUA
                        OBJ(lua) {
                                char *str = llua_getstring(obj->data.s);
@@ -4589,41 +4720,8 @@ static void generate_text_internal(char *p, int p_max_size,
                        OBJ(lua_parse) {
                                char *str = llua_getstring(obj->data.s);
                                if (str) {
-                                       struct information *tmp_info;
-                                       struct text_object subroot;
-
-                                       tmp_info = malloc(sizeof(struct information));
-                                       memcpy(tmp_info, cur, sizeof(struct information));
-                                       parse_conky_vars(&subroot, str, p, tmp_info);
-
-                                       free_text_objects(&subroot, 1);
-                                       free(tmp_info);
-                                       free(str);
-                               }
-                       }
-                       OBJ(lua_read_parse) {
-                               struct information *tmp_info;
-                               struct text_object subroot, subroot2;
-                               char func[64];
-                               char *text, *str;
-                               sscanf(obj->data.s, "%64s", func);
-                               text = obj->data.s + strlen(func) + 1;
-
-                               tmp_info = malloc(sizeof(struct information));
-                               memcpy(tmp_info, cur, sizeof(struct information));
-                               parse_conky_vars(&subroot, text, p, tmp_info);
-                               DBGP("evaluated '%s' to '%s'", text, p);
-
-                               str = llua_getstring_read(func, p);
-                               if (str) {
-                                       parse_conky_vars(&subroot2, str, p, tmp_info);
-                                       DBGP("evaluated '%s' to '%s'", str, p);
-
-                                       free(str);
-                                       free_text_objects(&subroot2, 1);
+                                       evaluate(str, p);
                                }
-                               free_text_objects(&subroot, 1);
-                               free(tmp_info);
                        }
                        OBJ(lua_bar) {
                                double per;
@@ -4796,7 +4894,11 @@ static void generate_text_internal(char *p, int p_max_size,
                                }
                        }
                        OBJ(if_running) {
+#ifdef __linux__
+                               if (!get_process_by_name(obj->data.ifblock.s)) {
+#else
                                if ((obj->data.ifblock.s) && system(obj->data.ifblock.s)) {
+#endif
                                        DO_JUMP;
                                }
                        }
@@ -4984,6 +5086,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);
                        }
@@ -5199,10 +5304,6 @@ static void generate_text_internal(char *p, int p_max_size,
 #undef mpd_printf
 #endif
 
-#ifdef XMMS2
-    free_xmms2();
-#endif
-
 #ifdef MOC
 #define MOC_PRINT(t, a) \
        snprintf(p, p_max_size, "%s", (moc.t ? moc.t : a))
@@ -5871,7 +5972,11 @@ static void generate_text_internal(char *p, int p_max_size,
                                        && (iconv_cd[iconv_selected - 1] != (iconv_t) (-1))) {
                                int bytes;
                                size_t dummy1, dummy2;
+#ifdef __FreeBSD__
+                               const char *ptr = buff_in;
+#else
                                char *ptr = buff_in;
+#endif
                                char *outptr = p;
 
                                dummy1 = dummy2 = a;
@@ -5906,6 +6011,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)
@@ -6093,10 +6212,10 @@ static void update_text_area(void)
        if (own_window && !fixed_pos) {
                x += workarea[0];
                y += workarea[1];
-               text_start_x = border_inner_margin + border_outer_margin + border_width;
-               text_start_y = border_inner_margin + border_outer_margin + border_width;
-               window.x = x - border_inner_margin - border_outer_margin - border_width;
-               window.y = y - border_inner_margin - border_outer_margin - border_width;
+               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
        {
@@ -6111,6 +6230,10 @@ static void update_text_area(void)
                text_start_x = x;
                text_start_y = y;
        }
+#ifdef HAVE_LUA
+       /* update lua window globals */
+       llua_update_window_table(text_start_x, text_start_y, text_width, text_height);
+#endif /* HAVE_LUA */
 }
 
 /* drawing stuff */
@@ -6665,18 +6788,18 @@ static void draw_line(char *s)
 
                                case ALIGNR:
                                {
-                                       /* TODO: add back in "+ border_inner_margin" to the end of
+                                       /* TODO: add back in "+ window.border_inner_margin" to the end of
                                         * this line? */
                                        int pos_x = text_start_x + text_width -
                                                get_string_width_special(s);
 
                                        /* printf("pos_x %i text_start_x %i text_width %i cur_x %i "
                                                "get_string_width(p) %i gap_x %i "
-                                               "specials[special_index].arg %i border_inner_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_inner_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;
                                        }
@@ -6722,26 +6845,29 @@ static void draw_line(char *s)
 static void draw_text(void)
 {
 #ifdef X11
+#ifdef HAVE_LUA
+       llua_draw_pre_hook();
+#endif /* HAVE_LUA */
        if (output_methods & TO_X) {
                cur_y = text_start_y;
 
                /* draw borders */
-               if (draw_borders && border_width > 0) {
+               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_inner_margin - border_width,
-                               text_start_y - border_inner_margin - border_width,
-                               text_width + border_inner_margin * 2 + border_width * 2,
-                               text_height + border_inner_margin * 2 + border_width * 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 */
@@ -6750,6 +6876,9 @@ static void draw_text(void)
        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)
@@ -6836,10 +6965,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_inner_margin - border_outer_margin - border_width,
-                       text_start_y - border_inner_margin - border_outer_margin - border_width,
-                       text_width + border_inner_margin * 2 + border_outer_margin * 2 + border_width * 2,
-                       text_height + border_inner_margin * 2 + border_outer_margin * 2 + border_width * 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 */
@@ -6945,21 +7074,63 @@ static void main_loop(void)
                                update_text_area();
 #ifdef OWN_WINDOW
                                if (own_window) {
+                                       int changed = 0;
+
                                        /* resize window if it isn't right size */
                                        if (!fixed_size
-                                               && (text_width + border_inner_margin * 2 + border_outer_margin * 2 + border_width * 2 != window.width
-                                               || text_height + border_inner_margin * 2 + border_outer_margin * 2 + border_width * 2 != window.height)) {
-                                                       window.width = text_width + border_inner_margin * 2 + border_outer_margin * 2 + border_width * 2;
-                                                       window.height = text_height + border_inner_margin * 2 + border_outer_margin * 2 + border_width * 2;
+                                               && (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);
                                                        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
 
@@ -6969,10 +7140,10 @@ static void main_loop(void)
                                if (use_xdbe) {
                                        XRectangle r;
 
-                                       r.x = text_start_x - border_inner_margin - border_outer_margin - border_width;
-                                       r.y = text_start_y - border_inner_margin - border_outer_margin - border_width;
-                                       r.width = text_width + border_inner_margin * 2 + border_outer_margin * 2 + border_width * 2;
-                                       r.height = text_height + border_inner_margin * 2 + border_outer_margin * 2 + border_width * 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
@@ -7025,8 +7196,8 @@ static void main_loop(void)
                                                                        }
                                                                }
 
-                                                               text_width = window.width - border_inner_margin * 2 - border_outer_margin * 2 - border_width * 2;
-                                                               text_height = window.height - border_inner_margin * 2 - border_outer_margin * 2 - border_width * 2;
+                                                               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;
@@ -7120,10 +7291,10 @@ static void main_loop(void)
                                if (use_xdbe) {
                                        XRectangle r;
 
-                                       r.x = text_start_x - border_inner_margin - border_outer_margin - border_width;
-                                       r.y = text_start_y - border_inner_margin - border_outer_margin - border_width;
-                                       r.width = text_width + border_inner_margin * 2 + border_outer_margin * 2 + border_width * 2;
-                                       r.height = text_height + border_inner_margin * 2 + border_outer_margin * 2 + border_width * 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
@@ -7337,7 +7508,7 @@ static void reload_config(void)
        }
 }
 
-static void clean_up(void)
+void clean_up(void)
 {
        int i;
        timed_thread_destroy_registered_threads();
@@ -7366,7 +7537,6 @@ static void clean_up(void)
                        XFlush(display);
                }
 
-               XFreeGC(display, window.gc);
                free_fonts();
        }
 
@@ -7406,6 +7576,9 @@ static void clean_up(void)
 #ifdef RSS
        free_rss_info();
 #endif
+#ifdef WEATHER
+       free_weather_info();
+#endif
 #ifdef HAVE_LUA
        llua_close();
 #endif /* HAVE_LUA */
@@ -7420,7 +7593,9 @@ static void clean_up(void)
                specials = NULL;
        }
 
+       clear_net_stats();
        clear_diskio_stats();
+       if(global_cpu != NULL) free(global_cpu);
 }
 
 static int string_to_bool(const char *s)
@@ -7502,6 +7677,10 @@ static void set_default_configurations_for_x(void)
 static void set_default_configurations(void)
 {
        int i;
+#ifdef MPD
+       char *mpd_env_host;
+       char *mpd_env_port;
+#endif
        update_uname();
        fork_to_background = 0;
        total_run_times = 0;
@@ -7519,8 +7698,36 @@ static void set_default_configurations(void)
        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;
@@ -7559,15 +7766,17 @@ static void set_default_configurations(void)
        sprintf(window.title, PACKAGE_NAME" (%s)", info.uname_s.nodename);
 #endif
        stippled_borders = 0;
-       border_inner_margin = 3;
-       border_outer_margin = 1;
-       border_width = 1;
+       window.border_inner_margin = 3;
+       window.border_outer_margin = 1;
+       window.border_width = 1;
        text_alignment = BOTTOM_LEFT;
        info.x11.monitor.number = 1;
        info.x11.monitor.current = 0;
 #endif /* X11 */
 
        for (i = 0; i < MAX_TEMPLATES; i++) {
+               if (template[i])
+                       free(template[i]);
                template[i] = strdup("");
        }
 
@@ -7686,12 +7895,12 @@ static void X11_create_window(void)
 {
        if (output_methods & TO_X) {
 #ifdef OWN_WINDOW
-               init_window(own_window, text_width + border_inner_margin * 2 + border_outer_margin * 2 + border_width * 2,
-                               text_height + border_inner_margin * 2 + border_outer_margin * 2 + border_width * 2, 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_inner_margin * 2 + border_outer_margin * 2 + border_width * 2,
-                               text_height + border_inner_margin * 2 + border_outer_margin * 2 + border_width * 2, 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 */
 
@@ -7725,6 +7934,10 @@ static void X11_create_window(void)
                selected_font = 0;
                update_text_area();     /* to get initial size of the window */
        }
+#ifdef HAVE_LUA
+       /* setup lua window globals */
+       llua_setup_window_table(text_start_x, text_start_y, text_width, text_height);
+#endif /* HAVE_LUA */
 }
 #endif /* X11 */
 
@@ -7742,9 +7955,7 @@ static FILE *open_config_file(const char *f)
 {
 #ifdef CONFIG_OUTPUT
        if (!strcmp(f, "==builtin==")) {
-#ifdef HAVE_FOPENCOOKIE
-               return fopencookie(NULL, "r", conf_cookie);
-#endif /* HAVE_FOPENCOOKIE */
+               return conf_cookie_open();
        } else
 #endif /* CONFIG_OUTPUT */
                return fopen(f, "r");
@@ -7874,28 +8085,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 border_inner_margin instead");
+                       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) {
-                               border_inner_margin = strtol(value, 0, 0);
-                               if (border_inner_margin < 0) border_inner_margin = 0;
+                               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_outer_margin = strtol(value, 0, 0);
-                               if (border_outer_margin < 0) border_outer_margin = 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);
-                               if (border_width < 0) border_width = 0;
+                               window.border_width = strtol(value, 0, 0);
+                               if (window.border_width < 0) window.border_width = 0;
                        } else {
                                CONF_ERR;
                        }
@@ -7990,7 +8207,7 @@ static void load_config_file(const char *f)
                }
                CONF("mpd_password") {
                        if (value) {
-                               mpd_set_password(value);
+                               mpd_set_password(value, 0);
                        } else {
                                CONF_ERR;
                        }
@@ -8312,6 +8529,8 @@ static void load_config_file(const char *f)
                                } 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 {
@@ -8502,10 +8721,9 @@ static void load_config_file(const char *f)
                }
 #ifdef HAVE_LUA
                CONF("lua_load") {
-                       llua_init();
-                       if(value) {
+                       if (value) {
                                char *ptr = strtok(value, " ");
-                               while(ptr) {
+                               while (ptr) {
                                        llua_load(ptr);
                                        ptr = strtok(NULL, " ");
                                }
@@ -8513,6 +8731,22 @@ static void load_config_file(const char *f)
                                CONF_ERR;
                        }
                }
+#ifdef X11
+               CONF("lua_draw_hook_pre") {
+                       if (value) {
+                               llua_set_draw_pre_hook(value);
+                       } else {
+                               CONF_ERR;
+                       }
+               }
+               CONF("lua_draw_hook_post") {
+                       if (value) {
+                               llua_set_draw_post_hook(value);
+                       } else {
+                               CONF_ERR;
+                       }
+               }
+#endif /* X11 */
 #endif /* HAVE_LUA */
 
                CONF("color0"){}
@@ -8818,7 +9052,10 @@ int main(int argc, char **argv)
        struct sigaction act, oact;
 
        g_signal_pending = 0;
+       max_user_text = MAX_USER_TEXT_DEFAULT;
+       current_config = 0;
        memset(&info, 0, sizeof(info));
+       memset(template, 0, sizeof(template));
        clear_net_stats();
 
 #ifdef TCP_PORT_MONITOR