1 /*
2 windows.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 along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "module.h"
22 #include "module-formats.h"
23 #include "modules.h"
24 #include "signals.h"
25 #include "commands.h"
26 #include "servers.h"
27 #include "misc.h"
28 #include "settings.h"
29
30 #include "levels.h"
31
32 #include "printtext.h"
33 #include "fe-windows.h"
34 #include "window-items.h"
35
36 GSList *windows; /* first in the list is the active window,
37 next is the last active, etc. */
38 GSequence *windows_seq;
39 WINDOW_REC *active_win;
40
41 static int daytag;
42 static int daycheck; /* 0 = don't check, 1 = time is 00:00, check,
43 2 = time is 00:00, already checked */
44
window_refnum_lookup(WINDOW_REC * window,void * refnum_p)45 static int window_refnum_lookup(WINDOW_REC *window, void *refnum_p)
46 {
47 int refnum = GPOINTER_TO_INT(refnum_p);
48 return window->refnum == refnum ? 0 : window->refnum < refnum ? -1 : 1;
49 }
50
windows_seq_begin(void)51 static GSequenceIter *windows_seq_begin(void)
52 {
53 return g_sequence_get_begin_iter(windows_seq);
54 }
55
windows_seq_end(void)56 static GSequenceIter *windows_seq_end(void)
57 {
58 return g_sequence_get_end_iter(windows_seq);
59 }
60
windows_seq_insert(WINDOW_REC * rec)61 static GSequenceIter *windows_seq_insert(WINDOW_REC *rec)
62 {
63 return g_sequence_insert_sorted(windows_seq, rec, (GCompareDataFunc)window_refnum_cmp, NULL);
64 }
65
windows_seq_refnum_lookup(int refnum)66 static GSequenceIter *windows_seq_refnum_lookup(int refnum)
67 {
68 return g_sequence_lookup(windows_seq, GINT_TO_POINTER(refnum), (GCompareDataFunc)window_refnum_lookup, NULL);
69 }
70
windows_seq_changed(GSequenceIter * iter)71 static void windows_seq_changed(GSequenceIter *iter)
72 {
73 g_sequence_sort_changed(iter, (GCompareDataFunc)window_refnum_cmp, NULL);
74 }
75
windows_seq_window_lookup(WINDOW_REC * rec)76 static GSequenceIter *windows_seq_window_lookup(WINDOW_REC *rec)
77 {
78 return g_sequence_lookup(windows_seq, rec, (GCompareDataFunc)window_refnum_cmp, NULL);
79 }
80
81 /* search to the numerically right iterator of refnum */
windows_seq_refnum_search_right(int refnum)82 static GSequenceIter *windows_seq_refnum_search_right(int refnum)
83 {
84 return g_sequence_search(windows_seq, GINT_TO_POINTER(refnum), (GCompareDataFunc)window_refnum_lookup, NULL);
85 }
86
87 /* we want to find the numerically left iterator of refnum, so we
88 search the right of the previous refnum. but we need to figure out
89 the case where the iterator is already at the beginning, i.e
90 iter->refnum >= refnum */
windows_seq_refnum_search_left(int refnum)91 static GSequenceIter *windows_seq_refnum_search_left(int refnum)
92 {
93 GSequenceIter *iter = windows_seq_refnum_search_right(refnum - 1);
94 return iter == windows_seq_begin() ? NULL : g_sequence_iter_prev(iter);
95 }
96
window_get_new_refnum(void)97 static int window_get_new_refnum(void)
98 {
99 WINDOW_REC *win;
100 GSequenceIter *iter, *end;
101 int refnum;
102
103 refnum = 1;
104 iter = windows_seq_begin();
105 end = windows_seq_end();
106
107 while (iter != end) {
108 win = g_sequence_get(iter);
109
110 if (refnum != win->refnum)
111 return refnum;
112
113 refnum++;
114 iter = g_sequence_iter_next(iter);
115 }
116
117 return refnum;
118 }
119
window_create(WI_ITEM_REC * item,int automatic)120 WINDOW_REC *window_create(WI_ITEM_REC *item, int automatic)
121 {
122 WINDOW_REC *rec;
123
124 rec = g_new0(WINDOW_REC, 1);
125 rec->refnum = window_get_new_refnum();
126 rec->level = settings_get_level("window_default_level");
127
128 windows = g_slist_prepend(windows, rec);
129 windows_seq_insert(rec);
130 signal_emit("window created", 2, rec, GINT_TO_POINTER(automatic));
131
132 if (item != NULL) window_item_add(rec, item, automatic);
133 if (windows->next == NULL || !automatic || settings_get_bool("window_auto_change")) {
134 if (automatic && windows->next != NULL)
135 signal_emit("window changed automatic", 1, rec);
136 window_set_active(rec);
137 }
138 return rec;
139 }
140
window_set_refnum0(WINDOW_REC * window,int refnum)141 static void window_set_refnum0(WINDOW_REC *window, int refnum)
142 {
143 int old_refnum;
144
145 g_return_if_fail(window != NULL);
146 g_return_if_fail(refnum >= 1);
147 if (window->refnum == refnum) return;
148
149 old_refnum = window->refnum;
150 window->refnum = refnum;
151 signal_emit("window refnum changed", 2, window, GINT_TO_POINTER(old_refnum));
152 }
153
154 /* removed_refnum was removed from the windows list, pack the windows so
155 there won't be any holes. If there is any holes after removed_refnum,
156 leave the windows behind it alone. */
windows_pack(int removed_refnum)157 static void windows_pack(int removed_refnum)
158 {
159 WINDOW_REC *window;
160 int refnum;
161 GSequenceIter *iter, *end;
162
163 refnum = removed_refnum + 1;
164 end = windows_seq_end();
165 iter = windows_seq_refnum_lookup(refnum);
166 if (iter == NULL) return;
167
168 while (iter != end) {
169 window = g_sequence_get(iter);
170
171 if (window == NULL || window->sticky_refnum || window->refnum != refnum)
172 break;
173
174 window_set_refnum0(window, refnum - 1);
175 windows_seq_changed(iter);
176
177 refnum++;
178 iter = g_sequence_iter_next(iter);
179 }
180 }
181
window_destroy(WINDOW_REC * window)182 void window_destroy(WINDOW_REC *window)
183 {
184 GSequenceIter *iter;
185 g_return_if_fail(window != NULL);
186
187 if (window->destroying) return;
188 window->destroying = TRUE;
189 windows = g_slist_remove(windows, window);
190 iter = windows_seq_window_lookup(window);
191 if (iter != NULL) g_sequence_remove(iter);
192
193 if (active_win == window) {
194 active_win = NULL; /* it's corrupted */
195 if (windows != NULL)
196 window_set_active(windows->data);
197 }
198
199 while (window->items != NULL)
200 window_item_destroy(window->items->data);
201
202 if (settings_get_bool("windows_auto_renumber"))
203 windows_pack(window->refnum);
204
205 signal_emit("window destroyed", 1, window);
206
207 while (window->bound_items != NULL)
208 window_bind_destroy(window, window->bound_items->data);
209
210 g_free_not_null(window->hilight_color);
211 g_free_not_null(window->servertag);
212 g_free_not_null(window->theme_name);
213 g_free_not_null(window->name);
214 g_free(window);
215 }
216
window_auto_destroy(WINDOW_REC * window)217 void window_auto_destroy(WINDOW_REC *window)
218 {
219 if (settings_get_bool("autoclose_windows") && windows->next != NULL &&
220 window->items == NULL && window->bound_items == NULL &&
221 window->level == 0 && !window->immortal)
222 window_destroy(window);
223 }
224
window_set_active(WINDOW_REC * window)225 void window_set_active(WINDOW_REC *window)
226 {
227 WINDOW_REC *old_window;
228
229 if (window == active_win)
230 return;
231
232 old_window = active_win;
233 active_win = window;
234 if (active_win != NULL) {
235 windows = g_slist_remove(windows, active_win);
236 windows = g_slist_prepend(windows, active_win);
237 }
238
239 if (active_win != NULL)
240 signal_emit("window changed", 2, active_win, old_window);
241 }
242
window_change_server(WINDOW_REC * window,void * server)243 void window_change_server(WINDOW_REC *window, void *server)
244 {
245 SERVER_REC *active, *connect;
246
247 if (server != NULL && SERVER(server)->disconnected)
248 return;
249
250 if (server == NULL) {
251 active = connect = NULL;
252 } else if (g_slist_find(servers, server) != NULL) {
253 active = server;
254 connect = NULL;
255 } else {
256 active = NULL;
257 connect = server;
258 }
259
260 if (window->connect_server != connect) {
261 window->connect_server = connect;
262 signal_emit("window connect changed", 2, window, connect);
263 }
264
265 if (window->active_server != active) {
266 window->active_server = active;
267 signal_emit("window server changed", 2, window, active);
268 }
269 }
270
window_set_refnum(WINDOW_REC * window,int refnum)271 void window_set_refnum(WINDOW_REC *window, int refnum)
272 {
273 GSequenceIter *other_iter, *window_iter;
274 int old_refnum;
275
276 g_return_if_fail(window != NULL);
277 g_return_if_fail(refnum >= 1);
278 if (window->refnum == refnum) return;
279
280 other_iter = windows_seq_refnum_lookup(refnum);
281 window_iter = windows_seq_refnum_lookup(window->refnum);
282
283 if (other_iter != NULL) {
284 WINDOW_REC *rec = g_sequence_get(other_iter);
285
286 rec->refnum = window->refnum;
287 signal_emit("window refnum changed", 2, rec, GINT_TO_POINTER(refnum));
288 }
289
290 old_refnum = window->refnum;
291 window->refnum = refnum;
292 signal_emit("window refnum changed", 2, window, GINT_TO_POINTER(old_refnum));
293
294 if (window_iter != NULL && other_iter != NULL) {
295 g_sequence_swap(other_iter, window_iter);
296 } else {
297 windows_seq_changed(window_iter);
298 }
299 }
300
window_set_name(WINDOW_REC * window,const char * name)301 void window_set_name(WINDOW_REC *window, const char *name)
302 {
303 g_free_not_null(window->name);
304 window->name = name == NULL || *name == '\0' ? NULL : g_strdup(name);
305
306 signal_emit("window name changed", 1, window);
307 }
308
window_set_history(WINDOW_REC * window,const char * name)309 void window_set_history(WINDOW_REC *window, const char *name)
310 {
311 char *oldname;
312 oldname = window->history_name;
313
314 if (name == NULL || *name == '\0')
315 window->history_name = NULL;
316 else
317 window->history_name = g_strdup(name);
318
319 signal_emit("window history changed", 2, window, oldname);
320
321 g_free_not_null(oldname);
322 }
323
window_clear_history(WINDOW_REC * window,const char * name)324 void window_clear_history(WINDOW_REC *window, const char *name)
325 {
326 signal_emit("window history cleared", 2, window, name);
327 }
328
window_set_level(WINDOW_REC * window,int level)329 void window_set_level(WINDOW_REC *window, int level)
330 {
331 g_return_if_fail(window != NULL);
332
333 window->level = level;
334 signal_emit("window level changed", 1, window);
335 }
336
window_set_immortal(WINDOW_REC * window,int immortal)337 void window_set_immortal(WINDOW_REC *window, int immortal)
338 {
339 g_return_if_fail(window != NULL);
340
341 window->immortal = immortal;
342 signal_emit("window immortal changed", 1, window);
343 }
344
345 /* return active item's name, or if none is active, window's name */
window_get_active_name(WINDOW_REC * window)346 const char *window_get_active_name(WINDOW_REC *window)
347 {
348 g_return_val_if_fail(window != NULL, NULL);
349
350 if (window->active != NULL)
351 return window->active->visible_name;
352
353 return window->name;
354 }
355
356 #define WINDOW_LEVEL_MATCH(window, server, level) \
357 (((window)->level & level) && \
358 (server == NULL || (window)->active_server == server))
359
window_find_level(void * server,int level)360 WINDOW_REC *window_find_level(void *server, int level)
361 {
362 GSList *tmp;
363 WINDOW_REC *match;
364
365 match = NULL;
366 for (tmp = windows; tmp != NULL; tmp = tmp->next) {
367 WINDOW_REC *rec = tmp->data;
368
369 if (WINDOW_LEVEL_MATCH(rec, server, level)) {
370 /* prefer windows without any items */
371 if (rec->items == NULL)
372 return rec;
373
374 if (match == NULL)
375 match = rec;
376 else if (active_win == rec) {
377 /* prefer active window over others */
378 match = rec;
379 }
380 }
381 }
382
383 return match;
384 }
385
window_find_closest(void * server,const char * name,int level)386 WINDOW_REC *window_find_closest(void *server, const char *name, int level)
387 {
388 WINDOW_REC *window,*namewindow=NULL;
389 WI_ITEM_REC *item;
390 int i;
391
392 /* match by name */
393 item = name == NULL ? NULL :
394 window_item_find(server, name);
395 if (item != NULL) {
396 namewindow = window_item_window(item);
397 if (namewindow != NULL &&
398 ((namewindow->level & level) != 0 ||
399 !settings_get_bool("window_check_level_first"))) {
400 /* match, but if multiple windows have the same level
401 we could be choosing a bad one here, eg.
402 name=nick1 would get nick2's query instead of
403 generic msgs window.
404
405 And check for prefixed !channel name --Borys */
406 if (g_ascii_strcasecmp(name, item->visible_name) == 0 ||
407 g_ascii_strcasecmp(name, (char *) window_item_get_target((WI_ITEM_REC *) item)) == 0)
408 return namewindow;
409 }
410 }
411
412 /* prefer windows without items */
413 for (i = 0; i < 2; i++) {
414 /* match by level */
415 if (level != MSGLEVEL_HILIGHT)
416 level &= ~(MSGLEVEL_HILIGHT | MSGLEVEL_NOHILIGHT);
417 window = window_find_level(server, level);
418 if (window != NULL && (i == 1 || window->items == NULL))
419 return window;
420
421 /* match by level - ignore server */
422 window = window_find_level(NULL, level);
423 if (window != NULL && (i == 1 || window->items == NULL))
424 return window;
425 }
426
427 /* still return item's window if we didnt find anything */
428 if (namewindow != NULL) return namewindow;
429
430 /* fallback to active */
431 return active_win;
432 }
433
window_find_refnum(int refnum)434 WINDOW_REC *window_find_refnum(int refnum)
435 {
436 GSequenceIter *iter;
437
438 iter = windows_seq_refnum_lookup(refnum);
439 if (iter != NULL) {
440 WINDOW_REC *rec = g_sequence_get(iter);
441
442 return rec;
443 }
444
445 return NULL;
446 }
447
window_find_name(const char * name)448 WINDOW_REC *window_find_name(const char *name)
449 {
450 GSList *tmp;
451
452 g_return_val_if_fail(name != NULL, NULL);
453
454 for (tmp = windows; tmp != NULL; tmp = tmp->next) {
455 WINDOW_REC *rec = tmp->data;
456
457 if (rec->name != NULL &&
458 g_ascii_strcasecmp(rec->name, name) == 0)
459 return rec;
460 }
461
462 return NULL;
463 }
464
window_find_item(SERVER_REC * server,const char * name)465 WINDOW_REC *window_find_item(SERVER_REC *server, const char *name)
466 {
467 WINDOW_REC *rec;
468 WI_ITEM_REC *item;
469
470 g_return_val_if_fail(name != NULL, NULL);
471
472 rec = window_find_name(name);
473 if (rec != NULL) return rec;
474
475 item = server == NULL ? NULL :
476 window_item_find(server, name);
477 if (item == NULL) {
478 /* not found from the active server - any server? */
479 item = window_item_find(NULL, name);
480 }
481
482 if (item == NULL)
483 return NULL;
484
485 return window_item_window(item);
486 }
487
window_refnum_prev(int refnum,int wrap)488 int window_refnum_prev(int refnum, int wrap)
489 {
490 WINDOW_REC *rec;
491 GSequenceIter *iter, *end;
492
493 iter = windows_seq_refnum_search_left(refnum);
494 end = windows_seq_end();
495
496 if (iter != NULL) {
497 rec = g_sequence_get(iter);
498 return rec->refnum;
499 }
500
501 if (wrap) {
502 iter = g_sequence_iter_prev(end);
503 if (iter != end) {
504 rec = g_sequence_get(iter);
505 return rec->refnum;
506 }
507 }
508
509 return -1;
510 }
511
window_refnum_next(int refnum,int wrap)512 int window_refnum_next(int refnum, int wrap)
513 {
514 WINDOW_REC *rec;
515 GSequenceIter *iter, *end;
516
517 iter = windows_seq_refnum_search_right(refnum);
518 end = windows_seq_end();
519
520 if (iter != end) {
521 rec = g_sequence_get(iter);
522 return rec->refnum;
523 }
524
525 if (wrap) {
526 iter = windows_seq_begin();
527 if (iter != end) {
528 rec = g_sequence_get(iter);
529 return rec->refnum;
530 }
531 }
532
533 return -1;
534 }
535
windows_refnum_last(void)536 int windows_refnum_last(void)
537 {
538 WINDOW_REC *rec;
539 GSequenceIter *end, *iter;
540
541 end = windows_seq_end();
542 iter = g_sequence_iter_prev(end);
543 if (iter != end) {
544 rec = g_sequence_get(iter);
545 return rec->refnum;
546 }
547
548 return -1;
549 }
550
window_refnum_cmp(WINDOW_REC * w1,WINDOW_REC * w2)551 int window_refnum_cmp(WINDOW_REC *w1, WINDOW_REC *w2)
552 {
553 return w1 == w2 ? 0 : w1->refnum < w2->refnum ? -1 : 1;
554 }
555
windows_get_sorted(void)556 GSList *windows_get_sorted(void)
557 {
558 GSequenceIter *iter, *begin;
559 GSList *sorted;
560
561 sorted = NULL;
562 iter = windows_seq_end();
563 begin = windows_seq_begin();
564
565 while (iter != begin) {
566 WINDOW_REC *rec;
567
568 iter = g_sequence_iter_prev(iter);
569 rec = g_sequence_get(iter);
570
571 sorted = g_slist_prepend(sorted, rec);
572 }
573
574 return sorted;
575 }
576
577 /* Add a new bind to window - if duplicate is found it's returned */
window_bind_add(WINDOW_REC * window,const char * servertag,const char * name)578 WINDOW_BIND_REC *window_bind_add(WINDOW_REC *window, const char *servertag,
579 const char *name)
580 {
581 WINDOW_BIND_REC *rec;
582
583 g_return_val_if_fail(window != NULL, NULL);
584 g_return_val_if_fail(servertag != NULL, NULL);
585 g_return_val_if_fail(name != NULL, NULL);
586
587 rec = window_bind_find(window, servertag, name);
588 if (rec != NULL)
589 return rec;
590
591 rec = g_new0(WINDOW_BIND_REC, 1);
592 rec->name = g_strdup(name);
593 rec->servertag = g_strdup(servertag);
594
595 window->bound_items = g_slist_append(window->bound_items, rec);
596 return rec;
597 }
598
window_bind_destroy(WINDOW_REC * window,WINDOW_BIND_REC * rec)599 void window_bind_destroy(WINDOW_REC *window, WINDOW_BIND_REC *rec)
600 {
601 g_return_if_fail(window != NULL);
602 g_return_if_fail(rec != NULL);
603
604 window->bound_items = g_slist_remove(window->bound_items, rec);
605
606 g_free(rec->servertag);
607 g_free(rec->name);
608 g_free(rec);
609 }
610
window_bind_find(WINDOW_REC * window,const char * servertag,const char * name)611 WINDOW_BIND_REC *window_bind_find(WINDOW_REC *window, const char *servertag,
612 const char *name)
613 {
614 GSList *tmp;
615
616 g_return_val_if_fail(window != NULL, NULL);
617 g_return_val_if_fail(servertag != NULL, NULL);
618 g_return_val_if_fail(name != NULL, NULL);
619
620 for (tmp = window->bound_items; tmp != NULL; tmp = tmp->next) {
621 WINDOW_BIND_REC *rec = tmp->data;
622
623 if (g_ascii_strcasecmp(rec->name, name) == 0 &&
624 g_ascii_strcasecmp(rec->servertag, servertag) == 0)
625 return rec;
626 }
627
628 return NULL;
629 }
630
window_bind_remove_unsticky(WINDOW_REC * window)631 void window_bind_remove_unsticky(WINDOW_REC *window)
632 {
633 GSList *tmp, *next;
634
635 for (tmp = window->bound_items; tmp != NULL; tmp = next) {
636 WINDOW_BIND_REC *rec = tmp->data;
637
638 next = tmp->next;
639 if (!rec->sticky)
640 window_bind_destroy(window, rec);
641 }
642 }
643
sig_server_connected(SERVER_REC * server)644 static void sig_server_connected(SERVER_REC *server)
645 {
646 GSList *tmp;
647
648 g_return_if_fail(server != NULL);
649
650 /* Try to keep some server assigned to windows..
651 Also change active window's server if the window is empty */
652 for (tmp = windows; tmp != NULL; tmp = tmp->next) {
653 WINDOW_REC *rec = tmp->data;
654
655 if ((rec->servertag == NULL ||
656 g_ascii_strcasecmp(rec->servertag, server->tag) == 0) &&
657 (rec->active_server == NULL ||
658 (rec == active_win && rec->items == NULL)))
659 window_change_server(rec, server);
660 }
661 }
662
sig_server_disconnected(SERVER_REC * server)663 static void sig_server_disconnected(SERVER_REC *server)
664 {
665 GSList *tmp;
666 SERVER_REC *new_server;
667
668 g_return_if_fail(server != NULL);
669
670 new_server = servers == NULL ? NULL : servers->data;
671 for (tmp = windows; tmp != NULL; tmp = tmp->next) {
672 WINDOW_REC *rec = tmp->data;
673
674 if (rec->active_server == server ||
675 rec->connect_server == server) {
676 window_change_server(rec, rec->servertag != NULL ?
677 NULL : new_server);
678 }
679 }
680 }
681
window_print_daychange(WINDOW_REC * window,struct tm * tm)682 static void window_print_daychange(WINDOW_REC *window, struct tm *tm)
683 {
684 THEME_REC *theme;
685 TEXT_DEST_REC dest;
686 char *format, str[256];
687 int ret;
688
689 theme = active_win->theme != NULL ? active_win->theme : current_theme;
690 format_create_dest(&dest, NULL, NULL, MSGLEVEL_NEVER, window);
691 format = format_get_text_theme(theme, MODULE_NAME, &dest,
692 TXT_DAYCHANGE);
693 ret = strftime(str, sizeof(str), format, tm);
694 g_free(format);
695 if (ret <= 0) return;
696
697 printtext_string_window(window, MSGLEVEL_NEVER, str);
698 }
699
color_24bit_256(const unsigned char rgb[])700 short color_24bit_256 (const unsigned char rgb[])
701 {
702 static const int cstep_size = 40;
703 static const int cstep_start = 0x5f;
704
705 static const int gstep_size = 10;
706 static const int gstep_start = 0x08;
707
708 int dist[3] = {0};
709 int r[3], gr[3];
710
711 size_t i;
712
713 for (i = 0; i < 3; ++i) {
714 const int n = rgb[i];
715 gr[i] = -1;
716 if (n < cstep_start /2) {
717 r[i] = 0;
718 dist[i] = -cstep_size/2;
719 }
720 else {
721 r[i] = 1+((n-cstep_start + cstep_size /2)/cstep_size);
722 dist[i] = ((n-cstep_start + cstep_size /2)%cstep_size - cstep_size/2);
723 }
724 if (n < gstep_start /2) {
725 gr[i] = -1;
726 }
727 else {
728 gr[i] = ((n-gstep_start + gstep_size /2)/gstep_size);
729 }
730 }
731 if (r[0] == r[1] && r[1] == r[2] &&
732 4*abs(dist[0]) < gstep_size && 4*abs(dist[1]) < gstep_size && 4*abs(dist[2]) < gstep_size) {
733 /* skip gray detection */
734 }
735 else {
736 const int j = r[1] == r[2] ? 0 : 1;
737 if ((r[0] == r[1] || r[j] == r[2]) && abs(r[j]-r[(j+1)%3]) <= 1) {
738 const int k = gr[1] == gr[2] ? 0 : 1;
739 if ((gr[0] == gr[1] || gr[k] == gr[2]) && abs(gr[k]-gr[(k+1)%3]) <= 2) {
740 if (gr[k] < 0) {
741 r[0] = r[1] = r[2] = 0;
742 }
743 else if (gr[k] > 23) {
744 r[0] = r[1] = r[2] = 5;
745 }
746 else {
747 r[0] = 6;
748 r[1] = (gr[k] / 6);
749 r[2] = gr[k]%6;
750 }
751 }
752 }
753 }
754 return 16 + r[0]*36 + r[1] * 6 + r[2];
755 }
756
sig_print_text(void)757 static void sig_print_text(void)
758 {
759 GSList *tmp;
760 time_t t;
761 struct tm *tm;
762
763 t = time(NULL);
764 tm = localtime(&t);
765 if (tm->tm_hour != 0 || tm->tm_min != 0)
766 return;
767
768 daycheck = 2;
769 signal_remove("print text", (SIGNAL_FUNC) sig_print_text);
770
771 /* day changed, print notice about it to every window */
772 for (tmp = windows; tmp != NULL; tmp = tmp->next)
773 window_print_daychange(tmp->data, tm);
774 }
775
sig_check_daychange(void)776 static int sig_check_daychange(void)
777 {
778 time_t t;
779 struct tm *tm;
780
781 t = time(NULL);
782 tm = localtime(&t);
783
784 if (daycheck == 1 && tm->tm_hour == 0 && tm->tm_min == 0) {
785 sig_print_text();
786 return TRUE;
787 }
788
789 if (tm->tm_hour != 23 || tm->tm_min != 59) {
790 daycheck = 0;
791 return TRUE;
792 }
793
794 /* time is 23:59 */
795 if (daycheck == 0) {
796 daycheck = 1;
797 signal_add("print text", (SIGNAL_FUNC) sig_print_text);
798 }
799 return TRUE;
800 }
801
read_settings(void)802 static void read_settings(void)
803 {
804 if (daytag != -1) {
805 g_source_remove(daytag);
806 daytag = -1;
807 }
808
809 if (settings_get_bool("timestamps"))
810 daytag = g_timeout_add(30000, (GSourceFunc) sig_check_daychange, NULL);
811 }
812
windows_init(void)813 void windows_init(void)
814 {
815 active_win = NULL;
816 windows_seq = g_sequence_new(NULL);
817 daycheck = 0; daytag = -1;
818 settings_add_bool("lookandfeel", "window_auto_change", FALSE);
819 settings_add_bool("lookandfeel", "windows_auto_renumber", TRUE);
820 settings_add_bool("lookandfeel", "window_check_level_first", FALSE);
821 settings_add_level("lookandfeel", "window_default_level", "NONE");
822
823 read_settings();
824 signal_add("server looking", (SIGNAL_FUNC) sig_server_connected);
825 signal_add("server connected", (SIGNAL_FUNC) sig_server_connected);
826 signal_add("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
827 signal_add("server connect failed", (SIGNAL_FUNC) sig_server_disconnected);
828 signal_add("setup changed", (SIGNAL_FUNC) read_settings);
829 }
830
windows_deinit(void)831 void windows_deinit(void)
832 {
833 if (daytag != -1) g_source_remove(daytag);
834 if (daycheck == 1) signal_remove("print text", (SIGNAL_FUNC) sig_print_text);
835
836 signal_remove("server looking", (SIGNAL_FUNC) sig_server_connected);
837 signal_remove("server connected", (SIGNAL_FUNC) sig_server_connected);
838 signal_remove("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
839 signal_remove("server connect failed", (SIGNAL_FUNC) sig_server_disconnected);
840 signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
841 g_sequence_free(windows_seq);
842 windows_seq = NULL;
843 }
844