Added SILC Thread Queue API
[runtime.git] / apps / irssi / src / fe-common / core / fe-windows.c
index fc4766d938a1d77d93379127af8ac4d6756b66e0..06621c776a2e83b7eaf435cff6ffc4456505d62c 100644 (file)
@@ -70,6 +70,7 @@ WINDOW_REC *window_create(WI_ITEM_REC *item, int automatic)
 
        rec = g_new0(WINDOW_REC, 1);
        rec->refnum = window_get_new_refnum();
+       rec->level = settings_get_level("window_default_level");
 
        windows = g_slist_prepend(windows, rec);
        signal_emit("window created", 2, rec, GINT_TO_POINTER(automatic));
@@ -108,9 +109,10 @@ void window_destroy(WINDOW_REC *window)
        window->destroying = TRUE;
        windows = g_slist_remove(windows, window);
 
-       if (active_win == window && windows != NULL) {
-                active_win = NULL; /* it's corrupted */
-               window_set_active(windows->data);
+       if (active_win == window) {
+               active_win = NULL; /* it's corrupted */
+               if (windows != NULL)
+                       window_set_active(windows->data);
        }
 
        while (window->items != NULL)
@@ -135,7 +137,7 @@ void window_auto_destroy(WINDOW_REC *window)
 {
        if (settings_get_bool("autoclose_windows") && windows->next != NULL &&
            window->items == NULL && window->bound_items == NULL &&
-           window->level == 0)
+           window->level == 0 && !window->immortal)
                 window_destroy(window);
 }
 
@@ -159,8 +161,30 @@ void window_set_active(WINDOW_REC *window)
 
 void window_change_server(WINDOW_REC *window, void *server)
 {
-       window->active_server = server;
-       signal_emit("window server changed", 2, window, server);
+       SERVER_REC *active, *connect;
+
+       if (server != NULL && SERVER(server)->disconnected)
+               return;
+
+       if (server == NULL) {
+               active = connect = NULL;
+       } else if (g_slist_find(servers, server) != NULL) {
+               active = server;
+               connect = NULL;
+       } else {
+               active = NULL;
+               connect = server;
+       }
+
+       if (window->connect_server != connect) {
+               window->connect_server = connect;
+               signal_emit("window connect changed", 2, window, connect);
+       }
+
+       if (window->active_server != active) {
+               window->active_server = active;
+               signal_emit("window server changed", 2, window, active);
+       } 
 }
 
 void window_set_refnum(WINDOW_REC *window, int refnum)
@@ -190,7 +214,7 @@ void window_set_refnum(WINDOW_REC *window, int refnum)
 void window_set_name(WINDOW_REC *window, const char *name)
 {
        g_free_not_null(window->name);
-       window->name = g_strdup(name);
+       window->name = name == NULL || *name == '\0' ? NULL : g_strdup(name);
 
        signal_emit("window name changed", 1, window);
 }
@@ -218,31 +242,49 @@ void window_set_level(WINDOW_REC *window, int level)
         signal_emit("window level changed", 1, window);
 }
 
+void window_set_immortal(WINDOW_REC *window, int immortal)
+{
+       g_return_if_fail(window != NULL);
+
+       window->immortal = immortal;
+        signal_emit("window immortal changed", 1, window);
+}
+
 /* return active item's name, or if none is active, window's name */
-char *window_get_active_name(WINDOW_REC *window)
+const char *window_get_active_name(WINDOW_REC *window)
 {
        g_return_val_if_fail(window != NULL, NULL);
 
        if (window->active != NULL)
-               return window->active->name;
+               return window->active->visible_name;
 
        return window->name;
 }
 
