diff --git a/src/core/expandos.c b/src/core/expandos.c index 9114a3c9..4659f5ac 100644 --- a/src/core/expandos.c +++ b/src/core/expandos.c @@ -54,7 +54,10 @@ static time_t client_start_time; static char *last_sent_msg, *last_sent_msg_body; static char *last_privmsg_from, *last_public_from; static char *sysname, *sysrelease, *sysarch; + static const char *timestamp_format; +static int timestamp_seconds; +static time_t last_timestamp; #define CHAR_EXPANDO(chr) \ (char_expandos[(int) (unsigned char) chr]) @@ -209,6 +212,38 @@ void expando_unbind(const char *key, int funccount, SIGNAL_FUNC *funcs) } } +/* Returns [, EXPANDO_ARG_xxx, , ..., -1] */ +int *expando_get_signals(const char *key) +{ + EXPANDO_REC *rec; + int *signals; + int n; + + g_return_val_if_fail(key != NULL, NULL); + + rec = expando_find(key); + if (rec == NULL || rec->signals < 0) + return NULL; + + if (rec->signals == 0) { + /* it's unknown when this expando changes.. + check it once in a second */ + signals = g_new(int, 3); + signals[0] = signal_get_uniq_id("expando timer"); + signals[1] = EXPANDO_ARG_NONE; + signals[2] = -1; + return signals; + } + + signals = g_new(int, rec->signals*2+1); + for (n = 0; n < rec->signals; n++) { + signals[n*2] = rec->signal_ids[n]; + signals[n*2+1] = rec->signal_args[n]; + } + signals[rec->signals*2] = -1; + return signals; +} + EXPANDO_FUNC expando_find_char(char chr) { return CHAR_EXPANDO(chr) == NULL ? NULL : @@ -437,13 +472,41 @@ static void sig_message_own_private(SERVER_REC *server, const char *msg, static int sig_timer(void) { + time_t now; + struct tm *tm; + int last_min; + signal_emit("expando timer", 0); + + /* check if $Z has changed */ + now = time(NULL); + if (last_timestamp != now) { + if (!timestamp_seconds) { + /* assume it changes every minute */ + tm = localtime(&last_timestamp); + last_min = tm->tm_min; + + tm = localtime(&now); + if (tm->tm_min == last_min) + return 1; + } + + signal_emit("time changed", 0); + last_timestamp = now; + } + return 1; } static void read_settings(void) { - timestamp_format = settings_get_str("timestamp_format"); + timestamp_format = settings_get_str("timestamp_format"); + timestamp_seconds = + strstr(timestamp_format, "%r") != NULL || + strstr(timestamp_format, "%s") != NULL || + strstr(timestamp_format, "%S") != NULL || + strstr(timestamp_format, "%T") != NULL; + } void expandos_init(void) @@ -457,6 +520,7 @@ void expandos_init(void) client_start_time = time(NULL); last_sent_msg = NULL; last_sent_msg_body = NULL; last_privmsg_from = NULL; last_public_from = NULL; + last_timestamp = 0; sysname = sysrelease = sysarch = NULL; #ifdef HAVE_SYS_UTSNAME_H @@ -523,7 +587,8 @@ void expandos_init(void) expando_create("Y", expando_realname, "window changed", EXPANDO_ARG_NONE, "window server changed", EXPANDO_ARG_WINDOW, NULL); - expando_create("Z", expando_time, NULL); + expando_create("Z", expando_time, + "time changed", EXPANDO_ARG_NONE, NULL); expando_create("$", expando_dollar, "", EXPANDO_NEVER, NULL); diff --git a/src/core/expandos.h b/src/core/expandos.h index 3dcb527e..cf057994 100644 --- a/src/core/expandos.h +++ b/src/core/expandos.h @@ -5,7 +5,7 @@ /* first argument of signal must match to active .. */ typedef enum { - EXPANDO_ARG_NONE, + EXPANDO_ARG_NONE = 1, EXPANDO_ARG_SERVER, EXPANDO_ARG_WINDOW, EXPANDO_ARG_WINDOW_ITEM, @@ -28,6 +28,9 @@ void expando_destroy(const char *key, EXPANDO_FUNC func); void expando_bind(const char *key, int funccount, SIGNAL_FUNC *funcs); void expando_unbind(const char *key, int funccount, SIGNAL_FUNC *funcs); +/* Returns [, EXPANDO_ARG_xxx, , ..., -1] */ +int *expando_get_signals(const char *key); + /* internal: */ EXPANDO_FUNC expando_find_char(char chr); EXPANDO_FUNC expando_find_long(const char *key); diff --git a/src/core/special-vars.c b/src/core/special-vars.c index 19a0b1b2..442342b6 100644 --- a/src/core/special-vars.c +++ b/src/core/special-vars.c @@ -597,41 +597,126 @@ void special_history_func_set(SPECIAL_HISTORY_FUNC func) history_func = func; } -static void special_vars_signals_do(const char *text, int funccount, - SIGNAL_FUNC *funcs, int bind) +static void update_signals_hash(GHashTable **hash, int *signals) { - char *ret; - int need_free; + void *signal_id; + int arg_type; + if (*hash == NULL) { + *hash = g_hash_table_new((GHashFunc) g_direct_hash, + (GCompareFunc) g_direct_equal); + } + + while (*signals != -1) { + signal_id = GINT_TO_POINTER(*signals); + arg_type = GPOINTER_TO_INT(g_hash_table_lookup(*hash, signal_id)); + if (arg_type != 0 && arg_type != signals[1]) { + /* same signal is used for different purposes .. + not sure if this should ever happen, but change + the argument type to none so it will at least + work. */ + arg_type = EXPANDO_ARG_NONE; + } + + if (arg_type == 0) arg_type = signals[1]; + g_hash_table_insert(*hash, signal_id, + GINT_TO_POINTER(arg_type)); + signals += 2; + } +} + +static void get_signal_hash(void *signal_id, void *arg_type, int **pos) +{ + (*pos)[0] = GPOINTER_TO_INT(signal_id); + (*pos)[1] = GPOINTER_TO_INT(arg_type); + (*pos) += 2; +} + +static int *get_signals_list(GHashTable *hash) +{ + int *signals, *pos; + + if (hash == NULL) { + /* no expandos in text - never needs updating */ + return NULL; + } + + pos = signals = g_new(int, g_hash_table_size(hash)*2 + 1); + g_hash_table_foreach(hash, (GHFunc) get_signal_hash, &pos); + *pos = -1; + + g_hash_table_destroy(hash); + return signals; + +} + +#define TASK_BIND 1 +#define TASK_UNBIND 2 +#define TASK_GET_SIGNALS 3 + +static int *special_vars_signals_task(const char *text, int funccount, + SIGNAL_FUNC *funcs, int task) +{ + GHashTable *signals; + char *expando; + int need_free, *expando_signals; + + signals = NULL; while (*text != '\0') { if (*text == '\\' && text[1] != '\0') { + /* escape */ text += 2; } else if (*text == '$' && text[1] != '\0') { + /* expando */ text++; - ret = parse_special((char **) &text, NULL, NULL, - NULL, &need_free, NULL, - PARSE_FLAG_GETNAME); - if (ret != NULL) { - if (bind) - expando_bind(ret, funccount, funcs); - else - expando_unbind(ret, funccount, funcs); - if (need_free) g_free(ret); - } + expando = parse_special((char **) &text, NULL, NULL, + NULL, &need_free, NULL, + PARSE_FLAG_GETNAME); + if (expando == NULL) + continue; + switch (task) { + case TASK_BIND: + expando_bind(expando, funccount, funcs); + break; + case TASK_UNBIND: + expando_unbind(expando, funccount, funcs); + break; + case TASK_GET_SIGNALS: + expando_signals = expando_get_signals(expando); + if (expando_signals != NULL) { + update_signals_hash(&signals, + expando_signals); + g_free(expando_signals); + } + break; + } + if (need_free) g_free(expando); + } else { + /* just a char */ + text++; } - else text++; } + + if (task == TASK_GET_SIGNALS) + return get_signals_list(signals); + + return NULL; } void special_vars_add_signals(const char *text, int funccount, SIGNAL_FUNC *funcs) { - special_vars_signals_do(text, funccount, funcs, TRUE); + special_vars_signals_task(text, funccount, funcs, TASK_BIND); } void special_vars_remove_signals(const char *text, int funccount, SIGNAL_FUNC *funcs) { - special_vars_signals_do(text, funccount, funcs, FALSE); + special_vars_signals_task(text, funccount, funcs, TASK_UNBIND); +} + +int *special_vars_get_signals(const char *text) +{ + return special_vars_signals_task(text, 0, NULL, TASK_GET_SIGNALS); } diff --git a/src/core/special-vars.h b/src/core/special-vars.h index c27a50a8..11262dad 100644 --- a/src/core/special-vars.h +++ b/src/core/special-vars.h @@ -31,5 +31,7 @@ void special_vars_add_signals(const char *text, int funccount, SIGNAL_FUNC *funcs); void special_vars_remove_signals(const char *text, int funccount, SIGNAL_FUNC *funcs); +/* Returns [, EXPANDO_ARG_xxx, , ..., -1] */ +int *special_vars_get_signals(const char *text); #endif