Added SILC Thread Queue API
[crypto.git] / apps / irssi / src / fe-text / statusbar-config.c
1 /*
2  statusbar-config.c : irssi
3
4     Copyright (C) 2001 Timo Sirainen
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "module.h"
22 #include "module-formats.h"
23 #include "signals.h"
24 #include "commands.h"
25 #include "settings.h"
26 #include "levels.h"
27 #include "lib-config/iconfig.h"
28
29 #include "statusbar.h"
30 #include "printtext.h"
31
32 static void read_statusbar_config_from_node(CONFIG_NODE *node);
33
34 static STATUSBAR_CONFIG_REC *
35 statusbar_config_create(STATUSBAR_GROUP_REC *group, const char *name)
36 {
37         STATUSBAR_CONFIG_REC *bar;
38
39         g_return_val_if_fail(group != NULL, NULL);
40         g_return_val_if_fail(name != NULL, NULL);
41
42         bar = g_new0(STATUSBAR_CONFIG_REC, 1);
43         group->config_bars = g_slist_append(group->config_bars, bar);
44
45         bar->name = g_strdup(name);
46         return bar;
47 }
48
49 static SBAR_ITEM_CONFIG_REC *
50 statusbar_item_config_create(STATUSBAR_CONFIG_REC *bar, const char *name,
51                              int priority, int right_alignment)
52 {
53         SBAR_ITEM_CONFIG_REC *rec;
54
55         g_return_val_if_fail(bar != NULL, NULL);
56         g_return_val_if_fail(name != NULL, NULL);
57
58         rec = g_new0(SBAR_ITEM_CONFIG_REC, 1);
59         bar->items = g_slist_append(bar->items, rec);
60
61         rec->name = g_strdup(name);
62         rec->priority = priority;
63         rec->right_alignment = right_alignment;
64
65         return rec;
66 }
67
68 static void statusbar_config_item_destroy(STATUSBAR_CONFIG_REC *barconfig,
69                                           SBAR_ITEM_CONFIG_REC *itemconfig)
70 {
71         barconfig->items = g_slist_remove(barconfig->items, itemconfig);
72
73         g_free(itemconfig->name);
74         g_free(itemconfig);
75 }
76
77 void statusbar_config_destroy(STATUSBAR_GROUP_REC *group,
78                               STATUSBAR_CONFIG_REC *config)
79 {
80         group->config_bars = g_slist_remove(group->config_bars, config);
81
82         while (config->items != NULL)
83                 statusbar_config_item_destroy(config, config->items->data);
84
85         g_free(config->name);
86         g_free(config);
87 }
88
89 static STATUSBAR_CONFIG_REC *
90 statusbar_config_find(STATUSBAR_GROUP_REC *group, const char *name)
91 {
92         GSList *tmp;
93
94         for (tmp = group->config_bars; tmp != NULL; tmp = tmp->next) {
95                 STATUSBAR_CONFIG_REC *config = tmp->data;
96
97                 if (strcmp(config->name, name) == 0)
98                         return config;
99         }
100
101         return NULL;
102 }
103
104 static void statusbar_reset_defaults(void)
105 {
106         CONFIG_REC *config;
107         CONFIG_NODE *node;
108
109         while (statusbar_groups != NULL)
110                 statusbar_group_destroy(statusbar_groups->data);
111         active_statusbar_group = NULL;
112
113         /* read the default statusbar settings from internal config */
114         config = config_open(NULL, -1);
115         config_parse_data(config, default_config, "internal");
116         node = config_node_traverse(config, "statusbar", FALSE);
117         if (node != NULL)
118                 read_statusbar_config_from_node(node);
119         config_close(config);
120 }
121
122 static void statusbar_read_items(CONFIG_NODE *items)
123 {
124         GSList *tmp;
125
126         tmp = config_node_first(items->value);
127         for (; tmp != NULL; tmp = config_node_next(tmp)) {
128                 CONFIG_NODE *node = tmp->data;
129
130                 statusbar_item_register(node->key, node->value, NULL);
131         }
132 }
133
134 static void statusbar_read_item(STATUSBAR_CONFIG_REC *bar, CONFIG_NODE *node)
135 {
136         int priority, right_alignment;
137
138         priority = config_node_get_int(node, "priority", 0);
139         right_alignment = strcmp(config_node_get_str(node, "alignment", ""), "right") == 0;
140         statusbar_item_config_create(bar, node->key,
141                                      priority, right_alignment);
142 }
143
144 static void statusbar_read(STATUSBAR_GROUP_REC *group, CONFIG_NODE *node)
145 {
146         STATUSBAR_CONFIG_REC *bar;
147         GSList *tmp;
148         const char *visible_str;
149
150         bar = statusbar_config_find(group, node->key);
151         if (config_node_get_bool(node, "disabled", FALSE)) {
152                 /* disabled, destroy it if it already exists */
153                 if (bar != NULL)
154                         statusbar_config_destroy(group, bar);
155                 return;
156         }
157
158         if (bar == NULL) {
159                 bar = statusbar_config_create(group, node->key);
160                 bar->type = STATUSBAR_TYPE_ROOT;
161                 bar->placement = STATUSBAR_BOTTOM;
162                 bar->position = 0;
163         }
164
165         visible_str = config_node_get_str(node, "visible", "");
166         if (g_strcasecmp(visible_str, "active") == 0)
167                 bar->visible = STATUSBAR_VISIBLE_ACTIVE;
168         else if (g_strcasecmp(visible_str, "inactive") == 0)
169                 bar->visible = STATUSBAR_VISIBLE_INACTIVE;
170         else
171                 bar->visible = STATUSBAR_VISIBLE_ALWAYS;
172
173         if (g_strcasecmp(config_node_get_str(node, "type", ""), "window") == 0)
174                 bar->type = STATUSBAR_TYPE_WINDOW;
175         if (g_strcasecmp(config_node_get_str(node, "placement", ""), "top") == 0)
176                 bar->placement = STATUSBAR_TOP;
177         bar->position = config_node_get_int(node, "position", 0);
178
179         node = config_node_section(node, "items", -1);
180         if (node != NULL) {
181                 /* we're overriding the items - destroy the old */
182                 while (bar->items != NULL)
183                         statusbar_config_item_destroy(bar, bar->items->data);
184
185                 tmp = config_node_first(node->value);
186                 for (; tmp != NULL; tmp = config_node_next(tmp))
187                         statusbar_read_item(bar, tmp->data);
188         }
189 }
190
191 static void statusbar_read_group(CONFIG_NODE *node)
192 {
193         STATUSBAR_GROUP_REC *group;
194         GSList *tmp;
195
196         group = statusbar_group_find(node->key);
197         if (group == NULL) {
198                 group = statusbar_group_create(node->key);
199                 if (active_statusbar_group == NULL)
200                         active_statusbar_group = group;
201         }
202
203         tmp = config_node_first(node->value);
204         for (; tmp != NULL; tmp = config_node_next(tmp))
205                 statusbar_read(group, tmp->data);
206 }
207
208 static void create_root_statusbars(void)
209 {
210         STATUSBAR_REC *bar;
211         GSList *tmp;
212
213         tmp = active_statusbar_group->config_bars;
214         for (; tmp != NULL; tmp = tmp->next) {
215                 STATUSBAR_CONFIG_REC *rec = tmp->data;
216
217                 if (rec->type == STATUSBAR_TYPE_ROOT) {
218                         bar = statusbar_create(active_statusbar_group, rec, NULL);
219                         statusbar_redraw(bar, TRUE);
220                 }
221         }
222 }
223
224 static void read_statusbar_config_from_node(CONFIG_NODE *node)
225 {
226         CONFIG_NODE *items;
227         GSList *tmp;
228
229         items = config_node_section(node, "items", -1);
230         if (items != NULL)
231                 statusbar_read_items(items);
232
233         tmp = config_node_first(node->value);
234         for (; tmp != NULL; tmp = config_node_next(tmp)) {
235                 if (tmp->data != items)
236                         statusbar_read_group(tmp->data);
237         }
238 }
239
240 static void read_statusbar_config(void)
241 {
242         CONFIG_NODE *node;
243
244         statusbar_reset_defaults();
245
246         node = iconfig_node_traverse("statusbar", FALSE);
247         if (node != NULL)
248                 read_statusbar_config_from_node(node);
249
250         create_root_statusbars();
251         statusbars_create_window_bars();
252 }
253
254 static const char *sbar_get_type(STATUSBAR_CONFIG_REC *rec)
255 {
256         return rec->type == STATUSBAR_TYPE_ROOT ? "root" :
257                 rec->type == STATUSBAR_TYPE_WINDOW ? "window" : "??";
258 }
259
260 static const char *sbar_get_placement(STATUSBAR_CONFIG_REC *rec)
261 {
262         return rec->placement == STATUSBAR_TOP ? "top" :
263                 rec->placement == STATUSBAR_BOTTOM ? "bottom" : "??";
264 }
265
266 static const char *sbar_get_visibility(STATUSBAR_CONFIG_REC *rec)
267 {
268         return rec->visible == STATUSBAR_VISIBLE_ALWAYS ? "always" :
269                 rec->visible == STATUSBAR_VISIBLE_ACTIVE ? "active" :
270                 rec->visible == STATUSBAR_VISIBLE_INACTIVE ? "inactive" : "??";
271 }
272
273 static void statusbar_list_items(STATUSBAR_CONFIG_REC *bar)
274 {
275         GSList *tmp;
276
277         printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
278                     TXT_STATUSBAR_INFO_ITEM_HEADER);
279
280         for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
281                 SBAR_ITEM_CONFIG_REC *rec = tmp->data;
282
283                 printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
284                             TXT_STATUSBAR_INFO_ITEM_NAME,
285                             rec->name, rec->priority,
286                             rec->right_alignment ? "right" : "left");
287         }
288
289         printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
290                     TXT_STATUSBAR_INFO_ITEM_FOOTER);
291 }
292
293 static void statusbar_print(STATUSBAR_CONFIG_REC *rec)
294 {
295         printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
296                     TXT_STATUSBAR_INFO_NAME, rec->name);
297
298         printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
299                     TXT_STATUSBAR_INFO_TYPE, sbar_get_type(rec));
300         printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
301                     TXT_STATUSBAR_INFO_PLACEMENT,
302                     sbar_get_placement(rec));
303         printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
304                     TXT_STATUSBAR_INFO_POSITION, rec->position);
305         printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
306                     TXT_STATUSBAR_INFO_VISIBLE,
307                     sbar_get_visibility(rec));
308
309         if (rec->items != NULL)
310                 statusbar_list_items(rec);
311 }
312
313 static void cmd_statusbar_list(void)
314 {
315         GSList *tmp;
316
317         printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_STATUSBAR_LIST_HEADER);
318
319         tmp = active_statusbar_group->config_bars;
320         for (; tmp != NULL; tmp = tmp->next) {
321                 STATUSBAR_CONFIG_REC *rec = tmp->data;
322
323                 printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
324                             TXT_STATUSBAR_LIST, rec->name, sbar_get_type(rec),
325                             sbar_get_placement(rec), rec->position,
326                             sbar_get_visibility(rec));
327         }
328
329         printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_STATUSBAR_LIST_FOOTER);
330 }
331
332 static void cmd_statusbar_print_info(const char *name)
333 {
334         GSList *tmp;
335
336         tmp = active_statusbar_group->config_bars;
337         for (; tmp != NULL; tmp = tmp->next) {
338                 STATUSBAR_CONFIG_REC *rec = tmp->data;
339
340                 if (g_strcasecmp(rec->name, name) == 0) {
341                         statusbar_print(rec);
342                         return;
343                 }
344         }
345
346         printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
347                     TXT_STATUSBAR_NOT_FOUND, name);
348 }
349
350 /* SYNTAX: STATUSBAR <name> ENABLE */
351 static void cmd_statusbar_enable(const char *data, void *server,
352                                  void *item, CONFIG_NODE *node)
353 {
354         iconfig_node_set_str(node, "disabled", NULL);
355 }
356
357 /* SYNTAX: STATUSBAR <name> DISABLE */
358 static void cmd_statusbar_disable(const char *data, void *server,
359                                   void *item, CONFIG_NODE *node)
360 {
361         iconfig_node_set_bool(node, "disabled", TRUE);
362 }
363
364 /* SYNTAX: STATUSBAR <name> RESET */
365 static void cmd_statusbar_reset(const char *data, void *server,
366                                 void *item, CONFIG_NODE *node)
367 {
368         CONFIG_NODE *parent;
369
370         parent = iconfig_node_traverse("statusbar", TRUE);
371         parent = config_node_section(parent, active_statusbar_group->name,
372                                      NODE_TYPE_BLOCK);
373
374         iconfig_node_set_str(parent, node->key, NULL);
375 }
376
377 /* SYNTAX: STATUSBAR <name> TYPE window|root */
378 static void cmd_statusbar_type(const char *data, void *server,
379                                void *item, CONFIG_NODE *node)
380 {
381         if (g_strcasecmp(data, "window") == 0)
382                 iconfig_node_set_str(node, "type", "window");
383         else if (g_strcasecmp(data, "root") == 0)
384                 iconfig_node_set_str(node, "type", "root");
385         else {
386                 printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
387                             TXT_STATUSBAR_UNKNOWN_TYPE, data);
388         }
389 }
390
391 /* SYNTAX: STATUSBAR <name> PLACEMENT top|bottom */
392 static void cmd_statusbar_placement(const char *data, void *server,
393                                     void *item, CONFIG_NODE *node)
394 {
395         if (g_strcasecmp(data, "top") == 0)
396                 iconfig_node_set_str(node, "placement", "top");
397         else if (g_strcasecmp(data, "bottom") == 0)
398                 iconfig_node_set_str(node, "placement", "bottom");
399         else {
400                 printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
401                             TXT_STATUSBAR_UNKNOWN_PLACEMENT, data);
402         }
403 }
404
405 /* SYNTAX: STATUSBAR <name> POSITION <num> */
406 static void cmd_statusbar_position(const char *data, void *server,
407                                    void *item, CONFIG_NODE *node)
408 {
409         iconfig_node_set_int(node, "position", atoi(data));
410 }
411
412 /* SYNTAX: STATUSBAR <name> VISIBLE always|active|inactive */
413 static void cmd_statusbar_visible(const char *data, void *server,
414                                   void *item, CONFIG_NODE *node)
415 {
416         if (g_strcasecmp(data, "always") == 0)
417                 iconfig_node_set_str(node, "visible", "always");
418         else if (g_strcasecmp(data, "active") == 0)
419                 iconfig_node_set_str(node, "visible", "active");
420         else if (g_strcasecmp(data, "inactive") == 0)
421                 iconfig_node_set_str(node, "visible", "inactive");
422         else {
423                 printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
424                             TXT_STATUSBAR_UNKNOWN_VISIBILITY, data);
425         }
426 }
427
428 static CONFIG_NODE *statusbar_items_section(CONFIG_NODE *parent)
429 {
430         STATUSBAR_CONFIG_REC *bar;
431         CONFIG_NODE *node;
432         GSList *tmp;
433
434         node = config_node_section(parent, "items", -1);
435         if (node != NULL)
436                 return node;
437
438         /* find the statusbar configuration from memory */
439         bar = statusbar_config_find(active_statusbar_group, parent->key);
440         if (bar == NULL) {
441                 printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
442                             TXT_STATUSBAR_NOT_FOUND, parent->key);
443                 return NULL;
444         }
445
446         /* since items list in config file overrides defaults,
447            we'll need to copy the whole list. */
448         parent = config_node_section(parent, "items", NODE_TYPE_BLOCK);
449         for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
450                 SBAR_ITEM_CONFIG_REC *rec = tmp->data;
451
452                 node = config_node_section(parent, rec->name,
453                                            NODE_TYPE_BLOCK);
454                 if (rec->priority != 0)
455                         iconfig_node_set_int(node, "priority", rec->priority);
456                 if (rec->right_alignment)
457                         iconfig_node_set_str(node, "alignment", "right");
458         }
459
460         return parent;
461 }
462
463 /* SYNTAX: STATUSBAR <name> ADD [-before | -after <item>]
464            [-priority #] [-alignment left|right] <item> */
465 static void cmd_statusbar_add(const char *data, void *server,
466                               void *item, CONFIG_NODE *node)
467 {
468         GHashTable *optlist;
469         char *name, *value;
470         void *free_arg;
471         int index;
472
473         node = statusbar_items_section(node);
474         if (node == NULL)
475                 return;
476
477         if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS,
478                             "statusbar add", &optlist, &name))
479                 return;
480
481         /* get the index */
482         index = -1;
483         value = g_hash_table_lookup(optlist, "before");
484         if (value != NULL) index = config_node_index(node, value);
485         value = g_hash_table_lookup(optlist, "after");
486         if (value != NULL) index = config_node_index(node, value)+1;
487
488         /* create/move item */
489         node = config_node_section_index(node, name, index, NODE_TYPE_BLOCK);
490
491         /* set the options */
492         value = g_hash_table_lookup(optlist, "priority");
493         if (value != NULL) iconfig_node_set_int(node, "priority", atoi(value));
494
495         value = g_hash_table_lookup(optlist, "alignment");
496         if (value != NULL) {
497                 iconfig_node_set_str(node, "alignment",
498                                      g_strcasecmp(value, "right") == 0 ?
499                                      "right" : NULL);
500         }
501
502         cmd_params_free(free_arg);
503 }
504
505 /* SYNTAX: STATUSBAR <name> REMOVE <item> */
506 static void cmd_statusbar_remove(const char *data, void *server,
507                                  void *item, CONFIG_NODE *node)
508 {
509         node = statusbar_items_section(node);
510         if (node == NULL)
511                 return;
512
513         if (config_node_section(node, data, -1) != NULL)
514                 iconfig_node_set_str(node, data, NULL);
515         else {
516                 printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
517                             TXT_STATUSBAR_ITEM_NOT_FOUND, data);
518         }
519 }
520
521 static void cmd_statusbar(const char *data)
522 {
523         CONFIG_NODE *node;
524         char *name, *cmd, *params, *signal;
525         void *free_arg;
526
527         if (!cmd_get_params(data, &free_arg, 3 | PARAM_FLAG_GETREST,
528                             &name, &cmd, &params))
529                 return;
530
531         if (*name == '\0') {
532                 /* list all statusbars */
533                 cmd_statusbar_list();
534                 cmd_params_free(free_arg);
535                 return;
536         }
537
538         if (*cmd == '\0') {
539                 /* print statusbar info */
540                 cmd_statusbar_print_info(name);
541                 cmd_params_free(free_arg);
542                 return;
543         }
544
545         /* lookup/create the statusbar node */
546         node = iconfig_node_traverse("statusbar", TRUE);
547         node = config_node_section(node, active_statusbar_group->name,
548                                    NODE_TYPE_BLOCK);
549         node = config_node_section(node, name, NODE_TYPE_BLOCK);
550
551         /* call the subcommand */
552         signal = g_strconcat("command statusbar ", cmd, NULL);
553         g_strdown(signal);
554         if (!signal_emit(signal, 4, params, NULL, NULL, node)) {
555                 printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
556                             TXT_STATUSBAR_UNKNOWN_COMMAND, cmd);
557         } else {
558                 read_statusbar_config();
559         }
560         g_free(signal);
561
562         cmd_params_free(free_arg);
563 }
564
565 void statusbar_config_init(void)
566 {
567         read_statusbar_config();
568         signal_add_last("setup reread", (SIGNAL_FUNC) read_statusbar_config);
569         signal_add("theme changed", (SIGNAL_FUNC) read_statusbar_config);
570
571         command_bind("statusbar", NULL, (SIGNAL_FUNC) cmd_statusbar);
572         command_bind("statusbar enable", NULL, (SIGNAL_FUNC) cmd_statusbar_enable);
573         command_bind("statusbar disable", NULL, (SIGNAL_FUNC) cmd_statusbar_disable);
574         command_bind("statusbar reset", NULL, (SIGNAL_FUNC) cmd_statusbar_reset);
575         command_bind("statusbar add", NULL, (SIGNAL_FUNC) cmd_statusbar_add);
576         command_bind("statusbar remove", NULL, (SIGNAL_FUNC) cmd_statusbar_remove);
577         command_bind("statusbar type", NULL, (SIGNAL_FUNC) cmd_statusbar_type);
578         command_bind("statusbar placement", NULL, (SIGNAL_FUNC) cmd_statusbar_placement);
579         command_bind("statusbar position", NULL, (SIGNAL_FUNC) cmd_statusbar_position);
580         command_bind("statusbar visible", NULL, (SIGNAL_FUNC) cmd_statusbar_visible);
581
582         command_set_options("statusbar add", "+before +after +priority +alignment");
583 }
584
585 void statusbar_config_deinit(void)
586 {
587         signal_remove("setup reread", (SIGNAL_FUNC) read_statusbar_config);
588         signal_remove("theme changed", (SIGNAL_FUNC) read_statusbar_config);
589
590         command_unbind("statusbar", (SIGNAL_FUNC) cmd_statusbar);
591         command_unbind("statusbar enable", (SIGNAL_FUNC) cmd_statusbar_enable);
592         command_unbind("statusbar disable", (SIGNAL_FUNC) cmd_statusbar_disable);
593         command_unbind("statusbar reset", (SIGNAL_FUNC) cmd_statusbar_reset);
594         command_unbind("statusbar add", (SIGNAL_FUNC) cmd_statusbar_add);
595         command_unbind("statusbar remove", (SIGNAL_FUNC) cmd_statusbar_remove);
596         command_unbind("statusbar type", (SIGNAL_FUNC) cmd_statusbar_type);
597         command_unbind("statusbar placement", (SIGNAL_FUNC) cmd_statusbar_placement);
598         command_unbind("statusbar position", (SIGNAL_FUNC) cmd_statusbar_position);
599         command_unbind("statusbar visible", (SIGNAL_FUNC) cmd_statusbar_visible);
600 }