Merged 0.7.99 irssi.
[crypto.git] / apps / irssi / src / fe-common / core / window-items.c
1 /*
2  window-items.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 "modules.h"
24 #include "signals.h"
25 #include "servers.h"
26 #include "settings.h"
27
28 #include "levels.h"
29
30 #include "fe-windows.h"
31 #include "window-items.h"
32 #include "printtext.h"
33
34 void window_item_add(WINDOW_REC *window, WI_ITEM_REC *item, int automatic)
35 {
36         g_return_if_fail(window != NULL);
37         g_return_if_fail(item != NULL);
38         g_return_if_fail(item->window == NULL);
39
40         item->window = window;
41
42         if (window->items == NULL) {
43                 window->active = item;
44                 window->active_server = item->server;
45         }
46
47         if (!automatic || settings_get_bool("window_auto_change")) {
48                 if (automatic)
49                         signal_emit("window changed automatic", 1, window);
50                 window_set_active(window);
51         }
52
53         window->items = g_slist_append(window->items, item);
54         signal_emit("window item new", 2, window, item);
55
56         if (g_slist_length(window->items) == 1 ||
57             (!automatic && settings_get_bool("autofocus_new_items"))) {
58                 window->active = NULL;
59                 window_item_set_active(window, item);
60         }
61 }
62
63 void window_item_remove(WI_ITEM_REC *item)
64 {
65         WINDOW_REC *window;
66
67         g_return_if_fail(item != NULL);
68
69         window = window_item_window(item);
70
71         if (window == NULL)
72                 return;
73
74         item->window = NULL;
75         window->items = g_slist_remove(window->items, item);
76
77         if (window->active == item) {
78                 window_item_set_active(window, window->items == NULL ? NULL :
79                                        window->items->data);
80         }
81
82         signal_emit("window item remove", 2, window, item);
83 }
84
85 void window_item_destroy(WI_ITEM_REC *item)
86 {
87         WINDOW_REC *window;
88
89         window = window_item_window(item);
90         window_item_remove(item);
91         item->destroy(item);
92 }
93
94 void window_item_change_server(WI_ITEM_REC *item, void *server)
95 {
96         WINDOW_REC *window;
97
98         g_return_if_fail(item != NULL);
99
100         window = window_item_window(item);
101         item->server = server;
102
103         signal_emit("window item server changed", 2, window, item);
104         if (window->active == item) window_change_server(window, item->server);
105 }
106
107 void window_item_set_active(WINDOW_REC *window, WI_ITEM_REC *item)
108 {
109         g_return_if_fail(window != NULL);
110
111         if (item != NULL && window_item_window(item) != window) {
112                 /* move item to different window */
113                 window_item_remove(item);
114                 window_item_add(window, item, FALSE);
115         }
116
117         if (window->active != item) {
118                 window->active = item;
119                 if (item != NULL && window->active_server != item->server)
120                         window_change_server(window, item->server);
121                 signal_emit("window item changed", 2, window, item);
122         }
123 }
124
125 /* Return TRUE if `item' is the active window item in the window.
126    `item' can be NULL. */
127 int window_item_is_active(WI_ITEM_REC *item)
128 {
129         WINDOW_REC *window;
130
131         if (item == NULL)
132                 return FALSE;
133
134         window = window_item_window(item);
135         if (window == NULL)
136                 return FALSE;
137
138         return window->active == item;
139 }
140
141 void window_item_prev(WINDOW_REC *window)
142 {
143         WI_ITEM_REC *last;
144         GSList *tmp;
145
146         g_return_if_fail(window != NULL);
147
148         last = NULL;
149         for (tmp = window->items; tmp != NULL; tmp = tmp->next) {
150                 WI_ITEM_REC *rec = tmp->data;
151
152                 if (rec != window->active)
153                         last = rec;
154                 else {
155                         /* current channel. did we find anything?
156                            if not, go to the last channel */
157                         if (last != NULL) break;
158                 }
159         }
160
161         if (last != NULL)
162                 window_item_set_active(window, last);
163 }
164
165 void window_item_next(WINDOW_REC *window)
166 {
167         WI_ITEM_REC *next;
168         GSList *tmp;
169         int gone;
170
171         g_return_if_fail(window != NULL);
172
173         next = NULL; gone = FALSE;
174         for (tmp = window->items; tmp != NULL; tmp = tmp->next) {
175                 WI_ITEM_REC *rec = tmp->data;
176
177                 if (rec == window->active)
178                         gone = TRUE;
179                 else {
180                         if (gone) {
181                                 /* found the next channel */
182                                 next = rec;
183                                 break;
184                         }
185
186                         if (next == NULL)
187                                 next = rec; /* fallback to first channel */
188                 }
189         }
190
191         if (next != NULL)
192                 window_item_set_active(window, next);
193 }
194
195 WI_ITEM_REC *window_item_find_window(WINDOW_REC *window,
196                                      void *server, const char *name)
197 {
198         GSList *tmp;
199
200         for (tmp = window->items; tmp != NULL; tmp = tmp->next) {
201                 WI_ITEM_REC *rec = tmp->data;
202
203                 if ((server == NULL || rec->server == server) &&
204                     g_strcasecmp(name, rec->name) == 0) return rec;
205         }
206
207         return NULL;
208 }
209
210 /* Find wanted window item by name. `server' can be NULL. */
211 WI_ITEM_REC *window_item_find(void *server, const char *name)
212 {
213         WI_ITEM_REC *item;
214         GSList *tmp;
215
216         g_return_val_if_fail(name != NULL, NULL);
217
218         for (tmp = windows; tmp != NULL; tmp = tmp->next) {
219                 WINDOW_REC *rec = tmp->data;
220
221                 item = window_item_find_window(rec, server, name);
222                 if (item != NULL) return item;
223         }
224
225         return NULL;
226 }
227
228 static int window_bind_has_sticky(WINDOW_REC *window)
229 {
230         GSList *tmp;
231
232         for (tmp = window->bound_items; tmp != NULL; tmp = tmp->next) {
233                 WINDOW_BIND_REC *rec = tmp->data;
234
235                 if (rec->sticky)
236                         return TRUE;
237         }
238
239         return FALSE;
240 }
241
242 void window_item_create(WI_ITEM_REC *item, int automatic)
243 {
244         WINDOW_REC *window;
245         WINDOW_BIND_REC *bind;
246         GSList *tmp, *sorted;
247         int clear_waiting, reuse_unused_windows;
248
249         g_return_if_fail(item != NULL);
250
251         reuse_unused_windows = settings_get_bool("reuse_unused_windows");
252
253         clear_waiting = TRUE;
254         window = NULL;
255         sorted = windows_get_sorted();
256         for (tmp = sorted; tmp != NULL; tmp = tmp->next) {
257                 WINDOW_REC *rec = tmp->data;
258
259                 /* is item bound to this window? */
260                 if (item->server != NULL) {
261                         bind = window_bind_find(rec, item->server->tag,
262                                                 item->name);
263                         if (bind != NULL) {
264                                 if (!bind->sticky)
265                                         window_bind_destroy(rec, bind);
266                                 window = rec;
267                                 clear_waiting = FALSE;
268                                 break;
269                         }
270                 }
271
272                 /* use this window IF:
273                      - reuse_unused_windows is ON
274                      - window has no existing items
275                      - window has no name
276                      - window has no sticky binds (/LAYOUT SAVEd)
277                      - we already haven't found "good enough" window,
278                        except if
279                          - this is the active window
280                          - old window had some temporary bounds and this
281                            one doesn't
282                      */
283                 if (reuse_unused_windows && rec->items == NULL &&
284                     rec->name == NULL && !window_bind_has_sticky(rec) &&
285                     (window == NULL || rec == active_win ||
286                      window->bound_items != NULL))
287                         window = rec;
288         }
289         g_slist_free(sorted);
290
291         if (window == NULL && !settings_get_bool("autocreate_windows")) {
292                 /* never create new windows automatically */
293                 window = active_win;
294         }
295
296         if (window == NULL) {
297                 /* create new window to use */
298                 if (settings_get_bool("autocreate_split_windows")) {
299                         signal_emit("gui window create override", 1,
300                                     GINT_TO_POINTER(0));
301                 }
302                 window = window_create(item, automatic);
303         } else {
304                 /* use existing window */
305                 window_item_add(window, item, automatic);
306         }
307
308         if (clear_waiting)
309                 window_bind_remove_unsticky(window);
310 }
311
312 static void signal_window_item_changed(WINDOW_REC *window, WI_ITEM_REC *item)
313 {
314         g_return_if_fail(window != NULL);
315
316         if (g_slist_length(window->items) > 1) {
317                 /* default to printing "talking with ...",
318                    you can override it it you wish */
319                 printformat(item->server, item->name, MSGLEVEL_CLIENTNOTICE,
320                             TXT_TALKING_WITH, item->name);
321         }
322 }
323
324 void window_items_init(void)
325 {
326         settings_add_bool("lookandfeel", "reuse_unused_windows", FALSE);
327         settings_add_bool("lookandfeel", "autocreate_windows", TRUE);
328         settings_add_bool("lookandfeel", "autocreate_split_windows", FALSE);
329         settings_add_bool("lookandfeel", "autofocus_new_items", TRUE);
330
331         signal_add_last("window item changed", (SIGNAL_FUNC) signal_window_item_changed);
332 }
333
334 void window_items_deinit(void)
335 {
336         signal_remove("window item changed", (SIGNAL_FUNC) signal_window_item_changed);
337 }