X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=apps%2Firssi%2Fsrc%2Ffe-common%2Fcore%2Fthemes.c;fp=apps%2Firssi%2Fsrc%2Ffe-common%2Fcore%2Fthemes.c;h=0000000000000000000000000000000000000000;hb=72c2de619079457f7a68100eb13385275a424a23;hp=b4407bda9e6b521c3a1e17453793341eecbaae5a;hpb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;p=runtime.git diff --git a/apps/irssi/src/fe-common/core/themes.c b/apps/irssi/src/fe-common/core/themes.c deleted file mode 100644 index b4407bda..00000000 --- a/apps/irssi/src/fe-common/core/themes.c +++ /dev/null @@ -1,1391 +0,0 @@ -/* - themes.c : irssi - - Copyright (C) 1999-2000 Timo Sirainen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "module.h" -#include "module-formats.h" -#include "signals.h" -#include "commands.h" -#include "levels.h" -#include "misc.h" -#include "special-vars.h" -#include "lib-config/iconfig.h" -#include "settings.h" - -#include "themes.h" -#include "printtext.h" - -#include "default-theme.h" - -GSList *themes; -THEME_REC *current_theme; -GHashTable *default_formats; - -static int init_finished; -static char *init_errors; -static THEME_REC *internal_theme; - -static int theme_read(THEME_REC *theme, const char *path); - -THEME_REC *theme_create(const char *path, const char *name) -{ - THEME_REC *rec; - - g_return_val_if_fail(path != NULL, NULL); - g_return_val_if_fail(name != NULL, NULL); - - rec = g_new0(THEME_REC, 1); - rec->refcount = 1; - rec->path = g_strdup(path); - rec->name = g_strdup(name); - rec->abstracts = g_hash_table_new((GHashFunc) g_str_hash, - (GCompareFunc) g_str_equal); - rec->modules = g_hash_table_new((GHashFunc) g_istr_hash, - (GCompareFunc) g_istr_equal); - themes = g_slist_append(themes, rec); - signal_emit("theme created", 1, rec); - - return rec; -} - -static void theme_abstract_destroy(char *key, char *value) -{ - g_free(key); - g_free(value); -} - -static void theme_module_destroy(const char *key, MODULE_THEME_REC *rec) -{ - int n; - - for (n = 0; n < rec->count; n++) { - g_free_not_null(rec->formats[n]); - g_free_not_null(rec->expanded_formats[n]); - } - g_free(rec->formats); - g_free(rec->expanded_formats); - - g_free(rec->name); - g_free(rec); -} - -static void theme_real_destroy(THEME_REC *rec) -{ - g_hash_table_foreach(rec->abstracts, (GHFunc) theme_abstract_destroy, NULL); - g_hash_table_destroy(rec->abstracts); - g_hash_table_foreach(rec->modules, (GHFunc) theme_module_destroy, NULL); - g_hash_table_destroy(rec->modules); - - g_slist_foreach(rec->replace_values, (GFunc) g_free, NULL); - g_slist_free(rec->replace_values); - - g_free(rec->path); - g_free(rec->name); - g_free(rec); -} - -static void theme_unref(THEME_REC *rec) -{ - if (--rec->refcount == 0) - theme_real_destroy(rec); -} - -void theme_destroy(THEME_REC *rec) -{ - themes = g_slist_remove(themes, rec); - signal_emit("theme destroyed", 1, rec); - - theme_unref(rec); -} - -static char *theme_replace_expand(THEME_REC *theme, int index, - char default_fg, char default_bg, - char *last_fg, char *last_bg, - char chr, int flags) -{ - GSList *rec; - char *ret, *abstract, data[2]; - - rec = g_slist_nth(theme->replace_values, index); - g_return_val_if_fail(rec != NULL, NULL); - - data[0] = chr; data[1] = '\0'; - - abstract = rec->data; - abstract = theme_format_expand_data(theme, (const char **) &abstract, - default_fg, default_bg, - last_fg, last_bg, flags); - ret = parse_special_string(abstract, NULL, NULL, data, NULL, - PARSE_FLAG_ONLY_ARGS); - g_free(abstract); - return ret; -} - -static const char *fgcolorformats = "nkrgybmpcwKRGYBMPCW"; -static const char *bgcolorformats = "n01234567"; - -#define IS_FGCOLOR_FORMAT(c) \ - ((c) != '\0' && strchr(fgcolorformats, c) != NULL) -#define IS_BGCOLOR_FORMAT(c) \ - ((c) != '\0' && strchr(bgcolorformats, c) != NULL) - -/* append "variable" part in $variable, ie. not the contents of the variable */ -static void theme_format_append_variable(GString *str, const char **format) -{ - const char *orig; - char *value, *args[1] = { NULL }; - int free_ret; - - orig = *format; - (*format)++; - - value = parse_special((char **) format, NULL, NULL, - args, &free_ret, NULL, PARSE_FLAG_ONLY_ARGS); - if (free_ret) g_free(value); - - if (**format != '\0') - (*format)++; - - /* append the variable name */ - value = g_strndup(orig, (int) (*format-orig)); - g_string_append(str, value); - g_free(value); -} - -/* append next "item", either a character, $variable or %format */ -static void theme_format_append_next(THEME_REC *theme, GString *str, - const char **format, - char default_fg, char default_bg, - char *last_fg, char *last_bg, - int flags) -{ - int index; - unsigned char chr; - - chr = **format; - if ((chr == '$' || chr == '%') && - (*format)[1] == '\0') { - /* last char, always append */ - g_string_append_c(str, chr); - (*format)++; - return; - } - - if (chr == '$') { - /* $variable .. we'll always need to skip this, since it - may contain characters that are in replace chars. */ - theme_format_append_variable(str, format); - return; - } - - if (**format == '%') { - /* format */ - (*format)++; - if (**format != '{' && **format != '}') { - chr = **format; - if (**format == 'n') { - /* %n = change to default color */ - g_string_append(str, "%n"); - - if (default_bg != 'n') { - g_string_append_c(str, '%'); - g_string_append_c(str, default_bg); - } - if (default_fg != 'n') { - g_string_append_c(str, '%'); - g_string_append_c(str, default_fg); - } - - *last_fg = default_fg; - *last_bg = default_bg; - } else { - if (IS_FGCOLOR_FORMAT(chr)) - *last_fg = chr; - if (IS_BGCOLOR_FORMAT(chr)) - *last_bg = chr; - g_string_append_c(str, '%'); - g_string_append_c(str, chr); - } - (*format)++; - return; - } - - /* %{ or %} gives us { or } char - keep the % char - though to make sure {} isn't treated as abstract */ - g_string_append_c(str, '%'); - chr = **format; - } - - index = (flags & EXPAND_FLAG_IGNORE_REPLACES) ? -1 : - theme->replace_keys[(int) (unsigned char) chr]; - if (index == -1) - g_string_append_c(str, chr); - else { - char *value; - - value = theme_replace_expand(theme, index, - default_fg, default_bg, - last_fg, last_bg, chr, flags); - g_string_append(str, value); - g_free(value); - } - - (*format)++; -} - -/* returns TRUE if data is empty, or the data is a $variable which is empty */ -static int data_is_empty(const char **data) -{ - /* since we don't know the real argument list, assume there's always - an argument in them */ - static char *arglist[] = { - "x", "x", "x", "x", "x", "x","x", "x", "x", "x", - NULL - }; - SERVER_REC *server; - const char *p; - char *ret; - int free_ret, empty; - - p = *data; - while (*p == ' ') p++; - - if (*p == '}') { - /* empty */ - *data = p+1; - return TRUE; - } - - if (*p != '$') { - /* not empty */ - return FALSE; - } - - /* variable - check if it's empty */ - p++; - - server = active_win == NULL ? NULL : - active_win->active_server != NULL ? - active_win->active_server : active_win->connect_server; - - ret = parse_special((char **) &p, server, - active_win == NULL ? NULL : active_win->active, - arglist, &free_ret, NULL, 0); - p++; - - while (*p == ' ') p++; - empty = *p == '}' && (ret == NULL || *ret == '\0'); - if (free_ret) g_free(ret); - - if (empty) { - /* empty */ - *data = p+1; - return TRUE; - } - - return FALSE; -} - -/* return "data" from {abstract data} string */ -char *theme_format_expand_get(THEME_REC *theme, const char **format) -{ - GString *str; - char *ret, dummy; - int braces = 1; /* we start with one brace opened */ - - str = g_string_new(NULL); - while (**format != '\0' && braces != 0) { - if (**format == '{') - braces++; - else if (**format == '}') - braces--; - else if ((braces > 1) && (**format == ' ')) { - g_string_append(str, "\\x20"); - (*format)++; - continue; - } else { - theme_format_append_next(theme, str, format, - 'n', 'n', - &dummy, &dummy, 0); - continue; - } - - if (braces == 0) { - (*format)++; - break; - } - - g_string_append_c(str, **format); - (*format)++; - } - - ret = str->str; - g_string_free(str, FALSE); - return ret; -} - -/* expand a single {abstract ...data... } */ -static char *theme_format_expand_abstract(THEME_REC *theme, - const char **formatp, - char default_fg, char default_bg, - int flags) -{ - GString *str; - const char *p, *format; - char *abstract, *data, *ret; - int len; - - format = *formatp; - - /* get abstract name first */ - p = format; - while (*p != '\0' && *p != ' ' && - *p != '{' && *p != '}') p++; - if (*p == '\0' || p == format) - return NULL; /* error */ - - len = (int) (p-format); - abstract = g_strndup(format, len); - - /* skip the following space, if there's any more spaces they're - treated as arguments */ - if (*p == ' ') { - len++; - if ((flags & EXPAND_FLAG_IGNORE_EMPTY) && data_is_empty(&p)) { - *formatp = p; - g_free(abstract); - return NULL; - } - } - *formatp = format+len; - - /* get the abstract data */ - data = g_hash_table_lookup(theme->abstracts, abstract); - g_free(abstract); - if (data == NULL) { - /* unknown abstract, just display the data */ - data = "$0-"; - } - abstract = g_strdup(data); - - /* we'll need to get the data part. it may contain - more abstracts, they are _NOT_ expanded. */ - data = theme_format_expand_get(theme, formatp); - len = strlen(data); - - if (len > 1 && i_isdigit(data[len-1]) && data[len-2] == '$') { - /* ends with $ .. this breaks things if next - character is digit or '-' */ - char digit, *tmp; - - tmp = data; - digit = tmp[len-1]; - tmp[len-1] = '\0'; - - data = g_strdup_printf("%s{%c}", tmp, digit); - g_free(tmp); - } - - ret = parse_special_string(abstract, NULL, NULL, data, NULL, - PARSE_FLAG_ONLY_ARGS); - g_free(abstract); - g_free(data); - str = g_string_new(NULL); - p = ret; - while (*p != '\0') { - if (*p == '\\') { - int chr; - p++; - chr = expand_escape(&p); - g_string_append_c(str, chr != -1 ? chr : *p); - } else - g_string_append_c(str, *p); - p++; - } - g_free(ret); - abstract = str->str; - g_string_free(str, FALSE); - - /* abstract may itself contain abstracts or replaces */ - p = abstract; - ret = theme_format_expand_data(theme, &p, default_fg, default_bg, - &default_fg, &default_bg, - flags | EXPAND_FLAG_LASTCOLOR_ARG); - g_free(abstract); - return ret; -} - -/* expand the data part in {abstract data} */ -char *theme_format_expand_data(THEME_REC *theme, const char **format, - char default_fg, char default_bg, - char *save_last_fg, char *save_last_bg, - int flags) -{ - GString *str; - char *ret, *abstract; - char last_fg, last_bg; - int recurse_flags; - - last_fg = default_fg; - last_bg = default_bg; - recurse_flags = flags & EXPAND_FLAG_RECURSIVE_MASK; - - str = g_string_new(NULL); - while (**format != '\0') { - if ((flags & EXPAND_FLAG_ROOT) == 0 && **format == '}') { - /* ignore } if we're expanding original string */ - (*format)++; - break; - } - - if (**format != '{') { - if ((flags & EXPAND_FLAG_LASTCOLOR_ARG) && - **format == '$' && (*format)[1] == '0') { - /* save the color before $0 .. - this is for the %n replacing */ - if (save_last_fg != NULL) { - *save_last_fg = last_fg; - save_last_fg = NULL; - } - if (save_last_bg != NULL) { - *save_last_bg = last_bg; - save_last_bg = NULL; - } - } - - theme_format_append_next(theme, str, format, - default_fg, default_bg, - &last_fg, &last_bg, - recurse_flags); - continue; - } - - (*format)++; - if (**format == '\0' || **format == '}') - break; /* error */ - - /* get a single {...} */ - abstract = theme_format_expand_abstract(theme, format, - last_fg, last_bg, - recurse_flags); - if (abstract != NULL) { - g_string_append(str, abstract); - g_free(abstract); - } - } - - if ((flags & EXPAND_FLAG_LASTCOLOR_ARG) == 0) { - /* save the last color */ - if (save_last_fg != NULL) - *save_last_fg = last_fg; - if (save_last_bg != NULL) - *save_last_bg = last_bg; - } - - ret = str->str; - g_string_free(str, FALSE); - return ret; -} - -#define IS_OLD_FORMAT(code, last_fg, last_bg) \ - (((code) == 'n' && (last_fg) == 'n' && (last_bg) == 'n') || \ - ((code) != 'n' && ((code) == (last_fg) || (code) == (last_bg)))) - -static char *theme_format_compress_colors(THEME_REC *theme, const char *format) -{ - GString *str; - char *ret, last_fg, last_bg; - - str = g_string_new(NULL); - - last_fg = last_bg = '\0'; - while (*format != '\0') { - if (*format == '$') { - /* $variable, skrip it entirely */ - theme_format_append_variable(str, &format); - last_fg = last_bg = '\0'; - } else if (*format != '%') { - /* a normal character */ - g_string_append_c(str, *format); - format++; - } else { - /* %format */ - format++; - if (IS_OLD_FORMAT(*format, last_fg, last_bg)) { - /* active color set again */ - } else if (IS_FGCOLOR_FORMAT(*format) && - format[1] == '%' && - IS_FGCOLOR_FORMAT(format[2]) && - (*format != 'n' || format[2] == 'n')) { - /* two fg colors in a row. bg colors are - so rare that we don't bother checking - them */ - } else { - /* some format, add it */ - g_string_append_c(str, '%'); - g_string_append_c(str, *format); - - if (IS_FGCOLOR_FORMAT(*format)) - last_fg = *format; - if (IS_BGCOLOR_FORMAT(*format)) - last_bg = *format; - } - format++; - } - } - - ret = str->str; - g_string_free(str, FALSE); - return ret; -} - -char *theme_format_expand(THEME_REC *theme, const char *format) -{ - char *data, *ret; - - g_return_val_if_fail(theme != NULL, NULL); - g_return_val_if_fail(format != NULL, NULL); - - data = theme_format_expand_data(theme, &format, 'n', 'n', NULL, NULL, - EXPAND_FLAG_ROOT); - ret = theme_format_compress_colors(theme, data); - g_free(data); - return ret; -} - -static MODULE_THEME_REC *theme_module_create(THEME_REC *theme, const char *module) -{ - MODULE_THEME_REC *rec; - FORMAT_REC *formats; - - rec = g_hash_table_lookup(theme->modules, module); - if (rec != NULL) return rec; - - formats = g_hash_table_lookup(default_formats, module); - g_return_val_if_fail(formats != NULL, NULL); - - rec = g_new0(MODULE_THEME_REC, 1); - rec->name = g_strdup(module); - - for (rec->count = 0; formats[rec->count].def != NULL; rec->count++) ; - rec->formats = g_new0(char *, rec->count); - rec->expanded_formats = g_new0(char *, rec->count); - - g_hash_table_insert(theme->modules, rec->name, rec); - return rec; -} - -static void theme_read_replaces(CONFIG_REC *config, THEME_REC *theme) -{ - GSList *tmp; - CONFIG_NODE *node; - const char *p; - int index; - - /* reset replace keys */ - for (index = 0; index < 256; index++) - theme->replace_keys[index] = -1; - index = 0; - - node = config_node_traverse(config, "replaces", FALSE); - if (node == NULL || node->type != NODE_TYPE_BLOCK) return; - - for (tmp = node->value; tmp != NULL; tmp = tmp->next) { - node = tmp->data; - - if (node->key != NULL && node->value != NULL) { - for (p = node->key; *p != '\0'; p++) - theme->replace_keys[(int) (unsigned char) *p] = index; - - theme->replace_values = - g_slist_append(theme->replace_values, - g_strdup(node->value)); - index++; - } - } -} - -static void theme_read_abstracts(CONFIG_REC *config, THEME_REC *theme) -{ - GSList *tmp; - CONFIG_NODE *node; - gpointer oldkey, oldvalue; - - node = config_node_traverse(config, "abstracts", FALSE); - if (node == NULL || node->type != NODE_TYPE_BLOCK) return; - - for (tmp = node->value; tmp != NULL; tmp = tmp->next) { - node = tmp->data; - - if (node->key == NULL || node->value == NULL) - continue; - - if (g_hash_table_lookup_extended(theme->abstracts, node->key, - &oldkey, &oldvalue)) { - /* new values override old ones */ - g_hash_table_remove(theme->abstracts, oldkey); - g_free(oldkey); - g_free(oldvalue); - } - - g_hash_table_insert(theme->abstracts, g_strdup(node->key), - g_strdup(node->value)); - } -} - -static void theme_set_format(THEME_REC *theme, MODULE_THEME_REC *rec, - const char *module, - const char *key, const char *value) -{ - int num; - - num = format_find_tag(module, key); - if (num != -1) { - rec->formats[num] = g_strdup(value); - rec->expanded_formats[num] = theme_format_expand(theme, value); - } -} - -static void theme_read_formats(THEME_REC *theme, const char *module, - CONFIG_REC *config, MODULE_THEME_REC *rec) -{ - CONFIG_NODE *node; - GSList *tmp; - - node = config_node_traverse(config, "formats", FALSE); - if (node == NULL) return; - node = config_node_section(node, module, -1); - if (node == NULL) return; - - for (tmp = node->value; tmp != NULL; tmp = tmp->next) { - node = tmp->data; - - if (node->key != NULL && node->value != NULL) { - theme_set_format(theme, rec, module, - node->key, node->value); - } - } -} - -static void theme_init_module(THEME_REC *theme, const char *module, - CONFIG_REC *config) -{ - MODULE_THEME_REC *rec; - FORMAT_REC *formats; - int n; - - formats = g_hash_table_lookup(default_formats, module); - g_return_if_fail(formats != NULL); - - rec = theme_module_create(theme, module); - - if (config != NULL) - theme_read_formats(theme, module, config, rec); - - /* expand the remaining formats */ - for (n = 0; n < rec->count; n++) { - if (rec->expanded_formats[n] == NULL) { - rec->expanded_formats[n] = - theme_format_expand(theme, formats[n].def); - } - } -} - -static void sig_print_errors(void) -{ - init_finished = TRUE; - - if (init_errors != NULL) { - signal_emit("gui dialog", 2, "error", init_errors); - g_free(init_errors); - } -} - -static void theme_read_module(THEME_REC *theme, const char *module) -{ - CONFIG_REC *config; - - config = config_open(theme->path, -1); - if (config != NULL) - config_parse(config); - - theme_init_module(theme, module, config); - - if (config != NULL) config_close(config); -} - -static void themes_read_module(const char *module) -{ - g_slist_foreach(themes, (GFunc) theme_read_module, (void *) module); -} - -static void theme_remove_module(THEME_REC *theme, const char *module) -{ - MODULE_THEME_REC *rec; - - rec = g_hash_table_lookup(theme->modules, module); - if (rec == NULL) return; - - g_hash_table_remove(theme->modules, module); - theme_module_destroy(module, rec); -} - -static void themes_remove_module(const char *module) -{ - g_slist_foreach(themes, (GFunc) theme_remove_module, (void *) module); -} - -void theme_register_module(const char *module, FORMAT_REC *formats) -{ - if (g_hash_table_lookup(default_formats, module) != NULL) - return; - - g_hash_table_insert(default_formats, g_strdup(module), formats); - themes_read_module(module); -} - -void theme_unregister_module(const char *module) -{ - gpointer key, value; - - if (default_formats == NULL) - return; /* already uninitialized */ - - if (!g_hash_table_lookup_extended(default_formats, module, &key, &value)) - return; - - g_hash_table_remove(default_formats, key); - g_free(key); - - themes_remove_module(module); -} - -void theme_set_default_abstract(const char *key, const char *value) -{ - gpointer oldkey, oldvalue; - - if (g_hash_table_lookup_extended(internal_theme->abstracts, key, - &oldkey, &oldvalue)) { - /* new values override old ones */ - g_hash_table_remove(internal_theme->abstracts, oldkey); - g_free(oldkey); - g_free(oldvalue); - } - - g_hash_table_insert(internal_theme->abstracts, - g_strdup(key), g_strdup(value)); -} - -static THEME_REC *theme_find(const char *name) -{ - GSList *tmp; - - for (tmp = themes; tmp != NULL; tmp = tmp->next) { - THEME_REC *rec = tmp->data; - - if (g_strcasecmp(rec->name, name) == 0) - return rec; - } - - return NULL; -} - -static void window_themes_update(void) -{ - GSList *tmp; - - for (tmp = windows; tmp != NULL; tmp = tmp->next) { - WINDOW_REC *rec = tmp->data; - - if (rec->theme_name != NULL) - rec->theme = theme_load(rec->theme_name); - } -} - -THEME_REC *theme_load(const char *setname) -{ - THEME_REC *theme, *oldtheme; - struct stat statbuf; - char *fname, *name, *p; - - name = g_strdup(setname); - p = strrchr(name, '.'); - if (p != NULL && strcmp(p, ".theme") == 0) { - /* remove the trailing .theme */ - *p = '\0'; - } - - theme = theme_find(name); - - /* check home dir */ - fname = g_strdup_printf("%s/%s.theme", get_irssi_dir(), name); - if (stat(fname, &statbuf) != 0) { - /* check global config dir */ - g_free(fname); - fname = g_strdup_printf(THEMESDIR"/%s.theme", name); - if (stat(fname, &statbuf) != 0) { - /* theme not found */ - g_free(fname); - g_free(name); - return theme; /* use the one in memory if possible */ - } - } - - if (theme != NULL && theme->last_modify == statbuf.st_mtime) { - /* theme not modified, use the one already in memory */ - g_free(fname); - g_free(name); - return theme; - } - - oldtheme = theme; - theme = theme_create(fname, name); - theme->last_modify = statbuf.st_mtime; - if (!theme_read(theme, theme->path)) { - /* error reading .theme file */ - theme_destroy(theme); - theme = NULL; - } - - if (oldtheme != NULL && theme != NULL) { - theme_destroy(oldtheme); - if (current_theme == oldtheme) - current_theme = theme; - window_themes_update(); - } - - g_free(fname); - g_free(name); - return theme; -} - -static void copy_abstract_hash(char *key, char *value, GHashTable *dest) -{ - g_hash_table_insert(dest, g_strdup(key), g_strdup(value)); -} - -static void theme_copy_abstracts(THEME_REC *dest, THEME_REC *src) -{ - g_hash_table_foreach(src->abstracts, (GHFunc) copy_abstract_hash, - dest->abstracts); -} - -typedef struct { - THEME_REC *theme; - CONFIG_REC *config; -} THEME_READ_REC; - -static void theme_read_modules(const char *module, void *value, - THEME_READ_REC *rec) -{ - theme_init_module(rec->theme, module, rec->config); -} - -static void read_error(const char *str) -{ - char *old; - - if (init_finished) - printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str); - else if (init_errors == NULL) - init_errors = g_strdup(str); - else { - old = init_errors; - init_errors = g_strconcat(init_errors, "\n", str, NULL); - g_free(old); - } -} - -static int theme_read(THEME_REC *theme, const char *path) -{ - CONFIG_REC *config; - THEME_READ_REC rec; - char *str; - - config = config_open(path, -1) ; - if (config == NULL) { - /* didn't exist or no access? */ - str = g_strdup_printf("Error reading theme file %s: %s", - path, g_strerror(errno)); - read_error(str); - g_free(str); - return FALSE; - } - - if (path == NULL) - config_parse_data(config, default_theme, "internal"); - else - config_parse(config); - - if (config_last_error(config) != NULL) { - str = g_strdup_printf("Ignored errors in theme %s:\n%s", - theme->name, config_last_error(config)); - read_error(str); - g_free(str); - } - - theme->default_color = - config_get_int(config, NULL, "default_color", -1); - theme->info_eol = config_get_bool(config, NULL, "info_eol", FALSE); - - /* FIXME: remove after 0.7.99 */ - if (theme->default_color == 0 && - config_get_int(config, NULL, "default_real_color", -1) != -1) - theme->default_color = -1; - theme_read_replaces(config, theme); - - if (path != NULL) - theme_copy_abstracts(theme, internal_theme); - theme_read_abstracts(config, theme); - - rec.theme = theme; - rec.config = config; - g_hash_table_foreach(default_formats, - (GHFunc) theme_read_modules, &rec); - config_close(config); - - return TRUE; -} - -typedef struct { - char *name; - char *short_name; -} THEME_SEARCH_REC; - -static int theme_search_equal(THEME_SEARCH_REC *r1, THEME_SEARCH_REC *r2) -{ - return g_strcasecmp(r1->short_name, r2->short_name); -} - -static void theme_get_modules(char *module, FORMAT_REC *formats, GSList **list) -{ - THEME_SEARCH_REC *rec; - - rec = g_new(THEME_SEARCH_REC, 1); - rec->name = module; - rec->short_name = strrchr(module, '/'); - if (rec->short_name != NULL) - rec->short_name++; else rec->short_name = module; - *list = g_slist_insert_sorted(*list, rec, (GCompareFunc) theme_search_equal); -} - -static GSList *get_sorted_modules(void) -{ - GSList *list; - - list = NULL; - g_hash_table_foreach(default_formats, (GHFunc) theme_get_modules, &list); - return list; -} - -static THEME_SEARCH_REC *theme_search(GSList *list, const char *module) -{ - THEME_SEARCH_REC *rec; - - while (list != NULL) { - rec = list->data; - - if (g_strcasecmp(rec->short_name, module) == 0) - return rec; - list = list->next; - } - - return NULL; -} - -static void theme_show(THEME_SEARCH_REC *rec, const char *key, const char *value, int reset) -{ - MODULE_THEME_REC *theme; - FORMAT_REC *formats; - const char *text, *last_title; - int n, first; - - formats = g_hash_table_lookup(default_formats, rec->name); - theme = g_hash_table_lookup(current_theme->modules, rec->name); - - last_title = NULL; first = TRUE; - for (n = 1; formats[n].def != NULL; n++) { - text = theme != NULL && theme->formats[n] != NULL ? - theme->formats[n] : formats[n].def; - - if (formats[n].tag == NULL) - last_title = text; - else if ((value != NULL && key != NULL && g_strcasecmp(formats[n].tag, key) == 0) || - (value == NULL && (key == NULL || stristr(formats[n].tag, key) != NULL))) { - if (first) { - printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_FORMAT_TITLE, rec->short_name, formats[0].def); - first = FALSE; - } - if (last_title != NULL) - printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_FORMAT_SUBTITLE, last_title); - if (reset || value != NULL) { - theme = theme_module_create(current_theme, rec->name); - g_free_not_null(theme->formats[n]); - g_free_not_null(theme->expanded_formats[n]); - - text = reset ? formats[n].def : value; - theme->formats[n] = reset ? NULL : g_strdup(value); - theme->expanded_formats[n] = theme_format_expand(current_theme, text); - } - printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_FORMAT_ITEM, formats[n].tag, text); - last_title = NULL; - } - } -} - -/* SYNTAX: FORMAT [-delete | -reset] [] [ []] */ -static void cmd_format(const char *data) -{ - GHashTable *optlist; - GSList *tmp, *modules; - char *module, *key, *value; - void *free_arg; - int reset; - - if (!cmd_get_params(data, &free_arg, 3 | PARAM_FLAG_GETREST | PARAM_FLAG_OPTIONS, - "format", &optlist, &module, &key, &value)) - return; - - modules = get_sorted_modules(); - if (*module == '\0') - module = NULL; - else if (theme_search(modules, module) == NULL) { - /* first argument isn't module.. */ - cmd_params_free(free_arg); - if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST | PARAM_FLAG_OPTIONS, - "format", &optlist, &key, &value)) - return; - module = NULL; - } - - reset = FALSE; - if (*key == '\0') key = NULL; - if (g_hash_table_lookup(optlist, "reset")) - reset = TRUE; - else if (g_hash_table_lookup(optlist, "delete")) - value = ""; - else if (*value == '\0') - value = NULL; - - for (tmp = modules; tmp != NULL; tmp = tmp->next) { - THEME_SEARCH_REC *rec = tmp->data; - - if (module == NULL || g_strcasecmp(rec->short_name, module) == 0) - theme_show(rec, key, value, reset); - } - g_slist_foreach(modules, (GFunc) g_free, NULL); - g_slist_free(modules); - - cmd_params_free(free_arg); -} - -typedef struct { - CONFIG_REC *config; - int save_all; -} THEME_SAVE_REC; - -static void module_save(const char *module, MODULE_THEME_REC *rec, - THEME_SAVE_REC *data) -{ - CONFIG_NODE *fnode, *node; - FORMAT_REC *formats; - int n; - - formats = g_hash_table_lookup(default_formats, rec->name); - if (formats == NULL) return; - - fnode = config_node_traverse(data->config, "formats", TRUE); - - node = config_node_section(fnode, rec->name, NODE_TYPE_BLOCK); - for (n = 1; formats[n].def != NULL; n++) { - if (rec->formats[n] != NULL) { - config_node_set_str(data->config, node, formats[n].tag, - rec->formats[n]); - } else if (data->save_all && formats[n].tag != NULL) { - config_node_set_str(data->config, node, formats[n].tag, - formats[n].def); - } - } - - if (node->value == NULL) { - /* not modified, don't keep the empty section */ - config_node_remove(data->config, fnode, node); - if (fnode->value == NULL) { - config_node_remove(data->config, - data->config->mainnode, fnode); - } - } -} - -static void theme_save(THEME_REC *theme, int save_all) -{ - CONFIG_REC *config; - THEME_SAVE_REC data; - char *path; - int ok; - - config = config_open(theme->path, -1); - if (config != NULL) - config_parse(config); - else { - if (g_strcasecmp(theme->name, "default") == 0) { - config = config_open(NULL, -1); - config_parse_data(config, default_theme, "internal"); - config_change_file_name(config, theme->path, 0660); - } else { - config = config_open(theme->path, 0660); - if (config == NULL) - return; - config_parse(config); - } - } - - data.config = config; - data.save_all = save_all; - g_hash_table_foreach(theme->modules, (GHFunc) module_save, &data); - - /* always save the theme to ~/.irssi/ */ - path = g_strdup_printf("%s/%s", get_irssi_dir(), - g_basename(theme->path)); - ok = config_write(config, path, 0660) == 0; - - printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, - ok ? TXT_THEME_SAVED : TXT_THEME_SAVE_FAILED, - path, config_last_error(config)); - - g_free(path); - config_close(config); -} - -/* save changed formats, -format saves all */ -static void cmd_save(const char *data) -{ - GSList *tmp; - GHashTable *optlist; - void *free_arg; - char *fname; - int saveall; - - if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS, - "save", &optlist, &fname)) - return; - - saveall = g_hash_table_lookup(optlist, "formats") != NULL; - for (tmp = themes; tmp != NULL; tmp = tmp->next) { - THEME_REC *theme = tmp->data; - - theme_save(theme, saveall); - } - - cmd_params_free(free_arg); -} - -static void complete_format_list(THEME_SEARCH_REC *rec, const char *key, GList **list) -{ - FORMAT_REC *formats; - int n, len; - - formats = g_hash_table_lookup(default_formats, rec->name); - - len = strlen(key); - for (n = 1; formats[n].def != NULL; n++) { - const char *item = formats[n].tag; - - if (item != NULL && g_strncasecmp(item, key, len) == 0) - *list = g_list_append(*list, g_strdup(item)); - } -} - -static GList *completion_get_formats(const char *module, const char *key) -{ - GSList *modules, *tmp; - GList *list; - - g_return_val_if_fail(key != NULL, NULL); - - list = NULL; - - modules = get_sorted_modules(); - if (*module == '\0' || theme_search(modules, module) != NULL) { - for (tmp = modules; tmp != NULL; tmp = tmp->next) { - THEME_SEARCH_REC *rec = tmp->data; - - if (*module == '\0' || g_strcasecmp(rec->short_name, module) == 0) - complete_format_list(rec, key, &list); - } - } - g_slist_foreach(modules, (GFunc) g_free, NULL); - g_slist_free(modules); - - return list; -} - -static void sig_complete_format(GList **list, WINDOW_REC *window, - const char *word, const char *line, int *want_space) -{ - const char *ptr; - int words; - - g_return_if_fail(list != NULL); - g_return_if_fail(word != NULL); - g_return_if_fail(line != NULL); - - ptr = line; - - words = 0; - if (*ptr != '\0') { - do { - ptr++; - words++; - ptr = strchr(ptr, ' '); - } while (ptr != NULL); - } - - if (words > 2) - return; - - *list = completion_get_formats(line, word); - if (*list != NULL) signal_stop(); -} - -static void change_theme(const char *name, int verbose) -{ - THEME_REC *rec; - - rec = theme_load(name); - if (rec != NULL) { - current_theme = rec; - signal_emit("theme changed", 1, rec); - - if (verbose) { - printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, - TXT_THEME_CHANGED, - rec->name, rec->path); - } - } else if (verbose) { - printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, - TXT_THEME_NOT_FOUND, name); - } -} - -static void read_settings(void) -{ - const char *theme; - int len; - - theme = settings_get_str("theme"); - len = strlen(current_theme->name); - if (strcmp(current_theme->name, theme) != 0 && - (strncmp(current_theme->name, theme, len) != 0 || - strcmp(theme+len, ".theme") != 0)) - change_theme(theme, TRUE); -} - -void themes_reload(void) -{ - GSList *refs; - char *fname; - - /* increase every theme's refcount, and destroy them. this way if - we want to use the theme before it's reloaded we don't crash. */ - refs = NULL; - while (themes != NULL) { - THEME_REC *theme = themes->data; - - refs = g_slist_prepend(refs, theme); - - theme->refcount++; - theme_destroy(theme); - } - - /* first there's default theme.. */ - current_theme = theme_load("default"); - if (current_theme == NULL) { - fname = g_strdup_printf("%s/default.theme", get_irssi_dir()); - current_theme = theme_create(fname, "default"); - current_theme->default_color = -1; - theme_read(current_theme, NULL); - g_free(fname); - } - - window_themes_update(); - change_theme(settings_get_str("theme"), FALSE); - - while (refs != NULL) { - theme_unref(refs->data); - refs = g_slist_remove(refs, refs->data); - } -} - -static THEME_REC *read_internal_theme(void) -{ - CONFIG_REC *config; - THEME_REC *theme; - - theme = theme_create("internal", "_internal"); - - config = config_open(NULL, -1); - config_parse_data(config, default_theme, "internal"); - theme_read_abstracts(config, theme); - config_close(config); - - return theme; -} - -void themes_init(void) -{ - settings_add_str("lookandfeel", "theme", "default"); - - default_formats = g_hash_table_new((GHashFunc) g_str_hash, - (GCompareFunc) g_str_equal); - internal_theme = read_internal_theme(); - - init_finished = FALSE; - init_errors = NULL; - - themes = NULL; - themes_reload(); - - command_bind("format", NULL, (SIGNAL_FUNC) cmd_format); - command_bind("save", NULL, (SIGNAL_FUNC) cmd_save); - signal_add("complete command format", (SIGNAL_FUNC) sig_complete_format); - signal_add("irssi init finished", (SIGNAL_FUNC) sig_print_errors); - signal_add("setup changed", (SIGNAL_FUNC) read_settings); - signal_add("setup reread", (SIGNAL_FUNC) themes_reload); - - command_set_options("format", "delete reset"); - command_set_options("save", "formats"); -} - -void themes_deinit(void) -{ - while (themes != NULL) - theme_destroy(themes->data); - theme_destroy(internal_theme); - - g_hash_table_destroy(default_formats); - default_formats = NULL; - - command_unbind("format", (SIGNAL_FUNC) cmd_format); - command_unbind("save", (SIGNAL_FUNC) cmd_save); - signal_remove("complete command format", (SIGNAL_FUNC) sig_complete_format); - signal_remove("irssi init finished", (SIGNAL_FUNC) sig_print_errors); - signal_remove("setup changed", (SIGNAL_FUNC) read_settings); - signal_remove("setup reread", (SIGNAL_FUNC) themes_reload); -}