From 3a922c3c1acd08bc59ffec419aa555cbecb1f3da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?= Date: Sun, 5 Jul 2015 15:57:53 +0200 Subject: [PATCH] degesch: start using "on_change" notifications Terminal attributes can be changed on the fly now. --- common.c | 18 +++++++++++-- degesch.c | 77 +++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 68 insertions(+), 27 deletions(-) diff --git a/common.c b/common.c index b116266..95590f5 100644 --- a/common.c +++ b/common.c @@ -1911,8 +1911,6 @@ config_schema_initialize_item (struct config_schema *schema, item->schema = schema; item->user_data = user_data; - if (schema->on_change) - schema->on_change (item); } static void @@ -1924,6 +1922,22 @@ config_schema_apply_to_object (struct config_schema *schema_array, config_schema_initialize_item (schema_array++, object, user_data); } +static void +config_schema_call_changed (struct config_item_ *item) +{ + if (item->type == CONFIG_ITEM_OBJECT) + { + struct str_map_iter iter; + str_map_iter_init (&iter, &item->value.object); + + struct config_item_ *child; + while ((child = str_map_iter_next (&iter))) + config_schema_call_changed (child); + } + else if (item->schema && item->schema->on_change) + item->schema->on_change (item); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // XXX: this doesn't necessarily have to be well designed at all diff --git a/degesch.c b/degesch.c index 80625a0..95e324f 100644 --- a/degesch.c +++ b/degesch.c @@ -1288,6 +1288,8 @@ server_destroy (void *self) struct app_context { + char *attrs_defaults[ATTR_COUNT]; ///< Default terminal attributes + // Configuration: struct config config; ///< Program configuration @@ -1380,7 +1382,10 @@ app_context_free (struct app_context *self) { config_free (&self->config); for (size_t i = 0; i < ATTR_COUNT; i++) + { + free (self->attrs_defaults[i]); free (self->attrs[i]); + } LIST_FOR_EACH (struct buffer, iter, self->buffers) { @@ -1411,7 +1416,8 @@ static bool irc_is_this_us (struct server *s, const char *prefix); // --- Configuration ----------------------------------------------------------- -// TODO: eventually add "on_change" callbacks +// TODO: "on_change" callbacks for everything +static void on_config_attribute_change (struct config_item_ *item); static bool config_validate_nonjunk_string @@ -1565,7 +1571,8 @@ static struct config_schema g_config_behaviour[] = static struct config_schema g_config_attributes[] = { -#define XX(x, y, z) { .name = y, .comment = z, .type = CONFIG_ITEM_STRING }, +#define XX(x, y, z) { .name = y, .comment = z, .type = CONFIG_ITEM_STRING, \ + .on_change = on_config_attribute_change }, ATTR_TABLE (XX) #undef XX {} @@ -1862,7 +1869,7 @@ log_message_attributed (void *user_data, const char *quote, const char *fmt, } static void -init_attribute (struct app_context *ctx, int id, const char *default_) +on_config_attribute_change (struct config_item_ *item) { static const char *table[ATTR_COUNT] = { @@ -1871,19 +1878,22 @@ init_attribute (struct app_context *ctx, int id, const char *default_) #undef XX }; - const char *user = get_config_string (ctx->config.root, table[id]); - if (user) - ctx->attrs[id] = xstrdup (user); - else - ctx->attrs[id] = xstrdup (default_); + struct app_context *ctx = item->user_data; + for (int id = 0; id < ATTR_COUNT; id++) + { + const char *user = get_config_string (ctx->config.root, table[id]); + free (ctx->attrs[id]); + ctx->attrs[id] = xstrdup (user ? user : ctx->attrs_defaults[id]); + } } static void init_colors (struct app_context *ctx) { bool have_ti = init_terminal (); + char **defaults = ctx->attrs_defaults; -#define INIT_ATTR(id, ti) init_attribute (ctx, ATTR_ ## id, have_ti ? (ti) : "") +#define INIT_ATTR(id, ti) defaults[ATTR_ ## id] = xstrdup (have_ti ? (ti) : "") INIT_ATTR (PROMPT, enter_bold_mode); INIT_ATTR (RESET, exit_attribute_mode); @@ -1913,6 +1923,10 @@ init_colors (struct app_context *ctx) } g_log_message_real = log_message_attributed; + + // Apply the default values so that we start with any formatting at all + config_schema_call_changed + (config_item_get (ctx->config.root, "attributes", NULL)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -8343,7 +8357,7 @@ load_configuration_file (const char *filename, struct error **e) struct error *error = NULL; if (!(root = config_item_parse (data.str, data.len, false, &error))) { - error_set (e, "configuration parse error: %s", error->message); + error_set (e, "Configuration parse error: %s", error->message); error_free (error); } end: @@ -8361,20 +8375,21 @@ load_configuration (struct app_context *ctx) if (filename) root = load_configuration_file (filename, &e); else - print_status ("configuration file not found"); + log_global_error (ctx, "Configuration file not found"); free (filename); if (e) { - print_error ("%s", e->message); + log_global_error (ctx, "#s", e->message); error_free (e); - e = NULL; } - - config_load (&ctx->config, root ? root : config_item_object ()); - - ctx->isolate_buffers = - get_config_boolean (ctx->config.root, "behaviour.isolate_buffers"); + if (root) + { + config_item_destroy (ctx->config.root); + ctx->config.root = NULL; + config_load (&ctx->config, root); + log_global_status (ctx, "Configuration loaded"); + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -8408,8 +8423,8 @@ load_server_from_config (struct app_context *ctx, buffer_add (ctx, buffer); buffer_activate (ctx, buffer); - // This fires any "on_change" callbacks config_schema_apply_to_object (g_config_server, subtree, s); + config_schema_call_changed (subtree); // XXX: is this desirable in here? I think we should do it only when // actually creating a new server instead of every time we load them. @@ -8427,7 +8442,7 @@ load_server_from_config (struct app_context *ctx, } static void -init_servers (struct app_context *ctx) +load_servers (struct app_context *ctx) { struct config_item_ *servers = config_item_get (ctx->config.root, "servers", NULL); @@ -8713,14 +8728,26 @@ main (int argc, char *argv[]) SSL_load_error_strings (); atexit (ERR_free_strings); - setup_signal_handlers (); + // Bootstrap configuration, so that we can access schema items at all register_config_modules (&ctx); + config_load (&ctx.config, config_item_object ()); + + // The following part is a bit brittle because of interdependencies + setup_signal_handlers (); + init_colors (&ctx); + init_global_buffer (&ctx); + init_poller_events (&ctx); load_configuration (&ctx); - init_colors (&ctx); - init_poller_events (&ctx); - init_global_buffer (&ctx); - init_servers (&ctx); + // TODO: this won't be needed after adding an "on_change" callback + ctx.isolate_buffers = + get_config_boolean (ctx.config.root, "behaviour.isolate_buffers"); + + // At this moment we can safely call any "on_change" callbacks + config_schema_call_changed (ctx.config.root); + + // Finally, we juice the configuration for some servers to create + load_servers (&ctx); refresh_prompt (&ctx); input_start (&ctx.input, argv[0]);