--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dynamic-layout.diff Wed Aug 08 12:30:46 2012 +0300
@@ -0,0 +1,65 @@
+# HG changeset patch
+# Parent ebe29230ffb5572d2c37ab811d34ae970d6293ca
+[work-in-progress] Allow user to specify top to bottom window order
+
+diff -r ebe29230ffb5 mcabber/mcabber/utils.c
+--- a/mcabber/mcabber/utils.c Wed Aug 01 23:44:09 2012 +0300
++++ b/mcabber/mcabber/utils.c Fri Aug 03 14:35:36 2012 +0300
+@@ -650,6 +650,42 @@
+ g_free(arglst);
+ }
+
++// parse_list(arg, cb, udata)
++// Calls cb for every element in space/semicolon/comma-separated list.
++// Designed to work in-place, so, no escapes, quoting etc.
++// Terminates parsing if callback returns false.
++void parse_list(const char *arg, parse_list_cb_t cb, void *udata)
++{
++ const char *p, *start;
++ enum {
++ in_space,
++ in_string,
++ } state;
++
++ if (!arg)
++ return;
++
++ state = in_space;
++ while ( *p ) {
++ if ( *p == ' ' || *p == ';' || *p == ',' ) {
++ if ( state == in_string ) {
++ if ( ! cb ( start, p, udata ) )
++ return;
++ state = in_space;
++ }
++ } else {
++ if ( state == in_space ) {
++ start = p;
++ state = in_string;
++ }
++ }
++ p ++;
++ }
++
++ if ( state == in_string )
++ cb ( start, p, udata );
++}
++
+ // replace_nl_with_dots(bufstr)
+ // Replace '\n' with "(...)" (or with a NUL if the string is too short)
+ void replace_nl_with_dots(char *bufstr)
+diff -r ebe29230ffb5 mcabber/mcabber/utils.h
+--- a/mcabber/mcabber/utils.h Wed Aug 01 23:44:09 2012 +0300
++++ b/mcabber/mcabber/utils.h Fri Aug 03 14:35:36 2012 +0300
+@@ -43,6 +43,11 @@
+ char **split_arg(const char *arg, unsigned int n, int dontstriplast);
+ void free_arg_lst(char **arglst);
+
++/* fast in-place string split on space/semicolon/comma
++ * stops processing if callback returns false value */
++typedef int (*parse_list_cb_t)(const char *start, const char *end, void *udata);
++void parse_list(const char *arg, parse_list_cb_t cb, void *udata);
++
+ void replace_nl_with_dots(char *bufstr);
+ char *ut_expand_tabs(const char *text);
+
--- a/templates.diff Wed Aug 01 23:43:46 2012 +0300
+++ b/templates.diff Wed Aug 08 12:30:46 2012 +0300
@@ -1,10 +1,10 @@
# HG changeset patch
-# Parent 456d832740146c5c9a0428c9ca0a1a0c431481b0
+# Parent 9ad6f102a38b4e7b040f8efc311de6a2dda22805
[work-in-progress] Use templates for statusbars
-diff -r 456d83274014 mcabber/CMakeLists.txt
---- a/mcabber/CMakeLists.txt Fri Jul 20 17:29:53 2012 +0300
-+++ b/mcabber/CMakeLists.txt Fri Jul 20 17:30:20 2012 +0300
+diff -r 9ad6f102a38b mcabber/CMakeLists.txt
+--- a/mcabber/CMakeLists.txt Fri Aug 03 14:40:25 2012 +0300
++++ b/mcabber/CMakeLists.txt Mon Aug 06 22:53:57 2012 +0300
@@ -154,8 +154,8 @@
## Define targets
@@ -16,9 +16,9 @@
xmpp xmpp_helper xmpp_iq xmpp_iqrequest xmpp_muc xmpp_s10n )
if ( NOT MODULES_ENABLE )
list ( APPEND mcabber_SUBSYSTEMS extcmd fifo )
-diff -r 456d83274014 mcabber/mcabber/parser.c
+diff -r 9ad6f102a38b mcabber/mcabber/parser.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/mcabber/parser.c Fri Jul 20 17:30:20 2012 +0300
++++ b/mcabber/mcabber/parser.c Mon Aug 06 22:53:57 2012 +0300
@@ -0,0 +1,853 @@
+
+/* Copyright 2012 Myhailo Danylenko
@@ -873,9 +873,9 @@
+}
+
+/* vim: se ts=4 sw=4: */
-diff -r 456d83274014 mcabber/mcabber/parser.h
+diff -r 9ad6f102a38b mcabber/mcabber/parser.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/mcabber/parser.h Fri Jul 20 17:30:20 2012 +0300
++++ b/mcabber/mcabber/parser.h Mon Aug 06 22:53:57 2012 +0300
@@ -0,0 +1,77 @@
+
+#ifndef MCABBER_PARSER_H
@@ -954,10 +954,57 @@
+
+# endif
+
-diff -r 456d83274014 mcabber/mcabber/templates.c
+diff -r 9ad6f102a38b mcabber/mcabber/settings.c
+--- a/mcabber/mcabber/settings.c Fri Aug 03 14:40:25 2012 +0300
++++ b/mcabber/mcabber/settings.c Mon Aug 06 22:53:57 2012 +0300
+@@ -363,6 +363,32 @@
+ return 0;
+ }
+
++// settings_tmpl_set(option, value)
++// Sets option, escaping it for use in templates.
++// Could be more efficient with notifiers instead of guards.
++void settings_tmpl_set(const gchar *key, const gchar *value)
++{
++ if (value && *value) {
++ const gchar *p = strchr(value, '%');
++ if (p) {
++ GString *result = g_string_new(NULL);
++ const gchar *s = value;
++ while (p) {
++ g_string_append_len(result, s, p - s + 1);
++ g_string_append_c(result, '%');
++ s = ++ p;
++ p = strchr(s, '%');
++ }
++ if (*s)
++ g_string_append(result, s);
++ settings_set(SETTNIGS_TYPE_OPTION, key, result -> str);
++ g_string_free(result, TRUE);
++ return;
++ }
++ }
++ settings_set ( SETTNIGS_TYPE_OPTION, key, value );
++}
++
+ // settings_get_status_msg(status)
+ // Return a string with the current status message:
+ // - if there is a user-defined message ("message" option),
+diff -r 9ad6f102a38b mcabber/mcabber/settings.h
+--- a/mcabber/mcabber/settings.h Fri Aug 03 14:40:25 2012 +0300
++++ b/mcabber/mcabber/settings.h Mon Aug 06 22:53:57 2012 +0300
+@@ -37,6 +37,7 @@
+ void settings_opt_set_raw(const gchar *key, const gchar *value);
+ void settings_set(guint type, const gchar *key, const gchar *value);
+ void settings_del(guint type, const gchar *key);
++void settings_tmpl_set(const gchar *key, const gchar *value);
+ const gchar *settings_get(guint type, const gchar *key);
+ int settings_get_int(guint type, const gchar *key);
+ const gchar *settings_get_status_msg(enum imstatus status);
+diff -r 9ad6f102a38b mcabber/mcabber/templates.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/mcabber/templates.c Fri Jul 20 17:30:20 2012 +0300
-@@ -0,0 +1,277 @@
++++ b/mcabber/mcabber/templates.c Mon Aug 06 22:53:57 2012 +0300
+@@ -0,0 +1,368 @@
+
+/* Copyright 2012 Myhailo Danylenko
+ *
@@ -991,15 +1038,26 @@
+//
+
+typedef void (*tmpl_callback_t) ( const gchar * expansion, gpointer udata );
++typedef void (*tmpl_root_callback_t) ( const tmpl_link_struct_t * expansion, gpointer udata );
++
++typedef enum {
++ root_template, // fully processed $ and % templates
++ shortcut_template, // no-callback $-only but %-propagating templates
++ user_template, // $-only templates with callback
++} template_type_t;
+
+typedef struct {
-+ gchar * name;
-+ tmpl_callback_t callback;
-+ gpointer userdata;
-+ gboolean in_use;
-+ GSList * guards;
-+ gboolean changed;
-+ gchar * prev_expansion;
++ gchar * name; // variable name
++ template_type_t type; // can be only one (for simplicity)
++ tmpl_callback_t callback; // for root it is %-callback, for user it is $-callback
++ gpointer userdata; // userdata for callback
++ GSList * guards; // $-guards
++ gboolean in_use; // to mark root templates for drop
++ gboolean changed; // $-changed flag
++ gboolean chunk_changed; // %-changed flag
++ gchar * expansion; // expansion of template
++ GSList * templates; // root templates, that use this chunk template // roots? :D
++ GSList * chunks; // chunk templates in use by this root template
+} template_t;
+
+typedef struct {
@@ -1007,9 +1065,17 @@
+ GSList * templates;
+} tmpl_guard_t;
+
-+static GHashTable * tmpl_templates = NULL;
-+static GHashTable * tmpl_guards = NULL;
-+static guint tmpl_attached_id = 0;
++typedef struct tmpl_link_struct tmpl_link_t;
++struct tmpl_link_struct {
++ tmpl_link_type_t type;
++ guint color;
++ gchar * string;
++ tmpl_link_t * next;
++};
++
++static GHashTable * tmpl_templates = NULL;
++static GHashTable * tmpl_guards = NULL;
++static guint tmpl_attached_id = 0;
+
+//
+// predeclarations
@@ -1029,10 +1095,18 @@
+ guard -> templates = g_slist_remove ( guard -> templates, template );
+}
+
++// [cb] drops template from chunk's 'templates' list
++static void tmpl_unchunk ( gpointer data, gpointer udata )
++{
++ template_t * chunk = data;
++ template_t * template = udata;
++ chunk -> templates = g_slist_remove ( chunk -> templates, template );
++}
++
+// [destructor cb] releases guard hash table entry
+static void tmpl_free_guard ( gpointer data )
+{
-+ tmpl_guard_t *guard = data;
++ tmpl_guard_t * guard = data;
+ settings_del_guard ( guard -> name );
+ g_slist_free ( guard -> templates );
+ g_free ( guard -> name );
@@ -1042,14 +1116,32 @@
+// [destructor cb] releases taken guards and frees command
+static void tmpl_free_template ( gpointer data )
+{
-+ template_t *template = data;
++ template_t * template = data;
++ // not running unchunk, as it was done earlier
++ // or it is global destruction and chunk may no longer exist
++ g_slist_free ( template -> chunks );
++ g_slist_free ( template -> templates );
+ g_slist_foreach ( template -> guards, tmpl_unguard, template );
+ g_slist_free ( template -> guards );
+ g_free ( template -> name );
-+ g_free ( template -> prev_expansion );
++ g_free ( template -> expansion );
+ g_slice_free ( template_t, template );
+}
+
++// [cb] sets changed flag on template
++static void template_set_changed ( gpointer data, gpointer udata )
++{
++ template_t * template = data;
++ template -> changed = TRUE;
++}
++
++// [cb] sets chunk_changed flag on template
++static void template_set_chunk_changed ( gpointer data, gpointer udata )
++{
++ template_t * template = data;
++ template -> chunk_changed = TRUE;
++}
++
+// install guard (name must be glib-allocated string)
+static void tmpl_install_guard ( gchar *name, template_t *template, settings_guard_t callback )
+{
@@ -1092,24 +1184,17 @@
+ return result;
+}
+
-+// [cb] mark unused guards for removal
-+static gboolean tmpl_drop_unused_guards ( gpointer key, gpointer value, gpointer udata )
-+{
-+ tmpl_guard_t * guard = value;
-+ if ( guard -> templates == NULL )
-+ return TRUE;
-+ return FALSE;
-+}
-+
-+// [cb] mark deleted templates for removal, reevaluate changed
-+static gboolean reevaluate_template ( gpointer key, gpointer value, gpointer udata )
++// [cb]
++// drop dependencies for unused root templates,
++// update expansion of all $-changed templates,
++// reinstall guards,
++// mark dependencies as %-changed,
++// call $-callbacks
++static void evaluate_template1 ( gpointer key, gpointer value, gpointer udata )
+{
+ template_t * template = value;
+
-+ if ( ! template -> in_use )
-+ return TRUE;
-+
-+ if ( template -> changed ) {
++ if ( template -> changed && template -> in_use ) {
+ const gchar * expression = settings_opt_get ( template -> name );
+ gchar * expansion = NULL;
+ // release guards (but do not free them)
@@ -1130,15 +1215,71 @@
+ // re-install guard on template itself
+ tmpl_install_guard ( g_strdup ( template -> name ), template, tmpl_guard );
+ template -> changed = FALSE;
-+ // pass result to callback
-+ if ( g_strcmp0 ( expansion, template -> prev_expansion ) ) {
-+ g_free ( template -> prev_expansion );
-+ template -> prev_expansion = expansion;
-+ template -> callback ( expansion, template -> userdata );
++ // check, if expansion has changed
++ if ( g_strcmp0 ( expansion, template -> expansion ) ) {
++ g_free ( template -> expansion );
++ template -> expansion = expansion;
++ if ( template -> type == user_template )
++ // pass result to callback
++ template -> callback ( expansion, template -> userdata );
++ else if ( template -> type == chunk_template )
++ // mark %-dependencies as %-changed
++ g_slist_foreach ( template -> templates, tmpl_set_chunk_changed, NULL );
++ else if ( template -> type == root_template )
++ // mark self as %-changed
++ template -> chunk_changed = TRUE;
++ else
++ g_assert_not_reached ();
+ } else
+ g_free ( expansion );
+ }
++}
+
++// [cb]
++// evaluate %-changed templates,
++// rebuild dependencies, call %-callbacks
++static void evaluate_template2 ( gpointer key, gpointer value, gpointer udata )
++{
++ template_t * template = value;
++
++ if ( template -> type == root_template ) {
++ if ( ! template -> in_use ) {
++ // release chunks
++ g_slist_foreach ( template -> chunks, tmpl_unchunk, template );
++ g_slist_free ( template -> chunks );
++ template -> chunks = NULL;
++ } else if ( template -> chun_changed ) {
++ const char *expansion = template -> expansion;
++ // release chunks
++ g_slist_foreach ( template -> chunks, tmpl_unchunk, template );
++ g_slist_free ( template -> chunks );
++ template -> chunks = NULL;
++ // evaluate template
++ GError * error = NULL;
++ template_link_t * result = tmpl_chunk_expand ( expansion, tmpl_get_chunk, template, NULL, &error );
++ // FIXME
++ }
++ }
++}
++
++// [cb] mark deleted templates for removal
++static gboolean tmpl_drop_unused_templates ( gpointer key, gpointer value, gpointer udata )
++{
++ template_t * template = value;
++ if ( template -> type == chunk_template )
++ // drop chunk templates with no dependent root templates
++ return template -> templates == NULL;
++ else
++ // drop user templates, marked as unused
++ return ! template -> in_use;
++}
++
++// [cb] mark unused guards for removal
++static gboolean tmpl_drop_unused_guards ( gpointer key, gpointer value, gpointer udata )
++{
++ tmpl_guard_t * guard = value;
++ if ( guard -> templates == NULL )
++ return TRUE;
+ return FALSE;
+}
+
@@ -1147,8 +1288,12 @@
+{
+ // allow reschedule in a process of reevaluation
+ tmpl_attached_id = 0;
-+ // drop removed & reevaluate changed templates
-+ g_hash_table_foreach_remove ( tmpl_templates, reevaluate_template, NULL );
++ // release chunks of unused root templates, update expansion of $-changed templates, call $-callbacks
++ g_hash_table_foreach ( tmpl_templates, evaluate_template1, NULL );
++ // reevaluate %-changed templates, call %-callbacks
++ g_hash_table_foreach ( tmpl_templates, evaluate_template2, NULL );
++ // drop removed chunk-templates
++ g_hash_table_foreach_remove ( tmpl_templates, tmpl_drop_unused_templates, NULL );
+ // free unused guards TODO do only when needed
+ g_hash_table_foreach_remove ( tmpl_guards, tmpl_drop_unused_guards, NULL );
+ // always return false, this is oneshot idle call
@@ -1166,13 +1311,6 @@
+ }
+}
+
-+// [cb] sets changed flag on template
-+static void template_set_changed ( gpointer data, gpointer udata )
-+{
-+ template_t * template = data;
-+ template -> changed = TRUE;
-+}
-+
+// [guard] generic guard for variable
+static gchar *tmpl_guard ( const gchar *key, const gchar *new_value )
+{
@@ -1235,9 +1373,9 @@
+}
+
+/* vim: se ts=4 sw=4: */
-diff -r 456d83274014 mcabber/mcabber/templates.h
+diff -r 9ad6f102a38b mcabber/mcabber/templates.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/mcabber/templates.h Fri Jul 20 17:30:20 2012 +0300
++++ b/mcabber/mcabber/templates.h Mon Aug 06 22:53:57 2012 +0300
@@ -0,0 +1,44 @@
+
+/* Copyright 2012 Myhailo Danylenko
@@ -1283,64 +1421,3 @@
+void templates_uninit ( void );
+
+/* vim: se ts=4 sw=4: */
-diff -r 456d83274014 mcabber/mcabber/utils.c
---- a/mcabber/mcabber/utils.c Fri Jul 20 17:29:53 2012 +0300
-+++ b/mcabber/mcabber/utils.c Fri Jul 20 17:30:20 2012 +0300
-@@ -650,6 +650,42 @@
- g_free(arglst);
- }
-
-+// parse_list(arg, cb, udata)
-+// Calls cb for every element in space/semicolon/comma-separated list.
-+// Designed to work in-place, so, no escapes, quoting etc.
-+// Terminates parsing if callback returns false.
-+void parse_list(const char *arg, parse_list_cb_t cb, void *udata)
-+{
-+ const char *p, *start;
-+ enum {
-+ in_space,
-+ in_string,
-+ } state;
-+
-+ if (!arg)
-+ return;
-+
-+ state = in_space;
-+ while ( *p ) {
-+ if ( *p == ' ' || *p == ';' || *p == ',' ) {
-+ if ( state == in_string ) {
-+ if ( ! cb ( start, p, udata ) )
-+ return;
-+ state = in_space;
-+ }
-+ } else {
-+ if ( state == in_space ) {
-+ start = p;
-+ state = in_string;
-+ }
-+ }
-+ p ++;
-+ }
-+
-+ if ( state == in_string )
-+ cb ( start, p, udata );
-+}
-+
- // replace_nl_with_dots(bufstr)
- // Replace '\n' with "(...)" (or with a NUL if the string is too short)
- void replace_nl_with_dots(char *bufstr)
-diff -r 456d83274014 mcabber/mcabber/utils.h
---- a/mcabber/mcabber/utils.h Fri Jul 20 17:29:53 2012 +0300
-+++ b/mcabber/mcabber/utils.h Fri Jul 20 17:30:20 2012 +0300
-@@ -43,6 +43,11 @@
- char **split_arg(const char *arg, unsigned int n, int dontstriplast);
- void free_arg_lst(char **arglst);
-
-+/* fast in-place string split on space/semicolon/comma
-+ * stops processing if callback returns false value */
-+typedef int (*parse_list_cb_t)(const char *start, const char *end, void *udata);
-+void parse_list(const char *arg, parse_list_cb_t cb, void *udata);
-+
- void replace_nl_with_dots(char *bufstr);
- char *ut_expand_tabs(const char *text);
-