+#define WINDOW_LEVEL_MATCH(window, server, level) \
+       (((window)->level & level) && \
+        (server == NULL || (window)->active_server == server))
+
 WINDOW_REC *window_find_level(void *server, int level)
 {
-       WINDOW_REC *match;
        GSList *tmp;
+       WINDOW_REC *match;
 
        match = NULL;
        for (tmp = windows; tmp != NULL; tmp = tmp->next) {
                WINDOW_REC *rec = tmp->data;
 
-               if ((server == NULL || rec->active_server == server) &&
-                   (rec->level & level)) {
-                       if (server == NULL || rec->active_server == server)
+               if (WINDOW_LEVEL_MATCH(rec, server, level)) {
+                       /* prefer windows without any items */
+                       if (rec->items == NULL)
                                return rec;
-                       match = rec;
+
+                       if (match == NULL)
+                               match = rec;
+                       else if (active_win == rec) {
+                               /* prefer active window over others */
+                               match = rec;
+                       }
                }
        }
 
@@ -251,24 +293,47 @@ WINDOW_REC *window_find_level(void *server, int level)
 
 WINDOW_REC *window_find_closest(void *server, const char *name, int level)
 {
-       WINDOW_REC *window;
+       WINDOW_REC *window,*namewindow=NULL;
        WI_ITEM_REC *item;
+       int i;
 
        /* match by name */
        item = name == NULL ? NULL :
                window_item_find(server, name);
-       if (item != NULL)
-                return window_item_window(item);
+       if (item != NULL) {
+               namewindow = window_item_window(item);
+               if (namewindow != NULL &&
+                   ((namewindow->level & level) != 0 ||
+                    !settings_get_bool("window_check_level_first"))) {
+                       /* match, but if multiple windows have the same level
+                          we could be choosing a bad one here, eg.
+                          name=nick1 would get nick2's query instead of
+                          generic msgs window.
+
+                          And check for prefixed !channel name --Borys  */
+                       if (g_strcasecmp(name, item->visible_name) == 0 ||
+                           g_strcasecmp(name, (char *) window_item_get_target((WI_ITEM_REC *) item)) == 0)
+                               return namewindow;
+               }
+       }
 
-       /* match by level */
-       if (level != MSGLEVEL_HILIGHT)
-               level &= ~(MSGLEVEL_HILIGHT | MSGLEVEL_NOHILIGHT);
-       window = window_find_level(server, level);
-       if (window != NULL) return window;
+       /* prefer windows without items */
+       for (i = 0; i < 2; i++) {
+               /* match by level */
+               if (level != MSGLEVEL_HILIGHT)
+                       level &= ~(MSGLEVEL_HILIGHT | MSGLEVEL_NOHILIGHT);
+               window = window_find_level(server, level);
+               if (window != NULL && (i == 1 || window->items == NULL))
+                       return window;
+
+               /* match by level - ignore server */
+               window = window_find_level(NULL, level);
+               if (window != NULL && (i == 1 || window->items == NULL))
+                       return window;
+       }
 
-       /* match by level - ignore server */
-       window = window_find_level(NULL, level);
-       if (window != NULL) return window;
+       /* still return item's window if we didnt find anything */
+       if (namewindow != NULL) return namewindow;
 
        /* fallback to active */
        return active_win;
@@ -316,23 +381,11 @@ WINDOW_REC *window_find_item(SERVER_REC *server, const char *name)
 
        item = server == NULL ? NULL :
                window_item_find(server, name);
-       if (item == NULL && server == NULL) {
+       if (item == NULL) {
                /* not found from the active server - any server? */
                item = window_item_find(NULL, name);
        }
 
-       if (item == NULL) {
-               char *chan;
-
-               /* still nothing? maybe user just left the # in front of
-                  channel, try again with it.. */
-               chan = g_strdup_printf("#%s", name);
-               item = server == NULL ? NULL :
-                       window_item_find(server, chan);
-               if (item == NULL) item = window_item_find(NULL, chan);
-               g_free(chan);
-       }
-
        if (item == NULL)
                return 0;
 
@@ -478,7 +531,7 @@ void window_bind_remove_unsticky(WINDOW_REC *window)
        }
 }
 
-static void sig_server_looking(SERVER_REC *server)
+static void sig_server_connected(SERVER_REC *server)
 {
        GSList *tmp;
 
@@ -508,7 +561,8 @@ static void sig_server_disconnected(SERVER_REC *server)
        for (tmp = windows; tmp != NULL; tmp = tmp->next) {
                WINDOW_REC *rec = tmp->data;
 
-               if (rec->active_server == server) {
+               if (rec->active_server == server ||
+                   rec->connect_server == server) {
                        window_change_server(rec, rec->servertag != NULL ?
                                             NULL : new_server);
                }
@@ -594,9 +648,12 @@ void windows_init(void)
        daycheck = 0; daytag = -1;
        settings_add_bool("lookandfeel", "window_auto_change", FALSE);
        settings_add_bool("lookandfeel", "windows_auto_renumber", TRUE);
+       settings_add_bool("lookandfeel", "window_check_level_first", FALSE);
+       settings_add_level("lookandfeel", "window_default_level", "NONE");
 
        read_settings();
-       signal_add("server looking", (SIGNAL_FUNC) sig_server_looking);
+       signal_add("server looking", (SIGNAL_FUNC) sig_server_connected);
+       signal_add("server connected", (SIGNAL_FUNC) sig_server_connected);
        signal_add("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
        signal_add("server connect failed", (SIGNAL_FUNC) sig_server_disconnected);
        signal_add("setup changed", (SIGNAL_FUNC) read_settings);
@@ -607,7 +664,8 @@ void windows_deinit(void)
        if (daytag != -1) g_source_remove(daytag);
        if (daycheck == 1) signal_remove("print text", (SIGNAL_FUNC) sig_print_text);
 
-       signal_remove("server looking", (SIGNAL_FUNC) sig_server_looking);
+       signal_remove("server looking", (SIGNAL_FUNC) sig_server_connected);
+       signal_remove("server connected", (SIGNAL_FUNC) sig_server_connected);
        signal_remove("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
        signal_remove("server connect failed", (SIGNAL_FUNC) sig_server_disconnected);
        signal_remove("setup changed", (SIGNAL_FUNC) read_settings);