# HG changeset patch # User Myhailo Danylenko # Date 1344418246 -10800 # Node ID 0ee5e9903fa1085ecb2e88ebf56aa877c411e2ee # Parent 446ad24e6187a842f81032e954dac461b9e27cf8 Add fix-create-new-cat.diff diff -r 446ad24e6187 -r 0ee5e9903fa1 dynamic-layout.diff --- /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); + diff -r 446ad24e6187 -r 0ee5e9903fa1 fix-create-new-cat.diff --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fix-create-new-cat.diff Wed Aug 08 12:30:46 2012 +0300 @@ -0,0 +1,20 @@ +# HG changeset patch +# Parent 26edaf6ea10b8db2ed07da3e4ad9bee03077de84 + +diff -r 26edaf6ea10b mcabber/mcabber/compl.c +--- a/mcabber/mcabber/compl.c Mon Jul 30 22:39:17 2012 +0200 ++++ b/mcabber/mcabber/compl.c Wed Aug 08 12:15:20 2012 +0300 +@@ -97,10 +97,11 @@ + // as it is likely to change in future. + guint compl_new_category(void) + { ++ const guint maxcat = 8 * sizeof (registered_cats); + guint i = 0; +- while ((registered_cats >> i) & 1) ++ while ((registered_cats >> i) & 1 && i < maxcat) + i++; +- if (i >= 8 * sizeof (registered_cats)) ++ if (i >= maxcat) + return 0; + else { + guint64 id = 1 << i; diff -r 446ad24e6187 -r 0ee5e9903fa1 series --- a/series Wed Aug 01 23:43:46 2012 +0300 +++ b/series Wed Aug 08 12:30:46 2012 +0300 @@ -1,3 +1,4 @@ +fix-create-new-cat.diff update-help.diff add-offline-message.diff fix-receipts.diff @@ -8,4 +9,5 @@ roster-state-colors.diff add-cmake.diff use-gslice.diff +dynamic-layout.diff templates.diff diff -r 446ad24e6187 -r 0ee5e9903fa1 templates.diff --- 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); -