addition of silc.css
[crypto.git] / apps / irssi / src / fe-common / core / window-commands.c
1 /*
2  window-commands.c : irssi
3
4     Copyright (C) 2000 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 "misc.h"
26 #include "servers.h"
27
28 #include "levels.h"
29
30 #include "themes.h"
31 #include "fe-windows.h"
32 #include "window-items.h"
33 #include "windows-layout.h"
34 #include "printtext.h"
35
36 static void cmd_window(const char *data, void *server, WI_ITEM_REC *item)
37 {
38         if (is_numeric(data, 0)) {
39                 signal_emit("command window refnum", 3, data, server, item);
40                 return;
41         }
42
43         command_runsub("window", data, server, item);
44 }
45
46 /* SYNTAX: WINDOW NEW [hide] */
47 static void cmd_window_new(const char *data, void *server, WI_ITEM_REC *item)
48 {
49         WINDOW_REC *window;
50         int type;
51
52         g_return_if_fail(data != NULL);
53
54         type = (g_strncasecmp(data, "hid", 3) == 0 || g_strcasecmp(data, "tab") == 0) ? 1 :
55                 (g_strcasecmp(data, "split") == 0 ? 2 : 0);
56         signal_emit("gui window create override", 1, GINT_TO_POINTER(type));
57
58         window = window_create(NULL, FALSE);
59         window_change_server(window, server);
60 }
61
62 /* SYNTAX: WINDOW CLOSE [<first> [<last>] */
63 static void cmd_window_close(const char *data)
64 {
65         GSList *tmp, *destroys;
66         char *first, *last;
67         int first_num, last_num;
68         void *free_arg;
69
70         if (!cmd_get_params(data, &free_arg, 2, &first, &last))
71                 return;
72
73         if ((*first != '\0' && !is_numeric(first, '\0')) ||
74             ((*last != '\0') && !is_numeric(last, '\0'))) {
75                 cmd_params_free(free_arg);
76                 return;
77         }
78
79         first_num = *first == '\0' ? active_win->refnum : atoi(first);
80         last_num = *last == '\0' ? active_win->refnum : atoi(last);
81
82         /* get list of windows to destroy */
83         destroys = NULL;
84         for (tmp = windows; tmp != NULL; tmp = tmp->next) {
85                 WINDOW_REC *rec = tmp->data;
86
87                 if (rec->refnum >= first_num && rec->refnum <= last_num)
88                         destroys = g_slist_append(destroys, rec);
89         }
90
91         /* really destroy the windows */
92         while (destroys != NULL) {
93                 WINDOW_REC *rec = destroys->data;
94
95                 if (windows->next != NULL)
96                         window_destroy(rec);
97
98                 destroys = g_slist_remove(destroys, rec);
99         }
100
101         cmd_params_free(free_arg);
102 }
103
104 /* SYNTAX: WINDOW REFNUM <number> */
105 static void cmd_window_refnum(const char *data)
106 {
107         WINDOW_REC *window;
108
109         if (!is_numeric(data, 0))
110                 return;
111
112         window = window_find_refnum(atoi(data));
113         if (window != NULL)
114                 window_set_active(window);
115 }
116
117 /* return the first window number with the highest activity */
118 static WINDOW_REC *window_highest_activity(WINDOW_REC *window)
119 {
120         WINDOW_REC *rec, *max_win;
121         GSList *tmp;
122         int max_act, through;
123
124         g_return_val_if_fail(window != NULL, NULL);
125
126         max_win = NULL; max_act = 0; through = FALSE;
127
128         tmp = g_slist_find(windows, window);
129         for (;; tmp = tmp->next) {
130                 if (tmp == NULL) {
131                         tmp = windows;
132                         through = TRUE;
133                 }
134
135                 if (through && tmp->data == window)
136                         break;
137
138                 rec = tmp->data;
139
140                 if (rec->data_level > 0 && max_act < rec->data_level) {
141                         max_act = rec->data_level;
142                         max_win = rec;
143                 }
144         }
145
146         return max_win;
147 }
148
149 /* SYNTAX: WINDOW GOTO active|<number>|<name> */
150 static void cmd_window_goto(const char *data)
151 {
152         WINDOW_REC *window;
153
154         g_return_if_fail(data != NULL);
155
156         if (is_numeric(data, 0)) {
157                 cmd_window_refnum(data);
158                 return;
159         }
160
161         if (g_strcasecmp(data, "active") == 0)
162                 window = window_highest_activity(active_win);
163         else
164                 window = window_find_item(active_win->active_server, data);
165
166         if (window != NULL)
167                 window_set_active(window);
168 }
169
170 /* SYNTAX: WINDOW NEXT */
171 static void cmd_window_next(void)
172 {
173         int num;
174
175         num = window_refnum_next(active_win->refnum, TRUE);
176         if (num < 1) num = windows_refnum_last();
177
178         window_set_active(window_find_refnum(num));
179 }
180
181 /* SYNTAX: WINDOW LAST */
182 static void cmd_window_last(void)
183 {
184         if (windows->next != NULL)
185                 window_set_active(windows->next->data);
186 }
187
188 /* SYNTAX: WINDOW PREVIOUS */
189 static void cmd_window_previous(void)
190 {
191         int num;
192
193         num = window_refnum_prev(active_win->refnum, TRUE);
194         if (num < 1) num = window_refnum_next(0, TRUE);
195
196         window_set_active(window_find_refnum(num));
197 }
198
199 /* SYNTAX: WINDOW LEVEL [<level>] */
200 static void cmd_window_level(const char *data)
201 {
202         char *level;
203
204         g_return_if_fail(data != NULL);
205
206         window_set_level(active_win, combine_level(active_win->level, data));
207
208         level = active_win->level == 0 ? g_strdup("NONE") :
209                 bits2level(active_win->level);
210         printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
211                            TXT_WINDOW_LEVEL, level);
212         g_free(level);
213 }
214
215 /* SYNTAX: WINDOW SERVER [-sticky | -unsticky] <tag> */
216 static void cmd_window_server(const char *data)
217 {
218         GHashTable *optlist;
219         SERVER_REC *server;
220         char *tag;
221         void *free_arg;
222
223         if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS,
224                             "window server", &optlist, &tag))
225                 return;
226
227         if (*tag == '\0' &&
228             (g_hash_table_lookup(optlist, "sticky") != NULL ||
229              g_hash_table_lookup(optlist, "unsticky") != NULL)) {
230                 tag = active_win->active_server->tag;
231         }
232
233         if (*tag == '\0')
234                 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
235         server = server_find_tag(tag);
236
237         if (g_hash_table_lookup(optlist, "unsticky") != NULL &&
238             active_win->servertag != NULL) {
239                 g_free_and_null(active_win->servertag);
240                 printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
241                                    TXT_UNSET_SERVER_STICKY, server->tag);
242         }
243
244         if (active_win->servertag != NULL &&
245             g_hash_table_lookup(optlist, "sticky") == NULL) {
246                 printformat_window(active_win, MSGLEVEL_CLIENTERROR,
247                                    TXT_ERROR_SERVER_STICKY);
248         } else if (server == NULL) {
249                 printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
250                                    TXT_UNKNOWN_SERVER_TAG, tag);
251         } else if (active_win->active == NULL) {
252                 window_change_server(active_win, server);
253                 if (g_hash_table_lookup(optlist, "sticky") != NULL) {
254                         g_free_not_null(active_win->servertag);
255                         active_win->servertag = g_strdup(server->tag);
256                         printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
257                                            TXT_SET_SERVER_STICKY, server->tag);
258                 }
259                 printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
260                                    TXT_SERVER_CHANGED,
261                                    server->tag, server->connrec->address,
262                                    server->connrec->chatnet == NULL ? "" :
263                                    server->connrec->chatnet);
264         }
265
266         cmd_params_free(free_arg);
267 }
268
269 static void cmd_window_item(const char *data, void *server, WI_ITEM_REC *item)
270 {
271         command_runsub("window item", data, server, item);
272 }
273
274 /* SYNTAX: WINDOW ITEM PREV */
275 static void cmd_window_item_prev(void)
276 {
277         window_item_prev(active_win);
278 }
279
280 /* SYNTAX: WINDOW ITEM NEXT */
281 static void cmd_window_item_next(void)
282 {
283         window_item_next(active_win);
284 }
285
286 /* SYNTAX: WINDOW ITEM GOTO <name> */
287 static void cmd_window_item_goto(const char *data, SERVER_REC *server)
288 {
289         WI_ITEM_REC *item;
290
291         item = window_item_find_window(active_win, server, data);
292         if (item != NULL)
293                 window_item_set_active(active_win, item);
294 }
295
296 /* SYNTAX: WINDOW ITEM MOVE <number>|<name> */
297 static void cmd_window_item_move(const char *data, SERVER_REC *server,
298                                  WI_ITEM_REC *item)
299 {
300         WINDOW_REC *window;
301
302         if (is_numeric(data, '\0')) {
303                 /* move current window item to specified window */
304                 window = window_find_refnum(atoi(data));
305         } else {
306                 /* move specified window item to current window */
307                 item = window_item_find(server, data);
308                 window = active_win;
309         }
310         if (window != NULL && item != NULL)
311                 window_item_set_active(window, item);
312 }
313
314 /* SYNTAX: WINDOW NUMBER [-sticky] <number> */
315 static void cmd_window_number(const char *data)
316 {
317         GHashTable *optlist;
318         char *refnum;
319         void *free_arg;
320         int num;
321
322         if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS,
323                             "window number", &optlist, &refnum))
324                 return;
325
326         if (*refnum == '\0')
327                 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
328
329         num = atoi(refnum);
330         if (num < 1) {
331                 printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
332                                    TXT_REFNUM_TOO_LOW);
333         } else {
334                 window_set_refnum(active_win, num);
335                 active_win->sticky_refnum =
336                         g_hash_table_lookup(optlist, "sticky") != NULL;
337         }
338
339         cmd_params_free(free_arg);
340 }
341
342 /* SYNTAX: WINDOW NAME <name> */
343 static void cmd_window_name(const char *data)
344 {
345         window_set_name(active_win, data);
346 }
347
348 /* we're moving the first window to last - move the first contiguous block
349    of refnums to left. Like if there's windows 1..5 and 7..10, move 1 to
350    11, 2..5 to 1..4 and leave 7..10 alone  */
351 static void windows_move_left(WINDOW_REC *move_window)
352 {
353         WINDOW_REC *window;
354         int refnum;
355
356         window_set_refnum(move_window, windows_refnum_last()+1);
357         for (refnum = 2;; refnum++) {
358                 window = window_find_refnum(refnum);
359                 if (window == NULL) break;
360
361                 window_set_refnum(window, refnum-1);
362         }
363 }
364
365 /* we're moving the last window to first - make some space so we can use the
366    refnum 1 */
367 static void windows_move_right(WINDOW_REC *move_window)
368 {
369         WINDOW_REC *window;
370         int refnum;
371
372         /* find the first unused refnum, like if there's windows
373            1..5 and 7..10, we only need to move 1..5 to 2..6 */
374         refnum = 1;
375         while (window_find_refnum(refnum) != NULL) refnum++;
376
377         refnum--;
378         while (refnum > 0) {
379                 window = window_find_refnum(refnum);
380                 g_return_if_fail(window != NULL);
381                 window_set_refnum(window, window == move_window ? 1 : refnum+1);
382
383                 refnum--;
384         }
385 }
386
387 static void cmd_window_move_left(void)
388 {
389         int refnum;
390
391         refnum = window_refnum_prev(active_win->refnum, TRUE);
392         if (refnum != -1) {
393                 window_set_refnum(active_win, refnum);
394                 return;
395         }
396
397         windows_move_left(active_win);
398 }
399
400 static void cmd_window_move_right(void)
401 {
402         int refnum;
403
404         refnum = window_refnum_next(active_win->refnum, TRUE);
405         if (refnum != -1) {
406                 window_set_refnum(active_win, refnum);
407                 return;
408         }
409
410         windows_move_right(active_win);
411 }
412
413 /* SYNTAX: WINDOW MOVE <number>|left|right */
414 static void cmd_window_move(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
415 {
416         int new_refnum, refnum;
417
418         if (!is_numeric(data, 0)) {
419                 command_runsub("window move", data, server, item);
420                 return;
421         }
422
423         new_refnum = atoi(data);
424         if (new_refnum > active_win->refnum) {
425                 for (;;) {
426                         refnum = window_refnum_next(active_win->refnum, FALSE);
427                         if (refnum == -1 || refnum > new_refnum)
428                                 break;
429
430                         window_set_refnum(active_win, refnum);
431                 }
432         } else {
433                 for (;;) {
434                         refnum = window_refnum_prev(active_win->refnum, FALSE);
435                         if (refnum == -1 || refnum < new_refnum)
436                                 break;
437
438                         window_set_refnum(active_win, refnum);
439                 }
440         }
441 }
442
443 /* SYNTAX: WINDOW LIST */
444 static void cmd_window_list(void)
445 {
446         GSList *tmp, *sorted;
447         char *levelstr;
448
449         sorted = windows_get_sorted();
450         printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_WINDOWLIST_HEADER);
451         for (tmp = sorted; tmp != NULL; tmp = tmp->next) {
452                 WINDOW_REC *rec = tmp->data;
453
454                 levelstr = bits2level(rec->level);
455                 printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_WINDOWLIST_LINE,
456                             rec->refnum, rec->name == NULL ? "" : rec->name,
457                             rec->active == NULL ? "" : rec->active->name,
458                             rec->active_server == NULL ? "" : ((SERVER_REC *) rec->active_server)->tag,
459                             levelstr);
460                 g_free(levelstr);
461         }
462         g_slist_free(sorted);
463         printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_WINDOWLIST_FOOTER);
464 }
465
466 /* SYNTAX: WINDOW THEME <name> */
467 static void cmd_window_theme(const char *data)
468 {
469         THEME_REC *theme;
470
471         g_free_not_null(active_win->theme_name);
472         active_win->theme_name = g_strdup(data);
473
474         active_win->theme = theme = theme_load(data);
475         if (theme != NULL) {
476                 printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
477                                    TXT_WINDOW_THEME_CHANGED,
478                                    theme->name, theme->path);
479         } else {
480                 printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
481                                    TXT_THEME_NOT_FOUND, data);
482         }
483 }
484
485 static void cmd_layout(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
486 {
487         command_runsub("layout", data, server, item);
488 }
489
490 /* SYNTAX: FOREACH WINDOW <command> */
491 static void cmd_foreach_window(const char *data)
492 {
493         WINDOW_REC *old;
494         GSList *tmp;
495
496         old = active_win;
497         for (tmp = windows; tmp != NULL; tmp = tmp->next) {
498                 WINDOW_REC *rec = tmp->data;
499
500                 active_win = rec;
501                 signal_emit("send command", 3, data, rec->active_server,
502                             rec->active);
503         }
504         active_win = old;
505 }
506
507 void window_commands_init(void)
508 {
509         command_bind("window", NULL, (SIGNAL_FUNC) cmd_window);
510         command_bind("window new", NULL, (SIGNAL_FUNC) cmd_window_new);
511         command_bind("window close", NULL, (SIGNAL_FUNC) cmd_window_close);
512         command_bind("window kill", NULL, (SIGNAL_FUNC) cmd_window_close);
513         command_bind("window server", NULL, (SIGNAL_FUNC) cmd_window_server);
514         command_bind("window refnum", NULL, (SIGNAL_FUNC) cmd_window_refnum);
515         command_bind("window goto", NULL, (SIGNAL_FUNC) cmd_window_goto);
516         command_bind("window previous", NULL, (SIGNAL_FUNC) cmd_window_previous);
517         command_bind("window next", NULL, (SIGNAL_FUNC) cmd_window_next);
518         command_bind("window last", NULL, (SIGNAL_FUNC) cmd_window_last);
519         command_bind("window level", NULL, (SIGNAL_FUNC) cmd_window_level);
520         command_bind("window item", NULL, (SIGNAL_FUNC) cmd_window_item);
521         command_bind("window item prev", NULL, (SIGNAL_FUNC) cmd_window_item_prev);
522         command_bind("window item next", NULL, (SIGNAL_FUNC) cmd_window_item_next);
523         command_bind("window item goto", NULL, (SIGNAL_FUNC) cmd_window_item_goto);
524         command_bind("window item move", NULL, (SIGNAL_FUNC) cmd_window_item_move);
525         command_bind("window number", NULL, (SIGNAL_FUNC) cmd_window_number);
526         command_bind("window name", NULL, (SIGNAL_FUNC) cmd_window_name);
527         command_bind("window move", NULL, (SIGNAL_FUNC) cmd_window_move);
528         command_bind("window move left", NULL, (SIGNAL_FUNC) cmd_window_move_left);
529         command_bind("window move right", NULL, (SIGNAL_FUNC) cmd_window_move_right);
530         command_bind("window list", NULL, (SIGNAL_FUNC) cmd_window_list);
531         command_bind("window theme", NULL, (SIGNAL_FUNC) cmd_window_theme);
532         command_bind("layout", NULL, (SIGNAL_FUNC) cmd_layout);
533         /* SYNTAX: LAYOUT SAVE */
534         command_bind("layout save", NULL, (SIGNAL_FUNC) windows_layout_save);
535         /* SYNTAX: LAYOUT RESET */
536         command_bind("layout reset", NULL, (SIGNAL_FUNC) windows_layout_reset);
537         command_bind("foreach window", NULL, (SIGNAL_FUNC) cmd_foreach_window);
538
539         command_set_options("window number", "sticky");
540         command_set_options("window server", "sticky unsticky");
541 }
542
543 void window_commands_deinit(void)
544 {
545         command_unbind("window", (SIGNAL_FUNC) cmd_window);
546         command_unbind("window new", (SIGNAL_FUNC) cmd_window_new);
547         command_unbind("window close", (SIGNAL_FUNC) cmd_window_close);
548         command_unbind("window kill", (SIGNAL_FUNC) cmd_window_close);
549         command_unbind("window server", (SIGNAL_FUNC) cmd_window_server);
550         command_unbind("window refnum", (SIGNAL_FUNC) cmd_window_refnum);
551         command_unbind("window goto", (SIGNAL_FUNC) cmd_window_goto);
552         command_unbind("window previous", (SIGNAL_FUNC) cmd_window_previous);
553         command_unbind("window next", (SIGNAL_FUNC) cmd_window_next);
554         command_unbind("window last", (SIGNAL_FUNC) cmd_window_last);
555         command_unbind("window level", (SIGNAL_FUNC) cmd_window_level);
556         command_unbind("window item", (SIGNAL_FUNC) cmd_window_item);
557         command_unbind("window item prev", (SIGNAL_FUNC) cmd_window_item_prev);
558         command_unbind("window item next", (SIGNAL_FUNC) cmd_window_item_next);
559         command_unbind("window item goto", (SIGNAL_FUNC) cmd_window_item_goto);
560         command_unbind("window item move", (SIGNAL_FUNC) cmd_window_item_move);
561         command_unbind("window number", (SIGNAL_FUNC) cmd_window_number);
562         command_unbind("window name", (SIGNAL_FUNC) cmd_window_name);
563         command_unbind("window move", (SIGNAL_FUNC) cmd_window_move);
564         command_unbind("window move left", (SIGNAL_FUNC) cmd_window_move_left);
565         command_unbind("window move right", (SIGNAL_FUNC) cmd_window_move_right);
566         command_unbind("window list", (SIGNAL_FUNC) cmd_window_list);
567         command_unbind("window theme", (SIGNAL_FUNC) cmd_window_theme);
568         command_unbind("layout", (SIGNAL_FUNC) cmd_layout);
569         command_unbind("layout save", (SIGNAL_FUNC) windows_layout_save);
570         command_unbind("layout reset", (SIGNAL_FUNC) windows_layout_reset);
571         command_unbind("foreach window", (SIGNAL_FUNC) cmd_foreach_window);
572 }