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