imported irssi.
[silc.git] / apps / irssi / src / fe-text / mainwindows.c
1 /*
2  mainwindows.c : irssi
3
4     Copyright (C) 1999-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 "levels.h"
26 #include "misc.h"
27 #include "settings.h"
28 #include "printtext.h"
29
30 #include "screen.h"
31 #include "statusbar.h"
32 #include "gui-windows.h"
33
34 #define NEW_WINDOW_SIZE (WINDOW_MIN_SIZE + 1)
35
36 GSList *mainwindows;
37 MAIN_WINDOW_REC *active_mainwin;
38
39 static int reserved_up, reserved_down;
40 static int screen_width, screen_height;
41
42 static MAIN_WINDOW_REC *find_window_with_room(void)
43 {
44         MAIN_WINDOW_REC *biggest_rec;
45         GSList *tmp;
46         int space, biggest;
47
48         biggest = 0; biggest_rec = NULL;
49         for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
50                 MAIN_WINDOW_REC *rec = tmp->data;
51
52                 space = rec->height;
53                 if (space >= WINDOW_MIN_SIZE+NEW_WINDOW_SIZE && space > biggest) {
54                         biggest = space;
55                         biggest_rec = rec;
56                 }
57         }
58
59         return biggest_rec;
60 }
61
62 #ifdef USE_CURSES_WINDOWS
63 static void create_curses_window(MAIN_WINDOW_REC *window)
64 {
65         window->curses_win = newwin(window->height, window->width,
66                                     window->first_line, 0);
67         idlok(window->curses_win, 1);
68 }
69 #endif
70
71 static void mainwindow_resize(MAIN_WINDOW_REC *window, int xdiff, int ydiff)
72 {
73         GSList *tmp;
74
75         if (xdiff == 0 && ydiff == 0)
76                 return;
77
78         window->width += xdiff;
79         window->height = window->last_line-window->first_line+1;
80 #ifdef USE_CURSES_WINDOWS
81 #ifdef HAVE_CURSES_WRESIZE
82         wresize(window->curses_win, window->height, window->width);
83         mvwin(window->curses_win, window->first_line, 0);
84 #else
85         delwin(window->curses_win);
86         create_curses_window(window);
87 #endif
88 #endif
89
90         for (tmp = windows; tmp != NULL; tmp = tmp->next) {
91                 WINDOW_REC *rec = tmp->data;
92
93                 if (rec->gui_data != NULL &&
94                     WINDOW_GUI(rec)->parent == window)
95                         gui_window_resize(rec, window->width, window->height);
96         }
97
98         textbuffer_view_set_window(WINDOW_GUI(window->active)->view,
99                                    window->curses_win);
100         signal_emit("mainwindow resized", 1, window);
101 }
102
103 void mainwindows_recreate(void)
104 {
105         GSList *tmp;
106
107         for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
108                 MAIN_WINDOW_REC *rec = tmp->data;
109
110 #ifdef USE_CURSES_WINDOWS
111                 create_curses_window(rec);
112 #endif
113                 textbuffer_view_set_window(WINDOW_GUI(rec->active)->view,
114                                            rec->curses_win);
115         }
116 }
117
118 MAIN_WINDOW_REC *mainwindow_create(void)
119 {
120         MAIN_WINDOW_REC *rec, *parent;
121         int space;
122
123         rec = g_new0(MAIN_WINDOW_REC, 1);
124         rec->width = screen_width;
125         rec->statusbar_lines = 1;
126
127         if (mainwindows == NULL) {
128                 active_mainwin = rec;
129
130                 rec->first_line = reserved_up;
131                 rec->last_line = screen_height-1 -
132                         reserved_down-rec->statusbar_lines;
133                 rec->height = rec->last_line-rec->first_line+1;
134         } else {
135                 parent = WINDOW_GUI(active_win)->parent;
136                 if (parent->height < WINDOW_MIN_SIZE+NEW_WINDOW_SIZE)
137                         parent = find_window_with_room();
138                 if (parent == NULL)
139                         return NULL; /* not enough space */
140
141                 space = (parent->height-parent->statusbar_lines)/2;
142                 rec->first_line = parent->first_line;
143                 rec->last_line = rec->first_line + space-rec->statusbar_lines;
144                 rec->height = rec->last_line-rec->first_line+1;
145                 parent->first_line = rec->last_line+1+rec->statusbar_lines;
146                 parent->height = parent->last_line-parent->first_line+1;
147
148                 mainwindow_resize(parent, 0, -space-1);
149         }
150
151 #ifdef USE_CURSES_WINDOWS
152         rec->curses_win = newwin(rec->height, rec->width, rec->first_line, 0);
153         refresh();
154 #endif
155
156         mainwindows = g_slist_append(mainwindows, rec);
157         signal_emit("mainwindow created", 1, rec);
158         return rec;
159 }
160
161 static MAIN_WINDOW_REC *mainwindows_find_lower(int line)
162 {
163         MAIN_WINDOW_REC *best;
164         GSList *tmp;
165
166         best = NULL;
167         for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
168                 MAIN_WINDOW_REC *rec = tmp->data;
169
170                 if (rec->first_line > line &&
171                     (best == NULL || rec->first_line < best->first_line))
172                         best = rec;
173         }
174
175         return best;
176 }
177
178 static MAIN_WINDOW_REC *mainwindows_find_upper(int line)
179 {
180         MAIN_WINDOW_REC *best;
181         GSList *tmp;
182
183         best = NULL;
184         for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
185                 MAIN_WINDOW_REC *rec = tmp->data;
186
187                 if (rec->last_line < line &&
188                     (best == NULL || rec->last_line > best->last_line))
189                         best = rec;
190         }
191
192         return best;
193 }
194
195 static void mainwindows_add_space(int first_line, int last_line)
196 {
197         MAIN_WINDOW_REC *rec;
198         int size;
199
200         if (last_line < first_line)
201                 return;
202
203         size = last_line-first_line+1;
204
205         rec = mainwindows_find_lower(last_line);
206         if (rec != NULL) {
207                 rec->first_line = first_line;
208                 mainwindow_resize(rec, 0, size);
209                 return;
210         }
211
212         rec = mainwindows_find_upper(first_line);
213         if (rec != NULL) {
214                 rec->last_line = last_line-rec->statusbar_lines;
215                 mainwindow_resize(rec, 0, size);
216         }
217 }
218
219 static void gui_windows_remove_parent(MAIN_WINDOW_REC *window)
220 {
221         MAIN_WINDOW_REC *new_parent;
222         GSList *tmp;
223
224         new_parent = mainwindows->data;
225         for (tmp = windows; tmp != NULL; tmp = tmp->next) {
226                 WINDOW_REC *rec = tmp->data;
227
228                 if (rec->gui_data != NULL && WINDOW_GUI(rec)->parent == window)
229                         gui_window_reparent(rec, new_parent);
230         }
231 }
232
233 void mainwindow_destroy(MAIN_WINDOW_REC *window)
234 {
235         g_return_if_fail(window != NULL);
236
237 #ifdef USE_CURSES_WINDOWS
238         delwin(window->curses_win);
239 #endif
240
241         mainwindows = g_slist_remove(mainwindows, window);
242         signal_emit("mainwindow destroyed", 1, window);
243
244         if (!quitting && mainwindows != NULL) {
245                 gui_windows_remove_parent(window);
246                 mainwindows_add_space(window->first_line, window->last_line+window->statusbar_lines);
247
248                 mainwindows_redraw();
249                 statusbar_redraw(NULL);
250         }
251         g_free(window);
252
253         if (active_mainwin == window) active_mainwin = NULL;
254 }
255
256 void mainwindows_redraw(void)
257 {
258         GSList *tmp;
259
260         screen_refresh_freeze();
261         for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
262                 MAIN_WINDOW_REC *rec = tmp->data;
263
264                 gui_window_redraw(rec->active);
265         }
266         screen_refresh_thaw();
267 }
268
269 static int mainwindows_compare(MAIN_WINDOW_REC *w1, MAIN_WINDOW_REC *w2)
270 {
271         return w1->first_line < w2->first_line ? -1 : 1;
272 }
273
274 static int mainwindows_compare_reverse(MAIN_WINDOW_REC *w1, MAIN_WINDOW_REC *w2)
275 {
276         return w1->first_line < w2->first_line ? 1 : -1;
277 }
278
279 GSList *mainwindows_get_sorted(int reverse)
280 {
281         GSList *tmp, *list;
282
283         list = NULL;
284         for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
285                 list = g_slist_insert_sorted(list, tmp->data, (GCompareFunc)
286                                              (reverse ? mainwindows_compare_reverse : mainwindows_compare));
287         }
288
289         return list;
290 }
291
292 static void mainwindows_resize_too_small(int xdiff, int ydiff)
293 {
294         GSList *sorted, *tmp;
295         int space, moved;
296
297         /* terminal is too small - just take the space whereever possible */
298         sorted = mainwindows_get_sorted(FALSE);
299         moved = 0;
300         for (tmp = sorted; tmp != NULL; tmp = tmp->next) {
301                 MAIN_WINDOW_REC *rec = tmp->data;
302
303                 space = rec->height;
304                 if (ydiff == 0 || space <= 0) {
305                         if (moved > 0) {
306                                 rec->first_line -= moved;
307                                 rec->last_line -= moved;
308                                 signal_emit("mainwindow moved", 1, rec);
309                         }
310                         continue;
311                 }
312
313                 if (space > -ydiff) space = -ydiff;
314                 ydiff += space;
315                 rec->first_line -= moved;
316                 moved += space;
317                 rec->last_line -= space;
318                 mainwindow_resize(rec, xdiff, -space);
319         }
320         g_slist_free(sorted);
321 }
322
323 static void mainwindows_resize_smaller(int xdiff, int ydiff)
324 {
325         GSList *sorted, *tmp;
326         int space;
327
328         space = 0;
329         for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
330                 MAIN_WINDOW_REC *rec = tmp->data;
331
332                 space += rec->height-WINDOW_MIN_SIZE;
333         }
334
335         if (space < -ydiff) {
336                 /* not enough space, use different algorithm */
337                 mainwindows_resize_too_small(xdiff, ydiff);
338                 return;
339         }
340
341         /* resize windows that have space */
342         sorted = mainwindows_get_sorted(TRUE);
343         for (tmp = sorted; tmp != NULL && ydiff < 0; tmp = tmp->next) {
344                 MAIN_WINDOW_REC *rec = tmp->data;
345
346                 space = rec->height-WINDOW_MIN_SIZE;
347                 if (space <= 0) {
348                         rec->first_line += ydiff;
349                         rec->last_line += ydiff;
350                         signal_emit("mainwindow moved", 1, rec);
351                         continue;
352                 }
353
354                 if (space <= 0) space = 1;
355                 if (space > -ydiff) space = -ydiff;
356                 rec->last_line += ydiff;
357                 ydiff += space;
358                 rec->first_line += ydiff;
359
360                 mainwindow_resize(rec, xdiff, -space);
361         }
362         g_slist_free(sorted);
363 }
364
365 static void mainwindows_resize_bigger(int xdiff, int ydiff)
366 {
367         GSList *sorted, *tmp;
368         int moved, space;
369
370         sorted = mainwindows_get_sorted(FALSE);
371         moved = 0;
372         for (tmp = sorted; tmp != NULL; tmp = tmp->next) {
373                 MAIN_WINDOW_REC *rec = tmp->data;
374
375                 space = rec->height-WINDOW_MIN_SIZE;
376                 if (ydiff == 0 || (space >= 0 && tmp->next != NULL)) {
377                         if (moved > 0) {
378                                 rec->first_line += moved;
379                                 rec->last_line += moved;
380                                 signal_emit("mainwindow moved", 1, rec);
381                         }
382                         continue;
383                 }
384
385                 if (space < 0 && tmp->next != NULL) {
386                         /* space below minimum */
387                         space = -space;
388                         if (space > ydiff) space = ydiff;
389                 } else {
390                         /* lowest window - give all the extra space for it */
391                         space = ydiff;
392                 }
393                 ydiff -= space;
394                 rec->first_line += moved;
395                 moved += space;
396                 rec->last_line += moved;
397
398                 mainwindow_resize(rec, xdiff, space);
399         }
400         g_slist_free(sorted);
401 }
402
403 void mainwindows_resize_horiz(int xdiff)
404 {
405         GSList *tmp;
406
407         for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
408                 MAIN_WINDOW_REC *rec = tmp->data;
409
410                 mainwindow_resize(rec, xdiff, 0);
411         }
412 }
413
414 void mainwindows_resize(int width, int height)
415 {
416         int xdiff, ydiff;
417
418         xdiff = width-screen_width;
419         ydiff = height-screen_height;
420         screen_width = width;
421         screen_height = height;
422
423         screen_refresh_freeze();
424         if (ydiff < 0)
425                 mainwindows_resize_smaller(xdiff, ydiff);
426         else if (ydiff > 0)
427                 mainwindows_resize_bigger(xdiff, ydiff);
428         else if (xdiff != 0)
429                 mainwindows_resize_horiz(xdiff);
430
431         irssi_redraw();
432         screen_refresh_thaw();
433 }
434
435 int mainwindows_reserve_lines(int count, int up)
436 {
437         MAIN_WINDOW_REC *window;
438         int ret;
439
440         if (up) {
441                 g_return_val_if_fail(count > 0 || reserved_up > count, -1);
442
443                 ret = reserved_up;
444                 reserved_up += count;
445
446                 window = mainwindows_find_lower(-1);
447                 if (window != NULL) window->first_line += count;
448         } else {
449                 g_return_val_if_fail(count > 0 || reserved_down > count, -1);
450
451                 ret = reserved_down;
452                 reserved_down += count;
453
454                 window = mainwindows_find_upper(screen_height);
455                 if (window != NULL) window->last_line -= count;
456         }
457
458         if (window != NULL)
459                 mainwindow_resize(window, 0, -count);
460
461         return ret;
462 }
463
464 static void mainwindows_resize_two(MAIN_WINDOW_REC *grow_win,
465                                    MAIN_WINDOW_REC *shrink_win, int count)
466 {
467         mainwindow_resize(grow_win, 0, count);
468         mainwindow_resize(shrink_win, 0, -count);
469         gui_window_redraw(grow_win->active);
470         gui_window_redraw(shrink_win->active);
471         statusbar_redraw(grow_win->statusbar);
472         statusbar_redraw(shrink_win->statusbar);
473 }
474
475 static int mainwindow_grow(MAIN_WINDOW_REC *window, int count)
476 {
477         MAIN_WINDOW_REC *shrink_win;
478
479         /* shrink lower window */
480         shrink_win = mainwindows_find_lower(window->last_line);
481         if (shrink_win != NULL && shrink_win->height-count >= WINDOW_MIN_SIZE) {
482                 window->last_line += count;
483                 shrink_win->first_line += count;
484         } else {
485                 /* shrink upper window */
486                 shrink_win = mainwindows_find_upper(window->first_line);
487                 if (shrink_win == NULL ||
488                     shrink_win->height-count < WINDOW_MIN_SIZE)
489                         return FALSE;
490
491                 window->first_line -= count;
492                 shrink_win->last_line -= count;
493         }
494
495         mainwindows_resize_two(window, shrink_win, count);
496         return TRUE;
497 }
498
499 static int mainwindow_shrink(MAIN_WINDOW_REC *window, int count)
500 {
501         MAIN_WINDOW_REC *grow_win;
502
503         if (window->height-count < WINDOW_MIN_SIZE)
504                 return FALSE;
505
506         grow_win = mainwindows_find_lower(window->last_line);
507         if (grow_win != NULL) {
508                 window->last_line -= count;
509                 grow_win->first_line -= count;
510         } else {
511                 grow_win = mainwindows_find_upper(window->first_line);
512                 if (grow_win == NULL) return FALSE;
513
514                 window->first_line += count;
515                 grow_win->last_line += count;
516         }
517
518         mainwindows_resize_two(grow_win, window, count);
519         return TRUE;
520 }
521
522 void mainwindow_set_size(MAIN_WINDOW_REC *window, int size)
523 {
524         size -= window->height;
525         if (size < 0)
526                 mainwindow_shrink(window, size);
527         else
528                 mainwindow_grow(window, size);
529 }
530
531 /* SYNTAX: WINDOW GROW [<lines>] */
532 static void cmd_window_grow(const char *data)
533 {
534         MAIN_WINDOW_REC *window;
535         int count;
536
537         count = *data == '\0' ? 1 : atoi(data);
538         window = WINDOW_GUI(active_win)->parent;
539
540         if (!mainwindow_grow(window, count)) {
541                 printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
542                                    TXT_WINDOW_TOO_SMALL);
543         }
544 }
545
546 /* SYNTAX: WINDOW SHRINK [<lines>] */
547 static void cmd_window_shrink(const char *data)
548 {
549         MAIN_WINDOW_REC *window;
550         int count;
551
552         count = *data == '\0' ? 1 : atoi(data);
553         window = WINDOW_GUI(active_win)->parent;
554
555         if (!mainwindow_shrink(window, count)) {
556                 printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
557                                    TXT_WINDOW_TOO_SMALL);
558         }
559 }
560
561 /* SYNTAX: WINDOW SIZE <lines> */
562 static void cmd_window_size(const char *data)
563 {
564         char sizestr[MAX_INT_STRLEN];
565         int size;
566
567         if (!is_numeric(data, 0)) return;
568         size = atoi(data);
569
570         size -= WINDOW_GUI(active_win)->parent->height;
571         if (size == 0) return;
572
573         ltoa(sizestr, size < 0 ? -size : size);
574         if (size < 0)
575                 cmd_window_shrink(sizestr);
576         else
577                 cmd_window_grow(sizestr);
578 }
579
580 /* SYNTAX: WINDOW BALANCE */
581 static void cmd_window_balance(void)
582 {
583         GSList *sorted, *tmp;
584         int avail_size, unit_size, bigger_units;
585         int windows, last_line, old_size;
586
587         windows = g_slist_length(mainwindows);
588         if (windows == 1) return;
589
590         avail_size = screen_height - reserved_up-reserved_down;
591         unit_size = avail_size/windows;
592         bigger_units = avail_size%windows;
593
594         sorted = mainwindows_get_sorted(FALSE);
595         last_line = 0;
596         for (tmp = sorted; tmp != NULL; tmp = tmp->next) {
597                 MAIN_WINDOW_REC *rec = tmp->data;
598
599                 old_size = rec->height;
600                 rec->first_line = last_line+1;
601                 rec->last_line = rec->first_line-1 + unit_size -
602                         rec->statusbar_lines;
603                 rec->height = rec->last_line-rec->first_line+1;
604
605                 if (bigger_units > 0) {
606                         rec->last_line++;
607                         bigger_units--;
608                 }
609                 last_line = rec->last_line + rec->statusbar_lines;
610
611                 mainwindow_resize(rec, 0, rec->height-old_size);
612         }
613         g_slist_free(sorted);
614
615         mainwindows_redraw();
616         statusbar_redraw(NULL);
617 }
618
619 /* SYNTAX: WINDOW HIDE [<number>|<name>] */
620 static void cmd_window_hide(const char *data)
621 {
622         WINDOW_REC *window;
623
624         if (mainwindows->next == NULL) {
625                 printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
626                                    TXT_CANT_HIDE_LAST);
627                 return;
628         }
629
630         if (*data == '\0')
631                 window = active_win;
632         else if (is_numeric(data, 0)) {
633                 window = window_find_refnum(atoi(data));
634                 if (window == NULL) {
635                         printformat_window(active_win, MSGLEVEL_CLIENTERROR,
636                                            TXT_REFNUM_NOT_FOUND, data);
637                 }
638         } else {
639                 window = window_find_item(active_win->active_server, data);
640         }
641
642         if (window == NULL || !is_window_visible(window))
643                 return;
644
645         if (WINDOW_GUI(window)->parent->sticky_windows != NULL) {
646                 printformat_window(active_win, MSGLEVEL_CLIENTERROR,
647                                    TXT_CANT_HIDE_STICKY_WINDOWS);
648                 return;
649         }
650
651         mainwindow_destroy(WINDOW_GUI(window)->parent);
652
653         if (active_mainwin == NULL) {
654                 active_mainwin = WINDOW_GUI(active_win)->parent;
655                 window_set_active(active_mainwin->active);
656         }
657 }
658
659 /* SYNTAX: WINDOW SHOW <number>|<name> */
660 static void cmd_window_show(const char *data)
661 {
662         MAIN_WINDOW_REC *parent;
663         WINDOW_REC *window;
664
665         if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
666
667         if (is_numeric(data, '\0')) {
668                 window = window_find_refnum(atoi(data));
669                 if (window == NULL) {
670                         printformat_window(active_win, MSGLEVEL_CLIENTERROR,
671                                            TXT_REFNUM_NOT_FOUND, data);
672                 }
673         } else {
674                 window = window_find_item(active_win->active_server, data);
675         }
676
677         if (window == NULL || is_window_visible(window))
678                 return;
679
680         if (WINDOW_GUI(window)->parent->sticky_windows != NULL) {
681                 printformat_window(active_win, MSGLEVEL_CLIENTERROR,
682                                    TXT_CANT_SHOW_STICKY_WINDOWS);
683                 return;
684         }
685
686         parent = mainwindow_create();
687         if (settings_get_bool("autostick_split_windows")) {
688                 parent->sticky_windows =
689                         g_slist_append(parent->sticky_windows, window);
690         }
691         parent->active = window;
692         gui_window_reparent(window, parent);
693
694         active_mainwin = NULL;
695         window_set_active(window);
696 }
697
698 /* SYNTAX: WINDOW UP */
699 static void cmd_window_up(void)
700 {
701         MAIN_WINDOW_REC *rec;
702
703         rec = mainwindows_find_upper(active_mainwin->first_line);
704         if (rec != NULL)
705                 window_set_active(rec->active);
706 }
707
708 /* SYNTAX: WINDOW DOWN */
709 static void cmd_window_down(void)
710 {
711         MAIN_WINDOW_REC *rec;
712
713         rec = mainwindows_find_lower(active_mainwin->last_line);
714         if (rec != NULL)
715                 window_set_active(rec->active);
716 }
717
718 /* SYNTAX: WINDOW LEFT */
719 static void cmd_window_left(const char *data, SERVER_REC *server, void *item)
720 {
721         MAIN_WINDOW_REC *parent;
722         WINDOW_REC *window;
723         int pos, num;
724
725         window = NULL;
726         if (active_mainwin->sticky_windows == NULL) {
727                 /* no sticky windows, go to previous non-sticky window */
728                 num = active_win->refnum;
729                 do {
730                         num = window_refnum_prev(num, TRUE);
731                         if (num < 0) {
732                                 window = NULL;
733                                 break;
734                         }
735                         window = window_find_refnum(num);
736                         parent = WINDOW_GUI(window)->parent;
737                 } while (g_slist_find(parent->sticky_windows, window) != NULL);
738         } else {
739                 pos = g_slist_index(active_mainwin->sticky_windows,
740                                     active_win);
741                 if (pos > 0) {
742                         window = g_slist_nth_data(
743                                         active_mainwin->sticky_windows, pos-1);
744                 } else {
745                         window = g_slist_last(
746                                         active_mainwin->sticky_windows)->data;
747                 }
748         }
749
750         if (window != NULL)
751                 window_set_active(window);
752 }
753
754 /* SYNTAX: WINDOW RIGHT */
755 static void cmd_window_right(void)
756 {
757         MAIN_WINDOW_REC *parent;
758         WINDOW_REC *window;
759         GSList *tmp;
760         int num;
761
762         window = NULL;
763         if (active_mainwin->sticky_windows == NULL) {
764                 /* no sticky windows, go to next non-sticky window */
765                 num = active_win->refnum;
766                 do {
767                         num = window_refnum_next(num, TRUE);
768                         if (num < 0) {
769                                 window = NULL;
770                                 break;
771                         }
772                         window = window_find_refnum(num);
773                         parent = WINDOW_GUI(window)->parent;
774                 } while (g_slist_find(parent->sticky_windows, window) != NULL);
775         } else {
776                 tmp = g_slist_find(active_mainwin->sticky_windows, active_win);
777                 if (tmp != NULL) {
778                         window = tmp->next != NULL ? tmp->next->data :
779                                 active_mainwin->sticky_windows->data;
780                 }
781         }
782
783         if (window != NULL)
784                 window_set_active(window);
785 }
786
787 static void mainwindow_change_window(MAIN_WINDOW_REC *mainwin,
788                                      WINDOW_REC *window)
789 {
790         MAIN_WINDOW_REC *parent;
791         GSList *tmp;
792
793         if (mainwin->sticky_windows != NULL) {
794                 /* sticky window */
795                 window_set_active(mainwin->sticky_windows->data);
796                 return;
797         }
798
799         for (tmp = windows; tmp != NULL; tmp = tmp->next) {
800                 WINDOW_REC *rec = tmp->data;
801
802                 parent = WINDOW_GUI(rec)->parent;
803                 if (rec != window &&
804                     g_slist_find(parent->sticky_windows, rec) == NULL) {
805                         window_set_active(rec);
806                         return;
807                 }
808         }
809
810         /* no more non-sticky windows, remove main window */
811         mainwindow_destroy(mainwin);
812 }
813
814 /* SYNTAX: WINDOW STICK [ON|OFF|<ref#>] */
815 static void cmd_window_stick(const char *data)
816 {
817         MAIN_WINDOW_REC *window = active_mainwin;
818
819         if (is_numeric(data, '\0')) {
820                 WINDOW_REC *win = window_find_refnum(atoi(data));
821                 if (win == NULL) {
822                         printformat_window(active_win, MSGLEVEL_CLIENTERROR,
823                                            TXT_REFNUM_NOT_FOUND, data);
824                         return;
825                 }
826                 window = WINDOW_GUI(win)->parent;
827         }
828
829         if (g_strncasecmp(data, "OF", 2) == 0 || toupper(*data) == 'N') {
830                 /* unset sticky */
831                 if (g_slist_find(window->sticky_windows, active_win) == NULL) {
832                         printformat_window(active_win, MSGLEVEL_CLIENTERROR,
833                                            TXT_WINDOW_NOT_STICKY);
834                 } else {
835                         window->sticky_windows =
836                                 g_slist_remove(window->sticky_windows,
837                                                active_win);
838                         printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
839                                            TXT_WINDOW_UNSET_STICKY);
840                 }
841         } else {
842                 /* set sticky */
843                 active_mainwin->sticky_windows =
844                         g_slist_remove(active_mainwin->sticky_windows,
845                                        active_win);
846
847                 if (g_slist_find(window->sticky_windows, active_win) == NULL) {
848                         window->sticky_windows =
849                                 g_slist_append(window->sticky_windows,
850                                                active_win);
851                 }
852                 if (window != active_mainwin) {
853                         WINDOW_REC *movewin;
854
855                         movewin = active_win;
856                         gui_window_reparent(movewin, window);
857                         mainwindow_change_window(active_mainwin, movewin);
858
859                         active_mainwin = window;
860                         window_set_active(movewin);
861                 }
862
863                 printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
864                                    TXT_WINDOW_SET_STICKY);
865         }
866 }
867
868 void mainwindows_init(void)
869 {
870         screen_width = COLS;
871         screen_height = LINES;
872
873         mainwindows = NULL;
874         active_mainwin = NULL;
875         reserved_up = reserved_down = 0;
876
877         /* for entry line */
878         mainwindows_reserve_lines(1, FALSE);
879
880         command_bind("window grow", NULL, (SIGNAL_FUNC) cmd_window_grow);
881         command_bind("window shrink", NULL, (SIGNAL_FUNC) cmd_window_shrink);
882         command_bind("window size", NULL, (SIGNAL_FUNC) cmd_window_size);
883         command_bind("window balance", NULL, (SIGNAL_FUNC) cmd_window_balance);
884         command_bind("window hide", NULL, (SIGNAL_FUNC) cmd_window_hide);
885         command_bind("window show", NULL, (SIGNAL_FUNC) cmd_window_show);
886         command_bind("window up", NULL, (SIGNAL_FUNC) cmd_window_up);
887         command_bind("window down", NULL, (SIGNAL_FUNC) cmd_window_down);
888         command_bind("window left", NULL, (SIGNAL_FUNC) cmd_window_left);
889         command_bind("window right", NULL, (SIGNAL_FUNC) cmd_window_right);
890         command_bind("window stick", NULL, (SIGNAL_FUNC) cmd_window_stick);
891 }
892
893 void mainwindows_deinit(void)
894 {
895         while (mainwindows != NULL)
896                 mainwindow_destroy(mainwindows->data);
897
898         command_unbind("window grow", (SIGNAL_FUNC) cmd_window_grow);
899         command_unbind("window shrink", (SIGNAL_FUNC) cmd_window_shrink);
900         command_unbind("window size", (SIGNAL_FUNC) cmd_window_size);
901         command_unbind("window balance", (SIGNAL_FUNC) cmd_window_balance);
902         command_unbind("window hide", (SIGNAL_FUNC) cmd_window_hide);
903         command_unbind("window show", (SIGNAL_FUNC) cmd_window_show);
904         command_unbind("window up", (SIGNAL_FUNC) cmd_window_up);
905         command_unbind("window down", (SIGNAL_FUNC) cmd_window_down);
906         command_unbind("window left", (SIGNAL_FUNC) cmd_window_left);
907         command_unbind("window right", (SIGNAL_FUNC) cmd_window_right);
908         command_unbind("window stick", (SIGNAL_FUNC) cmd_window_stick);
909 }