From 3a922c3c1acd08bc59ffec419aa555cbecb1f3da Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
Date: Sun, 5 Jul 2015 15:57:53 +0200
Subject: degesch: start using "on_change" notifications
Terminal attributes can be changed on the fly now.
---
common.c | 18 +++++++++++++--
degesch.c | 75 +++++++++++++++++++++++++++++++++++++++++++--------------------
2 files changed, 67 insertions(+), 26 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);
- load_configuration (&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_poller_events (&ctx);
init_global_buffer (&ctx);
- init_servers (&ctx);
+ init_poller_events (&ctx);
+ load_configuration (&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]);
--
cgit v1.2.3-70-g09d2