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