2000-04-26 04:03:38 -04:00
|
|
|
/*
|
|
|
|
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.
|
|
|
|
|
2007-05-08 14:41:10 -04:00
|
|
|
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.,
|
|
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2000-04-26 04:03:38 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "module.h"
|
2000-07-21 14:53:04 -04:00
|
|
|
#include "module-formats.h"
|
2000-04-26 04:03:38 -04:00
|
|
|
#include "signals.h"
|
2000-05-15 04:25:45 -04:00
|
|
|
#include "commands.h"
|
|
|
|
#include "levels.h"
|
2000-04-26 04:03:38 -04:00
|
|
|
#include "misc.h"
|
2000-10-27 19:06:26 -04:00
|
|
|
#include "special-vars.h"
|
2000-04-26 04:03:38 -04:00
|
|
|
#include "lib-config/iconfig.h"
|
|
|
|
#include "settings.h"
|
|
|
|
|
|
|
|
#include "themes.h"
|
2000-10-28 16:14:19 -04:00
|
|
|
#include "printtext.h"
|
2000-04-26 04:03:38 -04:00
|
|
|
|
2000-12-01 21:01:51 -05:00
|
|
|
#include "default-theme.h"
|
|
|
|
|
2000-04-26 04:03:38 -04:00
|
|
|
GSList *themes;
|
|
|
|
THEME_REC *current_theme;
|
2000-05-15 04:25:45 -04:00
|
|
|
GHashTable *default_formats;
|
2000-04-26 04:03:38 -04:00
|
|
|
|
2001-01-07 02:58:15 -05:00
|
|
|
static int init_finished;
|
2001-01-04 14:01:01 -05:00
|
|
|
static char *init_errors;
|
2002-12-28 10:25:10 -05:00
|
|
|
static THEME_REC *internal_theme;
|
2001-01-04 14:01:01 -05:00
|
|
|
|
2002-12-28 10:25:10 -05:00
|
|
|
static int theme_read(THEME_REC *theme, const char *path);
|
2000-07-31 17:16:09 -04:00
|
|
|
|
2000-04-26 04:03:38 -04:00
|
|
|
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);
|
2002-08-22 16:49:07 -04:00
|
|
|
rec->refcount = 1;
|
2000-04-26 04:03:38 -04:00
|
|
|
rec->path = g_strdup(path);
|
|
|
|
rec->name = g_strdup(name);
|
2000-10-27 19:06:26 -04:00
|
|
|
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);
|
2000-07-31 17:16:09 -04:00
|
|
|
themes = g_slist_append(themes, rec);
|
2000-04-26 04:03:38 -04:00
|
|
|
signal_emit("theme created", 1, rec);
|
|
|
|
|
|
|
|
return rec;
|
|
|
|
}
|
|
|
|
|
2000-10-27 19:06:26 -04:00
|
|
|
static void theme_abstract_destroy(char *key, char *value)
|
|
|
|
{
|
|
|
|
g_free(key);
|
|
|
|
g_free(value);
|
|
|
|
}
|
|
|
|
|
2000-05-15 04:25:45 -04:00
|
|
|
static void theme_module_destroy(const char *key, MODULE_THEME_REC *rec)
|
2000-04-26 04:03:38 -04:00
|
|
|
{
|
2000-05-15 04:25:45 -04:00
|
|
|
int n;
|
2000-04-26 04:03:38 -04:00
|
|
|
|
2000-10-27 19:06:26 -04:00
|
|
|
for (n = 0; n < rec->count; n++) {
|
|
|
|
g_free_not_null(rec->formats[n]);
|
|
|
|
g_free_not_null(rec->expanded_formats[n]);
|
|
|
|
}
|
2000-05-15 04:25:45 -04:00
|
|
|
g_free(rec->formats);
|
2000-10-27 19:06:26 -04:00
|
|
|
g_free(rec->expanded_formats);
|
2000-04-26 04:03:38 -04:00
|
|
|
|
|
|
|
g_free(rec->name);
|
|
|
|
g_free(rec);
|
|
|
|
}
|
|
|
|
|
2002-08-22 16:49:07 -04:00
|
|
|
static void theme_real_destroy(THEME_REC *rec)
|
2000-04-26 04:03:38 -04:00
|
|
|
{
|
2000-10-27 19:06:26 -04:00
|
|
|
g_hash_table_foreach(rec->abstracts, (GHFunc) theme_abstract_destroy, NULL);
|
|
|
|
g_hash_table_destroy(rec->abstracts);
|
2000-05-15 04:25:45 -04:00
|
|
|
g_hash_table_foreach(rec->modules, (GHFunc) theme_module_destroy, NULL);
|
2000-04-26 04:03:38 -04:00
|
|
|
g_hash_table_destroy(rec->modules);
|
|
|
|
|
2000-10-27 19:06:26 -04:00
|
|
|
g_slist_foreach(rec->replace_values, (GFunc) g_free, NULL);
|
|
|
|
g_slist_free(rec->replace_values);
|
|
|
|
|
2000-04-26 04:03:38 -04:00
|
|
|
g_free(rec->path);
|
|
|
|
g_free(rec->name);
|
|
|
|
g_free(rec);
|
|
|
|
}
|
|
|
|
|
2002-08-22 16:49:07 -04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2000-10-27 20:04:21 -04:00
|
|
|
static char *theme_replace_expand(THEME_REC *theme, int index,
|
2014-01-09 09:20:29 -05:00
|
|
|
theme_rm_col default_fg, theme_rm_col default_bg,
|
|
|
|
theme_rm_col *last_fg, theme_rm_col *last_bg,
|
2001-03-14 21:26:12 -05:00
|
|
|
char chr, int flags)
|
2000-10-27 19:06:26 -04:00
|
|
|
{
|
|
|
|
GSList *rec;
|
2000-10-27 20:04:21 -04:00
|
|
|
char *ret, *abstract, data[2];
|
2000-10-27 19:06:26 -04:00
|
|
|
|
|
|
|
rec = g_slist_nth(theme->replace_values, index);
|
|
|
|
g_return_val_if_fail(rec != NULL, NULL);
|
|
|
|
|
|
|
|
data[0] = chr; data[1] = '\0';
|
2000-10-27 20:04:21 -04:00
|
|
|
|
|
|
|
abstract = rec->data;
|
|
|
|
abstract = theme_format_expand_data(theme, (const char **) &abstract,
|
2001-03-14 21:26:12 -05:00
|
|
|
default_fg, default_bg,
|
|
|
|
last_fg, last_bg, flags);
|
2001-09-20 11:58:14 -04:00
|
|
|
ret = parse_special_string(abstract, NULL, NULL, data, NULL,
|
2001-09-20 12:50:27 -04:00
|
|
|
PARSE_FLAG_ONLY_ARGS);
|
2000-10-27 20:04:21 -04:00
|
|
|
g_free(abstract);
|
|
|
|
return ret;
|
2000-10-27 19:06:26 -04:00
|
|
|
}
|
|
|
|
|
2001-03-14 21:26:12 -05:00
|
|
|
static const char *fgcolorformats = "nkrgybmpcwKRGYBMPCW";
|
|
|
|
static const char *bgcolorformats = "n01234567";
|
2000-10-27 20:04:21 -04:00
|
|
|
|
2001-03-14 21:26:12 -05:00
|
|
|
#define IS_FGCOLOR_FORMAT(c) \
|
|
|
|
((c) != '\0' && strchr(fgcolorformats, c) != NULL)
|
|
|
|
#define IS_BGCOLOR_FORMAT(c) \
|
|
|
|
((c) != '\0' && strchr(bgcolorformats, c) != NULL)
|
2000-10-27 20:48:36 -04:00
|
|
|
|
|
|
|
/* 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,
|
2001-09-20 12:50:27 -04:00
|
|
|
args, &free_ret, NULL, PARSE_FLAG_ONLY_ARGS);
|
2000-10-27 20:48:36 -04:00
|
|
|
if (free_ret) g_free(value);
|
2002-02-17 04:37:23 -05:00
|
|
|
|
|
|
|
if (**format != '\0')
|
|
|
|
(*format)++;
|
2000-10-27 20:48:36 -04:00
|
|
|
|
|
|
|
/* append the variable name */
|
|
|
|
value = g_strndup(orig, (int) (*format-orig));
|
|
|
|
g_string_append(str, value);
|
|
|
|
g_free(value);
|
|
|
|
}
|
2000-10-27 20:04:21 -04:00
|
|
|
|
2014-01-09 09:20:29 -05:00
|
|
|
static inline int chr_is_valid_rgb(const char format[])
|
|
|
|
{
|
|
|
|
int tmp;
|
|
|
|
for (tmp = 1; tmp < 7; ++tmp) {
|
|
|
|
if (!isxdigit(format[tmp]))
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int chr_is_valid_ext(const char format[])
|
|
|
|
{
|
|
|
|
if (format[1] < '0' || format[1] > '7')
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (format[1] == '7') {
|
|
|
|
if (!isalpha(format[2]) || format[2] == 'y' || format[2] == 'Y'
|
|
|
|
|| format[2] =='z' || format[2] == 'Z')
|
|
|
|
return 2;
|
|
|
|
} else if (format[1] == '0') {
|
|
|
|
if (!isxdigit(format[2]))
|
|
|
|
return 2;
|
|
|
|
} else if (!isalnum(format[2]))
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-10-27 20:04:21 -04:00
|
|
|
/* append next "item", either a character, $variable or %format */
|
2000-10-27 19:06:26 -04:00
|
|
|
static void theme_format_append_next(THEME_REC *theme, GString *str,
|
2000-10-27 20:04:21 -04:00
|
|
|
const char **format,
|
2014-01-09 09:20:29 -05:00
|
|
|
theme_rm_col default_fg, theme_rm_col default_bg,
|
|
|
|
theme_rm_col *last_fg, theme_rm_col *last_bg,
|
2001-03-14 21:26:12 -05:00
|
|
|
int flags)
|
2000-10-27 19:06:26 -04:00
|
|
|
{
|
|
|
|
int index;
|
2001-03-24 11:03:05 -05:00
|
|
|
unsigned char chr;
|
2014-01-09 09:20:29 -05:00
|
|
|
char *t;
|
2000-10-27 20:04:21 -04:00
|
|
|
|
|
|
|
chr = **format;
|
|
|
|
if ((chr == '$' || chr == '%') &&
|
|
|
|
(*format)[1] == '\0') {
|
|
|
|
/* last char, always append */
|
|
|
|
g_string_append_c(str, chr);
|
|
|
|
(*format)++;
|
|
|
|
return;
|
|
|
|
}
|
2000-10-27 19:06:26 -04:00
|
|
|
|
2000-10-27 20:04:21 -04:00
|
|
|
if (chr == '$') {
|
2000-10-27 19:06:26 -04:00
|
|
|
/* $variable .. we'll always need to skip this, since it
|
|
|
|
may contain characters that are in replace chars. */
|
2000-10-27 20:48:36 -04:00
|
|
|
theme_format_append_variable(str, format);
|
2000-10-27 19:06:26 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2000-10-27 20:04:21 -04:00
|
|
|
if (**format == '%') {
|
|
|
|
/* format */
|
|
|
|
(*format)++;
|
|
|
|
if (**format != '{' && **format != '}') {
|
|
|
|
chr = **format;
|
2001-03-14 21:26:12 -05:00
|
|
|
if (**format == 'n') {
|
|
|
|
/* %n = change to default color */
|
2001-03-16 21:32:32 -05:00
|
|
|
g_string_append(str, "%n");
|
|
|
|
|
2014-01-09 09:20:29 -05:00
|
|
|
if (default_bg.m[0] != 'n') {
|
2001-03-14 21:26:12 -05:00
|
|
|
g_string_append_c(str, '%');
|
2014-01-09 09:20:29 -05:00
|
|
|
g_string_append(str, default_bg.m);
|
2001-03-14 21:26:12 -05:00
|
|
|
}
|
2014-01-09 09:20:29 -05:00
|
|
|
if (default_fg.m[0] != 'n') {
|
2001-03-14 21:26:12 -05:00
|
|
|
g_string_append_c(str, '%');
|
2014-01-09 09:20:29 -05:00
|
|
|
g_string_append(str, default_fg.m);
|
2001-03-14 21:26:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
*last_fg = default_fg;
|
|
|
|
*last_bg = default_bg;
|
2014-01-09 09:20:29 -05:00
|
|
|
} else if (chr == 'z' || chr == 'Z') {
|
|
|
|
if (chr_is_valid_rgb(*format) == 0) {
|
|
|
|
t = chr == 'z' ? (*last_bg).m : (*last_fg).m;
|
|
|
|
strncpy(t, *format, 7);
|
|
|
|
t[7] = '\0';
|
|
|
|
g_string_append_c(str, '%');
|
|
|
|
g_string_append(str, t);
|
|
|
|
(*format)+=6;
|
|
|
|
} else {
|
|
|
|
g_string_append(str, "%%");
|
|
|
|
g_string_append_c(str, **format);
|
|
|
|
}
|
|
|
|
} else if (chr == 'x' || chr == 'X') {
|
|
|
|
if (chr_is_valid_ext(*format) == 0) {
|
|
|
|
t = chr == 'x' ? (*last_bg).m : (*last_fg).m;
|
|
|
|
strncpy(t, *format, 3);
|
|
|
|
t[3] = '\0';
|
|
|
|
g_string_append_c(str, '%');
|
|
|
|
g_string_append(str, t);
|
|
|
|
(*format)+=2;
|
|
|
|
} else {
|
|
|
|
g_string_append(str, "%%");
|
|
|
|
g_string_append_c(str, **format);
|
|
|
|
}
|
2001-03-14 21:26:12 -05:00
|
|
|
} else {
|
2014-01-09 09:20:29 -05:00
|
|
|
if (IS_FGCOLOR_FORMAT(chr)) {
|
|
|
|
(*last_fg).m[0] = chr;
|
|
|
|
(*last_fg).m[1] = '\0';
|
|
|
|
}
|
|
|
|
if (IS_BGCOLOR_FORMAT(chr)) {
|
|
|
|
(*last_bg).m[0] = chr;
|
|
|
|
(*last_bg).m[1] = '\0';
|
|
|
|
}
|
2001-03-14 21:26:12 -05:00
|
|
|
g_string_append_c(str, '%');
|
|
|
|
g_string_append_c(str, chr);
|
|
|
|
}
|
2000-10-27 20:04:21 -04:00
|
|
|
(*format)++;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-10-21 13:56:42 -04:00
|
|
|
/* %{ or %} gives us { or } char - keep the % char
|
|
|
|
though to make sure {} isn't treated as abstract */
|
|
|
|
g_string_append_c(str, '%');
|
2000-10-27 20:04:21 -04:00
|
|
|
chr = **format;
|
|
|
|
}
|
|
|
|
|
2001-03-14 21:26:12 -05:00
|
|
|
index = (flags & EXPAND_FLAG_IGNORE_REPLACES) ? -1 :
|
2002-02-22 07:56:24 -05:00
|
|
|
theme->replace_keys[(int) (unsigned char) chr];
|
2000-10-27 19:06:26 -04:00
|
|
|
if (index == -1)
|
2000-10-27 20:04:21 -04:00
|
|
|
g_string_append_c(str, chr);
|
2000-10-27 19:06:26 -04:00
|
|
|
else {
|
2000-10-27 20:48:36 -04:00
|
|
|
char *value;
|
|
|
|
|
2001-03-14 21:26:12 -05:00
|
|
|
value = theme_replace_expand(theme, index,
|
|
|
|
default_fg, default_bg,
|
|
|
|
last_fg, last_bg, chr, flags);
|
2000-10-27 19:06:26 -04:00
|
|
|
g_string_append(str, value);
|
|
|
|
g_free(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
(*format)++;
|
|
|
|
}
|
|
|
|
|
2001-11-15 15:02:15 -05:00
|
|
|
/* returns TRUE if data is empty, or the data is a $variable which is empty */
|
|
|
|
static int data_is_empty(const char **data)
|
|
|
|
{
|
2001-11-19 11:38:00 -05:00
|
|
|
/* since we don't know the real argument list, assume there's always
|
|
|
|
an argument in them */
|
2002-09-14 19:23:57 -04:00
|
|
|
static char *arglist[] = {
|
2001-11-19 11:38:00 -05:00
|
|
|
"x", "x", "x", "x", "x", "x","x", "x", "x", "x",
|
|
|
|
NULL
|
|
|
|
};
|
2002-09-14 19:23:57 -04:00
|
|
|
SERVER_REC *server;
|
2001-11-15 15:02:15 -05:00
|
|
|
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++;
|
2002-09-14 19:23:57 -04:00
|
|
|
|
|
|
|
server = active_win == NULL ? NULL :
|
|
|
|
active_win->active_server != NULL ?
|
|
|
|
active_win->active_server : active_win->connect_server;
|
|
|
|
|
|
|
|
ret = parse_special((char **) &p, server,
|
2001-11-20 07:38:03 -05:00
|
|
|
active_win == NULL ? NULL : active_win->active,
|
|
|
|
arglist, &free_ret, NULL, 0);
|
2001-11-15 15:02:15 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2002-12-04 15:51:51 -05:00
|
|
|
/* return "data" from {abstract data} string */
|
|
|
|
char *theme_format_expand_get(THEME_REC *theme, const char **format)
|
|
|
|
{
|
|
|
|
GString *str;
|
2014-01-09 09:20:29 -05:00
|
|
|
char *ret;
|
|
|
|
theme_rm_col dummy, reset;
|
|
|
|
dummy.m[0] = '\0';
|
|
|
|
strcpy(reset.m, "n");
|
2002-12-04 15:51:51 -05:00
|
|
|
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--;
|
2002-12-11 05:00:51 -05:00
|
|
|
else if ((braces > 1) && (**format == ' ')) {
|
|
|
|
g_string_append(str, "\\x20");
|
|
|
|
(*format)++;
|
|
|
|
continue;
|
|
|
|
} else {
|
2002-12-04 15:51:51 -05:00
|
|
|
theme_format_append_next(theme, str, format,
|
2014-01-09 09:20:29 -05:00
|
|
|
reset, reset,
|
2002-12-04 15:51:51 -05:00
|
|
|
&dummy, &dummy, 0);
|
|
|
|
continue;
|
|
|
|
}
|
2014-09-11 13:10:33 -04:00
|
|
|
|
2002-12-04 15:51:51 -05:00
|
|
|
if (braces == 0) {
|
|
|
|
(*format)++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_string_append_c(str, **format);
|
|
|
|
(*format)++;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = str->str;
|
|
|
|
g_string_free(str, FALSE);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2000-10-27 19:06:26 -04:00
|
|
|
/* expand a single {abstract ...data... } */
|
|
|
|
static char *theme_format_expand_abstract(THEME_REC *theme,
|
2000-10-27 20:04:21 -04:00
|
|
|
const char **formatp,
|
2014-01-09 09:20:29 -05:00
|
|
|
theme_rm_col *last_fg,
|
|
|
|
theme_rm_col *last_bg,
|
2001-03-14 21:26:12 -05:00
|
|
|
int flags)
|
2000-10-27 19:06:26 -04:00
|
|
|
{
|
2002-12-11 05:00:51 -05:00
|
|
|
GString *str;
|
2000-10-27 19:06:26 -04:00
|
|
|
const char *p, *format;
|
|
|
|
char *abstract, *data, *ret;
|
2014-01-09 09:20:29 -05:00
|
|
|
theme_rm_col default_fg, default_bg;
|
2000-10-27 19:06:26 -04:00
|
|
|
int len;
|
|
|
|
|
|
|
|
format = *formatp;
|
2014-01-09 09:20:29 -05:00
|
|
|
default_fg = *last_fg;
|
|
|
|
default_bg = *last_bg;
|
2000-10-27 19:06:26 -04:00
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
2001-03-14 21:26:12 -05:00
|
|
|
/* skip the following space, if there's any more spaces they're
|
|
|
|
treated as arguments */
|
|
|
|
if (*p == ' ') {
|
|
|
|
len++;
|
2001-11-15 15:02:15 -05:00
|
|
|
if ((flags & EXPAND_FLAG_IGNORE_EMPTY) && data_is_empty(&p)) {
|
|
|
|
*formatp = p;
|
|
|
|
g_free(abstract);
|
|
|
|
return NULL;
|
2001-03-14 21:26:12 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
*formatp = format+len;
|
2000-10-27 19:06:26 -04:00
|
|
|
|
|
|
|
/* get the abstract data */
|
|
|
|
data = g_hash_table_lookup(theme->abstracts, abstract);
|
|
|
|
g_free(abstract);
|
|
|
|
if (data == NULL) {
|
2000-10-27 21:52:16 -04:00
|
|
|
/* unknown abstract, just display the data */
|
|
|
|
data = "$0-";
|
2000-10-27 19:06:26 -04:00
|
|
|
}
|
|
|
|
abstract = g_strdup(data);
|
|
|
|
|
2001-03-14 21:26:12 -05:00
|
|
|
/* we'll need to get the data part. it may contain
|
2002-12-04 15:51:51 -05:00
|
|
|
more abstracts, they are _NOT_ expanded. */
|
|
|
|
data = theme_format_expand_get(theme, formatp);
|
2000-11-26 00:08:11 -05:00
|
|
|
len = strlen(data);
|
2001-03-14 21:26:12 -05:00
|
|
|
|
2002-01-27 15:45:59 -05:00
|
|
|
if (len > 1 && i_isdigit(data[len-1]) && data[len-2] == '$') {
|
2000-11-26 00:08:11 -05:00
|
|
|
/* ends with $<digit> .. 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);
|
|
|
|
}
|
|
|
|
|
2001-09-20 11:58:14 -04:00
|
|
|
ret = parse_special_string(abstract, NULL, NULL, data, NULL,
|
2001-09-20 12:50:27 -04:00
|
|
|
PARSE_FLAG_ONLY_ARGS);
|
2000-10-27 19:06:26 -04:00
|
|
|
g_free(abstract);
|
2001-03-14 21:26:12 -05:00
|
|
|
g_free(data);
|
2002-12-11 05:00:51 -05:00
|
|
|
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);
|
2001-03-14 21:26:12 -05:00
|
|
|
|
|
|
|
/* abstract may itself contain abstracts or replaces */
|
|
|
|
p = abstract;
|
|
|
|
ret = theme_format_expand_data(theme, &p, default_fg, default_bg,
|
2014-01-09 09:20:29 -05:00
|
|
|
last_fg, last_bg,
|
2001-03-14 21:26:12 -05:00
|
|
|
flags | EXPAND_FLAG_LASTCOLOR_ARG);
|
|
|
|
g_free(abstract);
|
2000-10-27 19:06:26 -04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2000-10-27 20:48:36 -04:00
|
|
|
/* expand the data part in {abstract data} */
|
2001-03-14 21:26:12 -05:00
|
|
|
char *theme_format_expand_data(THEME_REC *theme, const char **format,
|
2014-01-09 09:20:29 -05:00
|
|
|
theme_rm_col default_fg, theme_rm_col default_bg,
|
|
|
|
theme_rm_col *save_last_fg, theme_rm_col *save_last_bg,
|
2001-03-14 21:26:12 -05:00
|
|
|
int flags)
|
2000-10-27 19:06:26 -04:00
|
|
|
{
|
|
|
|
GString *str;
|
|
|
|
char *ret, *abstract;
|
2014-01-09 09:20:29 -05:00
|
|
|
theme_rm_col last_fg, last_bg;
|
2001-03-14 21:26:12 -05:00
|
|
|
int recurse_flags;
|
2000-10-27 19:06:26 -04:00
|
|
|
|
2001-03-14 21:26:12 -05:00
|
|
|
last_fg = default_fg;
|
|
|
|
last_bg = default_bg;
|
|
|
|
recurse_flags = flags & EXPAND_FLAG_RECURSIVE_MASK;
|
2000-10-27 19:06:26 -04:00
|
|
|
|
2001-03-14 21:26:12 -05:00
|
|
|
str = g_string_new(NULL);
|
2000-10-27 19:06:26 -04:00
|
|
|
while (**format != '\0') {
|
2000-10-27 20:48:36 -04:00
|
|
|
if ((flags & EXPAND_FLAG_ROOT) == 0 && **format == '}') {
|
|
|
|
/* ignore } if we're expanding original string */
|
2000-10-27 19:06:26 -04:00
|
|
|
(*format)++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (**format != '{') {
|
2001-03-14 21:26:12 -05:00
|
|
|
if ((flags & EXPAND_FLAG_LASTCOLOR_ARG) &&
|
2000-10-27 20:04:21 -04:00
|
|
|
**format == '$' && (*format)[1] == '0') {
|
|
|
|
/* save the color before $0 ..
|
|
|
|
this is for the %n replacing */
|
2001-03-14 21:26:12 -05:00
|
|
|
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;
|
|
|
|
}
|
2000-10-27 20:04:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
theme_format_append_next(theme, str, format,
|
2001-03-14 21:26:12 -05:00
|
|
|
default_fg, default_bg,
|
|
|
|
&last_fg, &last_bg,
|
|
|
|
recurse_flags);
|
2000-10-27 19:06:26 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
(*format)++;
|
|
|
|
if (**format == '\0' || **format == '}')
|
|
|
|
break; /* error */
|
|
|
|
|
|
|
|
/* get a single {...} */
|
2000-10-27 20:04:21 -04:00
|
|
|
abstract = theme_format_expand_abstract(theme, format,
|
2014-01-09 09:20:29 -05:00
|
|
|
&last_fg, &last_bg,
|
2001-03-14 21:26:12 -05:00
|
|
|
recurse_flags);
|
2000-10-27 19:06:26 -04:00
|
|
|
if (abstract != NULL) {
|
|
|
|
g_string_append(str, abstract);
|
|
|
|
g_free(abstract);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-10-27 20:48:36 -04:00
|
|
|
/* save the last color */
|
2001-03-14 21:26:12 -05:00
|
|
|
if (save_last_fg != NULL)
|
|
|
|
*save_last_fg = last_fg;
|
|
|
|
if (save_last_bg != NULL)
|
|
|
|
*save_last_bg = last_bg;
|
2000-10-27 20:48:36 -04:00
|
|
|
|
|
|
|
ret = str->str;
|
|
|
|
g_string_free(str, FALSE);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2001-03-14 21:26:12 -05:00
|
|
|
#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))))
|
|
|
|
|
2000-10-27 20:48:36 -04:00
|
|
|
static char *theme_format_compress_colors(THEME_REC *theme, const char *format)
|
|
|
|
{
|
|
|
|
GString *str;
|
2014-01-09 09:20:29 -05:00
|
|
|
char *ret;
|
|
|
|
char last_fg, last_bg;
|
2000-10-27 20:48:36 -04:00
|
|
|
|
|
|
|
str = g_string_new(NULL);
|
|
|
|
|
2002-02-10 10:09:58 -05:00
|
|
|
last_fg = last_bg = '\0';
|
2000-10-27 20:48:36 -04:00
|
|
|
while (*format != '\0') {
|
|
|
|
if (*format == '$') {
|
|
|
|
/* $variable, skrip it entirely */
|
|
|
|
theme_format_append_variable(str, &format);
|
2001-03-14 21:26:12 -05:00
|
|
|
last_fg = last_bg = '\0';
|
2000-10-27 20:48:36 -04:00
|
|
|
} else if (*format != '%') {
|
|
|
|
/* a normal character */
|
|
|
|
g_string_append_c(str, *format);
|
|
|
|
format++;
|
|
|
|
} else {
|
|
|
|
/* %format */
|
|
|
|
format++;
|
2001-03-14 21:26:12 -05:00
|
|
|
if (IS_OLD_FORMAT(*format, last_fg, last_bg)) {
|
2000-10-27 20:48:36 -04:00
|
|
|
/* active color set again */
|
2001-03-14 21:26:12 -05:00
|
|
|
} else if (IS_FGCOLOR_FORMAT(*format) &&
|
2000-10-27 20:48:36 -04:00
|
|
|
format[1] == '%' &&
|
2001-07-25 15:16:21 -04:00
|
|
|
IS_FGCOLOR_FORMAT(format[2]) &&
|
|
|
|
(*format != 'n' || format[2] == 'n')) {
|
2001-03-14 21:26:12 -05:00
|
|
|
/* two fg colors in a row. bg colors are
|
|
|
|
so rare that we don't bother checking
|
|
|
|
them */
|
2000-10-27 20:48:36 -04:00
|
|
|
} else {
|
|
|
|
/* some format, add it */
|
|
|
|
g_string_append_c(str, '%');
|
|
|
|
g_string_append_c(str, *format);
|
|
|
|
|
2001-03-14 21:26:12 -05:00
|
|
|
if (IS_FGCOLOR_FORMAT(*format))
|
|
|
|
last_fg = *format;
|
2014-01-09 09:20:29 -05:00
|
|
|
else if (*format == 'Z' || *format == 'X')
|
|
|
|
last_fg = '\0';
|
2001-03-14 21:26:12 -05:00
|
|
|
if (IS_BGCOLOR_FORMAT(*format))
|
|
|
|
last_bg = *format;
|
2014-01-09 09:20:29 -05:00
|
|
|
else if (*format == 'z' || *format == 'x')
|
|
|
|
last_bg = '\0';
|
2000-10-27 20:48:36 -04:00
|
|
|
}
|
|
|
|
format++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-10-27 19:06:26 -04:00
|
|
|
ret = str->str;
|
|
|
|
g_string_free(str, FALSE);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2001-03-14 21:26:12 -05:00
|
|
|
char *theme_format_expand(THEME_REC *theme, const char *format)
|
2000-10-27 19:06:26 -04:00
|
|
|
{
|
2000-10-27 20:48:36 -04:00
|
|
|
char *data, *ret;
|
2014-01-09 09:20:29 -05:00
|
|
|
theme_rm_col reset;
|
|
|
|
strcpy(reset.m, "n");
|
2000-10-27 20:48:36 -04:00
|
|
|
|
2000-10-27 19:06:26 -04:00
|
|
|
g_return_val_if_fail(theme != NULL, NULL);
|
|
|
|
g_return_val_if_fail(format != NULL, NULL);
|
|
|
|
|
2014-01-09 09:20:29 -05:00
|
|
|
data = theme_format_expand_data(theme, &format, reset, reset, NULL, NULL,
|
2000-10-27 20:48:36 -04:00
|
|
|
EXPAND_FLAG_ROOT);
|
2001-03-14 21:26:12 -05:00
|
|
|
ret = theme_format_compress_colors(theme, data);
|
2000-10-27 20:48:36 -04:00
|
|
|
g_free(data);
|
|
|
|
return ret;
|
2000-10-27 19:06:26 -04:00
|
|
|
}
|
|
|
|
|
2000-05-15 04:25:45 -04:00
|
|
|
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);
|
2000-10-27 19:06:26 -04:00
|
|
|
rec->expanded_formats = g_new0(char *, rec->count);
|
2000-05-15 04:25:45 -04:00
|
|
|
|
|
|
|
g_hash_table_insert(theme->modules, rec->name, rec);
|
|
|
|
return rec;
|
|
|
|
}
|
|
|
|
|
2000-10-27 19:06:26 -04:00
|
|
|
static void theme_read_replaces(CONFIG_REC *config, THEME_REC *theme)
|
|
|
|
{
|
|
|
|
GSList *tmp;
|
|
|
|
CONFIG_NODE *node;
|
2001-03-14 21:26:12 -05:00
|
|
|
const char *p;
|
|
|
|
int index;
|
2000-10-27 19:06:26 -04:00
|
|
|
|
2001-03-14 21:26:12 -05:00
|
|
|
/* reset replace keys */
|
|
|
|
for (index = 0; index < 256; index++)
|
|
|
|
theme->replace_keys[index] = -1;
|
|
|
|
index = 0;
|
|
|
|
|
2001-03-24 11:03:05 -05:00
|
|
|
node = config_node_traverse(config, "replaces", FALSE);
|
|
|
|
if (node == NULL || node->type != NODE_TYPE_BLOCK) return;
|
|
|
|
|
2000-10-27 19:06:26 -04:00
|
|
|
for (tmp = node->value; tmp != NULL; tmp = tmp->next) {
|
|
|
|
node = tmp->data;
|
|
|
|
|
|
|
|
if (node->key != NULL && node->value != NULL) {
|
2001-03-14 21:26:12 -05:00
|
|
|
for (p = node->key; *p != '\0'; p++)
|
2002-02-22 07:56:24 -05:00
|
|
|
theme->replace_keys[(int) (unsigned char) *p] = index;
|
2001-03-14 21:26:12 -05:00
|
|
|
|
2000-10-27 19:06:26 -04:00
|
|
|
theme->replace_values =
|
|
|
|
g_slist_append(theme->replace_values,
|
|
|
|
g_strdup(node->value));
|
2001-03-14 21:26:12 -05:00
|
|
|
index++;
|
2000-10-27 19:06:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void theme_read_abstracts(CONFIG_REC *config, THEME_REC *theme)
|
|
|
|
{
|
|
|
|
GSList *tmp;
|
|
|
|
CONFIG_NODE *node;
|
2001-03-14 21:26:12 -05:00
|
|
|
gpointer oldkey, oldvalue;
|
2000-10-27 19:06:26 -04:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2001-03-14 21:26:12 -05:00
|
|
|
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);
|
2000-10-27 19:06:26 -04:00
|
|
|
}
|
2001-03-14 21:26:12 -05:00
|
|
|
|
|
|
|
g_hash_table_insert(theme->abstracts, g_strdup(node->key),
|
|
|
|
g_strdup(node->value));
|
2000-10-27 19:06:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void theme_set_format(THEME_REC *theme, MODULE_THEME_REC *rec,
|
2000-11-20 22:00:05 -05:00
|
|
|
const char *module,
|
2000-10-27 19:06:26 -04:00
|
|
|
const char *key, const char *value)
|
|
|
|
{
|
2000-11-20 22:00:05 -05:00
|
|
|
int num;
|
2000-10-27 19:06:26 -04:00
|
|
|
|
2000-11-20 22:00:05 -05:00
|
|
|
num = format_find_tag(module, key);
|
|
|
|
if (num != -1) {
|
|
|
|
rec->formats[num] = g_strdup(value);
|
|
|
|
rec->expanded_formats[num] = theme_format_expand(theme, value);
|
2000-10-27 19:06:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-10-27 21:52:16 -04:00
|
|
|
static void theme_read_formats(THEME_REC *theme, const char *module,
|
2000-11-20 22:00:05 -05:00
|
|
|
CONFIG_REC *config, MODULE_THEME_REC *rec)
|
2000-05-15 04:25:45 -04:00
|
|
|
{
|
|
|
|
CONFIG_NODE *node;
|
|
|
|
GSList *tmp;
|
|
|
|
|
|
|
|
node = config_node_traverse(config, "formats", FALSE);
|
|
|
|
if (node == NULL) return;
|
2015-01-06 21:40:34 -05:00
|
|
|
node = config_node_section(config, node, module, -1);
|
2000-05-15 04:25:45 -04:00
|
|
|
if (node == NULL) return;
|
|
|
|
|
|
|
|
for (tmp = node->value; tmp != NULL; tmp = tmp->next) {
|
|
|
|
node = tmp->data;
|
|
|
|
|
2000-10-27 19:06:26 -04:00
|
|
|
if (node->key != NULL && node->value != NULL) {
|
2000-11-20 22:00:05 -05:00
|
|
|
theme_set_format(theme, rec, module,
|
2000-10-27 19:06:26 -04:00
|
|
|
node->key, node->value);
|
2000-05-15 04:25:45 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-10-27 21:52:16 -04:00
|
|
|
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)
|
2000-11-20 22:00:05 -05:00
|
|
|
theme_read_formats(theme, module, config, rec);
|
2000-10-27 21:52:16 -04:00
|
|
|
|
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-01-04 14:01:01 -05:00
|
|
|
static void sig_print_errors(void)
|
|
|
|
{
|
2001-01-07 02:58:15 -05:00
|
|
|
init_finished = TRUE;
|
2001-01-04 14:01:01 -05:00
|
|
|
|
|
|
|
if (init_errors != NULL) {
|
|
|
|
signal_emit("gui dialog", 2, "error", init_errors);
|
|
|
|
g_free(init_errors);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-05-15 04:25:45 -04:00
|
|
|
static void theme_read_module(THEME_REC *theme, const char *module)
|
|
|
|
{
|
|
|
|
CONFIG_REC *config;
|
|
|
|
|
|
|
|
config = config_open(theme->path, -1);
|
2001-01-04 14:01:01 -05:00
|
|
|
if (config != NULL)
|
2000-10-27 21:52:16 -04:00
|
|
|
config_parse(config);
|
|
|
|
|
|
|
|
theme_init_module(theme, module, config);
|
2000-05-15 04:25:45 -04:00
|
|
|
|
2000-10-27 21:52:16 -04:00
|
|
|
if (config != NULL) config_close(config);
|
2000-05-15 04:25:45 -04:00
|
|
|
}
|
|
|
|
|
2000-07-31 17:16:09 -04:00
|
|
|
static void themes_read_module(const char *module)
|
|
|
|
{
|
|
|
|
g_slist_foreach(themes, (GFunc) theme_read_module, (void *) module);
|
|
|
|
}
|
|
|
|
|
2000-05-15 04:25:45 -04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2000-07-31 17:16:09 -04:00
|
|
|
static void themes_remove_module(const char *module)
|
|
|
|
{
|
|
|
|
g_slist_foreach(themes, (GFunc) theme_remove_module, (void *) module);
|
|
|
|
}
|
|
|
|
|
2000-05-15 04:25:45 -04:00
|
|
|
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);
|
2000-07-31 17:16:09 -04:00
|
|
|
themes_read_module(module);
|
2000-05-15 04:25:45 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void theme_unregister_module(const char *module)
|
|
|
|
{
|
2000-11-26 04:22:18 -05:00
|
|
|
gpointer key, value;
|
|
|
|
|
|
|
|
if (default_formats == NULL)
|
|
|
|
return; /* already uninitialized */
|
2000-05-15 04:25:45 -04:00
|
|
|
|
|
|
|
if (!g_hash_table_lookup_extended(default_formats, module, &key, &value))
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_hash_table_remove(default_formats, key);
|
|
|
|
g_free(key);
|
|
|
|
|
2000-07-31 17:16:09 -04:00
|
|
|
themes_remove_module(module);
|
2000-05-15 04:25:45 -04:00
|
|
|
}
|
|
|
|
|
2002-12-28 10:25:10 -05:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2000-04-26 04:03:38 -04:00
|
|
|
static THEME_REC *theme_find(const char *name)
|
|
|
|
{
|
|
|
|
GSList *tmp;
|
|
|
|
|
|
|
|
for (tmp = themes; tmp != NULL; tmp = tmp->next) {
|
|
|
|
THEME_REC *rec = tmp->data;
|
|
|
|
|
2014-06-10 12:06:19 -04:00
|
|
|
if (g_ascii_strcasecmp(rec->name, name) == 0)
|
2000-04-26 04:03:38 -04:00
|
|
|
return rec;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2001-02-19 20:12:47 -05:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-01-11 04:14:21 -05:00
|
|
|
THEME_REC *theme_load(const char *setname)
|
2000-07-31 17:16:09 -04:00
|
|
|
{
|
2001-02-19 20:54:14 -05:00
|
|
|
THEME_REC *theme, *oldtheme;
|
2000-07-31 17:16:09 -04:00
|
|
|
struct stat statbuf;
|
2001-01-11 04:14:21 -05:00
|
|
|
char *fname, *name, *p;
|
|
|
|
|
|
|
|
name = g_strdup(setname);
|
|
|
|
p = strrchr(name, '.');
|
2015-04-07 21:39:05 -04:00
|
|
|
if (p != NULL && g_strcmp0(p, ".theme") == 0) {
|
2001-01-11 04:14:21 -05:00
|
|
|
/* remove the trailing .theme */
|
|
|
|
*p = '\0';
|
|
|
|
}
|
2000-07-31 17:16:09 -04:00
|
|
|
|
|
|
|
theme = theme_find(name);
|
|
|
|
|
|
|
|
/* check home dir */
|
2001-07-14 20:39:48 -04:00
|
|
|
fname = g_strdup_printf("%s/%s.theme", get_irssi_dir(), name);
|
2000-07-31 17:16:09 -04:00
|
|
|
if (stat(fname, &statbuf) != 0) {
|
|
|
|
/* check global config dir */
|
|
|
|
g_free(fname);
|
2001-07-05 19:16:18 -04:00
|
|
|
fname = g_strdup_printf(THEMESDIR"/%s.theme", name);
|
2000-07-31 17:16:09 -04:00
|
|
|
if (stat(fname, &statbuf) != 0) {
|
|
|
|
/* theme not found */
|
|
|
|
g_free(fname);
|
2001-01-11 04:14:21 -05:00
|
|
|
g_free(name);
|
2001-02-19 20:12:47 -05:00
|
|
|
return theme; /* use the one in memory if possible */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-02-19 20:54:14 -05:00
|
|
|
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;
|
2000-07-31 17:16:09 -04:00
|
|
|
}
|
|
|
|
|
2001-02-19 20:54:14 -05:00
|
|
|
oldtheme = theme;
|
2000-07-31 17:16:09 -04:00
|
|
|
theme = theme_create(fname, name);
|
2001-02-19 20:12:47 -05:00
|
|
|
theme->last_modify = statbuf.st_mtime;
|
2002-12-28 10:25:10 -05:00
|
|
|
if (!theme_read(theme, theme->path)) {
|
2001-02-19 20:54:14 -05:00
|
|
|
/* error reading .theme file */
|
|
|
|
theme_destroy(theme);
|
|
|
|
theme = NULL;
|
|
|
|
}
|
2000-07-31 17:16:09 -04:00
|
|
|
|
2001-02-19 20:54:14 -05:00
|
|
|
if (oldtheme != NULL && theme != NULL) {
|
|
|
|
theme_destroy(oldtheme);
|
2002-12-23 03:36:25 -05:00
|
|
|
if (current_theme == oldtheme)
|
|
|
|
current_theme = theme;
|
2001-02-19 20:12:47 -05:00
|
|
|
window_themes_update();
|
|
|
|
}
|
|
|
|
|
2000-07-31 17:16:09 -04:00
|
|
|
g_free(fname);
|
2001-01-11 04:14:21 -05:00
|
|
|
g_free(name);
|
2000-07-31 17:16:09 -04:00
|
|
|
return theme;
|
|
|
|
}
|
|
|
|
|
2002-12-28 10:25:10 -05:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2000-07-31 17:16:09 -04:00
|
|
|
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)
|
|
|
|
{
|
2000-10-27 21:52:16 -04:00
|
|
|
theme_init_module(rec->theme, module, rec->config);
|
2000-07-31 17:16:09 -04:00
|
|
|
}
|
2000-04-26 04:03:38 -04:00
|
|
|
|
2001-02-19 20:54:14 -05:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-12-28 10:25:10 -05:00
|
|
|
static int theme_read(THEME_REC *theme, const char *path)
|
2000-04-26 04:03:38 -04:00
|
|
|
{
|
2000-07-31 17:16:09 -04:00
|
|
|
CONFIG_REC *config;
|
|
|
|
THEME_READ_REC rec;
|
2001-02-19 20:54:14 -05:00
|
|
|
char *str;
|
|
|
|
|
2002-12-28 10:25:10 -05:00
|
|
|
config = config_open(path, -1) ;
|
2001-02-19 20:54:14 -05:00
|
|
|
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;
|
|
|
|
}
|
2000-04-26 04:03:38 -04:00
|
|
|
|
2002-12-28 10:25:10 -05:00
|
|
|
if (path == NULL)
|
|
|
|
config_parse_data(config, default_theme, "internal");
|
2001-02-19 20:54:14 -05:00
|
|
|
else
|
|
|
|
config_parse(config);
|
2001-01-04 14:01:01 -05:00
|
|
|
|
|
|
|
if (config_last_error(config) != NULL) {
|
2001-05-17 16:13:59 -04:00
|
|
|
str = g_strdup_printf("Ignored errors in theme %s:\n%s",
|
2001-01-07 02:58:15 -05:00
|
|
|
theme->name, config_last_error(config));
|
2001-02-19 20:54:14 -05:00
|
|
|
read_error(str);
|
|
|
|
g_free(str);
|
2001-01-04 14:01:01 -05:00
|
|
|
}
|
|
|
|
|
2001-02-10 05:19:47 -05:00
|
|
|
theme->default_color =
|
2001-10-28 06:30:26 -05:00
|
|
|
config_get_int(config, NULL, "default_color", -1);
|
2002-03-10 09:55:46 -05:00
|
|
|
theme->info_eol = config_get_bool(config, NULL, "info_eol", FALSE);
|
|
|
|
|
2001-03-14 21:26:12 -05:00
|
|
|
theme_read_replaces(config, theme);
|
|
|
|
|
2002-12-29 11:11:16 -05:00
|
|
|
if (path != NULL)
|
2002-12-28 10:25:10 -05:00
|
|
|
theme_copy_abstracts(theme, internal_theme);
|
2000-10-27 19:06:26 -04:00
|
|
|
theme_read_abstracts(config, theme);
|
2000-07-31 17:16:09 -04:00
|
|
|
|
|
|
|
rec.theme = theme;
|
|
|
|
rec.config = config;
|
|
|
|
g_hash_table_foreach(default_formats,
|
|
|
|
(GHFunc) theme_read_modules, &rec);
|
2000-05-15 04:25:45 -04:00
|
|
|
config_close(config);
|
2001-02-19 20:54:14 -05:00
|
|
|
|
|
|
|
return TRUE;
|
2000-05-15 04:25:45 -04:00
|
|
|
}
|
2000-04-26 04:03:38 -04:00
|
|
|
|
2000-05-15 04:25:45 -04:00
|
|
|
typedef struct {
|
|
|
|
char *name;
|
|
|
|
char *short_name;
|
|
|
|
} THEME_SEARCH_REC;
|
|
|
|
|
|
|
|
static int theme_search_equal(THEME_SEARCH_REC *r1, THEME_SEARCH_REC *r2)
|
|
|
|
{
|
2014-06-10 12:06:19 -04:00
|
|
|
return g_ascii_strcasecmp(r1->short_name, r2->short_name);
|
2000-05-15 04:25:45 -04:00
|
|
|
}
|
2000-04-26 04:03:38 -04:00
|
|
|
|
2000-05-15 04:25:45 -04:00
|
|
|
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);
|
|
|
|
}
|
2000-04-26 04:03:38 -04:00
|
|
|
|
2000-05-15 04:25:45 -04:00
|
|
|
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;
|
|
|
|
|
2014-06-10 12:06:19 -04:00
|
|
|
if (g_ascii_strcasecmp(rec->short_name, module) == 0)
|
2000-05-15 04:25:45 -04:00
|
|
|
return rec;
|
|
|
|
list = list->next;
|
2000-04-26 04:03:38 -04:00
|
|
|
}
|
|
|
|
|
2000-05-15 04:25:45 -04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2000-06-28 18:25:07 -04:00
|
|
|
static void theme_show(THEME_SEARCH_REC *rec, const char *key, const char *value, int reset)
|
2000-05-15 04:25:45 -04:00
|
|
|
{
|
|
|
|
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;
|
2014-06-10 12:06:19 -04:00
|
|
|
else if ((value != NULL && key != NULL && g_ascii_strcasecmp(formats[n].tag, key) == 0) ||
|
2000-05-15 04:25:45 -04:00
|
|
|
(value == NULL && (key == NULL || stristr(formats[n].tag, key) != NULL))) {
|
|
|
|
if (first) {
|
2001-01-07 14:42:59 -05:00
|
|
|
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_FORMAT_TITLE, rec->short_name, formats[0].def);
|
2000-05-15 04:25:45 -04:00
|
|
|
first = FALSE;
|
2000-04-26 04:03:38 -04:00
|
|
|
}
|
2000-05-15 04:25:45 -04:00
|
|
|
if (last_title != NULL)
|
2001-01-07 14:42:59 -05:00
|
|
|
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_FORMAT_SUBTITLE, last_title);
|
2000-06-28 18:25:07 -04:00
|
|
|
if (reset || value != NULL) {
|
2000-05-15 04:25:45 -04:00
|
|
|
theme = theme_module_create(current_theme, rec->name);
|
2000-06-28 18:25:07 -04:00
|
|
|
g_free_not_null(theme->formats[n]);
|
2000-10-27 19:06:26 -04:00
|
|
|
g_free_not_null(theme->expanded_formats[n]);
|
2000-06-28 18:25:07 -04:00
|
|
|
|
|
|
|
text = reset ? formats[n].def : value;
|
2000-11-25 21:49:21 -05:00
|
|
|
theme->formats[n] = reset ? NULL : g_strdup(value);
|
|
|
|
theme->expanded_formats[n] = theme_format_expand(current_theme, text);
|
2000-05-15 04:25:45 -04:00
|
|
|
}
|
2001-01-07 14:42:59 -05:00
|
|
|
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_FORMAT_ITEM, formats[n].tag, text);
|
2000-05-15 04:25:45 -04:00
|
|
|
last_title = NULL;
|
2000-04-26 04:03:38 -04:00
|
|
|
}
|
|
|
|
}
|
2000-05-15 04:25:45 -04:00
|
|
|
}
|
|
|
|
|
2000-07-23 19:19:22 -04:00
|
|
|
/* SYNTAX: FORMAT [-delete | -reset] [<module>] [<key> [<value>]] */
|
2000-05-15 04:25:45 -04:00
|
|
|
static void cmd_format(const char *data)
|
|
|
|
{
|
2000-06-28 18:25:07 -04:00
|
|
|
GHashTable *optlist;
|
2000-05-15 04:25:45 -04:00
|
|
|
GSList *tmp, *modules;
|
2000-06-17 21:18:12 -04:00
|
|
|
char *module, *key, *value;
|
|
|
|
void *free_arg;
|
2000-06-28 18:25:07 -04:00
|
|
|
int reset;
|
2000-05-15 04:25:45 -04:00
|
|
|
|
2000-06-28 18:25:07 -04:00
|
|
|
if (!cmd_get_params(data, &free_arg, 3 | PARAM_FLAG_GETREST | PARAM_FLAG_OPTIONS,
|
|
|
|
"format", &optlist, &module, &key, &value))
|
2000-06-17 21:18:12 -04:00
|
|
|
return;
|
2000-05-15 04:25:45 -04:00
|
|
|
|
2000-07-10 19:00:56 -04:00
|
|
|
modules = get_sorted_modules();
|
|
|
|
if (*module == '\0')
|
|
|
|
module = NULL;
|
|
|
|
else if (theme_search(modules, module) == NULL) {
|
2000-05-15 04:25:45 -04:00
|
|
|
/* first argument isn't module.. */
|
2000-06-17 21:18:12 -04:00
|
|
|
cmd_params_free(free_arg);
|
2000-06-28 18:25:07 -04:00
|
|
|
if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST | PARAM_FLAG_OPTIONS,
|
|
|
|
"format", &optlist, &key, &value))
|
2000-06-17 21:18:12 -04:00
|
|
|
return;
|
2000-07-10 19:00:56 -04:00
|
|
|
module = NULL;
|
2000-05-15 04:25:45 -04:00
|
|
|
}
|
|
|
|
|
2000-06-28 18:25:07 -04:00
|
|
|
reset = FALSE;
|
2000-05-15 04:25:45 -04:00
|
|
|
if (*key == '\0') key = NULL;
|
2000-06-28 18:25:07 -04:00
|
|
|
if (g_hash_table_lookup(optlist, "reset"))
|
|
|
|
reset = TRUE;
|
|
|
|
else if (g_hash_table_lookup(optlist, "delete"))
|
|
|
|
value = "";
|
|
|
|
else if (*value == '\0')
|
|
|
|
value = NULL;
|
2000-05-15 04:25:45 -04:00
|
|
|
|
|
|
|
for (tmp = modules; tmp != NULL; tmp = tmp->next) {
|
|
|
|
THEME_SEARCH_REC *rec = tmp->data;
|
|
|
|
|
2014-06-10 12:06:19 -04:00
|
|
|
if (module == NULL || g_ascii_strcasecmp(rec->short_name, module) == 0)
|
2000-06-28 18:25:07 -04:00
|
|
|
theme_show(rec, key, value, reset);
|
2000-05-15 04:25:45 -04:00
|
|
|
}
|
|
|
|
g_slist_foreach(modules, (GFunc) g_free, NULL);
|
|
|
|
g_slist_free(modules);
|
2000-04-26 04:03:38 -04:00
|
|
|
|
2000-06-17 21:18:12 -04:00
|
|
|
cmd_params_free(free_arg);
|
2000-04-26 04:03:38 -04:00
|
|
|
}
|
|
|
|
|
2002-01-18 11:23:57 -05:00
|
|
|
typedef struct {
|
|
|
|
CONFIG_REC *config;
|
|
|
|
int save_all;
|
|
|
|
} THEME_SAVE_REC;
|
|
|
|
|
2000-12-02 18:53:35 -05:00
|
|
|
static void module_save(const char *module, MODULE_THEME_REC *rec,
|
2002-01-18 11:23:57 -05:00
|
|
|
THEME_SAVE_REC *data)
|
2000-04-26 04:03:38 -04:00
|
|
|
{
|
2000-12-02 18:53:35 -05:00
|
|
|
CONFIG_NODE *fnode, *node;
|
2000-05-15 04:25:45 -04:00
|
|
|
FORMAT_REC *formats;
|
|
|
|
int n;
|
|
|
|
|
2000-12-02 18:53:35 -05:00
|
|
|
formats = g_hash_table_lookup(default_formats, rec->name);
|
2000-05-15 04:25:45 -04:00
|
|
|
if (formats == NULL) return;
|
|
|
|
|
2002-01-18 11:23:57 -05:00
|
|
|
fnode = config_node_traverse(data->config, "formats", TRUE);
|
2000-12-02 18:53:35 -05:00
|
|
|
|
2015-01-06 21:40:34 -05:00
|
|
|
node = config_node_section(data->config, fnode, rec->name, NODE_TYPE_BLOCK);
|
2002-01-18 11:23:57 -05:00
|
|
|
for (n = 1; formats[n].def != NULL; n++) {
|
2000-12-02 18:53:35 -05:00
|
|
|
if (rec->formats[n] != NULL) {
|
2002-01-18 11:23:57 -05:00
|
|
|
config_node_set_str(data->config, node, formats[n].tag,
|
2000-12-02 18:53:35 -05:00
|
|
|
rec->formats[n]);
|
2002-01-18 11:23:57 -05:00
|
|
|
} else if (data->save_all && formats[n].tag != NULL) {
|
|
|
|
config_node_set_str(data->config, node, formats[n].tag,
|
|
|
|
formats[n].def);
|
|
|
|
}
|
2000-12-02 18:53:35 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (node->value == NULL) {
|
|
|
|
/* not modified, don't keep the empty section */
|
2002-01-18 11:23:57 -05:00
|
|
|
config_node_remove(data->config, fnode, node);
|
|
|
|
if (fnode->value == NULL) {
|
|
|
|
config_node_remove(data->config,
|
|
|
|
data->config->mainnode, fnode);
|
|
|
|
}
|
2000-12-02 18:53:35 -05:00
|
|
|
}
|
2000-05-15 04:25:45 -04:00
|
|
|
}
|
|
|
|
|
2002-01-18 11:23:57 -05:00
|
|
|
static void theme_save(THEME_REC *theme, int save_all)
|
2000-05-15 04:25:45 -04:00
|
|
|
{
|
|
|
|
CONFIG_REC *config;
|
2002-01-18 11:23:57 -05:00
|
|
|
THEME_SAVE_REC data;
|
2000-07-31 17:16:09 -04:00
|
|
|
char *path;
|
2014-06-16 11:45:26 -04:00
|
|
|
char *basename;
|
2000-07-31 17:16:09 -04:00
|
|
|
int ok;
|
2000-05-15 04:25:45 -04:00
|
|
|
|
2000-12-02 18:53:35 -05:00
|
|
|
config = config_open(theme->path, -1);
|
|
|
|
if (config != NULL)
|
|
|
|
config_parse(config);
|
|
|
|
else {
|
2008-03-09 08:01:16 -04:00
|
|
|
if (g_ascii_strcasecmp(theme->name, "default") == 0) {
|
2000-12-02 18:53:35 -05:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-01-18 11:23:57 -05:00
|
|
|
data.config = config;
|
|
|
|
data.save_all = save_all;
|
|
|
|
g_hash_table_foreach(theme->modules, (GHFunc) module_save, &data);
|
2000-05-15 04:25:45 -04:00
|
|
|
|
2014-06-16 11:45:26 -04:00
|
|
|
basename = g_path_get_basename(theme->path);
|
2001-03-03 16:16:40 -05:00
|
|
|
/* always save the theme to ~/.irssi/ */
|
2014-06-16 11:45:26 -04:00
|
|
|
path = g_strdup_printf("%s/%s", get_irssi_dir(), basename);
|
2001-03-03 16:16:40 -05:00
|
|
|
ok = config_write(config, path, 0660) == 0;
|
2014-06-16 11:45:26 -04:00
|
|
|
g_free(basename);
|
2001-03-03 16:16:40 -05:00
|
|
|
|
2000-07-31 17:16:09 -04:00
|
|
|
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
|
2001-01-07 14:42:59 -05:00
|
|
|
ok ? TXT_THEME_SAVED : TXT_THEME_SAVE_FAILED,
|
2000-07-31 17:16:09 -04:00
|
|
|
path, config_last_error(config));
|
2001-03-03 16:16:40 -05:00
|
|
|
|
2000-07-31 17:16:09 -04:00
|
|
|
g_free(path);
|
2000-05-15 04:25:45 -04:00
|
|
|
config_close(config);
|
2000-04-26 04:03:38 -04:00
|
|
|
}
|
|
|
|
|
2002-01-18 11:23:57 -05:00
|
|
|
/* save changed formats, -format saves all */
|
|
|
|
static void cmd_save(const char *data)
|
2000-07-31 17:16:09 -04:00
|
|
|
{
|
|
|
|
GSList *tmp;
|
2002-01-18 11:23:57 -05:00
|
|
|
GHashTable *optlist;
|
|
|
|
void *free_arg;
|
|
|
|
char *fname;
|
|
|
|
int saveall;
|
2000-07-31 17:16:09 -04:00
|
|
|
|
2002-01-18 11:23:57 -05:00
|
|
|
if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS,
|
|
|
|
"save", &optlist, &fname))
|
|
|
|
return;
|
|
|
|
|
|
|
|
saveall = g_hash_table_lookup(optlist, "formats") != NULL;
|
2000-07-31 17:16:09 -04:00
|
|
|
for (tmp = themes; tmp != NULL; tmp = tmp->next) {
|
|
|
|
THEME_REC *theme = tmp->data;
|
|
|
|
|
2002-01-18 11:23:57 -05:00
|
|
|
theme_save(theme, saveall);
|
2000-07-31 17:16:09 -04:00
|
|
|
}
|
2002-01-18 11:23:57 -05:00
|
|
|
|
|
|
|
cmd_params_free(free_arg);
|
2000-07-31 17:16:09 -04:00
|
|
|
}
|
|
|
|
|
2000-07-07 16:49:23 -04:00
|
|
|
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;
|
|
|
|
|
2014-06-10 12:06:19 -04:00
|
|
|
if (item != NULL && g_ascii_strncasecmp(item, key, len) == 0)
|
2000-07-07 16:49:23 -04:00
|
|
|
*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;
|
|
|
|
|
2014-06-10 12:06:19 -04:00
|
|
|
if (*module == '\0' || g_ascii_strcasecmp(rec->short_name, module) == 0)
|
2000-07-07 16:49:23 -04:00
|
|
|
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;
|
2005-09-10 09:19:20 -04:00
|
|
|
if (*ptr != '\0') {
|
|
|
|
do {
|
|
|
|
ptr++;
|
|
|
|
words++;
|
|
|
|
ptr = strchr(ptr, ' ');
|
|
|
|
} while (ptr != NULL);
|
|
|
|
}
|
2000-07-07 16:49:23 -04:00
|
|
|
|
|
|
|
if (words > 2)
|
|
|
|
return;
|
|
|
|
|
|
|
|
*list = completion_get_formats(line, word);
|
|
|
|
if (*list != NULL) signal_stop();
|
|
|
|
}
|
|
|
|
|
2001-02-19 20:12:47 -05:00
|
|
|
static void change_theme(const char *name, int verbose)
|
2000-04-26 04:03:38 -04:00
|
|
|
{
|
|
|
|
THEME_REC *rec;
|
2000-07-31 17:16:09 -04:00
|
|
|
|
2001-02-19 20:12:47 -05:00
|
|
|
rec = theme_load(name);
|
|
|
|
if (rec != NULL) {
|
|
|
|
current_theme = rec;
|
2002-02-15 19:08:47 -05:00
|
|
|
signal_emit("theme changed", 1, rec);
|
|
|
|
|
2001-02-19 20:12:47 -05:00
|
|
|
if (verbose) {
|
2001-06-28 13:43:53 -04:00
|
|
|
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
|
|
|
|
TXT_THEME_CHANGED,
|
|
|
|
rec->name, rec->path);
|
2001-01-11 04:14:21 -05:00
|
|
|
}
|
2001-02-19 20:12:47 -05:00
|
|
|
} else if (verbose) {
|
|
|
|
printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
|
|
|
|
TXT_THEME_NOT_FOUND, name);
|
2000-07-31 17:16:09 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-02-19 20:12:47 -05:00
|
|
|
static void read_settings(void)
|
|
|
|
{
|
|
|
|
const char *theme;
|
2001-06-29 19:10:48 -04:00
|
|
|
int len;
|
2001-02-19 20:12:47 -05:00
|
|
|
|
|
|
|
theme = settings_get_str("theme");
|
2001-06-29 19:10:48 -04:00
|
|
|
len = strlen(current_theme->name);
|
2015-04-07 21:39:05 -04:00
|
|
|
if (g_strcmp0(current_theme->name, theme) != 0 &&
|
2001-06-29 19:10:48 -04:00
|
|
|
(strncmp(current_theme->name, theme, len) != 0 ||
|
2015-04-07 21:39:05 -04:00
|
|
|
g_strcmp0(theme+len, ".theme") != 0))
|
2001-02-19 20:12:47 -05:00
|
|
|
change_theme(theme, TRUE);
|
|
|
|
}
|
|
|
|
|
2002-12-28 10:25:10 -05:00
|
|
|
void themes_reload(void)
|
2000-07-31 17:16:09 -04:00
|
|
|
{
|
2002-08-22 16:49:07 -04:00
|
|
|
GSList *refs;
|
2000-07-31 17:16:09 -04:00
|
|
|
char *fname;
|
2000-05-15 04:25:45 -04:00
|
|
|
|
2002-08-22 16:49:07 -04:00
|
|
|
/* 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);
|
|
|
|
}
|
2000-04-26 04:03:38 -04:00
|
|
|
|
|
|
|
/* first there's default theme.. */
|
2000-07-31 17:16:09 -04:00
|
|
|
current_theme = theme_load("default");
|
|
|
|
if (current_theme == NULL) {
|
2001-07-14 20:39:48 -04:00
|
|
|
fname = g_strdup_printf("%s/default.theme", get_irssi_dir());
|
2000-07-31 17:16:09 -04:00
|
|
|
current_theme = theme_create(fname, "default");
|
2001-10-28 06:30:26 -05:00
|
|
|
current_theme->default_color = -1;
|
2002-12-28 10:25:10 -05:00
|
|
|
theme_read(current_theme, NULL);
|
2000-07-31 17:16:09 -04:00
|
|
|
g_free(fname);
|
|
|
|
}
|
|
|
|
|
2001-02-19 20:12:47 -05:00
|
|
|
window_themes_update();
|
2002-08-22 16:49:07 -04:00
|
|
|
change_theme(settings_get_str("theme"), FALSE);
|
|
|
|
|
|
|
|
while (refs != NULL) {
|
|
|
|
theme_unref(refs->data);
|
|
|
|
refs = g_slist_remove(refs, refs->data);
|
|
|
|
}
|
2000-07-31 17:16:09 -04:00
|
|
|
}
|
|
|
|
|
2002-12-28 10:25:10 -05:00
|
|
|
static THEME_REC *read_internal_theme(void)
|
|
|
|
{
|
|
|
|
CONFIG_REC *config;
|
|
|
|
THEME_REC *theme;
|
|
|
|
|
|
|
|
theme = theme_create("internal", "_internal");
|
2008-05-23 07:19:43 -04:00
|
|
|
theme->refcount++;
|
|
|
|
theme_destroy(theme);
|
2002-12-28 10:25:10 -05:00
|
|
|
|
|
|
|
config = config_open(NULL, -1);
|
|
|
|
config_parse_data(config, default_theme, "internal");
|
|
|
|
theme_read_abstracts(config, theme);
|
|
|
|
config_close(config);
|
|
|
|
|
|
|
|
return theme;
|
|
|
|
}
|
|
|
|
|
2000-07-31 17:16:09 -04:00
|
|
|
void themes_init(void)
|
|
|
|
{
|
|
|
|
settings_add_str("lookandfeel", "theme", "default");
|
2000-04-26 04:03:38 -04:00
|
|
|
|
2000-07-31 17:16:09 -04:00
|
|
|
default_formats = g_hash_table_new((GHashFunc) g_str_hash,
|
|
|
|
(GCompareFunc) g_str_equal);
|
2002-12-28 10:25:10 -05:00
|
|
|
internal_theme = read_internal_theme();
|
2000-07-31 17:16:09 -04:00
|
|
|
|
2001-01-07 02:58:15 -05:00
|
|
|
init_finished = FALSE;
|
2001-01-04 14:01:01 -05:00
|
|
|
init_errors = NULL;
|
|
|
|
|
2002-12-28 10:25:10 -05:00
|
|
|
themes_reload();
|
2000-05-15 04:25:45 -04:00
|
|
|
|
|
|
|
command_bind("format", NULL, (SIGNAL_FUNC) cmd_format);
|
|
|
|
command_bind("save", NULL, (SIGNAL_FUNC) cmd_save);
|
2000-07-07 16:49:23 -04:00
|
|
|
signal_add("complete command format", (SIGNAL_FUNC) sig_complete_format);
|
2001-01-07 02:58:15 -05:00
|
|
|
signal_add("irssi init finished", (SIGNAL_FUNC) sig_print_errors);
|
2000-07-31 17:16:09 -04:00
|
|
|
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
|
2002-12-28 10:25:10 -05:00
|
|
|
signal_add("setup reread", (SIGNAL_FUNC) themes_reload);
|
2000-06-28 18:25:07 -04:00
|
|
|
|
|
|
|
command_set_options("format", "delete reset");
|
2002-01-18 11:23:57 -05:00
|
|
|
command_set_options("save", "formats");
|
2000-04-26 04:03:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void themes_deinit(void)
|
|
|
|
{
|
2000-07-31 17:16:09 -04:00
|
|
|
while (themes != NULL)
|
|
|
|
theme_destroy(themes->data);
|
2002-12-28 10:25:10 -05:00
|
|
|
theme_destroy(internal_theme);
|
2000-05-15 04:25:45 -04:00
|
|
|
|
|
|
|
g_hash_table_destroy(default_formats);
|
2000-11-26 04:22:18 -05:00
|
|
|
default_formats = NULL;
|
2000-05-15 04:25:45 -04:00
|
|
|
|
|
|
|
command_unbind("format", (SIGNAL_FUNC) cmd_format);
|
|
|
|
command_unbind("save", (SIGNAL_FUNC) cmd_save);
|
2000-07-07 16:49:23 -04:00
|
|
|
signal_remove("complete command format", (SIGNAL_FUNC) sig_complete_format);
|
2001-01-07 02:58:15 -05:00
|
|
|
signal_remove("irssi init finished", (SIGNAL_FUNC) sig_print_errors);
|
2000-07-31 17:16:09 -04:00
|
|
|
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
|
2002-12-28 10:25:10 -05:00
|
|
|
signal_remove("setup reread", (SIGNAL_FUNC) themes_reload);
|
2000-04-26 04:03:38 -04:00
|
|
|
}
|